v1.9.40: add Codex integration — skill setup, deploy, GUI buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
IPGO Developer
2026-03-07 07:27:22 +00:00
parent ddd6951610
commit e2bdffb41e
14 changed files with 1067 additions and 130 deletions

View File

@@ -0,0 +1,88 @@
---
name: server-manager
description: Use ServerManager's shared local server inventory and ssh.py utility to manage configured SSH, Telnet, SQL, Redis, S3/MinIO, Grafana, Prometheus, and WinRM endpoints by alias without exposing credentials. Use when the user asks to operate on servers managed by ServerManager or when editing ServerManager's Claude/Codex integration.
metadata:
short-description: Safe remote ops through ServerManager aliases
---
# Server Manager
Use this skill for two cases:
1. The user wants work done on a server or service already configured in ServerManager.
2. The user wants to modify ServerManager's CLI/integration layer so Claude/Codex can use it safely.
## First Step
Before any server operation:
```bash
$HOME/.server-connections/codex-ssh --list
```
Read the `Type` column before choosing commands. Do not guess the server type.
If the wrapper is missing, run the doctor script for your platform:
```bash
$HOME/.codex/skills/server-manager/scripts/server-manager-doctor.sh
```
On Windows, use:
```bat
%USERPROFILE%\.codex\skills\server-manager\scripts\server-manager-doctor.cmd
```
## Hard Rules
- Never read `~/.server-connections/servers.json`, `settings.json`, or `encryption.py` directly.
- Never use `--list-full`.
- Never use raw `ssh`, `scp`, `rsync`, `redis-cli`, `mysql`, `psql`, `mc`, `aws s3`, or similar tools unless the user explicitly asks to bypass ServerManager.
- Maximum one connection attempt per action. If it times out or fails, report it and stop.
- `ALIAS "command"` is only for `ssh` and `telnet`.
- `rdp` and `vnc` are GUI-only. Do not invent CLI access.
- For S3/MinIO, list buckets and paths before upload, delete, or URL generation.
- Ask for confirmation before destructive actions if the user's intent is not explicit.
## Preferred Entry Points
Use the shared wrapper:
```bash
$HOME/.server-connections/codex-ssh ...
```
It delegates to the installed `ssh.py` backend without requiring a `python` alias.
Safe discovery commands:
```bash
$HOME/.server-connections/codex-ssh --list
$HOME/.server-connections/codex-ssh --info ALIAS
$HOME/.server-connections/codex-ssh --status
```
Read [references/command-matrix.md](references/command-matrix.md) when you need the per-type command matrix.
## Server Operation Workflow
1. Run `--list`.
2. Match the alias using notes/type, not credentials.
3. Pick commands strictly from the server type.
4. Execute exactly one action.
5. Report the result without exposing IPs, logins, passwords, ports, or secrets.
## Working On ServerManager Itself
Read [references/project.md](references/project.md) before changing integration code.
Source-of-truth files:
- `tools/ssh.py`: local CLI used by Claude/Codex
- `tools/skill-ssh.md`: current Claude `/ssh` instructions
- `core/claude_setup.py`: Claude installer logic
- `build.py`: auto-deploys shared CLI files after build
- `README.md` and `CLAUDE.md`: project-level rules and architecture
If you change command semantics in `tools/ssh.py`, update the user-facing instructions alongside it.

View File

@@ -0,0 +1,91 @@
# Command Matrix
Always identify the server type first with:
```bash
$HOME/.server-connections/codex-ssh --list
```
## Type To Command Map
| Type | Use | Do Not Use |
| --- | --- | --- |
| `ssh` | `ALIAS "command"`, `--upload`, `--download`, `--ping`, `--install-key` | n/a |
| `telnet` | `ALIAS "command"` | `--upload`, `--download`, `--install-key` |
| `mariadb`, `mssql`, `postgresql` | `--sql`, `--sql-databases`, `--sql-tables` | `ALIAS "command"` |
| `redis` | `--redis`, `--redis-info`, `--redis-keys` | `ALIAS "command"` |
| `s3` | `--s3-buckets`, `--s3-ls`, `--s3-upload`, `--s3-download`, `--s3-delete`, `--s3-url`, `--s3-create-bucket` | `ALIAS "command"`, SSH/SFTP commands |
| `grafana` | `--grafana-dashboards`, `--grafana-alerts` | `ALIAS "command"` |
| `prometheus` | `--prom-query`, `--prom-targets`, `--prom-alerts` | `ALIAS "command"` |
| `winrm` | `--ps`, `--cmd` | `ALIAS "command"` |
| `rdp`, `vnc` | GUI only | all CLI actions |
## Common Safe Commands
```bash
$HOME/.server-connections/codex-ssh --list
$HOME/.server-connections/codex-ssh --info ALIAS
$HOME/.server-connections/codex-ssh --status
$HOME/.server-connections/codex-ssh --set-note ALIAS "description"
```
## SSH And Telnet
```bash
$HOME/.server-connections/codex-ssh ALIAS "command"
$HOME/.server-connections/codex-ssh ALIAS --no-sudo "command"
$HOME/.server-connections/codex-ssh ALIAS --upload "local" //remote/path
$HOME/.server-connections/codex-ssh ALIAS --download //remote/path "local"
$HOME/.server-connections/codex-ssh ALIAS --ping
```
Use double slashes for remote SSH/SFTP paths when working from Git Bash style environments.
## SQL
```bash
$HOME/.server-connections/codex-ssh --sql ALIAS "SELECT * FROM table LIMIT 10"
$HOME/.server-connections/codex-ssh --sql-databases ALIAS
$HOME/.server-connections/codex-ssh --sql-tables ALIAS [database]
```
## Redis
```bash
$HOME/.server-connections/codex-ssh --redis ALIAS "GET key"
$HOME/.server-connections/codex-ssh --redis-info ALIAS
$HOME/.server-connections/codex-ssh --redis-keys ALIAS "pattern:*"
```
## S3 / MinIO
Before modifying objects:
```bash
$HOME/.server-connections/codex-ssh --s3-buckets ALIAS
$HOME/.server-connections/codex-ssh --s3-ls ALIAS bucket/prefix/
```
Then act:
```bash
$HOME/.server-connections/codex-ssh --s3-upload ALIAS "local" bucket/key
$HOME/.server-connections/codex-ssh --s3-download ALIAS bucket/key "local"
$HOME/.server-connections/codex-ssh --s3-delete ALIAS bucket/key
$HOME/.server-connections/codex-ssh --s3-url ALIAS bucket/key [seconds]
$HOME/.server-connections/codex-ssh --s3-create-bucket ALIAS bucket-name
```
Do not treat S3 as a shell filesystem.
## Grafana / Prometheus / WinRM
```bash
$HOME/.server-connections/codex-ssh --grafana-dashboards ALIAS
$HOME/.server-connections/codex-ssh --grafana-alerts ALIAS
$HOME/.server-connections/codex-ssh --prom-query ALIAS "up"
$HOME/.server-connections/codex-ssh --prom-targets ALIAS
$HOME/.server-connections/codex-ssh --prom-alerts ALIAS
$HOME/.server-connections/codex-ssh --ps ALIAS "Get-Process"
$HOME/.server-connections/codex-ssh --cmd ALIAS "dir"
```

View File

@@ -0,0 +1,68 @@
# Project Notes
This skill is based on `/home/code/CODING/server-manager`.
## What ServerManager Is
ServerManager is a cross-platform desktop GUI built with CustomTkinter. It manages multiple remote endpoint types through one local encrypted inventory:
- SSH / Telnet
- MariaDB / MSSQL / PostgreSQL
- Redis
- S3 / MinIO
- Grafana
- Prometheus
- WinRM
- RDP / VNC launchers
## Core Integration Model
The GUI and CLI share one local backend:
```text
ServerManager GUI <-> ~/.server-connections/servers.json <-> ~/.server-connections/ssh.py
```
The AI never needs raw credentials. It only uses aliases and the local CLI.
## Important Files
- `README.md`: product overview and install flow
- `CLAUDE.md`: project rules, architecture, security, workflow
- `tools/ssh.py`: CLI entry point used by AI tools
- `tools/skill-ssh.md`: current Claude `/ssh` instructions
- `core/claude_setup.py`: installer for shared CLI files, Claude command, and Codex skill
- `build.py`: auto-deploys `ssh.py`, `encryption.py`, Claude skill, and Codex skill after builds
## Architectural Shape
- `core/server_store.py`: encrypted storage, CRUD, observers, backups
- `core/connection_factory.py`: type-to-client factory with lazy imports
- `core/*_client.py`: protocol-specific backends
- `gui/app.py`: tab registry, conditional tabs by server type
- `gui/tabs/`: protocol-specific GUI surfaces
## Existing Local Agent Integration
Current setup installs:
- `~/.server-connections/ssh.py`
- `~/.server-connections/encryption.py`
- `~/.claude/commands/ssh.md`
- `~/.codex/skills/server-manager/`
- `~/.server-connections/codex-ssh` or `codex-ssh.cmd`
- a `~/.claude/CLAUDE.md` guidance block
The Codex skill mirrors the same safety model:
- use aliases only
- use the shared local CLI
- never read credentials directly
- choose commands by server type
## Local Findings
- `ssh.py` is executable and uses a `python3` shebang, so Codex does not need a `python` alias.
- `ssh.py` has no `--help`; use `--list`, `--info`, and `--status` for safe discovery.
- The Unix wrapper path covers both Linux and macOS through `codex-ssh-wrapper.sh`.
- Windows-native Codex wrapper support exists through `codex-ssh-wrapper.cmd`.

View File

@@ -0,0 +1,28 @@
@echo off
setlocal
set "SHARED_DIR=%SERVER_MANAGER_SHARED_DIR%"
if "%SHARED_DIR%"=="" set "SHARED_DIR=%USERPROFILE%\.server-connections"
set "SSH_SCRIPT=%SHARED_DIR%\ssh.py"
if not exist "%SSH_SCRIPT%" (
echo error: missing ssh.py at %SSH_SCRIPT% 1>&2
echo hint: install ServerManager shared CLI files first 1>&2
exit /b 1
)
where py >nul 2>&1
if not errorlevel 1 (
py -3 "%SSH_SCRIPT%" %*
exit /b %errorlevel%
)
where python >nul 2>&1
if not errorlevel 1 (
python "%SSH_SCRIPT%" %*
exit /b %errorlevel%
)
echo error: neither py nor python is available in PATH 1>&2
echo hint: install Python launcher or use ServerManager Setup on a machine with Python present 1>&2
exit /b 1

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
shared_dir="${SERVER_MANAGER_SHARED_DIR:-$HOME/.server-connections}"
ssh_script="${shared_dir}/ssh.py"
if [[ ! -x "$ssh_script" ]]; then
echo "error: missing executable ssh.py at ${ssh_script}" >&2
echo "hint: install ServerManager's shared CLI files first" >&2
exit 1
fi
exec "$ssh_script" "$@"

View File

@@ -0,0 +1,41 @@
@echo off
setlocal
set "SHARED_DIR=%SERVER_MANAGER_SHARED_DIR%"
if "%SHARED_DIR%"=="" set "SHARED_DIR=%USERPROFILE%\.server-connections"
set "CODEX_HOME=%USERPROFILE%\.codex\skills\server-manager"
set "FAILED=0"
if exist "%SHARED_DIR%\ssh.py" (
echo ok: found %SHARED_DIR%\ssh.py
) else (
echo error: missing %SHARED_DIR%\ssh.py 1>&2
set "FAILED=1"
)
if exist "%SHARED_DIR%\encryption.py" (
echo ok: found %SHARED_DIR%\encryption.py
) else (
echo error: missing %SHARED_DIR%\encryption.py 1>&2
set "FAILED=1"
)
if exist "%SHARED_DIR%\codex-ssh.cmd" (
echo ok: found %SHARED_DIR%\codex-ssh.cmd
) else (
echo error: missing %SHARED_DIR%\codex-ssh.cmd 1>&2
set "FAILED=1"
)
if exist "%CODEX_HOME%\SKILL.md" (
echo ok: found %CODEX_HOME%\SKILL.md
) else (
echo error: missing %CODEX_HOME%\SKILL.md 1>&2
set "FAILED=1"
)
if "%FAILED%"=="1" exit /b 1
echo ok: ServerManager Codex integration looks installed
exit /b 0

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
shared_dir="${SERVER_MANAGER_SHARED_DIR:-$HOME/.server-connections}"
ssh_script="${shared_dir}/ssh.py"
encryption_module="${shared_dir}/encryption.py"
wrapper="${shared_dir}/codex-ssh"
status=0
check_file() {
local path="$1"
if [[ -f "$path" ]]; then
printf '[ok] file %s\n' "$path"
else
printf '[missing] file %s\n' "$path" >&2
status=1
fi
}
check_exec() {
local path="$1"
if [[ -x "$path" ]]; then
printf '[ok] executable %s\n' "$path"
else
printf '[missing] executable %s\n' "$path" >&2
status=1
fi
}
check_file "$encryption_module"
check_exec "$ssh_script"
check_exec "$wrapper"
if [[ -d "/home/code/CODING/server-manager" ]]; then
printf '[ok] source repo /home/code/CODING/server-manager\n'
else
printf '[warn] source repo /home/code/CODING/server-manager not found\n'
fi
exit "$status"

View File

@@ -1,5 +1,15 @@
# Changelog # Changelog
## [Unreleased]
### Added
- Add Codex integration to Setup tab with dedicated install buttons and status rows
- Add packaged Codex skill deployment and local `codex-ssh` wrapper installation
- Add Windows `.cmd` wrappers for Codex skill installation/runtime
### Changed
- Extend `build.py` auto-deploy to sync Codex artifacts alongside Claude artifacts
- Update docs and i18n strings to describe Claude Code + Codex setup flow
## [1.8.24] - 2026-02-24 ## [1.8.24] - 2026-02-24

409
CODEX_SKILL_SETUP.md Normal file
View File

@@ -0,0 +1,409 @@
# Развёртывание Codex Skill Для ServerManager
Этот документ описывает текущее состояние интеграции `ServerManager -> Codex`, автоматическое и ручное развёртывание, проверку и все известные edge cases.
Поддерживаемый deployment target для этой интеграции:
- Linux
- macOS
- Windows
## Что именно разворачивается
Интеграция для Codex состоит из трёх слоёв:
1. Общий локальный backend:
- `~/.server-connections/ssh.py`
- `~/.server-connections/encryption.py`
- `~/.server-connections/servers.json`
2. Codex skill package:
- `~/.codex/skills/server-manager/`
3. Безопасный wrapper для вызова backend из Codex:
- `~/.server-connections/codex-ssh` на Linux/macOS
- `~/.server-connections/codex-ssh.cmd` на Windows
В репозитории исходники skill лежат здесь:
- [SKILL.md](/home/code/CODING/server-manager/.codex/skills/server-manager/SKILL.md)
- [command-matrix.md](/home/code/CODING/server-manager/.codex/skills/server-manager/references/command-matrix.md)
- [project.md](/home/code/CODING/server-manager/.codex/skills/server-manager/references/project.md)
- [server-manager-doctor.sh](/home/code/CODING/server-manager/.codex/skills/server-manager/scripts/server-manager-doctor.sh)
- [server-manager-doctor.cmd](/home/code/CODING/server-manager/.codex/skills/server-manager/scripts/server-manager-doctor.cmd)
- [codex-ssh-wrapper.sh](/home/code/CODING/server-manager/.codex/skills/server-manager/scripts/codex-ssh-wrapper.sh)
- [codex-ssh-wrapper.cmd](/home/code/CODING/server-manager/.codex/skills/server-manager/scripts/codex-ssh-wrapper.cmd)
## Как это работает
Модель безопасности та же, что и у Claude integration:
```text
Codex skill -> ~/.server-connections/codex-ssh -> ~/.server-connections/ssh.py -> encrypted servers.json
```
Ключевая идея:
- Codex видит только алиасы и безопасные результаты команд.
- `ssh.py` сам читает credentials из локального зашифрованного хранилища.
- Codex не должен читать `servers.json`, `settings.json` или `encryption.py` напрямую.
## Что уже автоматизировано
Теперь Codex integration встроена в продуктовый setup flow:
- `core/claude_setup.py` ставит `ssh.py`, `encryption.py`, `~/.claude/commands/ssh.md`, `~/.codex/skills/server-manager/`, wrapper `~/.server-connections/codex-ssh` и блок в `~/.claude/CLAUDE.md`
- вкладка `Setup` в GUI показывает отдельные статусы для Claude skill, Codex skill и Codex wrapper
- `build.py` после сборки автоматически синхронизирует Claude- и Codex-артефакты в локальный runtime
Платформенный split такой:
- Linux/macOS: используются `codex-ssh-wrapper.sh` и `server-manager-doctor.sh`
- Windows: используются `codex-ssh-wrapper.cmd` и `server-manager-doctor.cmd`
Ручная установка всё ещё полезна как fallback path, если нужен точечный repair или offline debugging.
## Предварительные условия
Перед установкой Codex skill должны уже существовать или быть установлены через `Setup`:
1. `~/.server-connections/ssh.py`
2. `~/.server-connections/encryption.py`
3. `~/.server-connections/servers.json`
4. `codex` CLI
Проверка:
```bash
ls -la ~/.server-connections
codex --help
```
Если `~/.server-connections/ssh.py` отсутствует:
1. Открыть ServerManager GUI
2. Перейти в `Setup`
3. Нажать `Install Everything`
Это поставит backend, Claude skill и Codex skill целиком.
## Рекомендуемый путь: установка через GUI
1. Открыть ServerManager
2. Перейти в `Setup`
3. Нажать `Install Everything`
4. Проверить, что зелёные статусы появились у:
- `ssh.py`
- `Encryption module`
- `Claude /ssh skill`
- `Codex skill`
- `Codex wrapper`
- `SSH key`
Для точечного ремонта можно использовать отдельные кнопки `Claude skill` и `Codex skill` в той же вкладке.
## Ручная установка Codex Skill
### 1. Скопировать skill package в глобальный Codex home
```bash
mkdir -p ~/.codex/skills
cp -R .codex/skills/server-manager ~/.codex/skills/server-manager
```
### 2. Установить wrapper в shared runtime directory
Linux/macOS:
```bash
install -m 755 .codex/skills/server-manager/scripts/codex-ssh-wrapper.sh ~/.server-connections/codex-ssh
```
Windows:
```bat
copy .codex\skills\server-manager\scripts\codex-ssh-wrapper.cmd %USERPROFILE%\.server-connections\codex-ssh.cmd
```
### 3. Проверить doctor script
Linux/macOS:
```bash
~/.codex/skills/server-manager/scripts/server-manager-doctor.sh
```
Windows:
```bat
%USERPROFILE%\.codex\skills\server-manager\scripts\server-manager-doctor.cmd
```
Ожидается:
- `ssh.py` найден
- `encryption.py` найден
- `codex-ssh` executable
### 4. Проверить wrapper без раскрытия credentials
Linux/macOS:
```bash
~/.server-connections/codex-ssh --list
```
Windows:
```bat
%USERPROFILE%\.server-connections\codex-ssh.cmd --list
```
Это безопасная базовая проверка. Она должна вывести список алиасов и типов серверов.
### 5. Перезапустить Codex
Если у вас уже была открыта интерактивная Codex session, её нужно перезапустить. Новый skill обычно подхватывается новым процессом Codex, а не уже живой сессией.
## Как проверить, что Codex реально видит skill
Самый надёжный способ:
```bash
codex exec --skip-git-repo-check -s read-only -C /tmp \
"A user asks: Using the locally installed ServerManager integration, what is the safest first command to enumerate configured servers? Reply with only the command."
```
Если skill подхватился корректно, Codex должен сам прочитать `~/.codex/skills/server-manager/SKILL.md` и ответить:
```bash
$HOME/.server-connections/codex-ssh --list
```
## Что Codex должен делать через skill
Правильный workflow для любой server operation:
1. Сначала `--list`
2. Прочитать колонку `Type`
3. Выбрать команду строго по типу сервера
4. Выполнить ровно одно подключение/одно действие
5. Вернуть результат без IP/логинов/паролей/портов
Безопасные discovery-команды:
```bash
$HOME/.server-connections/codex-ssh --list
$HOME/.server-connections/codex-ssh --info ALIAS
$HOME/.server-connections/codex-ssh --status
```
## Источники истины по интеграции
Если меняется поведение интеграции, проверять нужно в таком порядке:
1. [tools/ssh.py](/home/code/CODING/server-manager/tools/ssh.py)
2. [tools/skill-ssh.md](/home/code/CODING/server-manager/tools/skill-ssh.md)
3. [core/claude_setup.py](/home/code/CODING/server-manager/core/claude_setup.py)
4. [build.py](/home/code/CODING/server-manager/build.py)
5. [SKILL.md](/home/code/CODING/server-manager/.codex/skills/server-manager/SKILL.md)
6. [command-matrix.md](/home/code/CODING/server-manager/.codex/skills/server-manager/references/command-matrix.md)
Если меняется семантика `ssh.py`, нужно обновлять и Claude skill, и Codex skill.
## Edge Cases
### 1. `python` alias отсутствует
В этой среде `python` отсутствует, но `ssh.py` имеет shebang `#!/usr/bin/env python3` и executable bit.
Поэтому wrapper вызывает `ssh.py` напрямую:
```bash
~/.server-connections/codex-ssh --list
```
Это намеренно лучше, чем завязка на `python ~/.server-connections/ssh.py`.
### 2. `ssh.py --help` не поддерживается
`ssh.py` не имеет полноценного `--help`. Попытка вызвать `--help` возвращает список доступных alias'ов, а не usage.
Поэтому для безопасной проверки используются:
- `--list`
- `--info ALIAS`
- `--status`
### 3. Skill установлен в repo, но не установлен глобально
Наличие `.codex/skills/server-manager/` внутри репозитория полезно как source of truth, но новый Codex процесс по умолчанию ищет глобальные skills в `~/.codex/skills`.
Если skill есть только в repo:
- документация в проекте будет на месте
- глобальный Codex может его не увидеть
Для надёжности нужен именно глобальный install в `~/.codex/skills/server-manager`.
### 4. Wrapper отсутствует, а skill уже установлен
В этом случае Codex прочитает skill, но не сможет выполнить рекомендуемую команду `$HOME/.server-connections/codex-ssh ...`.
Проверка:
```bash
~/.codex/skills/server-manager/scripts/server-manager-doctor.sh
```
Исправление:
```bash
install -m 755 .codex/skills/server-manager/scripts/codex-ssh-wrapper.sh ~/.server-connections/codex-ssh
```
### 5. Backend отсутствует
Если нет `~/.server-connections/ssh.py` или `encryption.py`, skill бесполезен: он знает workflow, но не имеет локального transport layer.
Исправление:
1. Запустить ServerManager
2. `Setup -> Install Everything`
### 6. Интерактивный Codex уже был запущен до установки skill
Новая интерактивная сессия обычно увидит skill, старая может не увидеть.
Исправление:
- закрыть старую Codex session
- запустить новый процесс `codex`
### 7. `codex exec` не может проверить skill из-за sandbox/network policy
Во время non-interactive проверки Codex может упереться не в skill, а в сетевую политику среды:
- websocket backend заблокирован
- sandbox запрещает соединение
Симптом:
```text
failed to connect to websocket ... Operation not permitted
```
Это не означает, что skill неверный. Это означает, что проверка упёрлась в runtime policy Codex backend.
### 8. Повторная установка поверх существующего skill
GUI installer и `install_codex_skill()` синхронизируют дерево skill поверх существующей директории без полного удаления. Это безопасно для обычных обновлений.
Но при ручном `cp -R` возможен stale state, если какие-то файлы были удалены из repo, а старая глобальная копия осталась.
Полная ручная пересинхронизация нужна только если вы осознанно хотите очистить старые файлы:
1. удалить старую копию осознанно
2. снова скопировать skill целиком
Пример:
```bash
rm -rf ~/.codex/skills/server-manager
cp -R .codex/skills/server-manager ~/.codex/skills/server-manager
```
Делать это только если вы уверены, что хотите полностью пересобрать глобальную копию.
### 9. Изменился `tools/ssh.py`, но глобальная установка осталась старой
Это самый вероятный operational drift.
Что может устареть:
- `~/.server-connections/ssh.py`
- `~/.codex/skills/server-manager/*`
- `~/.server-connections/codex-ssh`
После изменения `tools/ssh.py` или skill docs нужно заново синхронизировать:
```bash
cp tools/ssh.py ~/.server-connections/ssh.py
cp core/encryption.py ~/.server-connections/encryption.py
rm -rf ~/.codex/skills/server-manager
cp -R .codex/skills/server-manager ~/.codex/skills/server-manager
install -m 755 .codex/skills/server-manager/scripts/codex-ssh-wrapper.sh ~/.server-connections/codex-ssh
```
### 10. Windows / macOS / Linux split
Сейчас runtime path intentionally разделён по платформам:
- Linux/macOS: shell wrapper `codex-ssh-wrapper.sh`
- Windows: native wrapper `codex-ssh-wrapper.cmd`
Installer на Windows кладёт wrapper как:
- `~/.server-connections/codex-ssh.cmd`
Installer на Linux/macOS кладёт wrapper как:
- `~/.server-connections/codex-ssh`
Что это закрывает:
- Linux/macOS path без platform-specific разветвления в skill
- запуск через `cmd.exe`
- запуск из PowerShell
- отсутствие bash-зависимости для стандартного Windows deployment path
Ограничение остаётся одно: в текущей среде я прогнал end-to-end smoke только на Linux. macOS и Windows path подготовлены в installer/docs, но не smoke-tested здесь из-за отсутствия соответствующих runner'ов.
### 11. `ssh.py` intentionally не должен читать secrets в контекст AI
Это не баг. Даже если кажется проще открыть `servers.json`, делать этого нельзя.
Skill намеренно запрещает:
- `cat ~/.server-connections/servers.json`
- `cat ~/.server-connections/settings.json`
- `python -c "...read servers.json..."`
- `--list-full`
### 12. fail2ban / anti-bruteforce edge case
Повторные неудачные подключения опасны. Поэтому skill зафиксирован как:
- максимум 1 попытка на действие
- при timeout/ошибке остановиться и сообщить пользователю
Это обязательное правило, а не рекомендация.
## Рекомендуемый Update Workflow
После любых изменений, затрагивающих Codex integration:
1. Обновить исходники в repo:
- `tools/ssh.py`
- `.codex/skills/server-manager/*`
- этот документ
2. Синхронизировать глобальную установку
3. Прогнать doctor
4. Прогнать `~/.server-connections/codex-ssh --list`
5. Прогнать свежий `codex exec` smoke test
## Минимальный Smoke Test
```bash
~/.codex/skills/server-manager/scripts/server-manager-doctor.sh
~/.server-connections/codex-ssh --list
codex exec --skip-git-repo-check -s read-only -C /tmp \
"A user asks: Using the locally installed ServerManager integration, what is the safest first command to enumerate configured servers? Reply with only the command."
```
## Что ещё желательно автоматизировать позже
Чтобы интеграция стала production-complete, в проект ещё полезно добавить:
1. отдельный smoke test script внутри репозитория для проверки именно Codex integration
2. e2e smoke test на Windows runner
3. e2e smoke test на macOS runner
4. optional PowerShell-native wrapper, если понадобится richer Windows logging

View File

@@ -2,7 +2,7 @@
<p align="center"> <p align="center">
<strong>Desktop GUI for managing remote servers</strong><br> <strong>Desktop GUI for managing remote servers</strong><br>
CustomTkinter + Paramiko | Dark Theme | Claude Code Integration CustomTkinter + Paramiko | Dark Theme | Claude Code + Codex Integration
</p> </p>
<p align="center"> <p align="center">
@@ -22,7 +22,7 @@
- **SFTP Transfer** — upload/download files with progress bar - **SFTP Transfer** — upload/download files with progress bar
- **SSH Keys** — generate ed25519, install on server, copy to clipboard - **SSH Keys** — generate ed25519, install on server, copy to clipboard
- **Status Monitor** — background check every 60 sec (online/offline badges) - **Status Monitor** — background check every 60 sec (online/offline badges)
- **Claude Code Integration** — one-click setup, shared config with `/ssh` skill - **Claude Code + Codex Integration** — one-click setup, shared config with `/ssh` skill and Codex skill
- **TOTP / 2FA** — Google Authenticator compatible codes with live countdown, one-click copy - **TOTP / 2FA** — Google Authenticator compatible codes with live countdown, one-click copy
- **Encryption** — servers.json encrypted with Fernet (passwords never stored in plaintext) - **Encryption** — servers.json encrypted with Fernet (passwords never stored in plaintext)
- **Backups** — manual and automatic backups with one-click restore - **Backups** — manual and automatic backups with one-click restore
@@ -62,23 +62,25 @@ Output goes to `releases/ServerManager-vX.Y.Z-{platform}.exe`
3. **Terminal** — select server → Terminal tab → type command → Run 3. **Terminal** — select server → Terminal tab → type command → Run
4. **Files** — select server → Files tab → set paths → Upload/Download 4. **Files** — select server → Files tab → set paths → Upload/Download
5. **Keys** — Keys tab → Generate Key → Install on Server 5. **Keys** — Keys tab → Generate Key → Install on Server
6. **Setup** — Setup tab → "Install Everything" → Claude Code ready 6. **Setup** — Setup tab → "Install Everything" → Claude Code and Codex ready
7. Status badges update automatically (green = online, red = offline) 7. Status badges update automatically (green = online, red = offline)
### Claude Code Integration ### Claude Code + Codex Integration
ServerManager and Claude Code share the same config file: `~/.server-connections/servers.json` ServerManager, Claude Code, and Codex share the same config file: `~/.server-connections/servers.json`
For Codex deployment and operational edge cases, see [`CODEX_SKILL_SETUP.md`](CODEX_SKILL_SETUP.md).
**How it works:** **How it works:**
``` ```
ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py (Claude Code) ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py backend
↕ ↕ ↕ ↕
Add/edit/delete /ssh skill Add/edit/delete Claude /ssh + Codex skill
servers in GUI executes commands servers in GUI execute commands
``` ```
- Add a server in GUI → Claude Code sees it immediately via `/ssh list` - Add a server in GUI → Claude Code and Codex see it immediately
- Both use the same `ssh.py` + `servers.json` - Both agents use the same `ssh.py` + `servers.json`
- Passwords **never** pass through the AI API - Passwords **never** pass through the AI API
**New SSH Commands:** **New SSH Commands:**
@@ -93,12 +95,14 @@ ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py (C
**Setup on a new machine:** **Setup on a new machine:**
1. Install ServerManager (clone repo or download binary) 1. Install ServerManager (clone repo or download binary)
2. Open Setup tab → click "Install Everything" 2. Open Setup tab → click "Install Everything"
3. Done. Claude Code now has `/ssh` skill and access to your servers 3. Done. Claude Code now has `/ssh`, and Codex now has the `server-manager` skill with access to your servers
The Setup tab installs: The Setup tab installs:
- `ssh.py``~/.server-connections/` (SSH utility) - `ssh.py``~/.server-connections/` (SSH utility)
- `encryption.py``~/.server-connections/` (encryption module for CLI) - `encryption.py``~/.server-connections/` (encryption module for CLI)
- `/ssh` skill → `~/.claude/commands/ssh.md` (Claude Code skill) - `/ssh` skill → `~/.claude/commands/ssh.md` (Claude Code skill)
- `server-manager` skill → `~/.codex/skills/server-manager/` (Codex skill package)
- `codex-ssh` wrapper → `~/.server-connections/` (safe Codex entry point)
- SSH key (ed25519) — if not exists - SSH key (ed25519) — if not exists
- Checks for duplicates — safe to run multiple times - Checks for duplicates — safe to run multiple times
@@ -140,7 +144,7 @@ App executes: sudo -S -p '' bash -c 'systemctl restart nginx'
- Passwords stored locally only, **never sent to any AI/API** - Passwords stored locally only, **never sent to any AI/API**
- SSH keys (ed25519) — recommended auth method - SSH keys (ed25519) — recommended auth method
- sudo password sent via stdin (not visible in process list) - sudo password sent via stdin (not visible in process list)
- When used with Claude Code: only alias + command are passed through the AI API, passwords stay in the local encrypted file - When used with Claude Code or Codex: only alias + command are passed through the AI API, passwords stay in the local encrypted file
- Automatic pre-encryption backup on first migration - Automatic pre-encryption backup on first migration
### Project Structure ### Project Structure
@@ -154,7 +158,7 @@ ServerManager/
│ ├── server_store.py # CRUD + encrypted JSON + observer + backups │ ├── server_store.py # CRUD + encrypted JSON + observer + backups
│ ├── encryption.py # Fernet encryption module │ ├── encryption.py # Fernet encryption module
│ ├── ssh_client.py # Paramiko SSH/SFTP wrapper │ ├── ssh_client.py # Paramiko SSH/SFTP wrapper
│ ├── claude_setup.py # Claude Code integration installer │ ├── claude_setup.py # Claude Code + Codex integration installer
│ ├── status_checker.py # Background monitoring │ ├── status_checker.py # Background monitoring
│ ├── totp.py # TOTP/2FA module (pyotp) │ ├── totp.py # TOTP/2FA module (pyotp)
│ ├── logger.py # Rotating file logger │ ├── logger.py # Rotating file logger
@@ -166,7 +170,7 @@ ServerManager/
│ ├── tabs/ # Terminal, Files, Info, Keys, Setup │ ├── tabs/ # Terminal, Files, Info, Keys, Setup
│ └── widgets/ # StatusBadge │ └── widgets/ # StatusBadge
├── tools/ # CLI tools (installed to ~/.server-connections/) ├── tools/ # CLI tools (installed to ~/.server-connections/)
│ ├── ssh.py # SSH utility for Claude Code │ ├── ssh.py # SSH utility for Claude Code / Codex
│ └── skill-ssh.md # /ssh skill template │ └── skill-ssh.md # /ssh skill template
├── config/ # Example configs ├── config/ # Example configs
├── releases/ # Built executables ├── releases/ # Built executables
@@ -187,7 +191,7 @@ pip install -r requirements.txt
python main.py python main.py
# → Setup tab → Install Everything # → Setup tab → Install Everything
# → Add your servers via + Add # → Add your servers via + Add
# → Done! Both GUI and Claude Code are ready # → Done! GUI, Claude Code, and Codex are ready
``` ```
--- ---
@@ -201,7 +205,7 @@ python main.py
- **SFTP** — загрузка и скачивание файлов с прогресс-баром - **SFTP** — загрузка и скачивание файлов с прогресс-баром
- **SSH-ключи** — генерация ed25519, установка на сервер, копирование - **SSH-ключи** — генерация ed25519, установка на сервер, копирование
- **Мониторинг** — фоновая проверка каждые 60 сек (бейджи online/offline) - **Мониторинг** — фоновая проверка каждые 60 сек (бейджи online/offline)
- **Интеграция с Claude Code** — установка в один клик, общий конфиг со скиллом `/ssh` - **Интеграция с Claude Code + Codex** — установка в один клик, общий конфиг со скиллом `/ssh` и Codex skill
- **TOTP / 2FA** — коды Google Authenticator с обратным отсчётом, копирование в один клик - **TOTP / 2FA** — коды Google Authenticator с обратным отсчётом, копирование в один клик
- **Шифрование** — servers.json зашифрован Fernet (пароли не хранятся в открытом виде) - **Шифрование** — servers.json зашифрован Fernet (пароли не хранятся в открытом виде)
- **Бэкапы** — ручные и автоматические с восстановлением в один клик - **Бэкапы** — ручные и автоматические с восстановлением в один клик
@@ -241,23 +245,23 @@ python build.py
3. **Терминал** — выберите сервер → вкладка Terminal → введите команду → Run 3. **Терминал** — выберите сервер → вкладка Terminal → введите команду → Run
4. **Файлы** — выберите сервер → вкладка Files → укажите пути → Upload/Download 4. **Файлы** — выберите сервер → вкладка Files → укажите пути → Upload/Download
5. **Ключи** — вкладка Keys → Generate Key → Install on Server 5. **Ключи** — вкладка Keys → Generate Key → Install on Server
6. **Настройка Claude** — вкладка Setup → "Install Everything" → Claude Code готов 6. **Настройка** — вкладка Setup → "Install Everything" → Claude Code и Codex готовы
7. Бейджи статуса обновляются автоматически (зелёный = online, красный = offline) 7. Бейджи статуса обновляются автоматически (зелёный = online, красный = offline)
### Интеграция с Claude Code ### Интеграция с Claude Code + Codex
ServerManager и Claude Code используют **один и тот же файл конфигурации**: `~/.server-connections/servers.json` ServerManager, Claude Code и Codex используют **один и тот же файл конфигурации**: `~/.server-connections/servers.json`
**Как это работает:** **Как это работает:**
``` ```
ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py (Claude Code) ServerManager GUI ←→ ~/.server-connections/servers.json ←→ backend ssh.py
↕ ↕ ↕ ↕
Добавил/изменил скилл /ssh Добавил/изменил Claude /ssh + Codex skill
сервер в GUI выполняет команды серверы в GUI выполняют команды
``` ```
- Добавил сервер в GUI → Claude Code сразу видит его через `/ssh list` - Добавил сервер в GUI → Claude Code и Codex сразу видят его
- Оба используют один `ssh.py` + `servers.json` - Оба агента используют один `ssh.py` + `servers.json`
- Пароли **никогда** не проходят через API нейронки - Пароли **никогда** не проходят через API нейронки
**Новые SSH команды:** **Новые SSH команды:**
@@ -272,12 +276,14 @@ ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py (C
**Настройка на новой машине:** **Настройка на новой машине:**
1. Установить ServerManager (клонировать репо или скачать бинарник) 1. Установить ServerManager (клонировать репо или скачать бинарник)
2. Открыть вкладку Setup → нажать "Install Everything" 2. Открыть вкладку Setup → нажать "Install Everything"
3. Готово. Claude Code теперь имеет скилл `/ssh` и доступ к серверам 3. Готово. Claude Code получает скилл `/ssh`, а Codex получает skill `server-manager` и доступ к серверам
Вкладка Setup устанавливает: Вкладка Setup устанавливает:
- `ssh.py``~/.server-connections/` (SSH-утилита) - `ssh.py``~/.server-connections/` (SSH-утилита)
- `encryption.py``~/.server-connections/` (модуль шифрования для CLI) - `encryption.py``~/.server-connections/` (модуль шифрования для CLI)
- скилл `/ssh``~/.claude/commands/ssh.md` (скилл Claude Code) - скилл `/ssh``~/.claude/commands/ssh.md` (скилл Claude Code)
- skill `server-manager``~/.codex/skills/server-manager/` (скилл Codex)
- wrapper `codex-ssh``~/.server-connections/` (безопасная точка входа для Codex)
- SSH-ключ (ed25519) — если ещё не создан - SSH-ключ (ed25519) — если ещё не создан
- Проверяет дубли — безопасно запускать повторно - Проверяет дубли — безопасно запускать повторно
@@ -319,7 +325,7 @@ ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py (C
- Пароли хранятся только локально, **никогда не передаются в AI/API** - Пароли хранятся только локально, **никогда не передаются в AI/API**
- SSH-ключи (ed25519) — рекомендуемый метод аутентификации - SSH-ключи (ed25519) — рекомендуемый метод аутентификации
- sudo-пароль передаётся через stdin (не виден в списке процессов) - sudo-пароль передаётся через stdin (не виден в списке процессов)
- При использовании с Claude Code: через API нейронки проходят только alias + команда, пароли остаются в зашифрованном локальном файле - При использовании с Claude Code или Codex: через API нейронки проходят только alias + команда, пароли остаются в зашифрованном локальном файле
- Автоматический пред-шифровальный бэкап при первой миграции - Автоматический пред-шифровальный бэкап при первой миграции
### Развёртывание на новой машине ### Развёртывание на новой машине
@@ -336,7 +342,7 @@ pip install -r requirements.txt
python main.py python main.py
# → Вкладка Setup → Install Everything # → Вкладка Setup → Install Everything
# → Добавить серверы через + Add # → Добавить серверы через + Add
# → Готово! GUI и Claude Code работают с одним конфигом # → Готово! GUI, Claude Code и Codex работают с одним конфигом
``` ```
--- ---
@@ -350,7 +356,7 @@ python main.py
- **SFTP传输** — 带进度条的文件上传/下载 - **SFTP传输** — 带进度条的文件上传/下载
- **SSH密钥** — 生成ed25519、安装到服务器、复制到剪贴板 - **SSH密钥** — 生成ed25519、安装到服务器、复制到剪贴板
- **状态监控** — 每60秒后台检查在线/离线徽标) - **状态监控** — 每60秒后台检查在线/离线徽标)
- **Claude Code集成** — 一键设置,与`/ssh`技能共享配置 - **Claude Code + Codex 集成** — 一键设置,与 `/ssh` 技能和 Codex skill 共享配置
- **TOTP / 2FA** — 兼容Google Authenticator的验证码实时倒计时一键复制 - **TOTP / 2FA** — 兼容Google Authenticator的验证码实时倒计时一键复制
- **加密** — servers.json使用Fernet加密密码不再以明文存储 - **加密** — servers.json使用Fernet加密密码不再以明文存储
- **备份** — 手动和自动备份,一键恢复 - **备份** — 手动和自动备份,一键恢复
@@ -390,34 +396,36 @@ python build.py
3. **终端** — 选择服务器 → Terminal标签 → 输入命令 → Run 3. **终端** — 选择服务器 → Terminal标签 → 输入命令 → Run
4. **文件** — 选择服务器 → Files标签 → 设置路径 → Upload/Download 4. **文件** — 选择服务器 → Files标签 → 设置路径 → Upload/Download
5. **密钥** — Keys标签 → Generate Key → Install on Server 5. **密钥** — Keys标签 → Generate Key → Install on Server
6. **设置Claude** — Setup标签 → "Install Everything" → Claude Code就绪 6. **设置** — Setup标签 → "Install Everything" → Claude Code 和 Codex 就绪
7. 状态徽标自动更新(绿色 = 在线,红色 = 离线) 7. 状态徽标自动更新(绿色 = 在线,红色 = 离线)
### Claude Code集成 ### Claude Code + Codex 集成
ServerManagerClaude Code共享**同一个配置文件**`~/.server-connections/servers.json` ServerManagerClaude Code 和 Codex 共享**同一个配置文件**`~/.server-connections/servers.json`
**工作原理:** **工作原理:**
``` ```
ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py (Claude Code) ServerManager GUI ←→ ~/.server-connections/servers.json ←→ ssh.py 后端
↕ ↕ ↕ ↕
在GUI中添加/编辑 /ssh技能 在GUI中添加/编辑 Claude /ssh + Codex skill
服务器 执行命令 服务器 执行命令
``` ```
- 在GUI中添加服务器 → Claude Code立即通过 `/ssh list` 看到 - 在GUI中添加服务器 → Claude Code 和 Codex 都会立即看到
-者使用相同的 `ssh.py` + `servers.json` -个代理都使用同一个 `ssh.py` + `servers.json`
- 密码**绝不**通过AI API传递 - 密码**绝不**通过AI API传递
**在新机器上设置:** **在新机器上设置:**
1. 安装ServerManager克隆仓库或下载二进制文件 1. 安装ServerManager克隆仓库或下载二进制文件
2. 打开Setup标签 → 点击 "Install Everything" 2. 打开Setup标签 → 点击 "Install Everything"
3. 完成。Claude Code现在拥有 `/ssh` 技能并可访问您的服务器 3. 完成。Claude Code 现在拥有 `/ssh` 技能Codex 现在拥有 `server-manager` 技能并可访问您的服务器
Setup标签安装 Setup标签安装
- `ssh.py``~/.server-connections/`SSH工具 - `ssh.py``~/.server-connections/`SSH工具
- `encryption.py``~/.server-connections/`CLI加密模块 - `encryption.py``~/.server-connections/`CLI加密模块
- `/ssh` 技能 → `~/.claude/commands/ssh.md`Claude Code技能 - `/ssh` 技能 → `~/.claude/commands/ssh.md`Claude Code技能
- `server-manager` 技能 → `~/.codex/skills/server-manager/`Codex技能包
- `codex-ssh` 包装器 → `~/.server-connections/`Codex安全入口
- SSH密钥ed25519— 如果不存在 - SSH密钥ed25519— 如果不存在
- 检查重复 — 可安全重复运行 - 检查重复 — 可安全重复运行
@@ -459,7 +467,7 @@ Setup标签安装
- 密码仅存储在本地,**绝不发送到任何AI/API** - 密码仅存储在本地,**绝不发送到任何AI/API**
- SSH密钥ed25519— 推荐的认证方式 - SSH密钥ed25519— 推荐的认证方式
- sudo密码通过stdin传递在进程列表中不可见 - sudo密码通过stdin传递在进程列表中不可见
- 与Claude Code配合使用时只有别名和命令通过AI API传递密码保留在本地加密文件中 - Claude Code 或 Codex 配合使用时:只有别名和命令通过 AI API 传递,密码保留在本地加密文件中
- 首次迁移时自动创建加密前备份 - 首次迁移时自动创建加密前备份
### 在新机器上部署 ### 在新机器上部署
@@ -476,7 +484,7 @@ pip install -r requirements.txt
python main.py python main.py
# → Setup标签 → Install Everything # → Setup标签 → Install Everything
# → 通过 + Add 添加服务器 # → 通过 + Add 添加服务器
# → 完成GUIClaude Code使用同一个配置 # → 完成GUIClaude Code 和 Codex 使用同一个配置
``` ```
--- ---

View File

@@ -115,6 +115,7 @@ def build():
"--add-data", f"tools/ssh.py{os.pathsep}tools", "--add-data", f"tools/ssh.py{os.pathsep}tools",
"--add-data", f"tools/skill-ssh.md{os.pathsep}tools", "--add-data", f"tools/skill-ssh.md{os.pathsep}tools",
"--add-data", f"core/encryption.py{os.pathsep}core", "--add-data", f"core/encryption.py{os.pathsep}core",
"--add-data", f".codex/skills/server-manager{os.pathsep}.codex/skills/server-manager",
] ]
# PNG icons for GUI (Material Design) # PNG icons for GUI (Material Design)
@@ -350,34 +351,32 @@ def cleanup_old_releases():
def deploy_shared_files(): def deploy_shared_files():
"""Auto-deploy ssh.py, encryption.py, skill to shared dirs after build. """Auto-deploy shared CLI files and local agent integrations after build."""
from core.claude_setup import (
install_claude_skill,
install_codex_skill,
install_ssh_script,
)
Ensures Claude Code /ssh skill always uses the latest version. deploy_steps = [
Without this, editing tools/ssh.py updates the exe but NOT the live install_ssh_script,
~/.server-connections/ssh.py that Claude Code actually calls. install_claude_skill,
""" install_codex_skill,
shared_dir = os.path.expanduser("~/.server-connections")
skill_dir = os.path.expanduser("~/.claude/commands")
deploy_map = [
(os.path.join(PROJECT_DIR, "tools", "ssh.py"),
os.path.join(shared_dir, "ssh.py")),
(os.path.join(PROJECT_DIR, "core", "encryption.py"),
os.path.join(shared_dir, "encryption.py")),
(os.path.join(PROJECT_DIR, "tools", "skill-ssh.md"),
os.path.join(skill_dir, "ssh.md")),
] ]
deployed = [] deployed = []
for src, dst in deploy_map: for step in deploy_steps:
if not os.path.exists(src): try:
continue result = step()
os.makedirs(os.path.dirname(dst), exist_ok=True) if result:
shutil.copy2(src, dst) deployed.append(result.replace("\n", "; "))
deployed.append(os.path.basename(dst)) except Exception as exc:
print(f"WARNING: auto-deploy step failed ({step.__name__}): {exc}")
if deployed: if deployed:
print(f"Auto-deployed to local: {', '.join(deployed)}") print("Auto-deployed to local:")
for item in deployed:
print(f"- {item}")
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -1,12 +1,15 @@
""" """
Claude Code integration setup. Local AI agent integration setup.
Installs ssh.py, encryption.py, /ssh skill, SSH key — everything needed Installs the shared ssh.py/encryption.py backend, Claude /ssh command,
for Claude Code to manage servers via the shared servers.json. Codex skill package, platform-specific wrappers, and SSH key material.
""" """
import os import os
import sys import re
import shutil import shutil
import subprocess
import sys
from core.logger import log from core.logger import log
SHARED_DIR = os.path.expanduser("~/.server-connections") SHARED_DIR = os.path.expanduser("~/.server-connections")
@@ -19,13 +22,24 @@ else:
SSH_SCRIPT_SRC = os.path.join(_BASE_DIR, "tools", "ssh.py") SSH_SCRIPT_SRC = os.path.join(_BASE_DIR, "tools", "ssh.py")
ENCRYPTION_SRC = os.path.join(_BASE_DIR, "core", "encryption.py") ENCRYPTION_SRC = os.path.join(_BASE_DIR, "core", "encryption.py")
SKILL_SRC = os.path.join(_BASE_DIR, "tools", "skill-ssh.md") CLAUDE_SKILL_SRC = os.path.join(_BASE_DIR, "tools", "skill-ssh.md")
SKILL_DST_DIR = os.path.expanduser("~/.claude/commands") CLAUDE_SKILL_DST_DIR = os.path.expanduser("~/.claude/commands")
SKILL_DST = os.path.join(SKILL_DST_DIR, "ssh.md") CLAUDE_SKILL_DST = os.path.join(CLAUDE_SKILL_DST_DIR, "ssh.md")
SSH_KEY_PATH = os.path.expanduser("~/.ssh/id_ed25519") SSH_KEY_PATH = os.path.expanduser("~/.ssh/id_ed25519")
GLOBAL_CLAUDE_MD = os.path.expanduser("~/.claude/CLAUDE.md") GLOBAL_CLAUDE_MD = os.path.expanduser("~/.claude/CLAUDE.md")
CODEX_SKILL_SRC_DIR = os.path.join(_BASE_DIR, ".codex", "skills", "server-manager")
CODEX_SKILL_DST_ROOT = os.path.expanduser("~/.codex/skills")
CODEX_SKILL_DST_DIR = os.path.join(CODEX_SKILL_DST_ROOT, "server-manager")
CODEX_SKILL_ENTRY = os.path.join(CODEX_SKILL_DST_DIR, "SKILL.md")
CODEX_WRAPPER_SRC_SH = os.path.join(CODEX_SKILL_SRC_DIR, "scripts", "codex-ssh-wrapper.sh")
CODEX_WRAPPER_SRC_CMD = os.path.join(CODEX_SKILL_SRC_DIR, "scripts", "codex-ssh-wrapper.cmd")
CODEX_WRAPPER_DST = os.path.join(
SHARED_DIR,
"codex-ssh.cmd" if sys.platform == "win32" else "codex-ssh",
)
_BLOCK_START = "<!-- server-manager:start -->" _BLOCK_START = "<!-- server-manager:start -->"
_BLOCK_END = "<!-- server-manager:end -->" _BLOCK_END = "<!-- server-manager:end -->"
@@ -67,6 +81,27 @@ python ~/.server-connections/ssh.py --status # online/offline
""" """
def _ensure_executable(path: str):
if sys.platform == "win32" or not os.path.exists(path):
return
mode = os.stat(path).st_mode
os.chmod(path, mode | 0o755)
def _copy_file(src: str, dst: str, executable: bool = False) -> str:
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy2(src, dst)
if executable:
_ensure_executable(dst)
return dst
def _copy_tree(src: str, dst: str) -> str:
os.makedirs(dst, exist_ok=True)
shutil.copytree(src, dst, dirs_exist_ok=True)
return dst
def check_status() -> dict: def check_status() -> dict:
"""Check what's installed and what's missing.""" """Check what's installed and what's missing."""
return { return {
@@ -74,7 +109,9 @@ def check_status() -> dict:
"servers_json": os.path.exists(os.path.join(SHARED_DIR, "servers.json")), "servers_json": os.path.exists(os.path.join(SHARED_DIR, "servers.json")),
"ssh_script": os.path.exists(os.path.join(SHARED_DIR, "ssh.py")), "ssh_script": os.path.exists(os.path.join(SHARED_DIR, "ssh.py")),
"encryption": os.path.exists(os.path.join(SHARED_DIR, "encryption.py")), "encryption": os.path.exists(os.path.join(SHARED_DIR, "encryption.py")),
"skill_installed": os.path.exists(SKILL_DST), "claude_skill_installed": os.path.exists(CLAUDE_SKILL_DST),
"codex_skill_installed": os.path.exists(CODEX_SKILL_ENTRY),
"codex_wrapper_installed": os.path.exists(CODEX_WRAPPER_DST),
"ssh_key_exists": os.path.exists(SSH_KEY_PATH), "ssh_key_exists": os.path.exists(SSH_KEY_PATH),
"ssh_key_pub": os.path.exists(SSH_KEY_PATH + ".pub"), "ssh_key_pub": os.path.exists(SSH_KEY_PATH + ".pub"),
} }
@@ -85,10 +122,9 @@ def install_ssh_script() -> str:
os.makedirs(SHARED_DIR, exist_ok=True) os.makedirs(SHARED_DIR, exist_ok=True)
results = [] results = []
# Copy ssh.py
dst = os.path.join(SHARED_DIR, "ssh.py") dst = os.path.join(SHARED_DIR, "ssh.py")
if os.path.exists(SSH_SCRIPT_SRC): if os.path.exists(SSH_SCRIPT_SRC):
shutil.copy2(SSH_SCRIPT_SRC, dst) _copy_file(SSH_SCRIPT_SRC, dst, executable=True)
log.info(f"ssh.py installed: {dst}") log.info(f"ssh.py installed: {dst}")
results.append(f"ssh.py installed: {dst}") results.append(f"ssh.py installed: {dst}")
elif os.path.exists(dst): elif os.path.exists(dst):
@@ -96,10 +132,9 @@ def install_ssh_script() -> str:
else: else:
results.append("ERROR: ssh.py source not found") results.append("ERROR: ssh.py source not found")
# Copy encryption.py
enc_dst = os.path.join(SHARED_DIR, "encryption.py") enc_dst = os.path.join(SHARED_DIR, "encryption.py")
if os.path.exists(ENCRYPTION_SRC): if os.path.exists(ENCRYPTION_SRC):
shutil.copy2(ENCRYPTION_SRC, enc_dst) _copy_file(ENCRYPTION_SRC, enc_dst)
log.info(f"encryption.py installed: {enc_dst}") log.info(f"encryption.py installed: {enc_dst}")
results.append(f"encryption.py installed: {enc_dst}") results.append(f"encryption.py installed: {enc_dst}")
elif os.path.exists(enc_dst): elif os.path.exists(enc_dst):
@@ -110,22 +145,59 @@ def install_ssh_script() -> str:
return "\n".join(results) return "\n".join(results)
def install_skill() -> str: def install_claude_skill() -> str:
"""Install /ssh skill for Claude Code.""" """Install /ssh skill for Claude Code."""
os.makedirs(SKILL_DST_DIR, exist_ok=True) os.makedirs(CLAUDE_SKILL_DST_DIR, exist_ok=True)
if os.path.exists(SKILL_SRC): if os.path.exists(CLAUDE_SKILL_SRC):
shutil.copy2(SKILL_SRC, SKILL_DST) _copy_file(CLAUDE_SKILL_SRC, CLAUDE_SKILL_DST)
log.info(f"Skill installed: {SKILL_DST}") log.info(f"Claude skill installed: {CLAUDE_SKILL_DST}")
return f"Skill installed: {SKILL_DST}" return f"Claude skill installed: {CLAUDE_SKILL_DST}"
# Fallback: check existing if os.path.exists(CLAUDE_SKILL_DST):
if os.path.exists(SKILL_DST): return f"Claude skill already exists: {CLAUDE_SKILL_DST}"
return f"Skill already exists: {SKILL_DST}"
# Generate minimal skill
skill_content = _generate_skill_content() skill_content = _generate_skill_content()
with open(SKILL_DST, "w", encoding="utf-8") as f: with open(CLAUDE_SKILL_DST, "w", encoding="utf-8") as f:
f.write(skill_content) f.write(skill_content)
log.info(f"Skill generated: {SKILL_DST}") log.info(f"Claude skill generated: {CLAUDE_SKILL_DST}")
return f"Skill generated: {SKILL_DST}" return f"Claude skill generated: {CLAUDE_SKILL_DST}"
def install_codex_skill() -> str:
"""Install ServerManager skill package for Codex and the local wrapper."""
results = []
if os.path.isdir(CODEX_SKILL_SRC_DIR):
_copy_tree(CODEX_SKILL_SRC_DIR, CODEX_SKILL_DST_DIR)
for rel_path in [
os.path.join("scripts", "server-manager-doctor.sh"),
os.path.join("scripts", "server-manager-doctor.cmd"),
os.path.join("scripts", "codex-ssh-wrapper.sh"),
os.path.join("scripts", "codex-ssh-wrapper.cmd"),
]:
_ensure_executable(os.path.join(CODEX_SKILL_DST_DIR, rel_path))
log.info(f"Codex skill installed: {CODEX_SKILL_DST_DIR}")
results.append(f"Codex skill installed: {CODEX_SKILL_DST_DIR}")
elif os.path.exists(CODEX_SKILL_ENTRY):
results.append(f"Codex skill already exists: {CODEX_SKILL_DST_DIR}")
else:
results.append("ERROR: Codex skill source not found")
wrapper_src = CODEX_WRAPPER_SRC_CMD if sys.platform == "win32" else CODEX_WRAPPER_SRC_SH
if os.path.exists(wrapper_src):
_copy_file(wrapper_src, CODEX_WRAPPER_DST, executable=(sys.platform != "win32"))
log.info(f"Codex wrapper installed: {CODEX_WRAPPER_DST}")
results.append(f"Codex wrapper installed: {CODEX_WRAPPER_DST}")
elif os.path.exists(CODEX_WRAPPER_DST):
results.append(f"Codex wrapper already exists: {CODEX_WRAPPER_DST}")
else:
results.append("ERROR: Codex wrapper source not found")
return "\n".join(results)
def install_skill() -> str:
"""Backward-compatible alias for the Claude /ssh skill installer."""
return install_claude_skill()
def generate_ssh_key() -> str: def generate_ssh_key() -> str:
@@ -135,7 +207,6 @@ def generate_ssh_key() -> str:
os.makedirs(os.path.dirname(SSH_KEY_PATH), exist_ok=True) os.makedirs(os.path.dirname(SSH_KEY_PATH), exist_ok=True)
import subprocess
try: try:
subprocess.run( subprocess.run(
["ssh-keygen", "-t", "ed25519", "-f", SSH_KEY_PATH, ["ssh-keygen", "-t", "ed25519", "-f", SSH_KEY_PATH,
@@ -156,11 +227,7 @@ def generate_ssh_key() -> str:
def install_global_claude_md() -> str: def install_global_claude_md() -> str:
"""Add/update server manager section in global ~/.claude/CLAUDE.md. """Add/update server manager section in global ~/.claude/CLAUDE.md."""
Uses start/end markers to safely replace existing block without duplication.
"""
import re
os.makedirs(os.path.dirname(GLOBAL_CLAUDE_MD), exist_ok=True) os.makedirs(os.path.dirname(GLOBAL_CLAUDE_MD), exist_ok=True)
existing = "" existing = ""
@@ -174,14 +241,12 @@ def install_global_claude_md() -> str:
) )
if pattern.search(existing): if pattern.search(existing):
# Блок уже есть — заменяем на актуальную версию
updated = pattern.sub(GLOBAL_CLAUDE_MD_BLOCK.strip(), existing) updated = pattern.sub(GLOBAL_CLAUDE_MD_BLOCK.strip(), existing)
with open(GLOBAL_CLAUDE_MD, "w", encoding="utf-8") as f: with open(GLOBAL_CLAUDE_MD, "w", encoding="utf-8") as f:
f.write(updated) f.write(updated)
log.info(f"Global CLAUDE.md block updated: {GLOBAL_CLAUDE_MD}") log.info(f"Global CLAUDE.md block updated: {GLOBAL_CLAUDE_MD}")
return f"Global CLAUDE.md block updated: {GLOBAL_CLAUDE_MD}" return f"Global CLAUDE.md block updated: {GLOBAL_CLAUDE_MD}"
else:
# Блока нет — добавляем в конец
with open(GLOBAL_CLAUDE_MD, "a", encoding="utf-8") as f: with open(GLOBAL_CLAUDE_MD, "a", encoding="utf-8") as f:
if existing and not existing.endswith("\n"): if existing and not existing.endswith("\n"):
f.write("\n") f.write("\n")
@@ -191,12 +256,13 @@ def install_global_claude_md() -> str:
def install_all() -> list[str]: def install_all() -> list[str]:
"""Full setup — install everything.""" """Full setup — install everything for Claude Code and Codex."""
results = [] results = []
steps = [ steps = [
("ssh_script", install_ssh_script), ("ssh_script", install_ssh_script),
("skill", install_skill), ("claude_skill", install_claude_skill),
("codex_skill", install_codex_skill),
("ssh_key", generate_ssh_key), ("ssh_key", generate_ssh_key),
("global_claude_md", install_global_claude_md), ("global_claude_md", install_global_claude_md),
] ]

View File

@@ -46,7 +46,7 @@ _EN = {
"about_desc": ( "about_desc": (
"Desktop application for managing remote servers.\n" "Desktop application for managing remote servers.\n"
"SSH terminal, SFTP file transfer, key management,\n" "SSH terminal, SFTP file transfer, key management,\n"
"encrypted credentials, and Claude Code integration." "encrypted credentials, and Claude Code / Codex integration."
), ),
"about_features_title": "⚡ Features", "about_features_title": "⚡ Features",
"about_features": ( "about_features": (
@@ -56,13 +56,13 @@ _EN = {
"• TOTP / 2FA (Google Authenticator)\n" "• TOTP / 2FA (Google Authenticator)\n"
"• Encrypted credentials (Fernet)\n" "• Encrypted credentials (Fernet)\n"
"• Automatic backups\n" "• Automatic backups\n"
"• Claude Code integration" "• Claude Code and Codex integration"
), ),
"about_howto_title": "🚀 Quick Start", "about_howto_title": "🚀 Quick Start",
"about_howto": ( "about_howto": (
"1. Click \"+ Add\" to add a server\n" "1. Click \"+ Add\" to add a server\n"
"2. Select server → Terminal / Files\n" "2. Select server → Terminal / Files\n"
"3. Setup tab → Claude Code integration" "3. Setup tab → Claude Code / Codex integration"
), ),
"version": "Version", "version": "Version",
"author": "Author", "author": "Author",
@@ -157,6 +157,12 @@ _EN = {
"no_public_key": "[!] No public key to copy", "no_public_key": "[!] No public key to copy",
# Setup # Setup
"agent_integration": "AI Agent Integration",
"agent_desc": (
"Setup everything so Claude Code and Codex can manage your servers via shared local skills.\n"
"ServerManager, Claude Code, and Codex share the same servers.json — add a server here,\n"
"both agents see it immediately."
),
"claude_integration": "Claude Code Integration", "claude_integration": "Claude Code Integration",
"claude_desc": ( "claude_desc": (
"Setup everything so Claude Code can manage your servers via /ssh skill.\n" "Setup everything so Claude Code can manage your servers via /ssh skill.\n"
@@ -169,11 +175,16 @@ _EN = {
"status_ssh_script": "ssh.py (CLI tool)", "status_ssh_script": "ssh.py (CLI tool)",
"status_encryption": "Encryption module", "status_encryption": "Encryption module",
"status_skill": "/ssh skill for Claude Code", "status_skill": "/ssh skill for Claude Code",
"status_claude_skill": "/ssh skill for Claude Code",
"status_codex_skill": "ServerManager skill for Codex",
"status_codex_wrapper": "Codex wrapper (codex-ssh)",
"status_ssh_key": "SSH key (ed25519)", "status_ssh_key": "SSH key (ed25519)",
"install_everything": "Install Everything", "install_everything": "Install Everything",
"installing_all": "Installing...", "installing_all": "Installing...",
"install_ssh_py": "ssh.py", "install_ssh_py": "ssh.py",
"install_skill": "/ssh skill", "install_skill": "/ssh skill",
"install_claude_skill": "Claude skill",
"install_codex_skill": "Codex skill",
"install_ssh_key": "SSH key", "install_ssh_key": "SSH key",
"refresh": "Refresh", "refresh": "Refresh",
"configuration": "Configuration", "configuration": "Configuration",
@@ -183,7 +194,7 @@ _EN = {
"select_backup": "Select backup...", "select_backup": "Select backup...",
"no_backups": "No backups", "no_backups": "No backups",
"restore": "Restore", "restore": "Restore",
"install_done": "Done! Claude Code can now use /ssh to manage your servers.", "install_done": "Done! Claude Code and Codex can now use ServerManager to manage your servers.",
"config_changed": "Config path changed: {path}", "config_changed": "Config path changed: {path}",
"backup_created": "Backup created: {name}", "backup_created": "Backup created: {name}",
"backup_failed": "Backup failed: {e}", "backup_failed": "Backup failed: {e}",
@@ -603,7 +614,7 @@ _RU = {
"about_desc": ( "about_desc": (
"Настольное приложение для управления удалёнными серверами.\n" "Настольное приложение для управления удалёнными серверами.\n"
"SSH-терминал, SFTP-передача файлов, управление ключами,\n" "SSH-терминал, SFTP-передача файлов, управление ключами,\n"
"шифрование паролей и интеграция с Claude Code." "шифрование паролей и интеграция с Claude Code / Codex."
), ),
"about_features_title": "⚡ Возможности", "about_features_title": "⚡ Возможности",
"about_features": ( "about_features": (
@@ -613,13 +624,13 @@ _RU = {
"• TOTP / 2FA (Google Authenticator)\n" "• TOTP / 2FA (Google Authenticator)\n"
"• Шифрование паролей (Fernet)\n" "• Шифрование паролей (Fernet)\n"
"• Автоматические бэкапы\n" "• Автоматические бэкапы\n"
"• Интеграция с Claude Code" "• Интеграция с Claude Code и Codex"
), ),
"about_howto_title": "🚀 Быстрый старт", "about_howto_title": "🚀 Быстрый старт",
"about_howto": ( "about_howto": (
"1. Нажмите \"+ Добавить\" для добавления сервера\n" "1. Нажмите \"+ Добавить\" для добавления сервера\n"
"2. Выберите сервер → Терминал / Файлы\n" "2. Выберите сервер → Терминал / Файлы\n"
"3. Вкладка Настройка → интеграция Claude Code" "3. Вкладка Настройка → интеграция Claude Code / Codex"
), ),
"version": "Версия", "version": "Версия",
"author": "Автор", "author": "Автор",
@@ -714,6 +725,12 @@ _RU = {
"no_public_key": "[!] Нет публичного ключа", "no_public_key": "[!] Нет публичного ключа",
# Setup # Setup
"agent_integration": "Интеграция AI-агентов",
"agent_desc": (
"Настройте всё, чтобы Claude Code и Codex могли управлять серверами через локальные skills.\n"
"ServerManager, Claude Code и Codex используют один и тот же servers.json — добавьте сервер здесь,\n"
"и оба агента увидят его сразу."
),
"claude_integration": "Интеграция с Claude Code", "claude_integration": "Интеграция с Claude Code",
"claude_desc": ( "claude_desc": (
"Настройте всё, чтобы Claude Code мог управлять серверами через скилл /ssh.\n" "Настройте всё, чтобы Claude Code мог управлять серверами через скилл /ssh.\n"
@@ -726,11 +743,16 @@ _RU = {
"status_ssh_script": "ssh.py (CLI-утилита)", "status_ssh_script": "ssh.py (CLI-утилита)",
"status_encryption": "Модуль шифрования", "status_encryption": "Модуль шифрования",
"status_skill": "Скилл /ssh для Claude Code", "status_skill": "Скилл /ssh для Claude Code",
"status_claude_skill": "Скилл /ssh для Claude Code",
"status_codex_skill": "Скилл ServerManager для Codex",
"status_codex_wrapper": "Обёртка Codex (codex-ssh)",
"status_ssh_key": "SSH-ключ (ed25519)", "status_ssh_key": "SSH-ключ (ed25519)",
"install_everything": "Установить всё", "install_everything": "Установить всё",
"installing_all": "Установка...", "installing_all": "Установка...",
"install_ssh_py": "ssh.py", "install_ssh_py": "ssh.py",
"install_skill": "Скилл /ssh", "install_skill": "Скилл /ssh",
"install_claude_skill": "Скилл Claude",
"install_codex_skill": "Скилл Codex",
"install_ssh_key": "SSH-ключ", "install_ssh_key": "SSH-ключ",
"refresh": "Обновить", "refresh": "Обновить",
"configuration": "Конфигурация", "configuration": "Конфигурация",
@@ -740,7 +762,7 @@ _RU = {
"select_backup": "Выберите бэкап...", "select_backup": "Выберите бэкап...",
"no_backups": "Нет бэкапов", "no_backups": "Нет бэкапов",
"restore": "Восстановить", "restore": "Восстановить",
"install_done": "Готово! Claude Code теперь может использовать /ssh для управления серверами.", "install_done": "Готово! Claude Code и Codex теперь могут использовать ServerManager для управления серверами.",
"config_changed": "Путь конфига изменён: {path}", "config_changed": "Путь конфига изменён: {path}",
"backup_created": "Бэкап создан: {name}", "backup_created": "Бэкап создан: {name}",
"backup_failed": "Ошибка бэкапа: {e}", "backup_failed": "Ошибка бэкапа: {e}",
@@ -1160,7 +1182,7 @@ _ZH = {
"about_desc": ( "about_desc": (
"用于管理远程服务器的桌面应用程序。\n" "用于管理远程服务器的桌面应用程序。\n"
"SSH终端、SFTP文件传输、密钥管理、\n" "SSH终端、SFTP文件传输、密钥管理、\n"
"凭据加密以及Claude Code集成。" "凭据加密以及Claude Code / Codex集成。"
), ),
"about_features_title": "⚡ 功能特点", "about_features_title": "⚡ 功能特点",
"about_features": ( "about_features": (
@@ -1170,13 +1192,13 @@ _ZH = {
"• TOTP / 2FAGoogle Authenticator\n" "• TOTP / 2FAGoogle Authenticator\n"
"• 凭据加密Fernet\n" "• 凭据加密Fernet\n"
"• 自动备份\n" "• 自动备份\n"
"• Claude Code集成" "• Claude Code 和 Codex 集成"
), ),
"about_howto_title": "🚀 快速开始", "about_howto_title": "🚀 快速开始",
"about_howto": ( "about_howto": (
"1. 点击\"+ 添加\"来添加服务器\n" "1. 点击\"+ 添加\"来添加服务器\n"
"2. 选择服务器 → 终端 / 文件\n" "2. 选择服务器 → 终端 / 文件\n"
"3. 设置标签 → Claude Code集成" "3. 设置标签 → Claude Code / Codex 集成"
), ),
"version": "版本", "version": "版本",
"author": "作者", "author": "作者",
@@ -1271,6 +1293,12 @@ _ZH = {
"no_public_key": "[!] 没有公钥可复制", "no_public_key": "[!] 没有公钥可复制",
# Setup # Setup
"agent_integration": "AI代理集成",
"agent_desc": (
"完成设置后Claude Code 和 Codex 都可以通过共享的本地技能来管理您的服务器。\n"
"ServerManager、Claude Code 和 Codex 共用同一个 servers.json — 在此添加服务器后,\n"
"两个代理都会立即看到。"
),
"claude_integration": "Claude Code集成", "claude_integration": "Claude Code集成",
"claude_desc": ( "claude_desc": (
"设置一切以便Claude Code通过/ssh技能管理您的服务器。\n" "设置一切以便Claude Code通过/ssh技能管理您的服务器。\n"
@@ -1283,11 +1311,16 @@ _ZH = {
"status_ssh_script": "ssh.pyCLI工具", "status_ssh_script": "ssh.pyCLI工具",
"status_encryption": "加密模块", "status_encryption": "加密模块",
"status_skill": "Claude Code的/ssh技能", "status_skill": "Claude Code的/ssh技能",
"status_claude_skill": "Claude Code 的 /ssh 技能",
"status_codex_skill": "Codex 的 ServerManager 技能",
"status_codex_wrapper": "Codex 包装器codex-ssh",
"status_ssh_key": "SSH密钥ed25519", "status_ssh_key": "SSH密钥ed25519",
"install_everything": "全部安装", "install_everything": "全部安装",
"installing_all": "安装中...", "installing_all": "安装中...",
"install_ssh_py": "ssh.py", "install_ssh_py": "ssh.py",
"install_skill": "/ssh技能", "install_skill": "/ssh技能",
"install_claude_skill": "Claude 技能",
"install_codex_skill": "Codex 技能",
"install_ssh_key": "SSH密钥", "install_ssh_key": "SSH密钥",
"refresh": "刷新", "refresh": "刷新",
"configuration": "配置", "configuration": "配置",
@@ -1297,7 +1330,7 @@ _ZH = {
"select_backup": "选择备份...", "select_backup": "选择备份...",
"no_backups": "无备份", "no_backups": "无备份",
"restore": "恢复", "restore": "恢复",
"install_done": "完成Claude Code现在可以使用/ssh来管理您的服务器。", "install_done": "完成Claude Code 和 Codex 现在可以使用 ServerManager 来管理您的服务器。",
"config_changed": "配置路径已更改:{path}", "config_changed": "配置路径已更改:{path}",
"backup_created": "备份已创建:{name}", "backup_created": "备份已创建:{name}",
"backup_failed": "备份失败:{e}", "backup_failed": "备份失败:{e}",

View File

@@ -1,5 +1,5 @@
""" """
Setup tab — one-click installation for Claude Code integration. Setup tab — one-click installation for local AI agent integration.
Includes configuration path management and backup/restore. Includes configuration path management and backup/restore.
""" """
@@ -8,7 +8,14 @@ import threading
from datetime import datetime from datetime import datetime
from tkinter import filedialog, messagebox from tkinter import filedialog, messagebox
import customtkinter as ctk import customtkinter as ctk
from core.claude_setup import check_status, install_all, install_ssh_script, install_skill, generate_ssh_key from core.claude_setup import (
check_status,
generate_ssh_key,
install_all,
install_claude_skill,
install_codex_skill,
install_ssh_script,
)
from core.i18n import t from core.i18n import t
from core.icons import icon_text, make_icon_button from core.icons import icon_text, make_icon_button
from core.logger import log from core.logger import log
@@ -25,13 +32,13 @@ class SetupTab(ctk.CTkFrame):
# Header # Header
self.header_label = ctk.CTkLabel( self.header_label = ctk.CTkLabel(
self._scroll, text=t("claude_integration"), self._scroll, text=t("agent_integration"),
font=ctk.CTkFont(size=20, weight="bold") font=ctk.CTkFont(size=20, weight="bold")
) )
self.header_label.pack(padx=20, pady=(20, 5)) self.header_label.pack(padx=20, pady=(20, 5))
self.desc_label = ctk.CTkLabel( self.desc_label = ctk.CTkLabel(
self._scroll, text=t("claude_desc"), self._scroll, text=t("agent_desc"),
text_color="#9ca3af", justify="center" text_color="#9ca3af", justify="center"
) )
self.desc_label.pack(padx=20, pady=(0, 15)) self.desc_label.pack(padx=20, pady=(0, 15))
@@ -53,7 +60,9 @@ class SetupTab(ctk.CTkFrame):
("servers_json", "status_servers_json"), ("servers_json", "status_servers_json"),
("ssh_script", "status_ssh_script"), ("ssh_script", "status_ssh_script"),
("encryption", "status_encryption"), ("encryption", "status_encryption"),
("skill_installed", "status_skill"), ("claude_skill_installed", "status_claude_skill"),
("codex_skill_installed", "status_codex_skill"),
("codex_wrapper_installed", "status_codex_wrapper"),
("ssh_key_exists", "status_ssh_key"), ("ssh_key_exists", "status_ssh_key"),
] ]
for key, i18n_key in status_items: for key, i18n_key in status_items:
@@ -82,17 +91,40 @@ class SetupTab(ctk.CTkFrame):
ind_frame = ctk.CTkFrame(btn_frame, fg_color="transparent") ind_frame = ctk.CTkFrame(btn_frame, fg_color="transparent")
ind_frame.pack(fill="x") ind_frame.pack(fill="x")
self.ssh_py_btn = make_icon_button(ind_frame, "confirm", t("install_ssh_py"), width=110, fg_color="#6b7280", top_btn_row = ctk.CTkFrame(ind_frame, fg_color="transparent")
command=self._install_script) top_btn_row.pack(fill="x", pady=(0, 5))
self.ssh_py_btn = make_icon_button(
top_btn_row, "confirm", t("install_ssh_py"), width=120, fg_color="#6b7280",
command=self._install_script
)
self.ssh_py_btn.pack(side="left", padx=(0, 5)) self.ssh_py_btn.pack(side="left", padx=(0, 5))
self.skill_btn = make_icon_button(ind_frame, "confirm", t("install_skill"), width=110, fg_color="#6b7280",
command=self._install_skill) self.claude_skill_btn = make_icon_button(
self.skill_btn.pack(side="left", padx=5) top_btn_row, "confirm", t("install_claude_skill"), width=130, fg_color="#6b7280",
self.ssh_key_btn = make_icon_button(ind_frame, "confirm", t("install_ssh_key"), width=110, fg_color="#6b7280", command=self._install_claude_skill
command=self._gen_key) )
self.ssh_key_btn.pack(side="left", padx=5) self.claude_skill_btn.pack(side="left", padx=5)
self.refresh_btn = make_icon_button(ind_frame, "refresh", t("refresh"), width=90, fg_color="#3b82f6",
command=self._refresh_status) self.codex_skill_btn = make_icon_button(
top_btn_row, "confirm", t("install_codex_skill"), width=130, fg_color="#6b7280",
command=self._install_codex_skill
)
self.codex_skill_btn.pack(side="left", padx=5)
bottom_btn_row = ctk.CTkFrame(ind_frame, fg_color="transparent")
bottom_btn_row.pack(fill="x")
self.ssh_key_btn = make_icon_button(
bottom_btn_row, "confirm", t("install_ssh_key"), width=120, fg_color="#6b7280",
command=self._gen_key
)
self.ssh_key_btn.pack(side="left", padx=(0, 5))
self.refresh_btn = make_icon_button(
bottom_btn_row, "refresh", t("refresh"), width=90, fg_color="#3b82f6",
command=self._refresh_status
)
self.refresh_btn.pack(side="right") self.refresh_btn.pack(side="right")
# ── Monitoring section ───────────────────────── # ── Monitoring section ─────────────────────────
@@ -328,8 +360,18 @@ class SetupTab(ctk.CTkFrame):
self._log(msg) self._log(msg)
self._refresh_status() self._refresh_status()
def _install_claude_skill(self):
msg = install_claude_skill()
self._log(msg)
self._refresh_status()
def _install_codex_skill(self):
msg = install_codex_skill()
self._log(msg)
self._refresh_status()
def _install_skill(self): def _install_skill(self):
msg = install_skill() msg = install_claude_skill()
self._log(msg) self._log(msg)
self._refresh_status() self._refresh_status()