tabby-ai-assistant 1.0.5 → 1.0.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/dist/components/chat/ai-sidebar.component.d.ts +147 -0
- package/dist/components/chat/chat-interface.component.d.ts +38 -6
- package/dist/components/settings/general-settings.component.d.ts +6 -3
- package/dist/components/settings/provider-config.component.d.ts +25 -12
- package/dist/components/terminal/command-preview.component.d.ts +38 -0
- package/dist/index-full.d.ts +8 -0
- package/dist/index-minimal.d.ts +3 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +1 -2
- package/dist/providers/tabby/ai-config.provider.d.ts +57 -5
- package/dist/providers/tabby/ai-hotkey.provider.d.ts +8 -14
- package/dist/providers/tabby/ai-toolbar-button.provider.d.ts +8 -9
- package/dist/services/chat/ai-sidebar.service.d.ts +89 -0
- package/dist/services/chat/chat-history.service.d.ts +78 -0
- package/dist/services/chat/chat-session.service.d.ts +57 -2
- package/dist/services/context/compaction.d.ts +90 -0
- package/dist/services/context/manager.d.ts +69 -0
- package/dist/services/context/memory.d.ts +116 -0
- package/dist/services/context/token-budget.d.ts +105 -0
- package/dist/services/core/ai-assistant.service.d.ts +40 -1
- package/dist/services/core/checkpoint.service.d.ts +130 -0
- package/dist/services/platform/escape-sequence.service.d.ts +132 -0
- package/dist/services/platform/platform-detection.service.d.ts +146 -0
- package/dist/services/providers/anthropic-provider.service.d.ts +5 -0
- package/dist/services/providers/base-provider.service.d.ts +6 -1
- package/dist/services/providers/glm-provider.service.d.ts +5 -0
- package/dist/services/providers/minimax-provider.service.d.ts +10 -1
- package/dist/services/providers/ollama-provider.service.d.ts +76 -0
- package/dist/services/providers/openai-compatible.service.d.ts +5 -0
- package/dist/services/providers/openai-provider.service.d.ts +5 -0
- package/dist/services/providers/vllm-provider.service.d.ts +82 -0
- package/dist/services/terminal/buffer-analyzer.service.d.ts +128 -0
- package/dist/services/terminal/terminal-manager.service.d.ts +185 -0
- package/dist/services/terminal/terminal-tools.service.d.ts +79 -0
- package/dist/types/ai.types.d.ts +92 -0
- package/dist/types/provider.types.d.ts +1 -1
- package/package.json +7 -10
- package/src/components/chat/ai-sidebar.component.ts +945 -0
- package/src/components/chat/chat-input.component.html +9 -24
- package/src/components/chat/chat-input.component.scss +3 -2
- package/src/components/chat/chat-interface.component.html +77 -69
- package/src/components/chat/chat-interface.component.scss +54 -4
- package/src/components/chat/chat-interface.component.ts +250 -34
- package/src/components/chat/chat-settings.component.scss +4 -4
- package/src/components/chat/chat-settings.component.ts +22 -11
- package/src/components/common/error-message.component.html +15 -0
- package/src/components/common/error-message.component.scss +77 -0
- package/src/components/common/error-message.component.ts +2 -96
- package/src/components/common/loading-spinner.component.html +4 -0
- package/src/components/common/loading-spinner.component.scss +57 -0
- package/src/components/common/loading-spinner.component.ts +2 -63
- package/src/components/security/consent-dialog.component.html +22 -0
- package/src/components/security/consent-dialog.component.scss +34 -0
- package/src/components/security/consent-dialog.component.ts +2 -55
- package/src/components/security/password-prompt.component.html +19 -0
- package/src/components/security/password-prompt.component.scss +30 -0
- package/src/components/security/password-prompt.component.ts +2 -54
- package/src/components/security/risk-confirm-dialog.component.html +8 -12
- package/src/components/security/risk-confirm-dialog.component.scss +8 -5
- package/src/components/security/risk-confirm-dialog.component.ts +6 -6
- package/src/components/settings/ai-settings-tab.component.html +16 -20
- package/src/components/settings/ai-settings-tab.component.scss +8 -5
- package/src/components/settings/ai-settings-tab.component.ts +12 -12
- package/src/components/settings/general-settings.component.html +8 -17
- package/src/components/settings/general-settings.component.scss +6 -3
- package/src/components/settings/general-settings.component.ts +62 -22
- package/src/components/settings/provider-config.component.html +19 -39
- package/src/components/settings/provider-config.component.scss +182 -39
- package/src/components/settings/provider-config.component.ts +119 -7
- package/src/components/settings/security-settings.component.scss +1 -1
- package/src/components/terminal/ai-toolbar-button.component.html +8 -0
- package/src/components/terminal/ai-toolbar-button.component.scss +20 -0
- package/src/components/terminal/ai-toolbar-button.component.ts +2 -30
- package/src/components/terminal/command-preview.component.html +61 -0
- package/src/components/terminal/command-preview.component.scss +72 -0
- package/src/components/terminal/command-preview.component.ts +127 -140
- package/src/components/terminal/command-suggestion.component.html +23 -0
- package/src/components/terminal/command-suggestion.component.scss +55 -0
- package/src/components/terminal/command-suggestion.component.ts +2 -77
- package/src/index-minimal.ts +32 -0
- package/src/index.ts +94 -11
- package/src/index.ts.backup +165 -0
- package/src/providers/tabby/ai-config.provider.ts +60 -51
- package/src/providers/tabby/ai-hotkey.provider.ts +23 -39
- package/src/providers/tabby/ai-settings-tab.provider.ts +2 -2
- package/src/providers/tabby/ai-toolbar-button.provider.ts +29 -24
- package/src/services/chat/ai-sidebar.service.ts +258 -0
- package/src/services/chat/chat-history.service.ts +308 -0
- package/src/services/chat/chat-history.service.ts.backup +239 -0
- package/src/services/chat/chat-session.service.ts +276 -3
- package/src/services/context/compaction.ts +483 -0
- package/src/services/context/manager.ts +442 -0
- package/src/services/context/memory.ts +519 -0
- package/src/services/context/token-budget.ts +422 -0
- package/src/services/core/ai-assistant.service.ts +280 -5
- package/src/services/core/ai-provider-manager.service.ts +2 -2
- package/src/services/core/checkpoint.service.ts +619 -0
- package/src/services/platform/escape-sequence.service.ts +499 -0
- package/src/services/platform/platform-detection.service.ts +494 -0
- package/src/services/providers/anthropic-provider.service.ts +28 -1
- package/src/services/providers/base-provider.service.ts +7 -1
- package/src/services/providers/glm-provider.service.ts +28 -1
- package/src/services/providers/minimax-provider.service.ts +209 -11
- package/src/services/providers/ollama-provider.service.ts +445 -0
- package/src/services/providers/openai-compatible.service.ts +9 -0
- package/src/services/providers/openai-provider.service.ts +9 -0
- package/src/services/providers/vllm-provider.service.ts +463 -0
- package/src/services/security/risk-assessment.service.ts +6 -2
- package/src/services/terminal/buffer-analyzer.service.ts +594 -0
- package/src/services/terminal/terminal-manager.service.ts +748 -0
- package/src/services/terminal/terminal-tools.service.ts +441 -0
- package/src/styles/ai-assistant.scss +78 -6
- package/src/types/ai.types.ts +144 -0
- package/src/types/provider.types.ts +1 -1
- package/tsconfig.json +9 -9
- package/webpack.config.js +28 -6
|
@@ -1,140 +1,13 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
2
|
import { CommandResponse } from '../../types/ai.types';
|
|
3
3
|
import { RiskLevel } from '../../types/security.types';
|
|
4
|
+
import { TerminalManagerService, TerminalInfo } from '../../services/terminal/terminal-manager.service';
|
|
5
|
+
import { LoggerService } from '../../services/core/logger.service';
|
|
4
6
|
|
|
5
7
|
@Component({
|
|
6
8
|
selector: 'app-command-preview',
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<div class="preview-header">
|
|
10
|
-
<h4>
|
|
11
|
-
<i class="icon-terminal"></i>
|
|
12
|
-
命令预览
|
|
13
|
-
</h4>
|
|
14
|
-
<button class="btn-close" (click)="close()">
|
|
15
|
-
<i class="icon-x"></i>
|
|
16
|
-
</button>
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
|
-
<div class="preview-content">
|
|
20
|
-
<!-- 风险级别 -->
|
|
21
|
-
<div class="risk-indicator" [ngClass]="'risk-' + riskLevel.toLowerCase()">
|
|
22
|
-
<i [class]="getRiskIcon()"></i>
|
|
23
|
-
<span>{{ getRiskText() }}</span>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<!-- 命令 -->
|
|
27
|
-
<div class="command-section">
|
|
28
|
-
<label>将要执行的命令:</label>
|
|
29
|
-
<div class="command-display">
|
|
30
|
-
<code>{{ command.command }}</code>
|
|
31
|
-
<button class="btn-copy" (click)="copyCommand()" title="复制">
|
|
32
|
-
<i class="icon-copy"></i>
|
|
33
|
-
</button>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<!-- 解释 -->
|
|
38
|
-
<div class="explanation-section">
|
|
39
|
-
<label>命令解释:</label>
|
|
40
|
-
<p>{{ command.explanation }}</p>
|
|
41
|
-
</div>
|
|
42
|
-
|
|
43
|
-
<!-- 置信度 -->
|
|
44
|
-
<div class="confidence-section" *ngIf="command.confidence">
|
|
45
|
-
<label>AI置信度:</label>
|
|
46
|
-
<div class="confidence-meter">
|
|
47
|
-
<div class="confidence-bar" [style.width.%]="command.confidence * 100"></div>
|
|
48
|
-
<span class="confidence-text">{{ (command.confidence * 100).toFixed(0) }}%</span>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<!-- 替代方案 -->
|
|
53
|
-
<div class="alternatives-section" *ngIf="command.alternatives && command.alternatives.length > 0">
|
|
54
|
-
<label>替代方案:</label>
|
|
55
|
-
<div class="alternatives-list">
|
|
56
|
-
<div
|
|
57
|
-
*ngFor="let alt of command.alternatives"
|
|
58
|
-
class="alternative-item"
|
|
59
|
-
(click)="selectAlternative(alt)">
|
|
60
|
-
<code>{{ alt.command }}</code>
|
|
61
|
-
<span class="alt-confidence">{{ (alt.confidence * 100).toFixed(0) }}%</span>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
<div class="preview-footer">
|
|
68
|
-
<button class="btn btn-secondary" (click)="close()">取消</button>
|
|
69
|
-
<button class="btn btn-primary" (click)="execute()">执行命令</button>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
`,
|
|
73
|
-
styles: [`
|
|
74
|
-
.command-preview {
|
|
75
|
-
background: var(--ai-bg-primary);
|
|
76
|
-
border: 1px solid var(--ai-border);
|
|
77
|
-
border-radius: 0.5rem;
|
|
78
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
79
|
-
max-width: 600px;
|
|
80
|
-
}
|
|
81
|
-
.preview-header {
|
|
82
|
-
display: flex;
|
|
83
|
-
justify-content: space-between;
|
|
84
|
-
align-items: center;
|
|
85
|
-
padding: 1rem;
|
|
86
|
-
background: var(--ai-bg-secondary);
|
|
87
|
-
border-bottom: 1px solid var(--ai-border);
|
|
88
|
-
}
|
|
89
|
-
.preview-content {
|
|
90
|
-
padding: 1rem;
|
|
91
|
-
max-height: 50vh;
|
|
92
|
-
overflow-y: auto;
|
|
93
|
-
}
|
|
94
|
-
.risk-indicator {
|
|
95
|
-
display: flex;
|
|
96
|
-
align-items: center;
|
|
97
|
-
gap: 0.5rem;
|
|
98
|
-
padding: 0.5rem;
|
|
99
|
-
margin-bottom: 1rem;
|
|
100
|
-
border-radius: 0.375rem;
|
|
101
|
-
}
|
|
102
|
-
.command-section, .explanation-section, .confidence-section, .alternatives-section {
|
|
103
|
-
margin-bottom: 1rem;
|
|
104
|
-
}
|
|
105
|
-
.command-display {
|
|
106
|
-
display: flex;
|
|
107
|
-
align-items: center;
|
|
108
|
-
gap: 0.5rem;
|
|
109
|
-
background: var(--ai-bg-secondary);
|
|
110
|
-
padding: 0.75rem;
|
|
111
|
-
border-radius: 0.375rem;
|
|
112
|
-
}
|
|
113
|
-
.alternatives-list {
|
|
114
|
-
background: var(--ai-bg-secondary);
|
|
115
|
-
border-radius: 0.375rem;
|
|
116
|
-
overflow: hidden;
|
|
117
|
-
}
|
|
118
|
-
.alternative-item {
|
|
119
|
-
padding: 0.75rem;
|
|
120
|
-
border-bottom: 1px solid var(--ai-border);
|
|
121
|
-
cursor: pointer;
|
|
122
|
-
transition: background-color 0.2s;
|
|
123
|
-
display: flex;
|
|
124
|
-
justify-content: space-between;
|
|
125
|
-
align-items: center;
|
|
126
|
-
}
|
|
127
|
-
.alternative-item:hover {
|
|
128
|
-
background-color: var(--ai-border);
|
|
129
|
-
}
|
|
130
|
-
.preview-footer {
|
|
131
|
-
padding: 1rem;
|
|
132
|
-
display: flex;
|
|
133
|
-
justify-content: flex-end;
|
|
134
|
-
gap: 0.5rem;
|
|
135
|
-
border-top: 1px solid var(--ai-border);
|
|
136
|
-
}
|
|
137
|
-
`]
|
|
9
|
+
templateUrl: './command-preview.component.html',
|
|
10
|
+
styleUrls: ['./command-preview.component.scss']
|
|
138
11
|
})
|
|
139
12
|
export class CommandPreviewComponent {
|
|
140
13
|
@Input() command: CommandResponse | null = null;
|
|
@@ -143,43 +16,157 @@ export class CommandPreviewComponent {
|
|
|
143
16
|
@Output() executed = new EventEmitter<CommandResponse>();
|
|
144
17
|
@Output() closed = new EventEmitter<void>();
|
|
145
18
|
|
|
19
|
+
// 终端选择
|
|
20
|
+
terminals: TerminalInfo[] = [];
|
|
21
|
+
selectedTerminalIndex = 0;
|
|
22
|
+
showTerminalSelector = false;
|
|
23
|
+
executionStatus: 'idle' | 'executing' | 'success' | 'error' = 'idle';
|
|
24
|
+
statusMessage = '';
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
private terminalManager: TerminalManagerService,
|
|
28
|
+
private logger: LoggerService
|
|
29
|
+
) {
|
|
30
|
+
this.loadTerminals();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 加载可用终端列表
|
|
35
|
+
*/
|
|
36
|
+
loadTerminals(): void {
|
|
37
|
+
this.terminals = this.terminalManager.getAllTerminalInfo();
|
|
38
|
+
// 默认选择当前活动终端
|
|
39
|
+
const activeIndex = this.terminals.findIndex(t => t.isActive);
|
|
40
|
+
if (activeIndex >= 0) {
|
|
41
|
+
this.selectedTerminalIndex = activeIndex;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
146
45
|
getRiskText(): string {
|
|
147
46
|
switch (this.riskLevel) {
|
|
148
47
|
case RiskLevel.LOW: return '低风险';
|
|
149
48
|
case RiskLevel.MEDIUM: return '中风险';
|
|
150
49
|
case RiskLevel.HIGH: return '高风险';
|
|
151
|
-
case RiskLevel.CRITICAL: return '
|
|
50
|
+
case RiskLevel.CRITICAL: return '极高风险';
|
|
152
51
|
default: return '未知风险';
|
|
153
52
|
}
|
|
154
53
|
}
|
|
155
54
|
|
|
156
55
|
getRiskIcon(): string {
|
|
157
56
|
switch (this.riskLevel) {
|
|
158
|
-
case RiskLevel.LOW: return '
|
|
159
|
-
case RiskLevel.MEDIUM: return '
|
|
160
|
-
case RiskLevel.HIGH: return '
|
|
161
|
-
case RiskLevel.CRITICAL: return '
|
|
162
|
-
default: return '
|
|
57
|
+
case RiskLevel.LOW: return 'fa fa-check-circle';
|
|
58
|
+
case RiskLevel.MEDIUM: return 'fa fa-exclamation-triangle';
|
|
59
|
+
case RiskLevel.HIGH: return 'fa fa-exclamation-circle';
|
|
60
|
+
case RiskLevel.CRITICAL: return 'fa fa-ban';
|
|
61
|
+
default: return 'fa fa-question-circle';
|
|
163
62
|
}
|
|
164
63
|
}
|
|
165
64
|
|
|
65
|
+
/**
|
|
66
|
+
* 复制命令到剪贴板
|
|
67
|
+
*/
|
|
166
68
|
copyCommand(): void {
|
|
167
69
|
if (this.command) {
|
|
168
70
|
navigator.clipboard.writeText(this.command.command);
|
|
71
|
+
this.statusMessage = '已复制到剪贴板';
|
|
72
|
+
setTimeout(() => this.statusMessage = '', 2000);
|
|
169
73
|
}
|
|
170
74
|
}
|
|
171
75
|
|
|
76
|
+
/**
|
|
77
|
+
* 执行命令到终端
|
|
78
|
+
*/
|
|
172
79
|
execute(): void {
|
|
173
|
-
if (this.command)
|
|
174
|
-
|
|
80
|
+
if (!this.command) return;
|
|
81
|
+
|
|
82
|
+
// 检查是否有可用终端
|
|
83
|
+
if (!this.terminalManager.hasTerminal()) {
|
|
84
|
+
this.executionStatus = 'error';
|
|
85
|
+
this.statusMessage = '没有可用的终端,请先打开一个终端标签';
|
|
86
|
+
return;
|
|
175
87
|
}
|
|
88
|
+
|
|
89
|
+
this.executionStatus = 'executing';
|
|
90
|
+
this.statusMessage = '正在执行...';
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
// 如果选择了特定终端,先切换到该终端
|
|
94
|
+
if (this.selectedTerminalIndex >= 0 && this.terminals.length > 0) {
|
|
95
|
+
this.terminalManager.focusTerminal(this.selectedTerminalIndex);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 发送命令到终端
|
|
99
|
+
const success = this.terminalManager.sendCommand(this.command.command, true);
|
|
100
|
+
|
|
101
|
+
if (success) {
|
|
102
|
+
this.executionStatus = 'success';
|
|
103
|
+
this.statusMessage = '命令已发送到终端';
|
|
104
|
+
this.logger.info('Command executed', { command: this.command.command });
|
|
105
|
+
|
|
106
|
+
// 触发执行事件
|
|
107
|
+
this.executed.emit(this.command);
|
|
108
|
+
|
|
109
|
+
// 2秒后关闭预览
|
|
110
|
+
setTimeout(() => this.close(), 2000);
|
|
111
|
+
} else {
|
|
112
|
+
this.executionStatus = 'error';
|
|
113
|
+
this.statusMessage = '发送命令失败';
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
this.executionStatus = 'error';
|
|
117
|
+
this.statusMessage = `执行错误: ${error instanceof Error ? error.message : '未知错误'}`;
|
|
118
|
+
this.logger.error('Failed to execute command', error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 仅插入命令(不执行)
|
|
124
|
+
*/
|
|
125
|
+
insertOnly(): void {
|
|
126
|
+
if (!this.command) return;
|
|
127
|
+
|
|
128
|
+
if (!this.terminalManager.hasTerminal()) {
|
|
129
|
+
this.statusMessage = '没有可用的终端';
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const success = this.terminalManager.sendCommand(this.command.command, false);
|
|
134
|
+
if (success) {
|
|
135
|
+
this.statusMessage = '命令已插入终端(未执行)';
|
|
136
|
+
setTimeout(() => this.close(), 1500);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 切换终端选择器
|
|
142
|
+
*/
|
|
143
|
+
toggleTerminalSelector(): void {
|
|
144
|
+
this.loadTerminals();
|
|
145
|
+
this.showTerminalSelector = !this.showTerminalSelector;
|
|
176
146
|
}
|
|
177
147
|
|
|
148
|
+
/**
|
|
149
|
+
* 选择终端
|
|
150
|
+
*/
|
|
151
|
+
selectTerminal(index: number): void {
|
|
152
|
+
this.selectedTerminalIndex = index;
|
|
153
|
+
this.showTerminalSelector = false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 关闭预览
|
|
158
|
+
*/
|
|
178
159
|
close(): void {
|
|
179
160
|
this.closed.emit();
|
|
180
161
|
}
|
|
181
162
|
|
|
163
|
+
/**
|
|
164
|
+
* 选择替代命令
|
|
165
|
+
*/
|
|
182
166
|
selectAlternative(alt: any): void {
|
|
183
|
-
|
|
167
|
+
if (this.command && alt) {
|
|
168
|
+
this.command = { ...this.command, command: alt.command || alt };
|
|
169
|
+
}
|
|
184
170
|
}
|
|
185
171
|
}
|
|
172
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<div class="command-suggestion" *ngIf="suggestions.length > 0">
|
|
2
|
+
<div class="suggestion-header">
|
|
3
|
+
<i class="fa fa-lightbulb-o"></i>
|
|
4
|
+
<span>AI命令建议</span>
|
|
5
|
+
<button class="btn-close" (click)="close()">
|
|
6
|
+
<i class="fa fa-times"></i>
|
|
7
|
+
</button>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="suggestion-list">
|
|
10
|
+
<div *ngFor="let suggestion of suggestions" class="suggestion-item" (click)="selectSuggestion(suggestion)">
|
|
11
|
+
<div class="suggestion-command">
|
|
12
|
+
<code>{{ suggestion.command }}</code>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="suggestion-explanation">
|
|
15
|
+
{{ suggestion.explanation }}
|
|
16
|
+
</div>
|
|
17
|
+
<div class="suggestion-confidence">
|
|
18
|
+
<span class="confidence-bar" [style.width.%]="suggestion.confidence * 100"></span>
|
|
19
|
+
<span class="confidence-text">{{ (suggestion.confidence * 100).toFixed(0) }}%</span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.command-suggestion {
|
|
2
|
+
background: var(--ai-bg-primary);
|
|
3
|
+
border: 1px solid var(--ai-border);
|
|
4
|
+
border-radius: 0.5rem;
|
|
5
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
6
|
+
max-width: 600px;
|
|
7
|
+
margin: 0.5rem auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.suggestion-header {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: 0.5rem;
|
|
14
|
+
padding: 0.75rem 1rem;
|
|
15
|
+
background: var(--ai-bg-secondary);
|
|
16
|
+
border-bottom: 1px solid var(--ai-border);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.suggestion-list {
|
|
20
|
+
max-height: 300px;
|
|
21
|
+
overflow-y: auto;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.suggestion-item {
|
|
25
|
+
padding: 1rem;
|
|
26
|
+
border-bottom: 1px solid var(--ai-border);
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
transition: background-color 0.2s;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.suggestion-item:hover {
|
|
32
|
+
background-color: var(--ai-bg-secondary);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.suggestion-item:last-child {
|
|
36
|
+
border-bottom: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.suggestion-command {
|
|
40
|
+
font-family: monospace;
|
|
41
|
+
margin-bottom: 0.5rem;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.suggestion-confidence {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 0.5rem;
|
|
48
|
+
margin-top: 0.5rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.confidence-bar {
|
|
52
|
+
height: 4px;
|
|
53
|
+
background: var(--ai-primary);
|
|
54
|
+
border-radius: 2px;
|
|
55
|
+
}
|
|
@@ -5,83 +5,8 @@ import { CommandResponse } from '../../types/ai.types';
|
|
|
5
5
|
|
|
6
6
|
@Component({
|
|
7
7
|
selector: 'app-command-suggestion',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<div class="suggestion-header">
|
|
11
|
-
<i class="icon-lightbulb"></i>
|
|
12
|
-
<span>AI命令建议</span>
|
|
13
|
-
<button class="btn-close" (click)="close()">
|
|
14
|
-
<i class="icon-x"></i>
|
|
15
|
-
</button>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="suggestion-list">
|
|
18
|
-
<div
|
|
19
|
-
*ngFor="let suggestion of suggestions"
|
|
20
|
-
class="suggestion-item"
|
|
21
|
-
(click)="selectSuggestion(suggestion)">
|
|
22
|
-
<div class="suggestion-command">
|
|
23
|
-
<code>{{ suggestion.command }}</code>
|
|
24
|
-
</div>
|
|
25
|
-
<div class="suggestion-explanation">
|
|
26
|
-
{{ suggestion.explanation }}
|
|
27
|
-
</div>
|
|
28
|
-
<div class="suggestion-confidence">
|
|
29
|
-
<span class="confidence-bar" [style.width.%]="suggestion.confidence * 100"></span>
|
|
30
|
-
<span class="confidence-text">{{ (suggestion.confidence * 100).toFixed(0) }}%</span>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
`,
|
|
36
|
-
styles: [`
|
|
37
|
-
.command-suggestion {
|
|
38
|
-
background: var(--ai-bg-primary);
|
|
39
|
-
border: 1px solid var(--ai-border);
|
|
40
|
-
border-radius: 0.5rem;
|
|
41
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
42
|
-
max-width: 600px;
|
|
43
|
-
margin: 0.5rem auto;
|
|
44
|
-
}
|
|
45
|
-
.suggestion-header {
|
|
46
|
-
display: flex;
|
|
47
|
-
align-items: center;
|
|
48
|
-
gap: 0.5rem;
|
|
49
|
-
padding: 0.75rem 1rem;
|
|
50
|
-
background: var(--ai-bg-secondary);
|
|
51
|
-
border-bottom: 1px solid var(--ai-border);
|
|
52
|
-
}
|
|
53
|
-
.suggestion-list {
|
|
54
|
-
max-height: 300px;
|
|
55
|
-
overflow-y: auto;
|
|
56
|
-
}
|
|
57
|
-
.suggestion-item {
|
|
58
|
-
padding: 1rem;
|
|
59
|
-
border-bottom: 1px solid var(--ai-border);
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
transition: background-color 0.2s;
|
|
62
|
-
}
|
|
63
|
-
.suggestion-item:hover {
|
|
64
|
-
background-color: var(--ai-bg-secondary);
|
|
65
|
-
}
|
|
66
|
-
.suggestion-item:last-child {
|
|
67
|
-
border-bottom: none;
|
|
68
|
-
}
|
|
69
|
-
.suggestion-command {
|
|
70
|
-
font-family: monospace;
|
|
71
|
-
margin-bottom: 0.5rem;
|
|
72
|
-
}
|
|
73
|
-
.suggestion-confidence {
|
|
74
|
-
display: flex;
|
|
75
|
-
align-items: center;
|
|
76
|
-
gap: 0.5rem;
|
|
77
|
-
margin-top: 0.5rem;
|
|
78
|
-
}
|
|
79
|
-
.confidence-bar {
|
|
80
|
-
height: 4px;
|
|
81
|
-
background: var(--ai-primary);
|
|
82
|
-
border-radius: 2px;
|
|
83
|
-
}
|
|
84
|
-
`]
|
|
8
|
+
templateUrl: './command-suggestion.component.html',
|
|
9
|
+
styleUrls: ['./command-suggestion.component.scss']
|
|
85
10
|
})
|
|
86
11
|
export class CommandSuggestionComponent implements OnInit, OnDestroy {
|
|
87
12
|
@Input() inputText = '';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|
5
|
+
|
|
6
|
+
// Tabby modules
|
|
7
|
+
import TabbyCoreModule, { ToolbarButtonProvider, ConfigProvider, HotkeyProvider } from 'tabby-core';
|
|
8
|
+
import TabbyTerminalModule from 'tabby-terminal';
|
|
9
|
+
import { SettingsTabProvider } from 'tabby-settings';
|
|
10
|
+
|
|
11
|
+
@NgModule({
|
|
12
|
+
imports: [
|
|
13
|
+
CommonModule,
|
|
14
|
+
FormsModule,
|
|
15
|
+
TabbyCoreModule,
|
|
16
|
+
TabbyTerminalModule,
|
|
17
|
+
NgbModule
|
|
18
|
+
],
|
|
19
|
+
providers: [
|
|
20
|
+
{ provide: ToolbarButtonProvider, useClass: (class {}), multi: true },
|
|
21
|
+
{ provide: SettingsTabProvider, useClass: (class {}), multi: true },
|
|
22
|
+
{ provide: ConfigProvider, useClass: (class {}), multi: true },
|
|
23
|
+
{ provide: HotkeyProvider, useClass: (class {}), multi: true }
|
|
24
|
+
],
|
|
25
|
+
declarations: [],
|
|
26
|
+
entryComponents: []
|
|
27
|
+
})
|
|
28
|
+
export default class AiAssistantModule {
|
|
29
|
+
constructor() {
|
|
30
|
+
console.log('AiAssistantModule initialized (minimal version)');
|
|
31
|
+
}
|
|
32
|
+
}
|