Refactor devcontainer setup with MCP servers and dynamic config

Ajout d'une configuration DevContainer complète avec MCP Servers (LSP multi-langages, GitHub/Gitea), scripts de setup automatisés (crazycoder-setup.sh, setup-devcontainer.sh), et optimisation de l’image Docker (rustup/cargo-binstall, nettoyage des artefacts). Mise à jour du README avec documentation MCP et gestion dynamique des variables d’environnement (.env généré automatiquement selon la forge détectée). Simplification des entrypoints et postStartCommand pour une initialisation plus fiable.
This commit is contained in:
2026-03-11 22:18:02 +01:00
parent d6fb4e33e5
commit 6556c84e29
9 changed files with 405 additions and 184 deletions

View File

@@ -1,150 +1,15 @@
#!/bin/bash
# docker-entrypoint.sh
# docker-entrypoint.sh — minimal, just sets up PATH and execs the command
export USERNAME=${USERNAME:-devuser}
export PATH=/usr/local/cargo/bin:/usr/local/go/bin:$HOME/.local/bin:$PATH
export WORKSPACE=${WORKSPACE:-/workspace}
export LOCAL_LLM_API=${LOCAL_LLM_API:-http://host.docker.internal:1248/v1}
export LLM_MODEL=${LLM_MODEL:-'ollama:qwen/qwen3-coder-next@4bit'}
export AICHAT_API_BASE=$(sed -E 's@(https?://[^/]+).*$@\1@' <<< $LOCAL_LLM_API)
export MAXTOKEN=${MAXTOKEN:-4096}
export NUM_CTX=${NUM_CTX:-32768}
export REPEAT_PENALTY=${REPEAT_PENALTY:-1.3}
export TEMPERATURE=${TEMPERATURE:-0.5}
export TOP_P=${TOP_P:-0.95}
export TOP_K=${TOP_K:-40}
export STOP=${STOP:-"[\"</s>\", \"\\n\\n\", \"def \", \"class \"]"}
# Set npm prefix to user directory so global installs don't require root
npm config set prefix "$HOME/.local"
# --- Initialise .ai_index si nécessaire ---
if [ ! -d "/workspace/.ai_index" ]; then
mkdir -p /workspace/.ai_index/ast
mkdir -p /workspace/.ai_index/embeddings
touch /workspace/.ai_index/graph.db
fi
# Clear Zed external_agents on each start so Zed can re-download without
# hitting "Directory not empty" on atomic rename.
rm -rf "$HOME/.local/share/zed/external_agents"
# --- Configure LOCAL_LLM_API pour Bash ---
if [ -n "$LOCAL_LLM_API" ]; then
if ! grep -q "LOCAL_LLM_API" /home/${USERNAME}/.bashrc; then
echo "export LOCAL_LLM_API=$LOCAL_LLM_API" >> /home/${USERNAME}/.bashrc
echo "export AICHAT_API_BASE=$AICHAT_API_BASE" >> /home/${USERNAME}/.bashrc
echo "export PATH=\$HOME/.cargo/bin:\$HOME/go/bin:\$HOME/.local/bin:\$PATH" >> /home/${USERNAME}/.bashrc
fi
# --- Configure aichat ---
mkdir -p /home/${USERNAME}/.config/aichat
AICHAT_CONFIG=/home/${USERNAME}/.config/aichat/config.yaml
cat > $AICHAT_CONFIG <<EOF
model: lmstudio:${LLM_MODEL#*:}
clients:
- type: openai-compatible
name: lmstudio
api_base: ${LOCAL_LLM_API}
api_key: placeholder
models:
- name: ${LLM_MODEL#*:}
max_input_tokens: ${NUM_CTX}
temperature: ${TEMPERATURE}
top_p: ${TOP_P}
EOF
chown ${USERNAME}:${USERNAME} ${AICHAT_CONFIG}
mkdir -p /home/${USERNAME}/.config/opencode
CONFIG_FILE=/home/${USERNAME}/.config/opencode/opencode.json
cat > $CONFIG_FILE <<EOF
{
"\$schema": "https://opencode.ai/config.json",
"mcp": {
"go-lsp-tools": {
"type": "local",
"command": ["mcp-language-server",
"--workspace", "$WORKSPACE",
"--lsp", "gopls"
],
"enabled": true,
"environment": {
"GOPATH": "$GOPATH"
}
},
"python-lsp-tools": {
"type": "local",
"command": ["mcp-language-server",
"--workspace", "$WORKSPACE",
"--lsp", "pyright-langserver",
"--", "--stdio"
],
"enabled": true
},
"rust-lsp-tools": {
"type": "local",
"command": ["mcp-language-server",
"--workspace", "$WORKSPACE",
"--lsp", "$(find /usr/local/rustup/toolchains -type f -name rust-analyzer)"
],
"enabled": true
},
"typescript-lsp-tools": {
"type": "local",
"command": ["mcp-language-server",
"--workspace", "$WORKSPACE",
"--lsp", "typescript-language-server",
"--", "--stdio"
],
"enabled": true
},
},
"provider": {
"lmstudio": {
"npm": "@ai-sdk/openai-compatible",
"name": "LM Studio (local)",
"options": {
"baseURL": "$LOCAL_LLM_API",
"apiKey": ""
},
"models": {
"qwen/qwen3-coder-next@4bit": {
"name": "Qwen 3 Coder Next 80B — (LLMStudio ; 4-bit)",
"limit": {
"context": 200000,
"output": 65536
},
"settings": {
"temperature": $TEMPERATURE,
"top_p": $TOP_P,
"top_k": $TOP_K,
"max_tokens": ${MAXTOKEN},
"num_ctx": ${NUM_CTX},
"repeat_penalty": ${REPEAT_PENALTY},
"stop": ${STOP}
}
},
"qwen/qwen3-coder-next@6bit": {
"name": "Qwen 3 Coder Next 80B — (LLMStudio ; 6-bit)",
"limit": {
"context": 200000,
"output": 65536
},
"settings": {
"temperature": $TEMPERATURE,
"top_p": $TOP_P,
"top_k": $TOP_K,
"max_tokens": ${MAXTOKEN},
"num_ctx": ${NUM_CTX},
"repeat_penalty": ${REPEAT_PENALTY},
"stop": ${STOP}
}
}
}
}
},
"model": "${LLM_MODEL}"
}
EOF
chown ${USERNAME}:${USERNAME} ${CONFIG_FILE}
fi
# --- Force Bash comme shell par défaut ---
if [ -z "$1" ]; then
exec /bin/bash
else