From c4947e0df93466cf681396ac4644912e46dc1921 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sat, 21 Feb 2026 13:17:51 +0100 Subject: [PATCH] Setup dev container and MCP infrastructure Add dev container configuration with docker-compose, Dockerfile, and entrypoint script - Create .devcontainer/devcontainer.json for VS Code dev container - Create .devcontainer/docker-compose.yml for container setup - Add Dockerfile with Python, Go, Rust, R, and jj tools - Add docker-entrypoint.sh to initialize .ai_index and start mcp-server - Add Makefile for container management and MCP operations - Add .gitignore entries for AI index - Add OpenCode global instructions - Add basic MCP server and tool for listing Go imports - Add Zed integration configuration - Update README with project vision and structure --- .devcontainer/devcontainer.json | 7 ++++ .devcontainer/docker-compose.yml | 15 ++++++++ .gitignore | 3 ++ .opencode/instructions.md | 29 ++++++++++++++ Dockerfile | 40 +++++++++++++++++++ Makefile | 66 ++++++++++++++++++++++++++++++++ README.md | 19 +++++++++ docker-compose.yml | 10 +++++ docker-entrypoint.sh | 14 +++++++ opt/bin/mcp-server | 5 +++ opt/dev-tools/list_imports.py | 27 +++++++++++++ opt/lm-client/readme.md | 3 ++ zed-integration/mcp.json | 9 +++++ 13 files changed, 247 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/docker-compose.yml create mode 100644 .opencode/instructions.md create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100755 docker-entrypoint.sh create mode 100755 opt/bin/mcp-server create mode 100644 opt/dev-tools/list_imports.py create mode 100644 opt/lm-client/readme.md create mode 100644 zed-integration/mcp.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e952670 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,7 @@ +{ + "name": "PMOCrazyCoder", + "dockerComposeFile": "docker-compose.yml", + "service": "pmocrazy-coder", + "workspaceFolder": "/workspace", + "remoteUser": "devuser" +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..0453cff --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3.8" + +services: + pmocrazy-coder: + build: + context: .. + dockerfile: Dockerfile + volumes: + - ..:/workspace + working_dir: /workspace + ports: + - "1248:1248" + user: devuser + entrypoint: ["/usr/local/bin/entrypoint.sh"] + command: ["bash", "-c", "tail -f /dev/null"] diff --git a/.gitignore b/.gitignore index 9f07a5a..eaa50ac 100644 --- a/.gitignore +++ b/.gitignore @@ -208,3 +208,6 @@ cython_debug/ # PyPI configuration file .pypirc + +# AI Index +.ai_index/ diff --git a/.opencode/instructions.md b/.opencode/instructions.md new file mode 100644 index 0000000..f9b7a88 --- /dev/null +++ b/.opencode/instructions.md @@ -0,0 +1,29 @@ +# OpenCode Global Instructions + +## Path handling rules + +- Always use relative paths. +- Never generate absolute paths (e.g. /Users/..., /home/..., C:\...). +- Never assume a specific username, OS, or local filesystem layout. +- All paths must be relative to the project root unless explicitly specified. +- Do not guess the current working directory. +- If the working directory is ambiguous, ask for clarification instead of inventing one. + +## Workspace assumptions + +- Assume the workspace root is the repository root. +- Do not hardcode environment-specific values. +- Do not infer the machine, OS, or home directory. + +## File generation rules + +- Generate only the requested file. +- Do not modify unrelated files. +- Do not add additional configuration unless explicitly requested. +- Output valid JSON with no comments when JSON is requested. + +## Determinism + +- Avoid creative alternatives. +- Do not propose multiple solutions unless asked. +- Produce a single, minimal, correct implementation. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e72f10c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y \ + python3 python3-pip \ + golang-go rustc cargo \ + r-base \ + sqlite3 build-essential git curl wget \ + bash zsh \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Installer jj +RUN curl -LO https://github.com/martinvonz/jj/releases/latest/download/jj-x86_64-unknown-linux-gnu \ + && chmod +x jj-x86_64-unknown-linux-gnu \ + && mv jj-x86_64-unknown-linux-gnu /opt/bin/jj + +# Installer jj_lsp (si binaire séparé) +RUN curl -LO https://github.com/martinvonz/jj/releases/latest/download/jj_lsp-x86_64-unknown-linux-gnu \ + && chmod +x jj_lsp-x86_64-unknown-linux-gnu \ + && mv jj_lsp-x86_64-unknown-linux-gnu /opt/bin/jj_lsp + +COPY opt/bin/ /opt/bin/ +COPY opt/dev-tools/ /opt/dev-tools/ +COPY opt/lm-client/ /opt/lm-client/ + +ENV PATH="/opt/bin:/opt/dev-tools:/opt/lm-client:${PATH}" + +ARG USERNAME=devuser +ARG USER_UID=1000 +ARG USER_GID=1000 +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME + +COPY docker-entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +USER $USERNAME +WORKDIR /workspace + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +CMD ["/bin/bash"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d8e42f6 --- /dev/null +++ b/Makefile @@ -0,0 +1,66 @@ +# Makefile pour dev container AI + MCP bootstrap + +# Variables +PROJECT_DIR := $(shell pwd) +CONTAINER_NAME := ai-dev-container +WORKSPACE := /workspace +MCP_LOG := $(WORKSPACE)/.ai_index/mcp.log + +# --- Dev Container Management --- + +# Build the container +build: + docker build -t $(CONTAINER_NAME) . + +# Run interactive container with mounted project +run: + docker run -v $(PROJECT_DIR):$(WORKSPACE) -it --rm $(CONTAINER_NAME) + +# Run container with MCP server in background +run-mcp: + docker run -v $(PROJECT_DIR):$(WORKSPACE) -it --rm $(CONTAINER_NAME) bash + +# --- MCP / Index Management --- + +# Initialize .ai_index +init-index: + @echo "[MAKE] Initializing .ai_index..." + mkdir -p $(PROJECT_DIR)/.ai_index/ast + mkdir -p $(PROJECT_DIR)/.ai_index/embeddings + @if [ ! -f $(PROJECT_DIR)/.ai_index/graph.db ]; then \ + sqlite3 $(PROJECT_DIR)/.ai_index/graph.db "VACUUM;"; \ + fi + +# Run MCP tool (list imports) +mcp-list: + @echo "[MAKE] Running MCP list_imports.py..." + python3 $(PROJECT_DIR)/opt/dev-tools/list_imports.py --project $(WORKSPACE) + +# Update embeddings (example) +embeddings: + @echo "[MAKE] Generating embeddings..." + python3 $(PROJECT_DIR)/opt/dev-tools/generate_embeddings.py --project $(WORKSPACE) + +# Update graph (example) +update-graph: + @echo "[MAKE] Updating dependency graph..." + python3 $(PROJECT_DIR)/opt/dev-tools/update_graph.py --project $(WORKSPACE) + +# Clean logs and temporary files +clean: + @echo "[MAKE] Cleaning .ai_index..." + rm -f $(PROJECT_DIR)/.ai_index/*.log + rm -rf $(PROJECT_DIR)/.ai_index/ast/* + rm -rf $(PROJECT_DIR)/.ai_index/embeddings/* + +# Restart MCP server inside container +restart-mcp: + docker exec -it $(CONTAINER_NAME) bash -c "\ + pkill -f mcp-server; \ + /opt/bin/mcp-server --project $(WORKSPACE) > $(MCP_LOG) 2>&1 & \ + " + +# --- Bootstrap for new project --- +# Build container, init index +bootstrap: build init-index + @echo "[MAKE] Bootstrap complete. Run 'make run' to start the container." diff --git a/README.md b/README.md new file mode 100644 index 0000000..723e3b2 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# 🧠 PMOCrazyCoder + +Un assistant IA **local**, pour coder en Go, Rust et R — +sans cloud, sans API key, tout sur votre M3 Max. + +## 🎯 Vision + +> *Un indexeur de code, des graphes de dépendances, et un assistant intelligent — +> intégré à Zed, 100 % local.* + +### 🛠️ Ce qu’on construit + +- ✅ MCP tools pour Zed (ex : `get_similar_functions`, `explain_imports`) +- ✅ Indexeur de code (Go / Rust / R) via Tree-sitter +- ✅ Graphe de dépendances & similarité (stocké localement) +- ✅ Tout tourne en local : **LM Studio** (`localhost:1248`) + LanceDB + Rust/Python + *(hors conteneur — le conteneur y accède via `host.docker.internal:1248`)* + +### 📦 Structure future (à venir) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d70da8b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3.8" + +services: + pmocrazy-coder: + build: . + volumes: + - .:/workspace + working_dir: /workspace + ports: + - "1248:1248" diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..e775281 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# docker-entrypoint.sh + +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 + +/opt/bin/mcp-server > /workspace/.ai_index/mcp.log 2>&1 & +MCP_PID=$! +echo $MCP_PID > /workspace/.ai_index/mcp.pid + +exec "$@" diff --git a/opt/bin/mcp-server b/opt/bin/mcp-server new file mode 100755 index 0000000..6f55b1e --- /dev/null +++ b/opt/bin/mcp-server @@ -0,0 +1,5 @@ +#!/bin/bash +echo "[MCP] Starting..." >> /workspace/.ai_index/mcp.log +python3 /opt/dev-tools/list_imports.py "$@" >> /workspace/.ai_index/mcp.log 2>&1 & +echo $! > /workspace/.ai_index/mcp.pid +wait diff --git a/opt/dev-tools/list_imports.py b/opt/dev-tools/list_imports.py new file mode 100644 index 0000000..63b0d56 --- /dev/null +++ b/opt/dev-tools/list_imports.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +import sys, json + +def get_imports_go(filepath: str) -> list[str]: + try: + with open(filepath) as f: + lines = f.readlines() + imports = [] + in_import_block = False + for line in lines: + stripped = line.strip() + if stripped == "import (": + in_import_block = True + continue + if stripped == ")" and in_import_block: + break + if in_import_block and stripped.startswith('"'): + imports.append(stripped.strip('"')) + return imports + except Exception as e: + return [f"error: {e}"] + +if __name__ == "__main__": + args = json.loads(sys.argv[1]) + filepath = args.get("file", "") + result = get_imports_go(filepath) + print(json.dumps({"result": result}, indent=2)) diff --git a/opt/lm-client/readme.md b/opt/lm-client/readme.md new file mode 100644 index 0000000..e8b016f --- /dev/null +++ b/opt/lm-client/readme.md @@ -0,0 +1,3 @@ +LM Studio client for Qwen3-Coder-Next +Download from: https://lmstudio.ai/ +Configure to run on localhost:1248 diff --git a/zed-integration/mcp.json b/zed-integration/mcp.json new file mode 100644 index 0000000..60eab76 --- /dev/null +++ b/zed-integration/mcp.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "pmocrazy-coder": { + "command": "python3", + "args": ["opt/dev-tools/list_imports.py"], + "cwd": "." + } + } +}