feat: add idempotent global CLAUDE.md install with start/end markers
Uses <!-- server-manager:start/end --> markers to safely add or replace the server-manager section. Re-running install_all() updates the block without creating duplicates. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,25 @@ SKILL_SRC = os.path.join(_BASE_DIR, "tools", "skill-ssh.md")
|
|||||||
SKILL_DST_DIR = os.path.expanduser("~/.claude/commands")
|
SKILL_DST_DIR = os.path.expanduser("~/.claude/commands")
|
||||||
SKILL_DST = os.path.join(SKILL_DST_DIR, "ssh.md")
|
SKILL_DST = os.path.join(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")
|
||||||
|
|
||||||
|
_BLOCK_START = "<!-- server-manager:start -->"
|
||||||
|
_BLOCK_END = "<!-- server-manager:end -->"
|
||||||
|
|
||||||
|
GLOBAL_CLAUDE_MD_BLOCK = f"""{_BLOCK_START}
|
||||||
|
## Server Manager — управление серверами
|
||||||
|
|
||||||
|
**ВСЕГДА** используй server manager для подключения к серверам. Никогда не используй `ssh`, `sshpass` или прямые подключения.
|
||||||
|
|
||||||
|
- Скилл: `/ssh ALIAS "command"` — выполнить команду на сервере
|
||||||
|
- Список серверов: `python3 ~/.server-connections/ssh.py --list`
|
||||||
|
- Документация: `~/.claude/commands/ssh.md`
|
||||||
|
- Memory bank: проект `global-infrastructure` → `techContext.md`
|
||||||
|
- Инфраструктура: https://git.sensey24.ru/aibot777/infrastructure-docs
|
||||||
|
|
||||||
|
**Запрещено:** использовать `ssh`, `sshpass`, читать `~/.server-connections/` напрямую, раскрывать IP/пароли/порты.
|
||||||
|
{_BLOCK_END}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def check_status() -> dict:
|
def check_status() -> dict:
|
||||||
@@ -112,6 +131,41 @@ def generate_ssh_key() -> str:
|
|||||||
return f"Key generated: {SSH_KEY_PATH}"
|
return f"Key generated: {SSH_KEY_PATH}"
|
||||||
|
|
||||||
|
|
||||||
|
def install_global_claude_md() -> str:
|
||||||
|
"""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)
|
||||||
|
|
||||||
|
existing = ""
|
||||||
|
if os.path.exists(GLOBAL_CLAUDE_MD):
|
||||||
|
with open(GLOBAL_CLAUDE_MD, encoding="utf-8") as f:
|
||||||
|
existing = f.read()
|
||||||
|
|
||||||
|
pattern = re.compile(
|
||||||
|
re.escape(_BLOCK_START) + r".*?" + re.escape(_BLOCK_END),
|
||||||
|
re.DOTALL
|
||||||
|
)
|
||||||
|
|
||||||
|
if pattern.search(existing):
|
||||||
|
# Блок уже есть — заменяем на актуальную версию
|
||||||
|
updated = pattern.sub(GLOBAL_CLAUDE_MD_BLOCK.strip(), existing)
|
||||||
|
with open(GLOBAL_CLAUDE_MD, "w", encoding="utf-8") as f:
|
||||||
|
f.write(updated)
|
||||||
|
log.info(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:
|
||||||
|
if existing and not existing.endswith("\n"):
|
||||||
|
f.write("\n")
|
||||||
|
f.write("\n" + GLOBAL_CLAUDE_MD_BLOCK)
|
||||||
|
log.info(f"Global CLAUDE.md block added: {GLOBAL_CLAUDE_MD}")
|
||||||
|
return f"Global CLAUDE.md block added: {GLOBAL_CLAUDE_MD}"
|
||||||
|
|
||||||
|
|
||||||
def install_all() -> list[str]:
|
def install_all() -> list[str]:
|
||||||
"""Full setup — install everything."""
|
"""Full setup — install everything."""
|
||||||
results = []
|
results = []
|
||||||
@@ -120,6 +174,7 @@ def install_all() -> list[str]:
|
|||||||
("ssh_script", install_ssh_script),
|
("ssh_script", install_ssh_script),
|
||||||
("skill", install_skill),
|
("skill", install_skill),
|
||||||
("ssh_key", generate_ssh_key),
|
("ssh_key", generate_ssh_key),
|
||||||
|
("global_claude_md", install_global_claude_md),
|
||||||
]
|
]
|
||||||
|
|
||||||
for name, func in steps:
|
for name, func in steps:
|
||||||
|
|||||||
Reference in New Issue
Block a user