Enhance Docker setup with new tools and configurations

Update Dockerfile to install additional tools (orla, rust-analyzer), configure user permissions, and set up bash completion.

Update docker-entrypoint.sh to export new environment variables and configure MCP language servers for multiple languages (Go, Python, Rust, TypeScript) with proper workspace and LSP settings.

Add new documentation file AGENTS.md with development guidelines and security rules.

Add pyproject.toml for Python project configuration with dependencies and dev tools.

Add src/PMOCrazyCoder.py as a new MCP server implementation with example tools.
This commit is contained in:
2026-02-21 21:04:13 +01:00
parent ea29352f7a
commit 9c914b989b
5 changed files with 182 additions and 37 deletions

View File

@@ -38,8 +38,15 @@ RUN curl -fsSL https://opencode.ai/install | bash && \
ENV GOPATH=/usr/local/go ENV GOPATH=/usr/local/go
ENV GOBIN=/usr/local/go/bin ENV GOBIN=/usr/local/go/bin
RUN go install golang.org/x/tools/gopls@latest RUN go install golang.org/x/tools/gopls@latest \
RUN go install github.com/isaacphi/mcp-language-server@latest && go install github.com/isaacphi/mcp-language-server@latest \
&& go install github.com/dorcha-inc/orla/cmd/orla@latest
RUN mkdir -p /etc/bash_completion.d \
&& orla completion bash > /etc/bash_completion.d/orla \
&& jj util completion bash > /etc/bash_completion.d/jj
RUN rustup component add rust-analyzer --toolchain nightly
ARG USERNAME=devuser ARG USERNAME=devuser
ARG USER_UID=1000 ARG USER_UID=1000
@@ -48,13 +55,19 @@ RUN groupadd --gid $USER_GID $USERNAME && \
useradd --uid $USER_UID \ useradd --uid $USER_UID \
--gid $USER_GID \ --gid $USER_GID \
-m $USERNAME \ -m $USERNAME \
--shell /bin/bash --shell /bin/bash && \
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME && \
chmod 440 /etc/sudoers.d/$USERNAME
COPY docker-entrypoint.sh /usr/local/bin/entrypoint.sh COPY docker-entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh
RUN mkdir -p /home/${USERNAME}/.config \
&& chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/.config
COPY --chown=${USERNAME}:${USERNAME} opencode /home/${USERNAME}/.config/opencode
USER $USERNAME USER $USERNAME
WORKDIR /workspace WORKDIR /workspace
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["/bin/bash"] CMD ["/bin/bash"]

View File

@@ -3,7 +3,10 @@
export USERNAME=${USERNAME:-devuser} export USERNAME=${USERNAME:-devuser}
export WORKSPACE=${WORKSPACE:-/workspace}
export LOCAL_LLM_API=${LOCAL_LLM_API:-http://host.docker.internal:1248/v1} 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 ORLA_OLLAMA_HOST=$(sed -E 's@(https?://[^/]+).*$@\1@' <<< $LOCAL_LLM_API)
export MAXTOKEN=${MAXTOKEN:-4096} export MAXTOKEN=${MAXTOKEN:-4096}
export NUM_CTX=${NUM_CTX:-32768} export NUM_CTX=${NUM_CTX:-32768}
export REPEAT_PENALTY=${REPEAT_PENALTY:-1.3} export REPEAT_PENALTY=${REPEAT_PENALTY:-1.3}
@@ -23,6 +26,8 @@ fi
if [ -n "$LOCAL_LLM_API" ]; then if [ -n "$LOCAL_LLM_API" ]; then
if ! grep -q "LOCAL_LLM_API" /home/${USERNAME}/.bashrc; then if ! grep -q "LOCAL_LLM_API" /home/${USERNAME}/.bashrc; then
echo "export LOCAL_LLM_API=$LOCAL_LLM_API" >> /home/${USERNAME}/.bashrc echo "export LOCAL_LLM_API=$LOCAL_LLM_API" >> /home/${USERNAME}/.bashrc
echo "export ORLA_OLLAMA_HOST=$ORLA_OLLAMA_HOST" >> /home/${USERNAME}/.bashrc
echo "export ORLA_MODEL='${LLM_MODEL}'" >> /home/${USERNAME}/.bashrc
fi fi
mkdir -p /home/${USERNAME}/.config/opencode mkdir -p /home/${USERNAME}/.config/opencode
@@ -31,6 +36,45 @@ if [ -n "$LOCAL_LLM_API" ]; then
cat > $CONFIG_FILE <<EOF cat > $CONFIG_FILE <<EOF
{ {
"\$schema": "https://opencode.ai/config.json", "\$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": { "provider": {
"lmstudio": { "lmstudio": {
"npm": "@ai-sdk/openai-compatible", "npm": "@ai-sdk/openai-compatible",
@@ -75,44 +119,13 @@ if [ -n "$LOCAL_LLM_API" ]; then
} }
} }
}, },
"model": "lmstudio/qwen/qwen3-coder-next@4bit" "model": "${LLM_MODEL}"
} }
EOF EOF
chown ${USERNAME}:${USERNAME} ${CONFIG_FILE} chown ${USERNAME}:${USERNAME} ${CONFIG_FILE}
fi fi
# --- Install MCP Language Server ---
if command -v mcp-language-server &> /dev/null; then
mkdir -p /home/${USERNAME}/.config/opencode
MCP_CONFIG=/home/${USERNAME}/.config/opencode/mcp_servers.json
cat > $MCP_CONFIG <<EOF
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": [
"--workspace",
"/workspace",
"--lsp",
"gopls"
],
"env": {
"PATH": "/usr/local/go/bin:/usr/local/cargo/bin:/usr/local/bin:$PATH",
"GOPATH": "/home/${USERNAME}/go",
"GOCACHE": "/home/${USERNAME}/.cache/go-build",
"GOMODCACHE": "/home/${USERNAME}/go/pkg/mod"
}
}
}
}
EOF
chown ${USERNAME}:${USERNAME} $MCP_CONFIG
fi
# --- Force Bash comme shell par défaut --- # --- Force Bash comme shell par défaut ---
if [ -z "$1" ]; then if [ -z "$1" ]; then
exec /bin/bash exec /bin/bash

49
opencode/AGENTs.md Normal file
View File

@@ -0,0 +1,49 @@
# AGENTS.md - Development Guidelines
## Code Style Guidelines
### General Principles
- Use relative paths only (never absolute paths)
- Operate strictly on explicitly mentioned files
- Generate minimal, single implementations
- Avoid speculation about missing files
## Error Handling
- Use structured error messages
- Avoid verbose stack traces in user-facing output
## Naming Conventions
- Variables/functions: `snake_case`
- Types/interfaces: `PascalCase`
- Constants: `UPPER_SNAKE_CASE`
## CRITICAL Security Rules
### File Operations
- **NEVER** delete files without explicit human authorization
- **NEVER** modify files outside the scope of the requested task
- Always use relative paths (never absolute paths)
### Version Control with `jj`
- Projects are managed with `jj` (Jujutsu), NOT Git
- **Before starting modifications to respond to a user prompt**, run `jj new` to create a commit
- This creates a baseline to revert all changes from that prompt if needed
- Do NOT run `jj new` for every individual file change—only once at the start of a prompt response
## File Generation Rules
- Output only requested files
- Do not modify unrelated files
- Valid JSON without comments when requested
- Assume no knowledge of other files unless provided
## MCP Tools
- Located in `/opt/dev-tools/`
- Use SQLite for graph storage (`.ai_index/graph.db`)
- Embeddings stored in `.ai_index/embeddings/`
- AST data in `.ai_index/ast/`
## LM Studio Integration
- Local LLM API: `http://host.docker.internal:1248`
- Model: `qwen/qwen3-coder-next@4bit`
- Context window: 32768 tokens
- Max output: 65536 tokens

33
pyproject.toml Normal file
View File

@@ -0,0 +1,33 @@
[project]
name = "pmocrazykoder"
version = "0.1.0"
description = "A crazy MCP server"
requires-python = ">=3.10"
dependencies = [
"crazy-mcp>=0.1.0",
]
[project.optional-dependencies]
dev = [
"ruff",
"black",
"mypy",
"isort",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
target-version = "py310"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W"]
ignore = []
[tool.black]
target-version = ["py310"]
[tool.mypy]
python_version = "3.10"

37
src/PMOCrazyCoder.py Normal file
View File

@@ -0,0 +1,37 @@
from crazy_mcp import Context, mcp
from crazy_mcp.tools import *
# Déclaration d'un outil
@mcp.tool(description="Renvoie le texte reçu")
def echo_texte(texte: str) -> str:
return f"Écho du serveur : {texte} mec"
# Déclaration d'un second outil pour démonstration
@mcp.tool(description="Renvoie le texte en majuscules")
def shout_texte(texte: str) -> str:
return texte.upper()
# Déclaration d'un outil pour additionner deux nombres
@mcp.tool(description="Additionne deux nombres")
def additionner(a: float, b: float) -> float:
return a + b
@mcp.tool
async def increment(ctx: Context) -> tuple[int, str]:
count = ctx.get_state("count") or 0
ctx.set_state("count", count + 1)
return count + 1, ctx.session_id
# Lancement du serveur MCP
if __name__ == "__main__":
mcp.run(
transport="http", # Transport réseau HTTP
host="0.0.0.0", # Adresse découte
port=7860, # Port TCP
path="/mcp", # Chemin MCP (par défaut /mcp)
)