Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions agent/app/dto/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,11 @@ type SystemProxy struct {
}

type TerminalAIInfo struct {
AIStatus string `json:"aiStatus"`
AIAccountID string `json:"aiAccountId"`
AIPrefix string `json:"aiPrefix"`
AIRiskCommands string `json:"aiRiskCommands"`
AIStatus string `json:"aiStatus"`
AIAccountID string `json:"aiAccountId"`
AIPrefix string `json:"aiPrefix" validate:"required,oneof=@ai #ai /ai"`
AIRiskCommands string `json:"aiRiskCommands"`
AIRiskCommandsDefault string `json:"aiRiskCommandsDefault"`
}

type CommonDescription struct {
Expand Down
11 changes: 6 additions & 5 deletions agent/app/service/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {

func (u *SettingService) GetTerminalAIInfo() (*dto.TerminalAIInfo, error) {
info := &dto.TerminalAIInfo{
AIStatus: constant.StatusDisable,
AIAccountID: "",
AIPrefix: "#",
AIRiskCommands: "[\"rm -rf\",\"mkfs\",\"dd if=\",\"curl | sh\",\"wget | sh\",\"chmod -R 777 /\",\"shutdown\",\"reboot\",\"poweroff\",\"init 0\",\":(){ :|:& };:\"]",
AIStatus: constant.StatusDisable,
AIAccountID: "",
AIPrefix: constant.DefaultTerminalAIPrefix,
AIRiskCommands: "[]",
AIRiskCommandsDefault: constant.DefaultTerminalAIRiskCommands,
}

if value, err := settingRepo.GetValueByKey("AIStatus"); err == nil && value != "" {
Expand All @@ -76,7 +77,7 @@ func (u *SettingService) GetTerminalAIInfo() (*dto.TerminalAIInfo, error) {
if value, err := settingRepo.GetValueByKey("AIAccountID"); err == nil {
info.AIAccountID = value
}
if value, err := settingRepo.GetValueByKey("AIPrefix"); err == nil && value != "" {
if value, err := settingRepo.GetValueByKey("AIPrefix"); err == nil {
info.AIPrefix = value
}
if value, err := settingRepo.GetValueByKey("AIRiskCommands"); err == nil && value != "" {
Expand Down
5 changes: 5 additions & 0 deletions agent/constant/terminal_ai.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package constant

const DefaultTerminalAIPrefix = "@ai"

const DefaultTerminalAIRiskCommands = "[\"rm\",\"mkfs\",\"dd if=\",\"dd of=/dev/\",\"wipefs\",\"fdisk\",\"parted\",\"sfdisk\",\"shred\",\"curl | sh\",\"wget | sh\",\"chmod -R 777 /\",\"shutdown\",\"reboot\",\"poweroff\",\"init 0\",\":(){ :|:& };:\"]"
3 changes: 3 additions & 0 deletions agent/i18n/lang/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,6 @@ PartitionDiskErr: 'Partition failed: {{ .err }}'
FormatDiskErr: 'Format failed: {{ .err }}'
MountDiskErr: 'Mount failed: {{ .err }}'
XfsNotFound: 'xfs not found; install xfsprogs first'

# terminal
TerminalAIBlockedRiskyCommand: 'blocked risky command: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/es-ES.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: 'Error al particionar, {{ .err }}'
FormatDiskErr: 'Error al formatear disco, {{ .err }}'
MountDiskErr: 'Error al montar disco, {{ .err }}'
XfsNotFound: 'No se detectó el sistema de archivos xfs instale xfsprogs primero'

# terminal
TerminalAIBlockedRiskyCommand: 'Comando de riesgo bloqueado: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/ja.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: 'パーティションに失敗しました、{{ .err }}'
FormatDiskErr: 'ディスクのフォーマットに失敗しました、{{ .err }}'
MountDiskErr: 'ディスクのマウントに失敗しました、{{ .err }}'
XfsNotFound: 'xfs ファイルシステムが検出されませんでした、最初に xfsprogs をインストールしてください'

# terminal
TerminalAIBlockedRiskyCommand: '危険なコマンドをブロックしました: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/ko.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: '파티션 분할에 실패했습니다, {{ .err }}'
FormatDiskErr: '디스크 포맷에 실패했습니다, {{ .err }}'
MountDiskErr: '디스크 마운트에 실패했습니다, {{ .err }}'
XfsNotFound: 'xfs 파일 시스템이 감지되지 않았습니다, 먼저 xfsprogs 를 설치하세요'

# terminal
TerminalAIBlockedRiskyCommand: '위험한 명령이 차단되었습니다: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/ms.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: 'Gagal membahagikan, {{ .err }}'
FormatDiskErr: 'Gagal memformat cakera, {{ .err }}'
MountDiskErr: 'Gagal mengkaitkan cakera, {{ .err }}'
XfsNotFound: 'Sistem fail xfs tidak dikesan, sila pasang xfsprogs terlebih dahulu'

# terminal
TerminalAIBlockedRiskyCommand: 'Perintah berisiko telah disekat: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/pt-BR.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: 'Falha ao particionar, {{ .err }}'
FormatDiskErr: 'Falha ao formatar disco, {{ .err }}'
MountDiskErr: 'Falha ao montar disco, {{ .err }}'
XfsNotFound: 'Sistema de arquivos xfs não detectado instale xfsprogs primeiro'

# terminal
TerminalAIBlockedRiskyCommand: 'Comando de risco bloqueado: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/ru.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: 'Не удалось разделить, {{ .err }}'
FormatDiskErr: 'Не удалось отформатировать диск, {{ .err }}'
MountDiskErr: 'Не удалось подключить диск, {{ .err }}'
XfsNotFound: 'Файловая система xfs не обнаружена, сначала установите xfsprogs'

# terminal
TerminalAIBlockedRiskyCommand: 'Опасная команда заблокирована: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/tr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: 'Bölümleme başarısız, {{ .err }}'
FormatDiskErr: 'Disk biçimlendirme başarısız, {{ .err }}'
MountDiskErr: 'Disk bağlama başarısız, {{ .err }}'
XfsNotFound: 'XFS dosya sistemi algılanmadı, lütfen önce xfsprogs''i yükleyin'

# terminal
TerminalAIBlockedRiskyCommand: 'Riskli komut engellendi: {{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/zh-Hant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,6 @@ PartitionDiskErr: '分區失敗,{{ .err }}'
FormatDiskErr: '格式化磁碟失敗,{{ .err }}'
MountDiskErr: '掛載磁碟失敗,{{ .err }}'
XfsNotFound: '未偵測到 xfs 檔案系統,請先安裝 xfsprogs'

# terminal
TerminalAIBlockedRiskyCommand: '已攔截風險命令:{{ .command }}'
3 changes: 3 additions & 0 deletions agent/i18n/lang/zh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,6 @@ PartitionDiskErr: "分区失败,{{ .err }}"
FormatDiskErr: "格式化磁盘失败,{{ .err }}"
MountDiskErr: "挂载磁盘失败,{{ .err }}"
XfsNotFound: "未检测到 xfs 文件系统,请先安装 xfsprogs"

# terminal
TerminalAIBlockedRiskyCommand: "已拦截风险命令:{{ .command }}"
4 changes: 2 additions & 2 deletions agent/init/migration/migrations/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -1124,12 +1124,12 @@ var AddAITerminalSettings = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "AIAccountID", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "AIPrefix", Value: "#"}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "AIPrefix", Value: constant.DefaultTerminalAIPrefix}).Error; err != nil {
return err
}
return tx.Create(&model.Setting{
Key: "AIRiskCommands",
Value: "[\"rm -rf\",\"mkfs\",\"dd if=\",\"curl | sh\",\"wget | sh\",\"chmod -R 777 /\",\"shutdown\",\"reboot\",\"poweroff\",\"init 0\",\":(){ :|:& };:\"]",
Value: constant.DefaultTerminalAIRiskCommands,
}).Error
},
}
27 changes: 2 additions & 25 deletions agent/utils/terminal/ai/config_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,6 @@ type TerminalRuntimeSettings struct {
RiskCommands []string
}

var defaultRiskCommands = []string{
"rm -rf",
"mkfs",
"dd if=",
"curl | sh",
"wget | sh",
"chmod -R 777 /",
"shutdown",
"reboot",
"poweroff",
"init 0",
":(){ :|:& };:",
}

func ResolveGeneratorConfig(accountID uint) (GeneratorConfig, time.Duration, error) {
account, err := loadAgentAccount(accountID)
if err != nil {
Expand Down Expand Up @@ -135,9 +121,6 @@ func LoadTerminalRuntimeSettings() (TerminalRuntimeSettings, GeneratorConfig, ti
if err != nil && !os.IsNotExist(err) {
return TerminalRuntimeSettings{}, GeneratorConfig{}, 0, err
}
if strings.TrimSpace(prefix) == "" {
prefix = "#"
}
riskCommands, err := loadRiskCommands()
if err != nil {
return TerminalRuntimeSettings{}, GeneratorConfig{}, 0, err
Expand Down Expand Up @@ -175,12 +158,12 @@ func loadRiskCommands() ([]string, error) {
value, err := loadAgentSettingValue("AIRiskCommands")
if err != nil {
if os.IsNotExist(err) {
return append([]string(nil), defaultRiskCommands...), nil
return []string{}, nil
}
return nil, err
}
if strings.TrimSpace(value) == "" {
return append([]string(nil), defaultRiskCommands...), nil
return []string{}, nil
}
var commands []string
if err := json.Unmarshal([]byte(value), &commands); err != nil {
Expand All @@ -190,9 +173,6 @@ func loadRiskCommands() ([]string, error) {
}

func normalizeRiskCommands(commands []string) []string {
if len(commands) == 0 {
return append([]string(nil), defaultRiskCommands...)
}
seen := make(map[string]struct{}, len(commands))
result := make([]string, 0, len(commands))
for _, command := range commands {
Expand All @@ -206,8 +186,5 @@ func normalizeRiskCommands(commands []string) []string {
seen[command] = struct{}{}
result = append(result, command)
}
if len(result) == 0 {
return append([]string(nil), defaultRiskCommands...)
}
return result
}
30 changes: 8 additions & 22 deletions agent/utils/terminal/ai_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import (
"strings"
"sync"
"time"
"unicode"
"unicode/utf8"

"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/i18n"
terminalai "github.com/1Panel-dev/1Panel/agent/utils/terminal/ai"
)

Expand Down Expand Up @@ -110,7 +110,9 @@ func (i *aiInputInterceptor) HandleEnter() (string, bool) {
return "", false
}
if i.isRiskCommand(resp.Command) {
return ": # blocked risky command: " + resp.Command, true
return ": # " + i18n.GetMsgWithMap("TerminalAIBlockedRiskyCommand", map[string]interface{}{
"command": resp.Command,
}), true
}
return resp.Command, strings.TrimSpace(resp.Command) != ""
}
Expand All @@ -131,12 +133,14 @@ func (i *aiInputInterceptor) TrackInput(data []byte) {
switch b {
case '\r', '\n':
i.currentLine = nil
case 0x03:
i.currentLine = nil
i.inEscapeSeq = false
case 0x08, 0x7f:
i.currentLine = trimLastRuneBytes(i.currentLine)
case lineClearControl:
i.currentLine = nil
case 0x1b:
// Ignore ANSI escape sequences such as arrow keys and bracketed paste markers.
i.inEscapeSeq = true
default:
if b < 0x20 && b != '\t' {
Expand Down Expand Up @@ -180,25 +184,7 @@ func firstNonEmpty(values ...string) string {
}

func sanitizeInputLine(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
var builder strings.Builder
builder.Grow(len(raw))
for _, r := range raw {
switch {
case unicode.IsControl(r) && r != '\t' && r != ' ':
continue
case unicode.In(r, unicode.Cf):
continue
case r == '\u00a0' || r == '\u2007' || r == '\u202f' || r == '\u3000':
builder.WriteRune(' ')
default:
builder.WriteRune(r)
}
}
return strings.TrimSpace(builder.String())
return strings.TrimSpace(raw)
}

func trimLastRuneBytes(data []byte) []byte {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/api/interface/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export namespace Setting {
aiAccountId: string;
aiPrefix: string;
aiRiskCommands: string;
aiRiskCommandsDefault?: string;
}
export interface SettingUpdate {
key: string;
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1396,11 +1396,10 @@ const message = {
'Use the selected model account to generate and fill commands. For local models like Ollama and vLLM, use a custom model account.',
aiAccountRequired: 'Please select an available AI account first.',
aiPrefix: 'Trigger Prefix',
aiPrefixHelper:
'When a line starts with this prefix and you press Enter, AI command generation will be triggered, for example # or //ai.',
aiPrefixHelper: 'Enter this prefix and press Enter to trigger AI command generation.',
aiRiskCommands: 'Risk Command Interception',
aiRiskCommandsHelper:
'Generated commands matching any of these fragments will be blocked and filled back as comments. Supports add, edit, and delete.',
'Generated commands matching any of these fragments will be blocked and filled back as comments. Leave empty to disable interception. Supports add, edit, and delete.',
aiAddRiskCommand: 'Add Risk Command',
aiRemoveRiskCommand: 'Delete',
aiSummary: 'When a line starts with the {0} prefix and you press Enter, AI command generation is triggered.',
Expand Down
21 changes: 10 additions & 11 deletions frontend/src/lang/modules/es-es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1429,21 +1429,20 @@ const message = {
cursorBar: 'Barra',
scrollback: 'Scrollback',
scrollSensitivity: 'Sensibilidad de scroll',
aiStatus: 'AI Terminal',
aiSettings: 'AI Terminal Settings',
aiStatus: 'Terminal de IA',
aiSettings: 'Configuración del terminal de IA',
aiAccountHelper:
'Use la cuenta de modelo seleccionada para generar y rellenar comandos. Para modelos locales como Ollama y vLLM, use una cuenta de modelo personalizada.',
aiPrefix: 'Trigger Prefix',
aiPrefixHelper:
'When a line starts with this prefix and you press Enter, AI command generation will be triggered, for example # or //ai.',
aiRiskCommands: 'Risk Command Interception',
aiPrefix: 'Prefijo de activación',
aiPrefixHelper: 'Introduzca este prefijo y pulse Enter para activar la generación de comandos por IA.',
aiRiskCommands: 'Intercepción de comandos de riesgo',
aiRiskCommandsHelper:
'Generated commands matching any of these fragments will be blocked and filled back as comments. Supports add, edit, and delete.',
aiAddRiskCommand: 'Add Risk Command',
aiRemoveRiskCommand: 'Delete',
aiSummary: 'When a line starts with the {0} prefix and you press Enter, AI command generation is triggered.',
'Los comandos generados que coincidan con cualquiera de estos fragmentos se bloquearán y se devolverán como comentarios. Déjelo vacío para desactivar la intercepción. Admite añadir, editar y eliminar.',
aiAddRiskCommand: 'Añadir comando de riesgo',
aiRemoveRiskCommand: 'Eliminar',
aiSummary: 'Cuando una línea comienza con el prefijo {0} y pulsa Enter, se activa la generación de comandos por IA.',
aiPrefixAsciiVisible:
'Only ASCII visible characters are supported. Spaces, CJK characters, and full-width symbols are not allowed.',
'Solo se admiten caracteres ASCII visibles. No se permiten espacios, caracteres CJK ni símbolos de ancho completo.',
saveHelper: '¿Está seguro de que desea guardar la configuración actual de la terminal?',
},
toolbox: {
Expand Down
21 changes: 10 additions & 11 deletions frontend/src/lang/modules/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1400,21 +1400,20 @@ const message = {
cursorBar: 'バー',
scrollback: 'スクロールバック',
scrollSensitivity: 'スクロール感度',
aiStatus: 'AI Terminal',
aiSettings: 'AI Terminal Settings',
aiStatus: 'AI ターミナル',
aiSettings: 'AI ターミナル設定',
aiAccountHelper:
'選択したモデルアカウントでコマンドを生成して補完します。Ollama や vLLM などのローカルモデルはカスタムモデルアカウントを使用してください。',
aiPrefix: 'Trigger Prefix',
aiPrefixHelper:
'When a line starts with this prefix and you press Enter, AI command generation will be triggered, for example # or //ai.',
aiRiskCommands: 'Risk Command Interception',
aiPrefix: 'トリガープレフィックス',
aiPrefixHelper: 'このプレフィックスを入力して Enter を押すと、AI コマンド生成がトリガーされます。',
aiRiskCommands: '危険コマンドの遮断',
aiRiskCommandsHelper:
'Generated commands matching any of these fragments will be blocked and filled back as comments. Supports add, edit, and delete.',
aiAddRiskCommand: 'Add Risk Command',
aiRemoveRiskCommand: 'Delete',
aiSummary: 'When a line starts with the {0} prefix and you press Enter, AI command generation is triggered.',
'これらの断片のいずれかに一致する生成コマンドはブロックされ、コメントとして埋め戻されます。空欄にすると遮断を無効化できます。追加、編集、削除に対応しています。',
aiAddRiskCommand: '危険コマンドを追加',
aiRemoveRiskCommand: '削除',
aiSummary: '行が {0} プレフィックスで始まり Enter を押すと、AI コマンド生成がトリガーされます。',
aiPrefixAsciiVisible:
'Only ASCII visible characters are supported. Spaces, CJK characters, and full-width symbols are not allowed.',
'ASCII の表示可能文字のみ対応しています。スペース、CJK 文字、全角記号は使用できません。',
saveHelper: '現在のターミナル設定を保存してもよろしいですか?',
},
toolbox: {
Expand Down
21 changes: 10 additions & 11 deletions frontend/src/lang/modules/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1374,21 +1374,20 @@ const message = {
cursorBar: '막대',
scrollback: '스크롤백',
scrollSensitivity: '스크롤 감도',
aiStatus: 'AI Terminal',
aiSettings: 'AI Terminal Settings',
aiStatus: 'AI 터미널',
aiSettings: 'AI 터미널 설정',
aiAccountHelper:
'선택한 모델 계정으로 명령을 생성하고 채웁니다. Ollama, vLLM 같은 로컬 모델은 사용자 지정 모델 계정을 사용하세요.',
aiPrefix: 'Trigger Prefix',
aiPrefixHelper:
'When a line starts with this prefix and you press Enter, AI command generation will be triggered, for example # or //ai.',
aiRiskCommands: 'Risk Command Interception',
aiPrefix: '트리거 접두사',
aiPrefixHelper: '이 접두사를 입력하고 Enter를 누르면 AI 명령 생성이 트리거됩니다.',
aiRiskCommands: '위험 명령 차단',
aiRiskCommandsHelper:
'Generated commands matching any of these fragments will be blocked and filled back as comments. Supports add, edit, and delete.',
aiAddRiskCommand: 'Add Risk Command',
aiRemoveRiskCommand: 'Delete',
aiSummary: 'When a line starts with the {0} prefix and you press Enter, AI command generation is triggered.',
'이 조각들 중 하나와 일치하는 생성 명령은 차단되고 주석으로 다시 채워집니다. 비워 두면 차단이 비활성화됩니다. 추가, 수정, 삭제를 지원합니다.',
aiAddRiskCommand: '위험 명령 추가',
aiRemoveRiskCommand: '삭제',
aiSummary: '{0} 접두사로 시작하는 줄에서 Enter를 누르면 AI 명령 생성이 트리거됩니다.',
aiPrefixAsciiVisible:
'Only ASCII visible characters are supported. Spaces, CJK characters, and full-width symbols are not allowed.',
'ASCII 표시 가능 문자만 지원합니다. 공백, CJK 문자 및 전각 기호는 사용할 수 없습니다.',
saveHelper: '현재 터미널 설정을 저장하시겠습니까?',
},
toolbox: {
Expand Down
Loading
Loading