tabby-ai-assistant 1.0.0

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 (134) hide show
  1. package/README.md +232 -0
  2. package/dist/components/chat/chat-input.component.d.ts +65 -0
  3. package/dist/components/chat/chat-interface.component.d.ts +71 -0
  4. package/dist/components/chat/chat-message.component.d.ts +53 -0
  5. package/dist/components/chat/chat-settings.component.d.ts +62 -0
  6. package/dist/components/common/error-message.component.d.ts +11 -0
  7. package/dist/components/common/loading-spinner.component.d.ts +4 -0
  8. package/dist/components/security/consent-dialog.component.d.ts +11 -0
  9. package/dist/components/security/password-prompt.component.d.ts +10 -0
  10. package/dist/components/security/risk-confirm-dialog.component.d.ts +36 -0
  11. package/dist/components/settings/ai-settings-tab.component.d.ts +72 -0
  12. package/dist/components/settings/general-settings.component.d.ts +60 -0
  13. package/dist/components/settings/provider-config.component.d.ts +182 -0
  14. package/dist/components/settings/security-settings.component.d.ts +23 -0
  15. package/dist/components/terminal/ai-toolbar-button.component.d.ts +10 -0
  16. package/dist/components/terminal/command-preview.component.d.ts +15 -0
  17. package/dist/components/terminal/command-suggestion.component.d.ts +16 -0
  18. package/dist/index.d.ts +8 -0
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.LICENSE.txt +18 -0
  21. package/dist/main.d.ts +8 -0
  22. package/dist/providers/tabby/ai-config.provider.d.ts +18 -0
  23. package/dist/providers/tabby/ai-hotkey.provider.d.ts +21 -0
  24. package/dist/providers/tabby/ai-settings-tab.provider.d.ts +11 -0
  25. package/dist/providers/tabby/ai-toolbar-button.provider.d.ts +17 -0
  26. package/dist/services/chat/chat-history.service.d.ts +67 -0
  27. package/dist/services/chat/chat-session.service.d.ts +58 -0
  28. package/dist/services/chat/command-generator.service.d.ts +49 -0
  29. package/dist/services/core/ai-assistant.service.d.ts +88 -0
  30. package/dist/services/core/ai-provider-manager.service.d.ts +119 -0
  31. package/dist/services/core/config-provider.service.d.ts +137 -0
  32. package/dist/services/core/logger.service.d.ts +21 -0
  33. package/dist/services/providers/anthropic-provider.service.d.ts +39 -0
  34. package/dist/services/providers/base-provider.service.d.ts +137 -0
  35. package/dist/services/providers/glm-provider.service.d.ts +91 -0
  36. package/dist/services/providers/minimax-provider.service.d.ts +93 -0
  37. package/dist/services/providers/openai-compatible.service.d.ts +39 -0
  38. package/dist/services/providers/openai-provider.service.d.ts +38 -0
  39. package/dist/services/security/consent-manager.service.d.ts +65 -0
  40. package/dist/services/security/password-manager.service.d.ts +67 -0
  41. package/dist/services/security/risk-assessment.service.d.ts +65 -0
  42. package/dist/services/security/security-validator.service.d.ts +36 -0
  43. package/dist/services/terminal/command-analyzer.service.d.ts +20 -0
  44. package/dist/services/terminal/context-menu.service.d.ts +24 -0
  45. package/dist/services/terminal/hotkey.service.d.ts +28 -0
  46. package/dist/services/terminal/terminal-context.service.d.ts +100 -0
  47. package/dist/types/ai.types.d.ts +107 -0
  48. package/dist/types/provider.types.d.ts +105 -0
  49. package/dist/types/security.types.d.ts +85 -0
  50. package/dist/types/terminal.types.d.ts +150 -0
  51. package/dist/utils/encryption.utils.d.ts +83 -0
  52. package/dist/utils/formatting.utils.d.ts +106 -0
  53. package/dist/utils/validation.utils.d.ts +83 -0
  54. package/integration-test-output.txt +50 -0
  55. package/integration-tests/api-integration.test.ts +183 -0
  56. package/jest.config.js +47 -0
  57. package/package.json +73 -0
  58. package/setup-jest.ts +37 -0
  59. package/src/components/chat/chat-input.component.html +61 -0
  60. package/src/components/chat/chat-input.component.scss +183 -0
  61. package/src/components/chat/chat-input.component.ts +149 -0
  62. package/src/components/chat/chat-interface.component.html +119 -0
  63. package/src/components/chat/chat-interface.component.scss +354 -0
  64. package/src/components/chat/chat-interface.component.ts +224 -0
  65. package/src/components/chat/chat-message.component.html +65 -0
  66. package/src/components/chat/chat-message.component.scss +178 -0
  67. package/src/components/chat/chat-message.component.ts +93 -0
  68. package/src/components/chat/chat-settings.component.html +132 -0
  69. package/src/components/chat/chat-settings.component.scss +172 -0
  70. package/src/components/chat/chat-settings.component.ts +168 -0
  71. package/src/components/common/error-message.component.ts +124 -0
  72. package/src/components/common/loading-spinner.component.ts +72 -0
  73. package/src/components/security/consent-dialog.component.ts +77 -0
  74. package/src/components/security/password-prompt.component.ts +79 -0
  75. package/src/components/security/risk-confirm-dialog.component.html +87 -0
  76. package/src/components/security/risk-confirm-dialog.component.scss +360 -0
  77. package/src/components/security/risk-confirm-dialog.component.ts +96 -0
  78. package/src/components/settings/ai-settings-tab.component.html +140 -0
  79. package/src/components/settings/ai-settings-tab.component.scss +371 -0
  80. package/src/components/settings/ai-settings-tab.component.ts +193 -0
  81. package/src/components/settings/general-settings.component.html +103 -0
  82. package/src/components/settings/general-settings.component.scss +285 -0
  83. package/src/components/settings/general-settings.component.ts +123 -0
  84. package/src/components/settings/provider-config.component.html +95 -0
  85. package/src/components/settings/provider-config.component.scss +60 -0
  86. package/src/components/settings/provider-config.component.ts +206 -0
  87. package/src/components/settings/security-settings.component.html +51 -0
  88. package/src/components/settings/security-settings.component.scss +66 -0
  89. package/src/components/settings/security-settings.component.ts +71 -0
  90. package/src/components/terminal/ai-toolbar-button.component.ts +49 -0
  91. package/src/components/terminal/command-preview.component.ts +185 -0
  92. package/src/components/terminal/command-suggestion.component.ts +128 -0
  93. package/src/index.ts +163 -0
  94. package/src/main.ts +16 -0
  95. package/src/providers/tabby/ai-config.provider.ts +70 -0
  96. package/src/providers/tabby/ai-hotkey.provider.ts +55 -0
  97. package/src/providers/tabby/ai-settings-tab.provider.ts +18 -0
  98. package/src/providers/tabby/ai-toolbar-button.provider.ts +49 -0
  99. package/src/services/chat/chat-history.service.ts +239 -0
  100. package/src/services/chat/chat-session.service.spec.ts +249 -0
  101. package/src/services/chat/chat-session.service.ts +180 -0
  102. package/src/services/chat/command-generator.service.ts +301 -0
  103. package/src/services/core/ai-assistant.service.ts +334 -0
  104. package/src/services/core/ai-provider-manager.service.ts +314 -0
  105. package/src/services/core/config-provider.service.ts +347 -0
  106. package/src/services/core/logger.service.ts +104 -0
  107. package/src/services/providers/anthropic-provider.service.ts +373 -0
  108. package/src/services/providers/base-provider.service.ts +369 -0
  109. package/src/services/providers/glm-provider.service.ts +467 -0
  110. package/src/services/providers/minimax-provider.service.ts +427 -0
  111. package/src/services/providers/openai-compatible.service.ts +394 -0
  112. package/src/services/providers/openai-provider.service.ts +376 -0
  113. package/src/services/security/consent-manager.service.ts +332 -0
  114. package/src/services/security/password-manager.service.ts +188 -0
  115. package/src/services/security/risk-assessment.service.ts +340 -0
  116. package/src/services/security/security-validator.service.ts +143 -0
  117. package/src/services/terminal/command-analyzer.service.ts +43 -0
  118. package/src/services/terminal/context-menu.service.ts +45 -0
  119. package/src/services/terminal/hotkey.service.ts +53 -0
  120. package/src/services/terminal/terminal-context.service.ts +317 -0
  121. package/src/styles/ai-assistant.scss +449 -0
  122. package/src/types/ai.types.ts +133 -0
  123. package/src/types/provider.types.ts +147 -0
  124. package/src/types/security.types.ts +103 -0
  125. package/src/types/terminal.types.ts +186 -0
  126. package/src/utils/encryption.utils.spec.ts +250 -0
  127. package/src/utils/encryption.utils.ts +271 -0
  128. package/src/utils/formatting.utils.ts +359 -0
  129. package/src/utils/validation.utils.spec.ts +225 -0
  130. package/src/utils/validation.utils.ts +314 -0
  131. package/tsconfig.json +45 -0
  132. package/webpack-docker.config.js +42 -0
  133. package/webpack.config.js +59 -0
  134. package/webpack.config.js.backup +57 -0
@@ -0,0 +1,106 @@
1
+ /**
2
+ * 格式化工具类
3
+ * 提供各种数据格式化功能
4
+ */
5
+ /**
6
+ * 格式化文件大小
7
+ */
8
+ export declare function formatFileSize(bytes: number, decimals?: number): string;
9
+ /**
10
+ * 格式化持续时间
11
+ */
12
+ export declare function formatDuration(milliseconds: number): string;
13
+ /**
14
+ * 格式化日期
15
+ */
16
+ export declare function formatDate(date: Date, format?: 'short' | 'long' | 'relative'): string;
17
+ /**
18
+ * 格式化数字
19
+ */
20
+ export declare function formatNumber(num: number, decimals?: number): string;
21
+ /**
22
+ * 格式化百分比
23
+ */
24
+ export declare function formatPercentage(value: number, total: number, decimals?: number): string;
25
+ /**
26
+ * 格式化令牌数量
27
+ */
28
+ export declare function formatTokens(tokens: number): string;
29
+ /**
30
+ * 格式化价格
31
+ */
32
+ export declare function formatPrice(amount: number, currency?: string): string;
33
+ /**
34
+ * 格式化命令输出(添加语法高亮)
35
+ */
36
+ export declare function formatCommandOutput(output: string): string;
37
+ /**
38
+ * 格式化风险级别
39
+ */
40
+ export declare function formatRiskLevel(level: string): {
41
+ text: string;
42
+ class: string;
43
+ };
44
+ /**
45
+ * 格式化置信度
46
+ */
47
+ export declare function formatConfidence(confidence: number): {
48
+ text: string;
49
+ class: string;
50
+ };
51
+ /**
52
+ * 截断文本
53
+ */
54
+ export declare function truncateText(text: string, maxLength: number, suffix?: string): string;
55
+ /**
56
+ * 格式化错误信息
57
+ */
58
+ export declare function formatError(error: Error | string): string;
59
+ /**
60
+ * 格式化字节数组
61
+ */
62
+ export declare function formatBytes(bytes: number[], separator?: string): string;
63
+ /**
64
+ * 格式化JSON(美化输出)
65
+ */
66
+ export declare function formatJson(json: string | object, indent?: number): string;
67
+ /**
68
+ * 格式化速度(bytes per second)
69
+ */
70
+ export declare function formatSpeed(bytesPerSecond: number): string;
71
+ /**
72
+ * 格式化进度条
73
+ */
74
+ export declare function formatProgressBar(current: number, total: number, width?: number): string;
75
+ /**
76
+ * 格式化文件路径(显示简化版本)
77
+ */
78
+ export declare function formatFilePath(path: string, maxLength?: number): string;
79
+ /**
80
+ * 格式化列表为文本
81
+ */
82
+ export declare function formatList(items: string[], delimiter?: string): string;
83
+ /**
84
+ * 格式化代码块
85
+ */
86
+ export declare function formatCodeBlock(code: string, language?: string): string;
87
+ /**
88
+ * 转义HTML
89
+ */
90
+ export declare function escapeHtml(text: string): string;
91
+ /**
92
+ * 清理文本(移除多余空白)
93
+ */
94
+ export declare function cleanText(text: string): string;
95
+ /**
96
+ * 驼峰命名格式化
97
+ */
98
+ export declare function toCamelCase(str: string): string;
99
+ /**
100
+ * 短横线命名格式化
101
+ */
102
+ export declare function toKebabCase(str: string): string;
103
+ /**
104
+ * 下划线命名格式化
105
+ */
106
+ export declare function toSnakeCase(str: string): string;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 验证工具类
3
+ * 提供各种数据验证和格式检查功能
4
+ */
5
+ /**
6
+ * 验证API密钥格式
7
+ */
8
+ export declare function validateApiKey(apiKey: string, provider: string): {
9
+ valid: boolean;
10
+ error?: string;
11
+ };
12
+ /**
13
+ * 验证URL格式
14
+ */
15
+ export declare function validateUrl(url: string): {
16
+ valid: boolean;
17
+ error?: string;
18
+ };
19
+ /**
20
+ * 验证模型名称
21
+ */
22
+ export declare function validateModel(model: string, _provider: string): {
23
+ valid: boolean;
24
+ error?: string;
25
+ };
26
+ /**
27
+ * 验证温度参数
28
+ */
29
+ export declare function validateTemperature(temperature: number): {
30
+ valid: boolean;
31
+ error?: string;
32
+ };
33
+ /**
34
+ * 验证最大令牌数
35
+ */
36
+ export declare function validateMaxTokens(maxTokens: number): {
37
+ valid: boolean;
38
+ error?: string;
39
+ };
40
+ /**
41
+ * 验证命令字符串
42
+ */
43
+ export declare function validateCommand(command: string): {
44
+ valid: boolean;
45
+ error?: string;
46
+ };
47
+ /**
48
+ * 验证邮箱格式
49
+ */
50
+ export declare function validateEmail(email: string): {
51
+ valid: boolean;
52
+ error?: string;
53
+ };
54
+ /**
55
+ * 验证密码强度
56
+ */
57
+ export declare function validatePassword(password: string): {
58
+ valid: boolean;
59
+ error?: string;
60
+ score: number;
61
+ };
62
+ /**
63
+ * 验证端口号
64
+ */
65
+ export declare function validatePort(port: number): {
66
+ valid: boolean;
67
+ error?: string;
68
+ };
69
+ /**
70
+ * 验证JSON格式
71
+ */
72
+ export declare function validateJson(jsonString: string): {
73
+ valid: boolean;
74
+ error?: string;
75
+ data?: any;
76
+ };
77
+ /**
78
+ * 验证文件路径
79
+ */
80
+ export declare function validateFilePath(path: string): {
81
+ valid: boolean;
82
+ error?: string;
83
+ };
@@ -0,0 +1,50 @@
1
+
2
+ > tabby-ai-assistant@1.0.0 test
3
+ > jest integration-tests/api-integration.test.ts --silent=false
4
+
5
+ FAIL integration-tests/api-integration.test.ts (12.559 s)
6
+ GLM API Integration Tests
7
+ √ should connect to GLM API successfully (490 ms)
8
+ × should handle API errors gracefully (467 ms)
9
+ × should generate command from natural language (474 ms)
10
+ OpenAI API Integration Tests
11
+ √ should test OpenAI API connectivity (10032 ms)
12
+
13
+ ● GLM API Integration Tests › should handle API errors gracefully
14
+
15
+ expect(received).toBe(expected) // Object.is equality
16
+
17
+ Expected: 401
18
+ Received: undefined
19
+
20
+   103 | console.log('✅ 错误处理测试通过');
21
+  104 | console.log('捕获到预期错误:', error.message);
22
+ > 105 | expect(error.response?.status).toBe(401);
23
+  | ^
24
+  106 | }
25
+  107 | }, 30000);
26
+  108 |
27
+
28
+ at Object.<anonymous> (integration-tests/api-integration.test.ts:105:44)
29
+
30
+ ● GLM API Integration Tests › should generate command from natural language
31
+
32
+ expect(received).toBeDefined()
33
+
34
+ Received: undefined
35
+
36
+   134 |
37
+  135 | expect(response.status).toBe(200);
38
+ > 136 | expect(response.data.content?.[0]?.text).toBeDefined();
39
+  | ^
40
+  137 | } catch (error: any) {
41
+  138 | console.error('❌ 命令生成测试失败:', error.message);
42
+  139 | throw error;
43
+
44
+ at Object.<anonymous> (integration-tests/api-integration.test.ts:136:54)
45
+
46
+ Test Suites: 1 failed, 1 total
47
+ Tests: 2 failed, 2 passed, 4 total
48
+ Snapshots: 0 total
49
+ Time: 13.256 s
50
+ Ran all test suites matching /integration-tests\\api-integration.test.ts/i.
@@ -0,0 +1,183 @@
1
+ /**
2
+ * 集成测试 - AI提供商API调用
3
+ * 使用真实API进行测试
4
+ */
5
+
6
+ import axios from 'axios';
7
+
8
+ // GLM API配置
9
+ const GLM_API_CONFIG = {
10
+ apiKey: 'e247e649f1534651a3f12bfe47d2c42f.qlrVZegtSW0nFdMI',
11
+ baseURL: 'https://open.bigmodel.cn/api/anthropic',
12
+ model: 'glm-4'
13
+ };
14
+
15
+ describe('GLM API Integration Tests', () => {
16
+ it('should connect to GLM API successfully', async () => {
17
+ try {
18
+ console.log('🔄 开始连接GLM API...');
19
+ console.log('API配置:', {
20
+ baseURL: GLM_API_CONFIG.baseURL,
21
+ model: GLM_API_CONFIG.model,
22
+ apiKeyLength: GLM_API_CONFIG.apiKey.length
23
+ });
24
+
25
+ const response = await axios.post(
26
+ `${GLM_API_CONFIG.baseURL}/messages`,
27
+ {
28
+ model: GLM_API_CONFIG.model,
29
+ max_tokens: 100,
30
+ messages: [
31
+ {
32
+ role: 'user',
33
+ content: 'Hello, can you respond?'
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ 'Authorization': `Bearer ${GLM_API_CONFIG.apiKey}`
41
+ },
42
+ timeout: 30000
43
+ }
44
+ );
45
+
46
+ console.log('✅ GLM API连接成功');
47
+ console.log('响应状态:', response.status);
48
+ console.log('响应数据结构:', JSON.stringify(response.data, null, 2));
49
+
50
+ expect(response.status).toBe(200);
51
+ expect(response.data).toBeDefined();
52
+ // GLM API可能使用不同的响应格式
53
+ if (response.data.content) {
54
+ expect(response.data.content).toBeDefined();
55
+ } else if (response.data.choices) {
56
+ expect(response.data.choices).toBeDefined();
57
+ console.log('choices格式响应:', response.data.choices);
58
+ }
59
+ } catch (error: any) {
60
+ console.error('❌ GLM API连接失败');
61
+ console.error('错误类型:', error.name);
62
+ console.error('错误信息:', error.message);
63
+ console.error('完整错误对象:', error.toJSON ? error.toJSON() : error);
64
+ if (error.response) {
65
+ console.error('响应状态:', error.response.status);
66
+ console.error('响应头:', error.response.headers);
67
+ console.error('响应数据:', error.response.data);
68
+ } else if (error.request) {
69
+ console.error('请求配置:', error.config);
70
+ console.error('无响应返回 - 可能是网络问题或超时');
71
+ }
72
+ throw error;
73
+ }
74
+ }, 60000);
75
+
76
+ it('should handle API errors gracefully', async () => {
77
+ try {
78
+ // 使用无效的API key测试错误处理
79
+ const response = await axios.post(
80
+ `${GLM_API_CONFIG.baseURL}/messages`,
81
+ {
82
+ model: GLM_API_CONFIG.model,
83
+ max_tokens: 100,
84
+ messages: [
85
+ {
86
+ role: 'user',
87
+ content: 'Test'
88
+ }
89
+ ]
90
+ },
91
+ {
92
+ headers: {
93
+ 'Content-Type': 'application/json',
94
+ 'Authorization': 'Bearer invalid-key'
95
+ },
96
+ timeout: 10000
97
+ }
98
+ );
99
+
100
+ // 如果到这里说明没有抛出错误,测试失败
101
+ fail('应该抛出API错误');
102
+ } catch (error: any) {
103
+ console.log('✅ 错误处理测试通过');
104
+ console.log('捕获到预期错误:', error.message);
105
+ expect(error.response?.status).toBe(401);
106
+ }
107
+ }, 30000);
108
+
109
+ it('should generate command from natural language', async () => {
110
+ try {
111
+ const response = await axios.post(
112
+ `${GLM_API_CONFIG.baseURL}/messages`,
113
+ {
114
+ model: GLM_API_CONFIG.model,
115
+ max_tokens: 200,
116
+ messages: [
117
+ {
118
+ role: 'user',
119
+ content: `请将以下自然语言转换为终端命令:"列出当前目录的所有文件"`
120
+ }
121
+ ]
122
+ },
123
+ {
124
+ headers: {
125
+ 'Content-Type': 'application/json',
126
+ 'Authorization': `Bearer ${GLM_API_CONFIG.apiKey}`
127
+ },
128
+ timeout: 30000
129
+ }
130
+ );
131
+
132
+ console.log('✅ 命令生成测试成功');
133
+ console.log('生成内容:', response.data.content?.[0]?.text);
134
+
135
+ expect(response.status).toBe(200);
136
+ expect(response.data.content?.[0]?.text).toBeDefined();
137
+ } catch (error: any) {
138
+ console.error('❌ 命令生成测试失败:', error.message);
139
+ throw error;
140
+ }
141
+ }, 60000);
142
+ });
143
+
144
+ // OpenAI API测试
145
+ const OPENAI_API_CONFIG = {
146
+ apiKey: 'sk-test-key', // 测试密钥
147
+ baseURL: 'https://api.openai.com/v1',
148
+ model: 'gpt-3.5-turbo'
149
+ };
150
+
151
+ describe('OpenAI API Integration Tests', () => {
152
+ it('should test OpenAI API connectivity', async () => {
153
+ try {
154
+ const response = await axios.post(
155
+ `${OPENAI_API_CONFIG.baseURL}/chat/completions`,
156
+ {
157
+ model: OPENAI_API_CONFIG.model,
158
+ max_tokens: 100,
159
+ messages: [
160
+ {
161
+ role: 'user',
162
+ content: 'Hello'
163
+ }
164
+ ]
165
+ },
166
+ {
167
+ headers: {
168
+ 'Content-Type': 'application/json',
169
+ 'Authorization': `Bearer ${OPENAI_API_CONFIG.apiKey}`
170
+ },
171
+ timeout: 10000
172
+ }
173
+ );
174
+
175
+ console.log('✅ OpenAI API测试完成');
176
+ console.log('响应状态:', response.status);
177
+ } catch (error: any) {
178
+ console.log('ℹ️ OpenAI API测试(使用测试密钥,预期失败)');
179
+ console.log('错误信息:', error.message);
180
+ // 对于OpenAI,我们只是测试连接,不强制要求成功
181
+ }
182
+ }, 30000);
183
+ });
package/jest.config.js ADDED
@@ -0,0 +1,47 @@
1
+ module.exports = {
2
+ preset: 'jest-preset-angular',
3
+ setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
4
+ testMatch: [
5
+ '**/?(*.)+(spec|test).ts'
6
+ ],
7
+ moduleFileExtensions: [
8
+ 'ts',
9
+ 'html',
10
+ 'js',
11
+ 'json'
12
+ ],
13
+ moduleNameMapper: {
14
+ '^@/(.*)$': '<rootDir>/src/$1',
15
+ '\\.(css|less|scss|sass)$': 'identity-obj-proxy'
16
+ },
17
+ transform: {
18
+ '^.+\\.ts$': 'ts-jest',
19
+ '\\.(html|css|scss)$': 'jest-preset-angular'
20
+ },
21
+ transformIgnorePatterns: [
22
+ 'node_modules/(?!.*\\.mjs$)'
23
+ ],
24
+ collectCoverageFrom: [
25
+ 'src/**/*.ts',
26
+ '!src/**/*.spec.ts',
27
+ '!src/**/*.d.ts',
28
+ '!src/main.ts',
29
+ '!src/index.ts'
30
+ ],
31
+ coverageDirectory: 'coverage',
32
+ coverageReporters: [
33
+ 'text',
34
+ 'lcov',
35
+ 'html'
36
+ ],
37
+ coverageThreshold: {
38
+ global: {
39
+ branches: 70,
40
+ functions: 70,
41
+ lines: 70,
42
+ statements: 70
43
+ }
44
+ },
45
+ testEnvironment: 'jsdom',
46
+ verbose: true
47
+ };
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "tabby-ai-assistant",
3
+ "version": "1.0.0",
4
+ "description": "Tabby终端AI助手插件 - 支持多AI提供商(OpenAI、Anthropic、Minimax、GLM)",
5
+ "main": "dist/index.js",
6
+ "typings": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "webpack --progress --color",
9
+ "watch": "webpack --progress --color --watch",
10
+ "clean": "rimraf dist build",
11
+ "test": "jest"
12
+ },
13
+ "keywords": [
14
+ "tabby-plugin",
15
+ "tabby",
16
+ "terminal",
17
+ "ai",
18
+ "assistant",
19
+ "openai",
20
+ "anthropic",
21
+ "minimax",
22
+ "glm",
23
+ "chatglm"
24
+ ],
25
+ "author": "Tabby AI Assistant Team",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/your-username/tabby-ai-assistant.git"
30
+ },
31
+ "homepage": "https://github.com/your-username/tabby-ai-assistant#readme",
32
+ "dependencies": {
33
+ "@angular/animations": "~15.2.10",
34
+ "@angular/common": "~15.2.10",
35
+ "@angular/core": "~15.2.10",
36
+ "@angular/forms": "~15.2.10",
37
+ "@angular/platform-browser": "~15.2.10",
38
+ "@angular/platform-browser-dynamic": "~15.2.10",
39
+ "@anthropic-ai/sdk": "^0.20.0",
40
+ "@ng-bootstrap/ng-bootstrap": "~14.2.0",
41
+ "axios": "^1.6.0",
42
+ "crypto-js": "^4.2.0",
43
+ "rxjs": "^7.8.1",
44
+ "tabby-core": "*",
45
+ "tabby-settings": "*",
46
+ "tabby-terminal": "*",
47
+ "zod": "^3.22.4"
48
+ },
49
+ "devDependencies": {
50
+ "@types/crypto-js": "^4.2.2",
51
+ "@types/jest": "^29.5.11",
52
+ "@types/node": "^20.11.5",
53
+ "angular2-template-loader": "^0.6.2",
54
+ "awesome-typescript-loader": "^5.2.1",
55
+ "css-loader": "^7.1.2",
56
+ "identity-obj-proxy": "^3.0.0",
57
+ "jest": "^29.7.0",
58
+ "jest-preset-angular": "^13.1.4",
59
+ "pug": "^3.0.3",
60
+ "pug-plain-loader": "^1.1.0",
61
+ "raw-loader": "^4.0.2",
62
+ "rimraf": "^6.0.1",
63
+ "sass": "^1.89.2",
64
+ "sass-loader": "^16.0.5",
65
+ "style-loader": "^3.3.1",
66
+ "to-string-loader": "^1.2.0",
67
+ "ts-jest": "^29.1.1",
68
+ "ts-loader": "^9.5.2",
69
+ "typescript": "^4.2.3",
70
+ "webpack": "^5.24.4",
71
+ "webpack-cli": "^4.5.0"
72
+ }
73
+ }
package/setup-jest.ts ADDED
@@ -0,0 +1,37 @@
1
+ // 简化测试配置
2
+ // 模拟localStorage
3
+ const localStorageMock = {
4
+ getItem: jest.fn(),
5
+ setItem: jest.fn(),
6
+ removeItem: jest.fn(),
7
+ clear: jest.fn(),
8
+ };
9
+ global.localStorage = localStorageMock as any;
10
+
11
+ // 模拟navigator.clipboard
12
+ Object.defineProperty(navigator, 'clipboard', {
13
+ value: {
14
+ writeText: jest.fn().mockImplementation(() => Promise.resolve()),
15
+ readText: jest.fn().mockImplementation(() => Promise.resolve())
16
+ }
17
+ });
18
+
19
+ // 模拟crypto
20
+ Object.defineProperty(global, 'crypto', {
21
+ value: {
22
+ getRandomValues: jest.fn().mockReturnValue(new Uint8Array(32)),
23
+ subtle: {
24
+ digest: jest.fn().mockImplementation(() => Promise.resolve(new ArrayBuffer(32)))
25
+ }
26
+ }
27
+ });
28
+
29
+ // 模拟console.log以减少测试输出噪音
30
+ global.console = {
31
+ ...console,
32
+ log: jest.fn(),
33
+ debug: jest.fn(),
34
+ info: jest.fn(),
35
+ warn: jest.fn(),
36
+ error: jest.fn()
37
+ };
@@ -0,0 +1,61 @@
1
+ <div class="chat-input-container">
2
+ <!-- 输入区域 -->
3
+ <div class="input-wrapper">
4
+ <textarea
5
+ #textInput
6
+ class="chat-textarea"
7
+ [value]="inputValue"
8
+ [placeholder]="placeholder"
9
+ [disabled]="disabled"
10
+ (keydown)="onKeydown($event)"
11
+ (input)="onInput($event)"
12
+ (compositionstart)="onCompositionStart()"
13
+ (compositionend)="onCompositionEnd()"
14
+ rows="1">
15
+ </textarea>
16
+
17
+ <!-- 字符计数 -->
18
+ <div class="char-counter" [ngClass]="{
19
+ 'warning': isNearLimit() && !isOverLimit(),
20
+ 'error': isOverLimit()
21
+ }">
22
+ {{ getCharCount() }} / {{ getCharLimit() }}
23
+ </div>
24
+ </div>
25
+
26
+ <!-- 操作按钮 -->
27
+ <div class="input-actions">
28
+ <!-- 清空按钮 -->
29
+ <button
30
+ *ngIf="inputValue && !disabled"
31
+ class="btn-icon"
32
+ (click)="clear()"
33
+ title="清空">
34
+ <i class="icon-clear"></i>
35
+ </button>
36
+
37
+ <!-- 发送按钮 -->
38
+ <button
39
+ class="btn-send"
40
+ [disabled]="!inputValue.trim() || disabled || isOverLimit()"
41
+ (click)="submit()"
42
+ title="发送 (Enter)">
43
+ <i class="icon-send"></i>
44
+ <span class="btn-text">发送</span>
45
+ </button>
46
+ </div>
47
+
48
+ <!-- 帮助提示 -->
49
+ <div class="input-hints">
50
+ <span class="hint-item">
51
+ <kbd>Enter</kbd> 发送
52
+ </span>
53
+ <span class="hint-item">
54
+ <kbd>Shift + Enter</kbd> 换行
55
+ </span>
56
+ <span class="hint-item" *ngIf="isNearLimit()">
57
+ <i class="icon-warning"></i>
58
+ 接近字符限制
59
+ </span>
60
+ </div>
61
+ </div>