tabby-ai-assistant 1.0.8 → 1.0.10

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 (54) hide show
  1. package/dist/components/chat/ai-sidebar.component.d.ts +16 -3
  2. package/dist/components/chat/chat-input.component.d.ts +4 -0
  3. package/dist/components/chat/chat-interface.component.d.ts +22 -1
  4. package/dist/components/chat/chat-settings.component.d.ts +21 -11
  5. package/dist/components/settings/ai-settings-tab.component.d.ts +14 -4
  6. package/dist/components/settings/general-settings.component.d.ts +43 -12
  7. package/dist/components/settings/provider-config.component.d.ts +110 -5
  8. package/dist/components/settings/security-settings.component.d.ts +14 -4
  9. package/dist/i18n/index.d.ts +48 -0
  10. package/dist/i18n/translations/en-US.d.ts +5 -0
  11. package/dist/i18n/translations/ja-JP.d.ts +5 -0
  12. package/dist/i18n/translations/zh-CN.d.ts +5 -0
  13. package/dist/i18n/types.d.ts +198 -0
  14. package/dist/index.js +1 -1
  15. package/dist/services/chat/ai-sidebar.service.d.ts +23 -1
  16. package/dist/services/core/theme.service.d.ts +53 -0
  17. package/dist/services/core/toast.service.d.ts +15 -0
  18. package/package.json +1 -1
  19. package/src/components/chat/ai-sidebar.component.scss +468 -0
  20. package/src/components/chat/ai-sidebar.component.ts +47 -344
  21. package/src/components/chat/chat-input.component.scss +2 -2
  22. package/src/components/chat/chat-input.component.ts +16 -5
  23. package/src/components/chat/chat-interface.component.html +11 -11
  24. package/src/components/chat/chat-interface.component.scss +410 -4
  25. package/src/components/chat/chat-interface.component.ts +105 -14
  26. package/src/components/chat/chat-message.component.scss +3 -3
  27. package/src/components/chat/chat-message.component.ts +3 -2
  28. package/src/components/chat/chat-settings.component.html +95 -61
  29. package/src/components/chat/chat-settings.component.scss +224 -50
  30. package/src/components/chat/chat-settings.component.ts +56 -30
  31. package/src/components/security/risk-confirm-dialog.component.scss +7 -7
  32. package/src/components/settings/ai-settings-tab.component.html +27 -27
  33. package/src/components/settings/ai-settings-tab.component.scss +34 -20
  34. package/src/components/settings/ai-settings-tab.component.ts +59 -20
  35. package/src/components/settings/general-settings.component.html +69 -40
  36. package/src/components/settings/general-settings.component.scss +151 -58
  37. package/src/components/settings/general-settings.component.ts +168 -55
  38. package/src/components/settings/provider-config.component.html +183 -60
  39. package/src/components/settings/provider-config.component.scss +332 -153
  40. package/src/components/settings/provider-config.component.ts +268 -19
  41. package/src/components/settings/security-settings.component.html +70 -39
  42. package/src/components/settings/security-settings.component.scss +104 -8
  43. package/src/components/settings/security-settings.component.ts +48 -10
  44. package/src/i18n/index.ts +129 -0
  45. package/src/i18n/translations/en-US.ts +193 -0
  46. package/src/i18n/translations/ja-JP.ts +193 -0
  47. package/src/i18n/translations/zh-CN.ts +193 -0
  48. package/src/i18n/types.ts +224 -0
  49. package/src/index.ts +6 -0
  50. package/src/services/chat/ai-sidebar.service.ts +157 -5
  51. package/src/services/core/theme.service.ts +480 -0
  52. package/src/services/core/toast.service.ts +36 -0
  53. package/src/styles/ai-assistant.scss +8 -88
  54. package/src/styles/themes.scss +161 -0
@@ -9,6 +9,7 @@ export interface AiSidebarConfig {
9
9
  showInToolbar?: boolean;
10
10
  sidebarVisible?: boolean;
11
11
  sidebarCollapsed?: boolean;
12
+ sidebarWidth?: number;
12
13
  }
13
14
  /**
14
15
  * AI Sidebar 服务 - 管理 AI 聊天侧边栏的生命周期
@@ -24,8 +25,13 @@ export declare class AiSidebarService {
24
25
  private sidebarComponentRef;
25
26
  private sidebarElement;
26
27
  private styleElement;
28
+ private resizeHandle;
27
29
  private _isVisible;
28
- private readonly SIDEBAR_WIDTH;
30
+ private readonly MIN_WIDTH;
31
+ private readonly MAX_WIDTH;
32
+ private readonly DEFAULT_WIDTH;
33
+ private currentWidth;
34
+ private isResizing;
29
35
  /**
30
36
  * 侧边栏是否可见
31
37
  */
@@ -78,6 +84,22 @@ export declare class AiSidebarService {
78
84
  * 移除布局 CSS
79
85
  */
80
86
  private removeLayoutCSS;
87
+ /**
88
+ * 设置 resize handle 拖动逻辑
89
+ */
90
+ private setupResizeHandler;
91
+ /**
92
+ * 更新布局 CSS(resize 时调用)
93
+ */
94
+ private updateLayoutCSS;
95
+ /**
96
+ * 加载保存的侧边栏宽度
97
+ */
98
+ private loadSidebarWidth;
99
+ /**
100
+ * 保存侧边栏宽度到配置
101
+ */
102
+ private saveSidebarWidth;
81
103
  /**
82
104
  * 获取插件配置
83
105
  */
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 主题服务 - 统一管理所有 AI 助手主题
3
+ * 通过动态 <style> 注入实现主题切换
4
+ */
5
+ import { OnDestroy } from '@angular/core';
6
+ import { ConfigService } from 'tabby-core';
7
+ import { ConfigProviderService } from './config-provider.service';
8
+ export type ThemeType = 'auto' | 'light' | 'dark' | 'pixel' | 'tech';
9
+ export declare class ThemeService implements OnDestroy {
10
+ private config;
11
+ private tabbyConfig;
12
+ private currentTheme$;
13
+ private tabbySubscription?;
14
+ private styleElement;
15
+ readonly theme$: import("rxjs").Observable<ThemeType>;
16
+ private readonly allThemeClasses;
17
+ private readonly containerSelectors;
18
+ constructor(config: ConfigProviderService, tabbyConfig: ConfigService);
19
+ private init;
20
+ /**
21
+ * 获取当前主题
22
+ */
23
+ getCurrentTheme(): ThemeType;
24
+ /**
25
+ * 设置并应用主题
26
+ */
27
+ setTheme(theme: ThemeType): void;
28
+ /**
29
+ * 核心方法:动态注入主题样式
30
+ */
31
+ applyTheme(theme: ThemeType): void;
32
+ /**
33
+ * 生成 CSS 变量字符串
34
+ */
35
+ private buildCssVariables;
36
+ /**
37
+ * 生成主题特定样式(像素风格、科技风格等)
38
+ */
39
+ private buildThemeStyles;
40
+ /**
41
+ * 更新 body 和 html 的类名
42
+ */
43
+ private updateBodyClasses;
44
+ /**
45
+ * 获取 Tabby 当前的有效主题
46
+ */
47
+ private getTabbyEffectiveTheme;
48
+ /**
49
+ * 刷新所有容器的主题类
50
+ */
51
+ refreshContainers(): void;
52
+ ngOnDestroy(): void;
53
+ }
@@ -0,0 +1,15 @@
1
+ export interface ToastMessage {
2
+ id: string;
3
+ type: 'success' | 'error' | 'warning' | 'info';
4
+ message: string;
5
+ duration?: number;
6
+ }
7
+ export declare class ToastService {
8
+ private toastSubject;
9
+ toast$: import("rxjs").Observable<ToastMessage>;
10
+ show(type: ToastMessage['type'], message: string, duration?: number): void;
11
+ success(message: string, duration?: number): void;
12
+ error(message: string, duration?: number): void;
13
+ warning(message: string, duration?: number): void;
14
+ info(message: string, duration?: number): void;
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tabby-ai-assistant",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Tabby终端AI助手插件 - 支持多AI提供商(OpenAI、Anthropic、Minimax、GLM、Ollama、vLLM)",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -0,0 +1,468 @@
1
+ // AI Sidebar 组件样式
2
+ // 使用 CSS 变量支持主题切换
3
+
4
+ :host {
5
+ display: block;
6
+ height: 100%;
7
+ width: 100%;
8
+ }
9
+
10
+ .ai-sidebar-container {
11
+ display: flex;
12
+ flex-direction: column;
13
+ height: 100%;
14
+ background: var(--ai-bg-primary, #1a1a1a);
15
+ color: var(--ai-text-primary, #f8f9fa);
16
+ position: relative;
17
+ }
18
+
19
+ // Header
20
+ .ai-sidebar-header {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ align-items: center;
24
+ padding: 12px 16px;
25
+ background: var(--ai-bg-secondary, #2d2d2d);
26
+ border-bottom: 1px solid var(--ai-border, #4a4a4a);
27
+
28
+ .header-title {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 8px;
32
+ font-weight: 600;
33
+ font-size: 14px;
34
+
35
+ .header-icon {
36
+ color: var(--ai-primary, #4dabf7);
37
+ }
38
+
39
+ .provider-badge {
40
+ padding: 2px 8px;
41
+ background: var(--ai-bg-tertiary, #3d3d3d);
42
+ border-radius: 10px;
43
+ font-size: 11px;
44
+ font-weight: 400;
45
+ color: var(--ai-text-secondary, #adb5bd);
46
+ }
47
+ }
48
+
49
+ .header-actions {
50
+ display: flex;
51
+ gap: 4px;
52
+
53
+ .btn {
54
+ padding: 4px 8px;
55
+ color: var(--ai-text-secondary, #adb5bd);
56
+ border: none;
57
+ background: transparent;
58
+ cursor: pointer;
59
+ border-radius: 4px;
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ transition: all 0.2s;
64
+
65
+ &:hover {
66
+ color: var(--ai-primary, #4dabf7);
67
+ background: var(--ai-bg-tertiary, #3d3d3d);
68
+ }
69
+
70
+ &.btn-close-sidebar:hover {
71
+ color: var(--ai-danger, #ff6b6b);
72
+ }
73
+ }
74
+ }
75
+ }
76
+
77
+ // Messages container
78
+ .ai-sidebar-messages {
79
+ flex: 1 !important;
80
+ height: 0;
81
+ overflow-y: auto !important;
82
+ overflow-x: hidden !important;
83
+ padding: 12px;
84
+ scroll-behavior: smooth;
85
+
86
+ &::-webkit-scrollbar {
87
+ width: 6px;
88
+ }
89
+
90
+ &::-webkit-scrollbar-track {
91
+ background: transparent;
92
+ }
93
+
94
+ &::-webkit-scrollbar-thumb {
95
+ background: var(--ai-border, #4a4a4a);
96
+ border-radius: 3px;
97
+
98
+ &:hover {
99
+ background: var(--ai-text-secondary, #adb5bd);
100
+ }
101
+ }
102
+ }
103
+
104
+ // Message items
105
+ .message-item {
106
+ display: flex;
107
+ gap: 10px;
108
+ align-items: flex-start;
109
+ margin-bottom: 12px;
110
+ animation: fadeIn 0.3s ease-in;
111
+
112
+ &:last-child {
113
+ margin-bottom: 0;
114
+ }
115
+
116
+ @keyframes fadeIn {
117
+ from {
118
+ opacity: 0;
119
+ transform: translateY(10px);
120
+ }
121
+ to {
122
+ opacity: 1;
123
+ transform: translateY(0);
124
+ }
125
+ }
126
+
127
+ &.user {
128
+ flex-direction: row-reverse;
129
+
130
+ .message-content {
131
+ background: var(--ai-user-message, #1e3a5f);
132
+ border-radius: 16px 16px 4px 16px;
133
+ border-left: 3px solid var(--ai-primary);
134
+ }
135
+
136
+ .message-avatar {
137
+ background: linear-gradient(135deg, var(--ai-primary) 0%, var(--ai-primary-hover) 100%);
138
+ color: #fff;
139
+ }
140
+ }
141
+
142
+ &.assistant {
143
+ .message-content {
144
+ background: var(--ai-assistant-message, #2d3748);
145
+ border-radius: 12px 12px 12px 0;
146
+ }
147
+
148
+ .message-avatar {
149
+ background: linear-gradient(135deg, var(--ai-secondary) 0%, var(--ai-text-secondary) 100%);
150
+ color: var(--ai-text-primary);
151
+ }
152
+ }
153
+
154
+ &.system {
155
+ justify-content: center;
156
+
157
+ .message-avatar {
158
+ display: none;
159
+ }
160
+
161
+ .message-content {
162
+ background: var(--ai-system-message, #3a3a3a);
163
+ border-radius: 8px;
164
+ font-style: italic;
165
+ text-align: center;
166
+ }
167
+ }
168
+
169
+ &.loading {
170
+ opacity: 0.7;
171
+ }
172
+
173
+ .message-avatar {
174
+ width: 28px;
175
+ height: 28px;
176
+ border-radius: 50%;
177
+ display: flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ flex-shrink: 0;
181
+ font-size: 12px;
182
+ }
183
+
184
+ .message-content {
185
+ max-width: 85%;
186
+ min-width: 60%;
187
+ padding: 10px 14px;
188
+
189
+ .message-header {
190
+ display: flex;
191
+ justify-content: space-between;
192
+ align-items: center;
193
+ margin-bottom: 4px;
194
+ font-size: 11px;
195
+ opacity: 0.8;
196
+
197
+ .message-role {
198
+ font-weight: 600;
199
+ color: var(--ai-primary, #4dabf7);
200
+ }
201
+
202
+ .message-time {
203
+ color: var(--ai-text-secondary, #adb5bd);
204
+ font-size: 11px;
205
+ }
206
+ }
207
+
208
+ .message-text {
209
+ font-size: 14px;
210
+ line-height: 1.6;
211
+ color: var(--ai-text-primary, #f8f9fa);
212
+ word-wrap: break-word;
213
+ white-space: pre-wrap;
214
+
215
+ // 代码块样式
216
+ code {
217
+ background: var(--ai-bg-tertiary, #3d3d3d);
218
+ padding: 2px 6px;
219
+ border-radius: 4px;
220
+ font-family: 'Courier New', 'Consolas', monospace;
221
+ font-size: 13px;
222
+ }
223
+
224
+ pre {
225
+ background: var(--ai-bg-tertiary, #3d3d3d);
226
+ padding: 12px;
227
+ border-radius: 8px;
228
+ overflow-x: auto;
229
+ margin: 8px 0;
230
+
231
+ code {
232
+ background: transparent;
233
+ padding: 0;
234
+ border-radius: 0;
235
+ }
236
+ }
237
+
238
+ // Markdown 表格样式
239
+ table {
240
+ width: 100%;
241
+ border-collapse: collapse;
242
+ margin: 8px 0;
243
+ font-size: 12px;
244
+
245
+ th, td {
246
+ border: 1px solid var(--ai-border, #4a4a4a);
247
+ padding: 6px 10px;
248
+ text-align: left;
249
+ }
250
+
251
+ th {
252
+ background: var(--ai-bg-tertiary, #3d3d3d);
253
+ font-weight: 600;
254
+ }
255
+
256
+ tr:nth-child(even) {
257
+ background: rgba(var(--ai-bg-secondary, #2d2d2d), 0.3);
258
+ }
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ // Loading dots
265
+ .loading-dots {
266
+ display: flex;
267
+ gap: 4px;
268
+ padding: 4px 0;
269
+
270
+ span {
271
+ width: 8px;
272
+ height: 8px;
273
+ border-radius: 50%;
274
+ background: var(--ai-primary, #4dabf7);
275
+ animation: loadingDot 1.4s infinite ease-in-out both;
276
+
277
+ &:nth-child(1) {
278
+ animation-delay: -0.32s;
279
+ }
280
+
281
+ &:nth-child(2) {
282
+ animation-delay: -0.16s;
283
+ }
284
+
285
+ &:nth-child(3) {
286
+ animation-delay: 0s;
287
+ }
288
+ }
289
+ }
290
+
291
+ @keyframes loadingDot {
292
+ 0%, 80%, 100% {
293
+ transform: scale(0.6);
294
+ opacity: 0.5;
295
+ }
296
+ 40% {
297
+ transform: scale(1);
298
+ opacity: 1;
299
+ }
300
+ }
301
+
302
+ // Scroll buttons
303
+ .scroll-btn {
304
+ position: absolute !important;
305
+ right: 20px;
306
+ width: 32px;
307
+ height: 32px;
308
+ border-radius: 50%;
309
+ border: 1px solid var(--ai-border, #4a4a4a);
310
+ background: var(--ai-bg-secondary, #2d2d2d);
311
+ color: var(--ai-text-primary, #f8f9fa);
312
+ cursor: pointer;
313
+ display: flex;
314
+ align-items: center;
315
+ justify-content: center;
316
+ z-index: 100 !important;
317
+ transition: all 0.2s ease;
318
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
319
+
320
+ &:hover {
321
+ background: var(--ai-bg-tertiary, #3d3d3d);
322
+ border-color: var(--ai-primary, #4dabf7);
323
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
324
+ }
325
+
326
+ &.scroll-top {
327
+ bottom: 120px;
328
+ }
329
+
330
+ &.scroll-bottom {
331
+ bottom: 75px;
332
+ }
333
+ }
334
+
335
+ // Input area
336
+ .ai-sidebar-input {
337
+ padding: 12px;
338
+ background: var(--ai-bg-secondary, #2d2d2d);
339
+ border-top: 1px solid var(--ai-border, #4a4a4a);
340
+
341
+ .input-container {
342
+ display: flex;
343
+ gap: 8px;
344
+ align-items: flex-end;
345
+ background: var(--ai-bg-primary, #1a1a1a);
346
+ border: 1px solid var(--ai-border, #4a4a4a);
347
+ border-radius: 12px;
348
+ padding: 4px;
349
+ transition: border-color 0.2s ease;
350
+
351
+ &:focus-within {
352
+ border-color: var(--ai-primary, #4dabf7);
353
+ }
354
+ }
355
+
356
+ .message-input {
357
+ flex: 1;
358
+ min-height: 36px;
359
+ max-height: 100px;
360
+ padding: 8px 12px;
361
+ border: none;
362
+ border-radius: 8px;
363
+ background: transparent;
364
+ color: var(--ai-text-primary, #f8f9fa);
365
+ font-size: 14px;
366
+ font-family: inherit;
367
+ resize: none;
368
+ outline: none;
369
+ line-height: 1.4;
370
+
371
+ &::placeholder {
372
+ color: var(--ai-text-secondary, #adb5bd);
373
+ font-size: 13px;
374
+ }
375
+
376
+ &:disabled {
377
+ opacity: 0.6;
378
+ cursor: not-allowed;
379
+ }
380
+ }
381
+
382
+ .send-btn {
383
+ width: 36px;
384
+ height: 36px;
385
+ border: none;
386
+ border-radius: 8px;
387
+ background: var(--ai-primary, #4dabf7);
388
+ color: #fff;
389
+ cursor: pointer;
390
+ display: flex;
391
+ align-items: center;
392
+ justify-content: center;
393
+ transition: all 0.2s ease;
394
+ flex-shrink: 0;
395
+
396
+ &:hover:not(:disabled) {
397
+ background: var(--ai-primary-hover, #339af0);
398
+ transform: scale(1.05);
399
+ box-shadow: 0 2px 8px rgba(77, 171, 247, 0.3);
400
+ }
401
+
402
+ &:disabled {
403
+ opacity: 0.5;
404
+ cursor: not-allowed;
405
+ background: var(--ai-bg-tertiary, #3d3d3d);
406
+ }
407
+ }
408
+
409
+ .input-footer {
410
+ margin-top: 6px;
411
+ display: flex;
412
+ justify-content: flex-end;
413
+
414
+ .char-count {
415
+ font-size: 11px;
416
+ color: var(--ai-text-secondary, #adb5bd);
417
+
418
+ &.warning {
419
+ color: var(--ai-warning, #fcc419);
420
+ }
421
+
422
+ &.danger {
423
+ color: var(--ai-danger, #ff6b6b);
424
+ }
425
+ }
426
+ }
427
+ }
428
+
429
+ // Resize handle
430
+ .ai-sidebar-resize-handle {
431
+ position: absolute;
432
+ top: 0;
433
+ right: -4px;
434
+ width: 8px;
435
+ height: 100%;
436
+ cursor: ew-resize;
437
+ background: transparent;
438
+ z-index: 1001;
439
+ transition: background 0.2s;
440
+
441
+ &:hover {
442
+ background: linear-gradient(to right,
443
+ transparent,
444
+ var(--ai-primary, #4dabf7) 40%,
445
+ var(--ai-primary, #4dabf7) 60%,
446
+ transparent
447
+ ) !important;
448
+ }
449
+
450
+ &:active {
451
+ background: var(--ai-primary, #4dabf7) !important;
452
+ }
453
+ }
454
+
455
+ // Responsive
456
+ @media (max-width: 768px) {
457
+ .ai-sidebar-header {
458
+ padding: 10px 12px;
459
+ }
460
+
461
+ .ai-sidebar-messages {
462
+ padding: 12px;
463
+ }
464
+
465
+ .ai-sidebar-input {
466
+ padding: 10px 12px;
467
+ }
468
+ }