Refactor workspace setup script for cross-platform compatibility and improved user management
- Added system detection logic to handle different OS types (Linux, macOS, Windows). - Enhanced user creation logic to support non-root execution and proper ownership. - Updated directory creation to use dynamic home paths based on detected OS. - Improved Git configuration and metadata capture with error handling. - Modularized system package installation based on OS type. - Streamlined Node.js, Python, and Rust setup scripts with error handling. - Updated shell configuration to include dynamic aliases and environment info script. - Deprecated `devcontainer_image` variable in favor of `devcontainer_repo_url` for better repository management. - Adjusted Terraform workspace configuration to support new repository URL and caching options.
This commit is contained in:
85
.devcontainer/Dockerfile
Normal file
85
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,85 @@
|
||||
# Start from the universal devcontainer base image
|
||||
FROM mcr.microsoft.com/devcontainers/universal:2-linux
|
||||
|
||||
# Switch to root for installations
|
||||
USER root
|
||||
|
||||
# Install additional development tools not included in features
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && \
|
||||
apt-get install -y \
|
||||
# Terminal tools
|
||||
ripgrep \
|
||||
fd-find \
|
||||
bat \
|
||||
eza \
|
||||
htop \
|
||||
btop \
|
||||
ncdu \
|
||||
ranger \
|
||||
tmux \
|
||||
neovim \
|
||||
# Development tools
|
||||
jq \
|
||||
yq \
|
||||
httpie \
|
||||
lazygit \
|
||||
lazydocker \
|
||||
# Build tools
|
||||
build-essential \
|
||||
cmake \
|
||||
pkg-config \
|
||||
# Database clients
|
||||
postgresql-client \
|
||||
redis-tools \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Rust-based tools using cargo
|
||||
USER codespace
|
||||
RUN cargo install \
|
||||
starship \
|
||||
zoxide \
|
||||
tokei \
|
||||
git-delta \
|
||||
--locked
|
||||
|
||||
# Install Node.js global packages
|
||||
RUN npm install -g \
|
||||
pnpm \
|
||||
yarn \
|
||||
turbo \
|
||||
@claude-ai/cli \
|
||||
vercel \
|
||||
netlify-cli \
|
||||
tsx \
|
||||
nodemon
|
||||
|
||||
# Install Python packages
|
||||
RUN pip install --user \
|
||||
poetry \
|
||||
pipenv \
|
||||
black \
|
||||
ruff \
|
||||
mypy \
|
||||
pytest \
|
||||
httpx \
|
||||
rich
|
||||
|
||||
# Create necessary directories with correct permissions
|
||||
USER root
|
||||
RUN mkdir -p /home/coder /workspaces && \
|
||||
chown -R 1000:1000 /home/coder /workspaces
|
||||
|
||||
# Copy our custom scripts
|
||||
COPY tf/scripts/*.sh /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/*.sh
|
||||
|
||||
# Switch to coder user
|
||||
USER coder
|
||||
WORKDIR /workspaces
|
||||
|
||||
# Set up shell configuration
|
||||
RUN echo 'eval "$(starship init zsh)"' >> ~/.zshrc && \
|
||||
echo 'eval "$(zoxide init zsh)"' >> ~/.zshrc && \
|
||||
echo 'alias ll="eza -la"' >> ~/.zshrc && \
|
||||
echo 'alias cat="bat"' >> ~/.zshrc && \
|
||||
echo 'alias find="fd"' >> ~/.zshrc
|
||||
99
.devcontainer/devcontainer.json
Normal file
99
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"name": "Coder Development Environment",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"context": ".."
|
||||
},
|
||||
"features": {
|
||||
// Core development tools
|
||||
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||
"installZsh": true,
|
||||
"configureZshAsDefaultShell": true,
|
||||
"installOhMyZsh": true,
|
||||
"upgradePackages": true,
|
||||
"username": "coder",
|
||||
"userUid": "1000",
|
||||
"userGid": "1000"
|
||||
},
|
||||
// Git and GitHub CLI
|
||||
"ghcr.io/devcontainers/features/git:1": {
|
||||
"version": "latest",
|
||||
"ppa": true
|
||||
},
|
||||
"ghcr.io/devcontainers/features/github-cli:1": {
|
||||
"version": "latest"
|
||||
},
|
||||
// Docker-in-Docker
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {
|
||||
"version": "latest",
|
||||
"enableNonRootDocker": true,
|
||||
"moby": true
|
||||
},
|
||||
// Node.js and npm
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
"version": "lts",
|
||||
"nodeGypDependencies": true
|
||||
},
|
||||
// Python
|
||||
"ghcr.io/devcontainers/features/python:1": {
|
||||
"version": "3.11",
|
||||
"installTools": true,
|
||||
"installJupyterlab": true
|
||||
},
|
||||
// Go
|
||||
"ghcr.io/devcontainers/features/go:1": {
|
||||
"version": "latest"
|
||||
},
|
||||
// Rust
|
||||
"ghcr.io/devcontainers/features/rust:1": {
|
||||
"version": "stable",
|
||||
"profile": "default"
|
||||
},
|
||||
// Terraform
|
||||
"ghcr.io/devcontainers/features/terraform:1": {
|
||||
"version": "latest"
|
||||
},
|
||||
// Additional tools
|
||||
"ghcr.io/devcontainers/features/aws-cli:1": {},
|
||||
"ghcr.io/devcontainers/features/azure-cli:1": {}
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"terminal.integrated.defaultProfile.linux": "zsh",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
},
|
||||
"python.linting.enabled": true,
|
||||
"python.formatting.provider": "black"
|
||||
},
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"golang.go",
|
||||
"rust-lang.rust-analyzer",
|
||||
"hashicorp.terraform",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"github.copilot",
|
||||
"github.copilot-chat"
|
||||
]
|
||||
}
|
||||
},
|
||||
"postCreateCommand": "bash .devcontainer/post-create.sh",
|
||||
"postStartCommand": "bash .devcontainer/post-start.sh",
|
||||
"remoteUser": "coder",
|
||||
"workspaceFolder": "/workspaces",
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind",
|
||||
"runArgs": [
|
||||
"--cap-add=SYS_PTRACE",
|
||||
"--security-opt",
|
||||
"seccomp=unconfined",
|
||||
"--network=host"
|
||||
],
|
||||
"containerEnv": {
|
||||
"SHELL": "/bin/zsh"
|
||||
}
|
||||
}
|
||||
34
.devcontainer/post-create.sh
Executable file
34
.devcontainer/post-create.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Running post-create setup..."
|
||||
|
||||
# Set up Git configuration
|
||||
git config --global init.defaultBranch main
|
||||
git config --global pull.rebase false
|
||||
|
||||
# Create common directories
|
||||
mkdir -p ~/bin ~/.local/bin ~/.config
|
||||
|
||||
# Run our setup scripts if they exist
|
||||
if [ -f /usr/local/bin/claude-install.sh ]; then
|
||||
echo "Installing Claude CLI..."
|
||||
/usr/local/bin/claude-install.sh
|
||||
fi
|
||||
|
||||
if [ -f /usr/local/bin/cursor-setup.sh ]; then
|
||||
echo "Setting up Cursor IDE support..."
|
||||
/usr/local/bin/cursor-setup.sh
|
||||
fi
|
||||
|
||||
if [ -f /usr/local/bin/windsurf-setup.sh ]; then
|
||||
echo "Setting up Windsurf IDE support..."
|
||||
/usr/local/bin/windsurf-setup.sh
|
||||
fi
|
||||
|
||||
if [ -f /usr/local/bin/git-hooks.sh ]; then
|
||||
echo "Setting up Git hooks..."
|
||||
/usr/local/bin/git-hooks.sh
|
||||
fi
|
||||
|
||||
echo "Post-create setup complete!"
|
||||
53
.devcontainer/post-start.sh
Executable file
53
.devcontainer/post-start.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Running post-start setup..."
|
||||
|
||||
# Set up environment variables
|
||||
export PATH="$PATH:$HOME/.local/bin:$HOME/bin"
|
||||
|
||||
# Initialize any services that need to be started
|
||||
if [ -n "$ENABLE_SERVICES" ] && [ "$ENABLE_SERVICES" = "true" ]; then
|
||||
echo "Services are enabled, checking connectivity..."
|
||||
|
||||
# Wait for services to be ready (if enabled)
|
||||
if [ -n "$POSTGRES_URL" ]; then
|
||||
echo "Waiting for PostgreSQL..."
|
||||
for i in {1..30}; do
|
||||
if pg_isready -d "$POSTGRES_URL" 2>/dev/null; then
|
||||
echo "PostgreSQL is ready!"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$REDIS_URL" ]; then
|
||||
echo "Checking Redis connectivity..."
|
||||
# Parse Redis URL to get host and port
|
||||
REDIS_HOST=$(echo "$REDIS_URL" | sed -E 's|redis://[^@]*@([^:]+):.*|\1|')
|
||||
REDIS_PORT=$(echo "$REDIS_URL" | sed -E 's|.*:([0-9]+).*|\1|')
|
||||
for i in {1..30}; do
|
||||
if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping 2>/dev/null | grep -q PONG; then
|
||||
echo "Redis is ready!"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Display welcome message
|
||||
echo ""
|
||||
echo "🚀 Workspace is ready!"
|
||||
echo "📂 Working directory: $(pwd)"
|
||||
echo "🌿 Git branch: $(git branch --show-current 2>/dev/null || echo 'no repo')"
|
||||
echo ""
|
||||
|
||||
# Clone repository if specified and not already present
|
||||
if [ -n "$CODER_WORKSPACE_REPO" ] && [ ! -d .git ]; then
|
||||
echo "Cloning repository: $CODER_WORKSPACE_REPO"
|
||||
git clone "$CODER_WORKSPACE_REPO" .
|
||||
fi
|
||||
|
||||
echo "Post-start setup complete!"
|
||||
36
.dockerignore
Normal file
36
.dockerignore
Normal file
@@ -0,0 +1,36 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# Terraform
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
.terraform/
|
||||
*.tfvars
|
||||
!terraform.tfvars.example
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Build artifacts
|
||||
*.log
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
LICENSE
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
20
tf/main.tf
20
tf/main.tf
@@ -160,8 +160,8 @@ locals {
|
||||
data.coder_parameter.repo.value
|
||||
)
|
||||
|
||||
# Development container image with all required tools
|
||||
devcontainer_image = var.devcontainer_image
|
||||
# Development container image is now built by envbuilder
|
||||
# devcontainer_image = var.devcontainer_image # Deprecated
|
||||
|
||||
# Environment variables for the development container
|
||||
dev_environment = {
|
||||
@@ -231,8 +231,20 @@ resource "docker_volume" "workspaces" {
|
||||
}
|
||||
}
|
||||
|
||||
# Development Container Image
|
||||
# Build the devcontainer image with envbuilder
|
||||
resource "envbuilder_cached_image" "devcontainer" {
|
||||
builder_image = "ghcr.io/coder/envbuilder:latest"
|
||||
git_url = var.devcontainer_repo_url
|
||||
|
||||
# Use the devcontainer.json from our repository
|
||||
devcontainer_dir = ".devcontainer"
|
||||
|
||||
# Cache settings for faster builds
|
||||
cache_repo = var.envbuilder_cache_repo
|
||||
}
|
||||
|
||||
# Development Container Image using envbuilder
|
||||
resource "docker_image" "devcontainer" {
|
||||
name = local.devcontainer_image
|
||||
name = envbuilder_cached_image.devcontainer.image
|
||||
keep_locally = true
|
||||
}
|
||||
|
||||
253
tf/main.tf.backup
Normal file
253
tf/main.tf.backup
Normal file
@@ -0,0 +1,253 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = "~> 2.0"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~> 2.25"
|
||||
}
|
||||
envbuilder = {
|
||||
source = "coder/envbuilder"
|
||||
version = "~> 1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "coder" {}
|
||||
provider "docker" {
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
provider "envbuilder" {}
|
||||
|
||||
# Data Sources
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
# Parameters
|
||||
data "coder_parameter" "repo" {
|
||||
name = "repo"
|
||||
display_name = "Repository"
|
||||
description = "Select a repository to clone"
|
||||
mutable = true
|
||||
order = 1
|
||||
|
||||
option {
|
||||
name = "Custom Development Environment"
|
||||
description = "Full-stack development with all services"
|
||||
value = "custom"
|
||||
}
|
||||
option {
|
||||
name = "vercel/next.js"
|
||||
description = "The React Framework"
|
||||
value = "https://github.com/vercel/next.js"
|
||||
}
|
||||
option {
|
||||
name = "Custom URL"
|
||||
description = "Specify a custom repo URL below"
|
||||
value = "custom-url"
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "custom_repo_url" {
|
||||
name = "custom_repo_url"
|
||||
display_name = "Custom Repository URL"
|
||||
description = "Enter a custom repository URL"
|
||||
default = ""
|
||||
mutable = true
|
||||
order = 2
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_services" {
|
||||
name = "enable_services"
|
||||
display_name = "Enable Database Services"
|
||||
description = "Enable PostgreSQL, Redis, Qdrant, and Docker Registry"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 3
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_ai_tools" {
|
||||
name = "enable_ai_tools"
|
||||
display_name = "Enable AI Assistant Tools"
|
||||
description = "Install Claude Code and AI development tools"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 4
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_claude_code" {
|
||||
name = "enable_claude_code"
|
||||
display_name = "Enable Claude Code CLI"
|
||||
description = "Install Claude Code command-line interface"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 5
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_cursor_support" {
|
||||
name = "enable_cursor_support"
|
||||
display_name = "Enable Cursor IDE Support"
|
||||
description = "Install Cursor IDE configuration and settings"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 6
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_windsurf_support" {
|
||||
name = "enable_windsurf_support"
|
||||
display_name = "Enable Windsurf IDE Support"
|
||||
description = "Install Windsurf IDE configuration and settings"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 7
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_jetbrains" {
|
||||
name = "enable_jetbrains"
|
||||
display_name = "Enable JetBrains Gateway"
|
||||
description = "Enable JetBrains Gateway integration for remote development"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 8
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_jupyter" {
|
||||
name = "enable_jupyter"
|
||||
display_name = "Enable Jupyter Lab"
|
||||
description = "Enable Jupyter Lab for data science and notebook development"
|
||||
type = "bool"
|
||||
default = "false"
|
||||
mutable = true
|
||||
order = 9
|
||||
}
|
||||
|
||||
data "coder_parameter" "enable_pgadmin" {
|
||||
name = "enable_pgadmin"
|
||||
display_name = "Enable pgAdmin"
|
||||
description = "Enable pgAdmin web interface for PostgreSQL management"
|
||||
type = "bool"
|
||||
default = "true"
|
||||
mutable = true
|
||||
order = 10
|
||||
}
|
||||
|
||||
# Local Variables
|
||||
locals {
|
||||
# Container and workspace naming - use ID for immutability
|
||||
container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
workspace_id = data.coder_workspace.me.id
|
||||
# Use workspace ID for volume naming to prevent destruction on rename
|
||||
volume_suffix = substr(data.coder_workspace.me.id, 0, 8)
|
||||
|
||||
# Git configuration
|
||||
git_author_name = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
|
||||
git_author_email = data.coder_workspace_owner.me.email
|
||||
|
||||
# Repository URL logic
|
||||
repo_url = (
|
||||
data.coder_parameter.repo.value == "custom" ? "https://github.com/coder/envbuilder" :
|
||||
data.coder_parameter.repo.value == "custom-url" ? data.coder_parameter.custom_repo_url.value :
|
||||
data.coder_parameter.repo.value
|
||||
)
|
||||
|
||||
# Development container image is now built by envbuilder
|
||||
# devcontainer_image = var.devcontainer_image # Deprecated
|
||||
|
||||
# Environment variables for the development container
|
||||
dev_environment = {
|
||||
# Git configuration
|
||||
"GIT_AUTHOR_NAME" = local.git_author_name
|
||||
"GIT_AUTHOR_EMAIL" = local.git_author_email
|
||||
"GIT_COMMITTER_NAME" = local.git_author_name
|
||||
"GIT_COMMITTER_EMAIL" = local.git_author_email
|
||||
|
||||
# Development tools
|
||||
"NODE_VERSION" = var.node_version
|
||||
"PYTHON_VERSION" = var.python_version
|
||||
"RUST_VERSION" = "stable"
|
||||
|
||||
# Service URLs (when services are enabled)
|
||||
"POSTGRES_URL" = data.coder_parameter.enable_services.value ? "postgresql://postgres:${var.postgres_password}@postgres-${local.workspace_id}:5432/postgres" : ""
|
||||
"REDIS_URL" = data.coder_parameter.enable_services.value ? "redis://:${var.redis_password}@redis-${local.workspace_id}:6379" : ""
|
||||
"QDRANT_URL" = data.coder_parameter.enable_services.value ? "http://qdrant-${local.workspace_id}:6333" : ""
|
||||
|
||||
# Development configuration
|
||||
"EDITOR" = "code"
|
||||
"PYTHONPATH" = "/workspaces"
|
||||
"CARGO_HOME" = "/home/coder/.cargo"
|
||||
"RUSTUP_HOME" = "/home/coder/.rustup"
|
||||
}
|
||||
|
||||
# Legacy service URLs for backward compatibility
|
||||
postgres_url = "postgresql://postgres:${var.postgres_password}@postgres-${local.workspace_id}:5432/postgres"
|
||||
redis_url = "redis://:${var.redis_password}@redis-${local.workspace_id}:6379"
|
||||
qdrant_url = "http://qdrant-${local.workspace_id}:6333"
|
||||
}
|
||||
|
||||
# Docker Network
|
||||
resource "docker_network" "workspace" {
|
||||
name = "coder-${local.workspace_id}"
|
||||
driver = "bridge"
|
||||
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = local.workspace_id
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.project"
|
||||
value = var.project_name
|
||||
}
|
||||
}
|
||||
|
||||
# Workspace Volume
|
||||
resource "docker_volume" "workspaces" {
|
||||
name = "workspaces-${local.workspace_id}"
|
||||
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = local.workspace_id
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.type"
|
||||
value = "workspace-data"
|
||||
}
|
||||
}
|
||||
|
||||
# Build the devcontainer image with envbuilder
|
||||
resource "envbuilder_cached_image" "devcontainer" {
|
||||
builder_image = "ghcr.io/coder/envbuilder:latest"
|
||||
git_url = var.devcontainer_repo_url
|
||||
|
||||
# Use the devcontainer.json from our repository
|
||||
devcontainer_dir = ".devcontainer"
|
||||
|
||||
# Cache settings for faster builds
|
||||
cache_repo = var.envbuilder_cache_repo != "" ? var.envbuilder_cache_repo : null
|
||||
|
||||
# Ensure we build for the correct architecture
|
||||
force_safe = true
|
||||
}
|
||||
|
||||
# Development Container Image using envbuilder
|
||||
resource "docker_image" "devcontainer" {
|
||||
name = envbuilder_cached_image.devcontainer.image
|
||||
keep_locally = true
|
||||
}
|
||||
@@ -92,7 +92,8 @@ output "development_tools" {
|
||||
value = {
|
||||
node_version = var.node_version
|
||||
python_version = var.python_version
|
||||
container_image = local.devcontainer_image
|
||||
container_image = docker_image.devcontainer.name
|
||||
git_repo_url = var.devcontainer_repo_url
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
214
tf/scripts.tf
214
tf/scripts.tf
@@ -1,169 +1,93 @@
|
||||
# =============================================================================
|
||||
# Provisioning Scripts - AI Development Tools and Extensions
|
||||
# Installation scripts for Cursor, Claude Code, Windsurf support
|
||||
# Provisioning Scripts - Minimal Setup
|
||||
# Most tools are now installed in the devcontainer image
|
||||
# =============================================================================
|
||||
|
||||
# =============================================================================
|
||||
# Claude Code CLI Installation
|
||||
# Workspace Initialization
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "claude_code_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_claude_code.value ? 1 : 0
|
||||
resource "coder_script" "workspace_init" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Claude Code CLI"
|
||||
icon = "/icon/ai.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "Installing Claude Code CLI..."
|
||||
|
||||
# Check if Claude is already installed
|
||||
if command -v claude &> /dev/null; then
|
||||
echo "Claude Code CLI is already installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install Claude Code CLI
|
||||
curl -fsSL https://claude.ai/install.sh | sh || {
|
||||
echo "Warning: Claude Code CLI installation failed or not available"
|
||||
exit 0
|
||||
}
|
||||
|
||||
echo "Claude Code CLI installation complete"
|
||||
EOT
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Cursor IDE Support Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "cursor_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_cursor_support.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Configure Cursor IDE Support"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "Configuring Cursor IDE support..."
|
||||
|
||||
# Create Cursor configuration directory
|
||||
mkdir -p ~/.config/cursor
|
||||
|
||||
# Add Cursor-specific settings
|
||||
cat > ~/.config/cursor/settings.json <<'EOF'
|
||||
{
|
||||
"workspaceFolder": "/workspaces",
|
||||
"remote.SSH.defaultExtensions": [
|
||||
"ms-python.python",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Cursor IDE support configured"
|
||||
EOT
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Windsurf IDE Support Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "windsurf_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_windsurf_support.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Configure Windsurf IDE Support"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "Configuring Windsurf IDE support..."
|
||||
|
||||
# Create Windsurf configuration directory
|
||||
mkdir -p ~/.config/windsurf
|
||||
|
||||
# Add Windsurf-specific settings
|
||||
cat > ~/.config/windsurf/settings.json <<'EOF'
|
||||
{
|
||||
"workspaceFolder": "/workspaces",
|
||||
"codeium.enabled": true
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Windsurf IDE support configured"
|
||||
EOT
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Development Tools and Extensions
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "dev_extensions" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Development Tools"
|
||||
display_name = "Initialize Workspace"
|
||||
icon = "/icon/tools.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = <<-EOT
|
||||
script = <<-EOF
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "Installing development tools and extensions..."
|
||||
|
||||
# Install VS Code extensions if code-server is available
|
||||
if command -v code-server &> /dev/null; then
|
||||
code-server --install-extension ms-python.python || true
|
||||
code-server --install-extension esbenp.prettier-vscode || true
|
||||
code-server --install-extension dbaeumer.vscode-eslint || true
|
||||
code-server --install-extension ms-azuretools.vscode-docker || true
|
||||
|
||||
echo "🚀 Initializing workspace..."
|
||||
|
||||
# Ensure workspace directory has correct permissions
|
||||
if [ -w /workspaces ]; then
|
||||
cd /workspaces
|
||||
else
|
||||
echo "Warning: /workspaces is not writable, staying in current directory"
|
||||
fi
|
||||
|
||||
# Install additional development tools
|
||||
if ! command -v ranger &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y ranger || true
|
||||
|
||||
# Clone repository if CODER_WORKSPACE_REPO is set and directory is empty
|
||||
if [ -n "$CODER_WORKSPACE_REPO" ] && [ -z "$(ls -A .)" ]; then
|
||||
echo "📥 Cloning repository: $CODER_WORKSPACE_REPO"
|
||||
git clone "$CODER_WORKSPACE_REPO" .
|
||||
fi
|
||||
|
||||
echo "Development tools installation complete"
|
||||
EOT
|
||||
|
||||
# Run any project-specific setup if present
|
||||
if [ -f .devcontainer/post-start.sh ]; then
|
||||
echo "🔧 Running project-specific setup..."
|
||||
bash .devcontainer/post-start.sh
|
||||
fi
|
||||
|
||||
echo "✅ Workspace initialization complete!"
|
||||
EOF
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Git Hooks and Metadata Capture Setup
|
||||
# Service Health Check (only if services are enabled)
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "git_hooks_setup" {
|
||||
resource "coder_script" "service_health" {
|
||||
count = data.coder_parameter.enable_services.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Setup Git Hooks"
|
||||
icon = "/icon/git.svg"
|
||||
display_name = "Check Service Health"
|
||||
icon = "/icon/database.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = <<-EOT
|
||||
script = <<-EOF
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "Setting up Git hooks and configuration..."
|
||||
|
||||
# Configure git
|
||||
git config --global user.name "${local.git_author_name}"
|
||||
git config --global user.email "${local.git_author_email}"
|
||||
git config --global init.defaultBranch main
|
||||
|
||||
# Create git hooks directory
|
||||
mkdir -p ~/.git-hooks
|
||||
|
||||
# Add a simple pre-commit hook template
|
||||
cat > ~/.git-hooks/pre-commit <<'EOF'
|
||||
#!/bin/bash
|
||||
# Pre-commit hook
|
||||
echo "Running pre-commit checks..."
|
||||
EOF
|
||||
chmod +x ~/.git-hooks/pre-commit
|
||||
|
||||
echo "Git hooks setup complete"
|
||||
EOT
|
||||
}
|
||||
|
||||
echo "🔍 Checking service connectivity..."
|
||||
|
||||
# Check PostgreSQL
|
||||
if [ -n "$POSTGRES_URL" ]; then
|
||||
if pg_isready -d "$POSTGRES_URL" 2>/dev/null; then
|
||||
echo "✅ PostgreSQL is ready"
|
||||
else
|
||||
echo "⚠️ PostgreSQL is not responding"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check Redis
|
||||
if [ -n "$REDIS_URL" ]; then
|
||||
REDIS_HOST=$(echo "$REDIS_URL" | sed -E 's|redis://[^@]*@([^:]+):.*|\1|')
|
||||
REDIS_PORT=$(echo "$REDIS_URL" | sed -E 's|.*:([0-9]+).*|\1|')
|
||||
if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping 2>/dev/null | grep -q PONG; then
|
||||
echo "✅ Redis is ready"
|
||||
else
|
||||
echo "⚠️ Redis is not responding"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check Qdrant
|
||||
if [ -n "$QDRANT_URL" ]; then
|
||||
if curl -s "$QDRANT_URL/readyz" | grep -q "ok"; then
|
||||
echo "✅ Qdrant is ready"
|
||||
else
|
||||
echo "⚠️ Qdrant is not responding"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "🏁 Service health check complete"
|
||||
EOF
|
||||
}
|
||||
72
tf/scripts.tf.disabled
Normal file
72
tf/scripts.tf.disabled
Normal file
@@ -0,0 +1,72 @@
|
||||
# =============================================================================
|
||||
# Provisioning Scripts - AI Development Tools and Extensions
|
||||
# Simplified scripts to avoid carriage return issues
|
||||
# =============================================================================
|
||||
|
||||
# =============================================================================
|
||||
# Claude Code CLI Installation
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "claude_code_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_claude_code.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Claude Code CLI"
|
||||
icon = "/icon/ai.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = "#!/bin/sh\ncommand -v claude >/dev/null 2>&1 || curl -fsSL https://claude.ai/install.sh | sh || echo 'Claude Code CLI installation skipped'"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Cursor IDE Support Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "cursor_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_cursor_support.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Configure Cursor IDE Support"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = "#!/bin/sh\nmkdir -p /home/coder/.config/cursor && printf '{\\n \"workspaceFolder\": \"/workspaces\",\\n \"remote.SSH.defaultExtensions\": [\\n \"ms-python.python\",\\n \"esbenp.prettier-vscode\",\\n \"dbaeumer.vscode-eslint\"\\n ]\\n}' > /home/coder/.config/cursor/settings.json"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Windsurf IDE Support Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "windsurf_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_windsurf_support.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Configure Windsurf IDE Support"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = "#!/bin/sh\nmkdir -p /home/coder/.config/windsurf && printf '{\\n \"workspaceFolder\": \"/workspaces\",\\n \"codeium.enabled\": true\\n}' > /home/coder/.config/windsurf/settings.json"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Development Tools and Extensions
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "dev_extensions" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Development Tools"
|
||||
icon = "/icon/tools.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = "#!/bin/sh\ncommand -v ranger >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y ranger) || true"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Git Hooks and Metadata Capture Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "git_hooks_setup" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Setup Git Hooks"
|
||||
icon = "/icon/git.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = "#!/bin/sh\ngit config --global user.name \"${local.git_author_name}\" && git config --global user.email \"${local.git_author_email}\" && git config --global init.defaultBranch main"
|
||||
}
|
||||
86
tf/scripts.tf.old
Normal file
86
tf/scripts.tf.old
Normal file
@@ -0,0 +1,86 @@
|
||||
# =============================================================================
|
||||
# Provisioning Scripts - AI Development Tools and Extensions
|
||||
# Installation scripts for Cursor, Claude Code, Windsurf support
|
||||
# Using base64 encoding to avoid line ending issues
|
||||
# =============================================================================
|
||||
|
||||
# =============================================================================
|
||||
# Claude Code CLI Installation
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "claude_code_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_claude_code.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Claude Code CLI"
|
||||
icon = "/icon/ai.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = file("${path.module}/scripts/claude-install.sh")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Cursor IDE Support Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "cursor_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_cursor_support.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Configure Cursor IDE Support"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = file("${path.module}/scripts/cursor-setup.sh")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Windsurf IDE Support Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "windsurf_setup" {
|
||||
count = data.coder_parameter.enable_ai_tools.value && data.coder_parameter.enable_windsurf_support.value ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Configure Windsurf IDE Support"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = file("${path.module}/scripts/windsurf-setup.sh")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Development Tools and Extensions
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "dev_extensions" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Development Tools"
|
||||
icon = "/icon/tools.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = file("${path.module}/scripts/dev-tools.sh")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Git Hooks and Metadata Capture Setup
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "git_hooks_setup" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Setup Git Hooks"
|
||||
icon = "/icon/git.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = file("${path.module}/scripts/git-hooks.sh")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Workspace Setup (Comprehensive Environment Configuration)
|
||||
# =============================================================================
|
||||
|
||||
resource "coder_script" "workspace_setup" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Setup Development Workspace"
|
||||
icon = "/icon/tools.svg"
|
||||
run_on_start = true
|
||||
|
||||
script = file("${path.module}/scripts/workspace-setup.sh")
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
#!/bin/bash
|
||||
# Convert CRLF to LF if present (handles Windows line endings)
|
||||
if command -v dos2unix >/dev/null 2>&1; then
|
||||
dos2unix "$0" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "🤖 Installing Claude Code CLI..."
|
||||
|
||||
@@ -9,9 +14,23 @@ if command -v claude >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Cross-platform home directory detection
|
||||
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
|
||||
HOME_DIR="${USERPROFILE:-$HOME}"
|
||||
BIN_DIR="$HOME_DIR/bin"
|
||||
# Windows/WSL/Git Bash compatibility
|
||||
export NVM_DIR="$HOME_DIR/.nvm"
|
||||
else
|
||||
HOME_DIR="$HOME"
|
||||
BIN_DIR="/home/coder/bin"
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
fi
|
||||
|
||||
# Ensure npm is available
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
||||
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
|
||||
# Use POSIX-compatible sourcing
|
||||
. "$NVM_DIR/nvm.sh"
|
||||
fi
|
||||
|
||||
if ! command -v npm >/dev/null 2>&1; then
|
||||
echo "❌ npm not found - Node.js installation required"
|
||||
@@ -28,37 +47,40 @@ if command -v claude >/dev/null 2>&1; then
|
||||
echo "💡 Use 'claude chat' for interactive assistance"
|
||||
echo "💡 Use 'claude edit <file>' to edit files with AI"
|
||||
|
||||
# Create helper script
|
||||
mkdir -p /home/coder/bin
|
||||
cat > /home/coder/bin/claude-help << 'CLAUDE_HELP_END'
|
||||
#!/bin/bash
|
||||
echo "🤖 Claude Code AI Assistant"
|
||||
echo "=========================="
|
||||
echo ""
|
||||
echo "Authentication:"
|
||||
echo " claude auth login # Authenticate with Anthropic"
|
||||
echo " claude auth logout # Sign out"
|
||||
echo " claude auth whoami # Check current user"
|
||||
echo ""
|
||||
echo "Interactive Chat:"
|
||||
echo " claude chat # Start interactive session"
|
||||
echo " claude chat 'question' # Single question"
|
||||
echo ""
|
||||
echo "File Editing:"
|
||||
echo " claude edit file.py # AI-powered file editing"
|
||||
echo " claude edit --help # Edit command options"
|
||||
echo ""
|
||||
echo "Code Analysis:"
|
||||
echo " claude analyze . # Analyze current directory"
|
||||
echo " claude review file.py # Code review"
|
||||
echo ""
|
||||
echo "Project Operations:"
|
||||
echo " claude init # Initialize Claude in project"
|
||||
echo " claude status # Show project status"
|
||||
echo ""
|
||||
echo "💡 For full documentation: https://docs.anthropic.com/claude/docs"
|
||||
CLAUDE_HELP_END
|
||||
chmod +x /home/coder/bin/claude-help
|
||||
# Create helper script with proper line endings
|
||||
mkdir -p "$BIN_DIR"
|
||||
|
||||
# Use printf instead of cat with heredoc to ensure consistent line endings
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf 'echo "🤖 Claude Code AI Assistant"\n'
|
||||
printf 'echo "=========================="\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "Authentication:"\n'
|
||||
printf 'echo " claude auth login # Authenticate with Anthropic"\n'
|
||||
printf 'echo " claude auth logout # Sign out"\n'
|
||||
printf 'echo " claude auth whoami # Check current user"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "Interactive Chat:"\n'
|
||||
printf 'echo " claude chat # Start interactive session"\n'
|
||||
printf 'echo " claude chat '\''question'\'' # Single question"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "File Editing:"\n'
|
||||
printf 'echo " claude edit file.py # AI-powered file editing"\n'
|
||||
printf 'echo " claude edit --help # Edit command options"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "Code Analysis:"\n'
|
||||
printf 'echo " claude analyze . # Analyze current directory"\n'
|
||||
printf 'echo " claude review file.py # Code review"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "Project Operations:"\n'
|
||||
printf 'echo " claude init # Initialize Claude in project"\n'
|
||||
printf 'echo " claude status # Show project status"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "💡 For full documentation: https://docs.anthropic.com/claude/docs"\n'
|
||||
} > "$BIN_DIR/claude-help"
|
||||
|
||||
chmod +x "$BIN_DIR/claude-help"
|
||||
|
||||
echo "💡 Run 'claude-help' for quick reference"
|
||||
else
|
||||
|
||||
@@ -1,182 +1,203 @@
|
||||
#!/bin/bash
|
||||
# Convert CRLF to LF if present (handles Windows line endings)
|
||||
if command -v dos2unix >/dev/null 2>&1; then
|
||||
dos2unix "$0" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "🎯 Setting up Cursor IDE support..."
|
||||
|
||||
# Create Cursor configuration directories
|
||||
mkdir -p /home/coder/.cursor-server/data/User
|
||||
mkdir -p /home/coder/.cursor-server/extensions
|
||||
# Cross-platform user and directory detection
|
||||
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
|
||||
HOME_DIR="${USERPROFILE:-$HOME}"
|
||||
USER_NAME="${USERNAME:-${USER:-coder}}"
|
||||
CURSOR_DIR="$HOME_DIR/.cursor-server"
|
||||
else
|
||||
HOME_DIR="${HOME:-/home/coder}"
|
||||
USER_NAME="${USER:-coder}"
|
||||
CURSOR_DIR="$HOME_DIR/.cursor-server"
|
||||
fi
|
||||
|
||||
# Create optimized Cursor settings
|
||||
cat > /home/coder/.cursor-server/data/User/settings.json << 'CURSOR_SETTINGS_END'
|
||||
# Create Cursor configuration directories
|
||||
mkdir -p "$CURSOR_DIR/data/User"
|
||||
mkdir -p "$CURSOR_DIR/extensions"
|
||||
|
||||
# Create optimized Cursor settings using printf to ensure LF line endings
|
||||
{
|
||||
"workbench.colorTheme": "Dark+ (default dark)",
|
||||
"editor.fontSize": 14,
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": true,
|
||||
"source.organizeImports": true
|
||||
},
|
||||
"files.autoSave": "afterDelay",
|
||||
"files.autoSaveDelay": 1000,
|
||||
"terminal.integrated.fontSize": 13,
|
||||
"git.enableSmartCommit": true,
|
||||
"git.confirmSync": false,
|
||||
"python.defaultInterpreterPath": "/home/coder/.venv/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": false,
|
||||
"python.linting.flake8Enabled": true,
|
||||
"typescript.preferences.includePackageJsonAutoImports": "auto",
|
||||
"javascript.preferences.includePackageJsonAutoImports": "auto",
|
||||
"cursor.chat.showInEditorContextMenu": true,
|
||||
"cursor.chat.alwaysShowInEditorContextMenu": true,
|
||||
"cursor.general.enableWindowAIFeatures": true
|
||||
}
|
||||
CURSOR_SETTINGS_END
|
||||
printf '{\n'
|
||||
printf ' "workbench.colorTheme": "Dark+ (default dark)",\n'
|
||||
printf ' "editor.fontSize": 14,\n'
|
||||
printf ' "editor.tabSize": 2,\n'
|
||||
printf ' "editor.insertSpaces": true,\n'
|
||||
printf ' "editor.formatOnSave": true,\n'
|
||||
printf ' "editor.codeActionsOnSave": {\n'
|
||||
printf ' "source.fixAll": true,\n'
|
||||
printf ' "source.organizeImports": true\n'
|
||||
printf ' },\n'
|
||||
printf ' "files.autoSave": "afterDelay",\n'
|
||||
printf ' "files.autoSaveDelay": 1000,\n'
|
||||
printf ' "terminal.integrated.fontSize": 13,\n'
|
||||
printf ' "git.enableSmartCommit": true,\n'
|
||||
printf ' "git.confirmSync": false,\n'
|
||||
printf ' "python.defaultInterpreterPath": "%s/.venv/bin/python",\n' "$HOME_DIR"
|
||||
printf ' "python.linting.enabled": true,\n'
|
||||
printf ' "python.linting.pylintEnabled": false,\n'
|
||||
printf ' "python.linting.flake8Enabled": true,\n'
|
||||
printf ' "typescript.preferences.includePackageJsonAutoImports": "auto",\n'
|
||||
printf ' "javascript.preferences.includePackageJsonAutoImports": "auto",\n'
|
||||
printf ' "cursor.chat.showInEditorContextMenu": true,\n'
|
||||
printf ' "cursor.chat.alwaysShowInEditorContextMenu": true,\n'
|
||||
printf ' "cursor.general.enableWindowAIFeatures": true\n'
|
||||
printf '}\n'
|
||||
} > "$CURSOR_DIR/data/User/settings.json"
|
||||
|
||||
# Create development tasks configuration
|
||||
mkdir -p /home/coder/.cursor-server/data/User
|
||||
cat > /home/coder/.cursor-server/data/User/tasks.json << 'CURSOR_TASKS_END'
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Dev Server",
|
||||
"type": "shell",
|
||||
"command": "npm run dev",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "new"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Python Dev Server",
|
||||
"type": "shell",
|
||||
"command": "uvicorn main:app --reload --host 0.0.0.0 --port 8000",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "new"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Install Dependencies",
|
||||
"type": "shell",
|
||||
"command": "npm install",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "new"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Python Install",
|
||||
"type": "shell",
|
||||
"command": "uv pip install -r requirements.txt",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "new"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
CURSOR_TASKS_END
|
||||
printf '{\n'
|
||||
printf ' "version": "2.0.0",\n'
|
||||
printf ' "tasks": [\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Dev Server",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "npm run dev",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' },\n'
|
||||
printf ' "problemMatcher": []\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Python Dev Server",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "uvicorn main:app --reload --host 0.0.0.0 --port 8000",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' },\n'
|
||||
printf ' "problemMatcher": []\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Install Dependencies",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "npm install",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' }\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Python Install",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "uv pip install -r requirements.txt",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' }\n'
|
||||
printf ' }\n'
|
||||
printf ' ]\n'
|
||||
printf '}\n'
|
||||
} > "$CURSOR_DIR/data/User/tasks.json"
|
||||
|
||||
# Create useful code snippets
|
||||
mkdir -p /home/coder/.cursor-server/data/User/snippets
|
||||
cat > /home/coder/.cursor-server/data/User/snippets/global.code-snippets << 'CURSOR_SNIPPETS_END'
|
||||
mkdir -p "$CURSOR_DIR/data/User/snippets"
|
||||
{
|
||||
"FastAPI Basic App": {
|
||||
"prefix": "fastapi-app",
|
||||
"body": [
|
||||
"from fastapi import FastAPI",
|
||||
"from fastapi.middleware.cors import CORSMiddleware",
|
||||
"",
|
||||
"app = FastAPI(title=\"${1:My API}\", version=\"0.1.0\")",
|
||||
"",
|
||||
"app.add_middleware(",
|
||||
" CORSMiddleware,",
|
||||
" allow_origins=[\"*\"],",
|
||||
" allow_credentials=True,",
|
||||
" allow_methods=[\"*\"],",
|
||||
" allow_headers=[\"*\"],",
|
||||
")",
|
||||
"",
|
||||
"@app.get(\"/\")",
|
||||
"async def root():",
|
||||
" return {\"message\": \"${2:Hello World}\"}",
|
||||
"",
|
||||
"@app.get(\"/health\")",
|
||||
"async def health():",
|
||||
" return {\"status\": \"healthy\"}",
|
||||
"",
|
||||
"if __name__ == \"__main__\":",
|
||||
" import uvicorn",
|
||||
" uvicorn.run(app, host=\"0.0.0.0\", port=8000)"
|
||||
],
|
||||
"description": "FastAPI basic application template"
|
||||
},
|
||||
"Next.js API Route": {
|
||||
"prefix": "nextapi",
|
||||
"body": [
|
||||
"import { NextRequest, NextResponse } from 'next/server';",
|
||||
"",
|
||||
"export async function ${1:GET}(request: NextRequest) {",
|
||||
" try {",
|
||||
" // Your API logic here",
|
||||
" return NextResponse.json({ message: '${2:Success}' });",
|
||||
" } catch (error) {",
|
||||
" return NextResponse.json(",
|
||||
" { error: 'Internal Server Error' },",
|
||||
" { status: 500 }",
|
||||
" );",
|
||||
" }",
|
||||
"}"
|
||||
],
|
||||
"description": "Next.js API route template"
|
||||
},
|
||||
"Database Connection": {
|
||||
"prefix": "db-connect",
|
||||
"body": [
|
||||
"import os",
|
||||
"from sqlalchemy import create_engine",
|
||||
"from sqlalchemy.orm import sessionmaker",
|
||||
"",
|
||||
"DATABASE_URL = os.getenv(",
|
||||
" \"POSTGRES_URL\",",
|
||||
" \"postgresql://postgres:password@localhost:5432/postgres\"",
|
||||
")",
|
||||
"",
|
||||
"engine = create_engine(DATABASE_URL)",
|
||||
"SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)",
|
||||
"",
|
||||
"def get_db():",
|
||||
" db = SessionLocal()",
|
||||
" try:",
|
||||
" yield db",
|
||||
" finally:",
|
||||
" db.close()"
|
||||
],
|
||||
"description": "Database connection setup"
|
||||
}
|
||||
}
|
||||
CURSOR_SNIPPETS_END
|
||||
printf '{\n'
|
||||
printf ' "FastAPI Basic App": {\n'
|
||||
printf ' "prefix": "fastapi-app",\n'
|
||||
printf ' "body": [\n'
|
||||
printf ' "from fastapi import FastAPI",\n'
|
||||
printf ' "from fastapi.middleware.cors import CORSMiddleware",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "app = FastAPI(title=\\"${1:My API}\\", version=\\"0.1.0\\")",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "app.add_middleware(",\n'
|
||||
printf ' " CORSMiddleware,",\n'
|
||||
printf ' " allow_origins=[\\"*\\"],",\n'
|
||||
printf ' " allow_credentials=True,",\n'
|
||||
printf ' " allow_methods=[\\"*\\"],",\n'
|
||||
printf ' " allow_headers=[\\"*\\"],",\n'
|
||||
printf ' ")",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "@app.get(\\"\\")\\",\n'
|
||||
printf ' "async def root():",\n'
|
||||
printf ' " return {\\"message\\": \\"${2:Hello World}\\"}",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "@app.get(\\"\/health\\")",\n'
|
||||
printf ' "async def health():",\n'
|
||||
printf ' " return {\\"status\\": \\"healthy\\"}",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "if __name__ == \\"__main__\\":",\n'
|
||||
printf ' " import uvicorn",\n'
|
||||
printf ' " uvicorn.run(app, host=\\"0.0.0.0\\", port=8000)"\n'
|
||||
printf ' ],\n'
|
||||
printf ' "description": "FastAPI basic application template"\n'
|
||||
printf ' },\n'
|
||||
printf ' "Next.js API Route": {\n'
|
||||
printf ' "prefix": "nextapi",\n'
|
||||
printf ' "body": [\n'
|
||||
printf ' "import { NextRequest, NextResponse } from '\''next\/server'\'';",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "export async function ${1:GET}(request: NextRequest) {",\n'
|
||||
printf ' " try {",\n'
|
||||
printf ' " \/\/ Your API logic here",\n'
|
||||
printf ' " return NextResponse.json({ message: '\''${2:Success}'\'' });",\n'
|
||||
printf ' " } catch (error) {",\n'
|
||||
printf ' " return NextResponse.json(",\n'
|
||||
printf ' " { error: '\''Internal Server Error'\'' },",\n'
|
||||
printf ' " { status: 500 }",\n'
|
||||
printf ' " );",\n'
|
||||
printf ' " }",\n'
|
||||
printf ' "}"\n'
|
||||
printf ' ],\n'
|
||||
printf ' "description": "Next.js API route template"\n'
|
||||
printf ' },\n'
|
||||
printf ' "Database Connection": {\n'
|
||||
printf ' "prefix": "db-connect",\n'
|
||||
printf ' "body": [\n'
|
||||
printf ' "import os",\n'
|
||||
printf ' "from sqlalchemy import create_engine",\n'
|
||||
printf ' "from sqlalchemy.orm import sessionmaker",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "DATABASE_URL = os.getenv(",\n'
|
||||
printf ' " \\"POSTGRES_URL\\",",\n'
|
||||
printf ' " \\"postgresql:\/\/postgres:password@localhost:5432\/postgres\\"",\n'
|
||||
printf ' ")",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "engine = create_engine(DATABASE_URL)",\n'
|
||||
printf ' "SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "def get_db():",\n'
|
||||
printf ' " db = SessionLocal()",\n'
|
||||
printf ' " try:",\n'
|
||||
printf ' " yield db",\n'
|
||||
printf ' " finally:",\n'
|
||||
printf ' " db.close()"\n'
|
||||
printf ' ],\n'
|
||||
printf ' "description": "Database connection setup"\n'
|
||||
printf ' }\n'
|
||||
printf '}\n'
|
||||
} > "$CURSOR_DIR/data/User/snippets/global.code-snippets"
|
||||
|
||||
# Set proper ownership
|
||||
chown -R coder:coder /home/coder/.cursor-server
|
||||
# Set proper ownership (Unix-like systems only)
|
||||
if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "cygwin" && "$OSTYPE" != "win32" ]]; then
|
||||
if command -v chown >/dev/null 2>&1; then
|
||||
chown -R "$USER_NAME:$USER_NAME" "$CURSOR_DIR" 2>/dev/null || {
|
||||
echo "⚠️ Could not set ownership - you may need to run with appropriate permissions"
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Cursor IDE support configured"
|
||||
echo "🎯 Cursor will use optimized settings for this development environment"
|
||||
@@ -1,120 +1,363 @@
|
||||
#!/bin/bash
|
||||
# Convert CRLF to LF if present (handles Windows line endings)
|
||||
if command -v dos2unix >/dev/null 2>&1; then
|
||||
dos2unix "$0" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "🔧 Installing development extensions and tools..."
|
||||
|
||||
# Ensure we're running as root for system packages
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "This script needs to run as root for system package installation"
|
||||
exit 1
|
||||
fi
|
||||
# Cross-platform system detection
|
||||
detect_system() {
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
SYSTEM="debian"
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
SYSTEM="rhel"
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
SYSTEM="arch"
|
||||
else
|
||||
SYSTEM="linux"
|
||||
fi
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
SYSTEM="macos"
|
||||
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
|
||||
SYSTEM="windows"
|
||||
else
|
||||
SYSTEM="unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
# Cross-platform package installation
|
||||
install_package() {
|
||||
local package="$1"
|
||||
case "$SYSTEM" in
|
||||
"debian")
|
||||
apt-get update >/dev/null 2>&1 || true
|
||||
apt-get install -y "$package"
|
||||
;;
|
||||
"rhel")
|
||||
yum install -y "$package" || dnf install -y "$package"
|
||||
;;
|
||||
"arch")
|
||||
pacman -S --noconfirm "$package"
|
||||
;;
|
||||
"macos")
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
brew install "$package"
|
||||
else
|
||||
echo "⚠️ Homebrew not found. Please install $package manually."
|
||||
fi
|
||||
;;
|
||||
"windows")
|
||||
if command -v choco >/dev/null 2>&1; then
|
||||
choco install -y "$package"
|
||||
elif command -v winget >/dev/null 2>&1; then
|
||||
winget install "$package"
|
||||
else
|
||||
echo "⚠️ Package manager not found. Please install $package manually."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ Unknown system. Please install $package manually."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Detect system and user info
|
||||
detect_system
|
||||
HOME_DIR="${HOME:-/home/coder}"
|
||||
USER_NAME="${USER:-coder}"
|
||||
|
||||
# Architecture detection for downloads
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
"x86_64") ARCH="x86_64" ;;
|
||||
"aarch64"|"arm64") ARCH="arm64" ;;
|
||||
*) ARCH="x86_64" ;; # Default fallback
|
||||
esac
|
||||
|
||||
# OS-specific binary suffix
|
||||
case "$SYSTEM" in
|
||||
"windows") BIN_SUFFIX=".exe" ;;
|
||||
*) BIN_SUFFIX="" ;;
|
||||
esac
|
||||
|
||||
# Check if we need elevated privileges (skip on Windows/macOS package managers)
|
||||
check_privileges() {
|
||||
if [[ "$SYSTEM" == "debian" || "$SYSTEM" == "rhel" || "$SYSTEM" == "arch" ]]; then
|
||||
if [ "$EUID" -ne 0 ] && ! command -v sudo >/dev/null 2>&1; then
|
||||
echo "This script needs root privileges or sudo for system package installation"
|
||||
exit 1
|
||||
fi
|
||||
SUDO_CMD="sudo"
|
||||
else
|
||||
SUDO_CMD=""
|
||||
fi
|
||||
}
|
||||
|
||||
check_privileges
|
||||
|
||||
echo "📦 Installing additional CLI tools..."
|
||||
|
||||
# Ensure curl is available first
|
||||
type -p curl >/dev/null || (apt-get update && apt-get install curl -y)
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "📥 Installing curl..."
|
||||
case "$SYSTEM" in
|
||||
"debian") $SUDO_CMD apt-get update && $SUDO_CMD apt-get install -y curl ;;
|
||||
"rhel") $SUDO_CMD yum install -y curl || $SUDO_CMD dnf install -y curl ;;
|
||||
"arch") $SUDO_CMD pacman -S --noconfirm curl ;;
|
||||
"macos") install_package curl ;;
|
||||
"windows") install_package curl ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Function to install various development tools
|
||||
install_development_tools() {
|
||||
echo "🛠️ Installing development utilities..."
|
||||
|
||||
# GitHub CLI
|
||||
if ! command -v gh &> /dev/null; then
|
||||
if ! command -v gh >/dev/null 2>&1; then
|
||||
echo "📥 Installing GitHub CLI..."
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
apt-get update
|
||||
apt-get install gh -y
|
||||
case "$SYSTEM" in
|
||||
"debian")
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | $SUDO_CMD dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
$SUDO_CMD chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
printf 'deb [arch=%s signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main\n' "$(dpkg --print-architecture)" | $SUDO_CMD tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
$SUDO_CMD apt-get update
|
||||
$SUDO_CMD apt-get install -y gh
|
||||
;;
|
||||
"macos")
|
||||
install_package gh
|
||||
;;
|
||||
"windows")
|
||||
install_package gh
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ Please install GitHub CLI manually for your system"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Docker Compose (if not already installed)
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
if ! command -v docker-compose >/dev/null 2>&1; then
|
||||
echo "🐳 Installing Docker Compose..."
|
||||
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
case "$SYSTEM" in
|
||||
"windows")
|
||||
echo "⚠️ Please install Docker Desktop for Windows which includes Docker Compose"
|
||||
;;
|
||||
"macos")
|
||||
echo "⚠️ Please install Docker Desktop for macOS which includes Docker Compose"
|
||||
;;
|
||||
*)
|
||||
COMPOSE_URL="https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)"
|
||||
curl -L "$COMPOSE_URL" -o docker-compose
|
||||
$SUDO_CMD mv docker-compose /usr/local/bin/docker-compose
|
||||
$SUDO_CMD chmod +x /usr/local/bin/docker-compose
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Lazygit for better git UI
|
||||
if ! command -v lazygit &> /dev/null; then
|
||||
if ! command -v lazygit >/dev/null 2>&1; then
|
||||
echo "🌿 Installing lazygit..."
|
||||
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v*([^"]+)".*/\1/')
|
||||
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
|
||||
tar xf lazygit.tar.gz lazygit
|
||||
install lazygit /usr/local/bin
|
||||
rm lazygit.tar.gz lazygit
|
||||
case "$SYSTEM" in
|
||||
"macos")
|
||||
install_package lazygit
|
||||
;;
|
||||
"windows")
|
||||
install_package lazygit
|
||||
;;
|
||||
*)
|
||||
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v*([^"]+)".*/\1/')
|
||||
case "$SYSTEM" in
|
||||
"linux")
|
||||
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_${ARCH}.tar.gz"
|
||||
;;
|
||||
*)
|
||||
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
|
||||
;;
|
||||
esac
|
||||
tar xf lazygit.tar.gz lazygit
|
||||
$SUDO_CMD install lazygit /usr/local/bin
|
||||
rm -f lazygit.tar.gz lazygit
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# btop for system monitoring
|
||||
if ! command -v btop &> /dev/null; then
|
||||
if ! command -v btop >/dev/null 2>&1; then
|
||||
echo "📊 Installing btop..."
|
||||
apt-get install btop -y
|
||||
case "$SYSTEM" in
|
||||
"debian") $SUDO_CMD apt-get install -y btop ;;
|
||||
"macos") install_package btop ;;
|
||||
"windows") install_package btop ;;
|
||||
*) echo "⚠️ Please install btop manually for your system" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# fd-find for better file searching
|
||||
if ! command -v fd &> /dev/null; then
|
||||
if ! command -v fd >/dev/null 2>&1; then
|
||||
echo "🔍 Installing fd-find..."
|
||||
apt-get install fd-find -y
|
||||
# Create symlink for easier usage
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd
|
||||
case "$SYSTEM" in
|
||||
"debian")
|
||||
$SUDO_CMD apt-get install -y fd-find
|
||||
# Create symlink for easier usage
|
||||
$SUDO_CMD ln -sf /usr/bin/fdfind /usr/local/bin/fd 2>/dev/null || true
|
||||
;;
|
||||
"macos")
|
||||
install_package fd
|
||||
;;
|
||||
"windows")
|
||||
install_package fd
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ Please install fd manually for your system"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# ripgrep for better text searching
|
||||
if ! command -v rg &> /dev/null; then
|
||||
if ! command -v rg >/dev/null 2>&1; then
|
||||
echo "🔎 Installing ripgrep..."
|
||||
apt-get install ripgrep -y
|
||||
case "$SYSTEM" in
|
||||
"debian") $SUDO_CMD apt-get install -y ripgrep ;;
|
||||
"macos") install_package ripgrep ;;
|
||||
"windows") install_package ripgrep ;;
|
||||
*) echo "⚠️ Please install ripgrep manually for your system" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# bat for better cat with syntax highlighting
|
||||
if ! command -v bat &> /dev/null; then
|
||||
if ! command -v bat >/dev/null 2>&1; then
|
||||
echo "🦇 Installing bat..."
|
||||
apt-get install bat -y
|
||||
# Create symlink for easier usage
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat
|
||||
case "$SYSTEM" in
|
||||
"debian")
|
||||
$SUDO_CMD apt-get install -y bat
|
||||
# Create symlink for easier usage
|
||||
$SUDO_CMD ln -sf /usr/bin/batcat /usr/local/bin/bat 2>/dev/null || true
|
||||
;;
|
||||
"macos")
|
||||
install_package bat
|
||||
;;
|
||||
"windows")
|
||||
install_package bat
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ Please install bat manually for your system"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# eza for better ls (modern replacement for exa)
|
||||
if ! command -v eza &> /dev/null; then
|
||||
if ! command -v eza >/dev/null 2>&1; then
|
||||
echo "📁 Installing eza..."
|
||||
curl -L "https://github.com/eza-community/eza/releases/latest/download/eza_x86_64-unknown-linux-gnu.tar.gz" | tar xz -C /usr/local/bin
|
||||
case "$SYSTEM" in
|
||||
"macos")
|
||||
install_package eza
|
||||
;;
|
||||
"windows")
|
||||
install_package eza
|
||||
;;
|
||||
*)
|
||||
case "$ARCH" in
|
||||
"arm64"|"aarch64")
|
||||
EZA_ARCH="aarch64"
|
||||
;;
|
||||
*)
|
||||
EZA_ARCH="x86_64"
|
||||
;;
|
||||
esac
|
||||
curl -L "https://github.com/eza-community/eza/releases/latest/download/eza_${EZA_ARCH}-unknown-linux-gnu.tar.gz" | $SUDO_CMD tar xz -C /usr/local/bin 2>/dev/null || {
|
||||
echo "⚠️ Could not install eza automatically"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# Install all development tools
|
||||
install_development_tools
|
||||
|
||||
# Switch to coder user for user-specific installations
|
||||
# Set up user-specific configurations
|
||||
echo "👤 Setting up user-specific tools..."
|
||||
su - coder << 'USER_SETUP_END'
|
||||
# Add useful aliases to .bashrc if not already present
|
||||
if ! grep -q "# Development tools aliases" ~/.bashrc; then
|
||||
cat >> ~/.bashrc << 'ALIASES_END'
|
||||
|
||||
# Development tools aliases
|
||||
alias cat='bat'
|
||||
alias ls='eza'
|
||||
alias ll='eza -la'
|
||||
alias la='eza -la'
|
||||
alias find='fd'
|
||||
alias grep='rg'
|
||||
alias git-ui='lazygit'
|
||||
alias top='btop'
|
||||
# Create user setup script to handle cross-platform differences
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# User-specific tool setup\n'
|
||||
printf '\n'
|
||||
printf '# Detect shell configuration file\n'
|
||||
printf 'if [[ "$SHELL" == *"zsh"* && -f "$HOME/.zshrc" ]]; then\n'
|
||||
printf ' SHELL_RC="$HOME/.zshrc"\n'
|
||||
printf 'elif [[ -f "$HOME/.bashrc" ]]; then\n'
|
||||
printf ' SHELL_RC="$HOME/.bashrc"\n'
|
||||
printf 'else\n'
|
||||
printf ' SHELL_RC="$HOME/.profile"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf '# Add useful aliases if not already present\n'
|
||||
printf 'if ! grep -q "# Development tools aliases" "$SHELL_RC" 2>/dev/null; then\n'
|
||||
printf ' printf "\\n# Development tools aliases\\n" >> "$SHELL_RC"\n'
|
||||
printf ' if command -v bat >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias cat='\''bat'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' if command -v eza >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias ls='\''eza'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias ll='\''eza -la'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias la='\''eza -la'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' if command -v fd >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias find='\''fd'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' if command -v rg >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias grep='\''rg'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' if command -v lazygit >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias git-ui='\''lazygit'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' if command -v btop >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias top='\''btop'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' printf "\\n" >> "$SHELL_RC"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf '# Install Node.js tools if npm is available\n'
|
||||
printf 'if command -v npm >/dev/null 2>&1; then\n'
|
||||
printf ' # Install tldr for better man pages\n'
|
||||
printf ' if ! command -v tldr >/dev/null 2>&1; then\n'
|
||||
printf ' npm install -g tldr 2>/dev/null || echo "⚠️ Could not install tldr"\n'
|
||||
printf ' fi\n'
|
||||
printf ' \n'
|
||||
printf ' # Install fkill for better process management\n'
|
||||
printf ' if ! command -v fkill >/dev/null 2>&1; then\n'
|
||||
printf ' npm install -g fkill-cli 2>/dev/null || echo "⚠️ Could not install fkill-cli"\n'
|
||||
printf ' fi\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf 'echo "✅ Development tools installed and configured!"\n'
|
||||
} > /tmp/user_setup.sh
|
||||
|
||||
ALIASES_END
|
||||
# Run user setup based on system type
|
||||
if [[ "$SYSTEM" == "windows" ]]; then
|
||||
# On Windows, run directly
|
||||
bash /tmp/user_setup.sh
|
||||
else
|
||||
# On Unix-like systems, try to switch to target user if different
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "bash /tmp/user_setup.sh" 2>/dev/null || {
|
||||
echo "⚠️ Could not switch to user $USER_NAME, running as current user"
|
||||
bash /tmp/user_setup.sh
|
||||
}
|
||||
else
|
||||
bash /tmp/user_setup.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install tldr for better man pages
|
||||
if ! command -v tldr &> /dev/null; then
|
||||
npm install -g tldr
|
||||
fi
|
||||
|
||||
# Install fkill for better process management
|
||||
if ! command -v fkill &> /dev/null; then
|
||||
npm install -g fkill-cli
|
||||
fi
|
||||
|
||||
echo "✅ Development tools installed and configured!"
|
||||
USER_SETUP_END
|
||||
# Clean up
|
||||
rm -f /tmp/user_setup.sh
|
||||
|
||||
echo "🎉 All development tools installed successfully!"
|
||||
echo "💡 Available tools: gh, docker-compose, lazygit, btop, fd, rg, bat, eza, tldr, fkill"
|
||||
echo "💡 Aliases configured: cat→bat, ls→eza, find→fd, grep→rg, git-ui→lazygit, top→btop"
|
||||
echo "💡 Aliases configured: cat→bat, ls→eza, find→fd, grep→rg, git-ui→lazygit, top→btop"
|
||||
echo "💡 Restart your shell or run 'source ~/.bashrc' (or ~/.zshrc) to use the new aliases"
|
||||
@@ -1,9 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Convert CRLF to LF if present (handles Windows line endings)
|
||||
if command -v dos2unix >/dev/null 2>&1; then
|
||||
dos2unix "$0" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "📝 Setting up Git hooks and metadata capture..."
|
||||
|
||||
# Ensure we're in the workspaces directory
|
||||
cd /workspaces
|
||||
# Cross-platform directory and user detection
|
||||
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
|
||||
HOME_DIR="${USERPROFILE:-$HOME}"
|
||||
USER_NAME="${USERNAME:-${USER:-coder}}"
|
||||
WORKSPACES_DIR="${HOME_DIR}/workspaces"
|
||||
TEMP_DIR="${TEMP:-/tmp}"
|
||||
else
|
||||
HOME_DIR="${HOME:-/home/coder}"
|
||||
USER_NAME="${USER:-coder}"
|
||||
WORKSPACES_DIR="/workspaces"
|
||||
TEMP_DIR="/tmp"
|
||||
fi
|
||||
|
||||
# Ensure workspaces directory exists and navigate to it
|
||||
mkdir -p "$WORKSPACES_DIR"
|
||||
cd "$WORKSPACES_DIR"
|
||||
|
||||
# Initialize git repository if it doesn't exist
|
||||
if [ ! -d ".git" ]; then
|
||||
@@ -14,70 +33,137 @@ fi
|
||||
# Create .git/hooks directory if it doesn't exist
|
||||
mkdir -p .git/hooks
|
||||
|
||||
# Create post-commit hook for metadata capture
|
||||
cat > .git/hooks/post-commit << 'POST_COMMIT_END'
|
||||
#!/bin/bash
|
||||
# Post-commit hook to capture git metadata
|
||||
echo "📝 Capturing git metadata after commit..."
|
||||
# Create post-commit hook for metadata capture using printf
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Post-commit hook to capture git metadata\n'
|
||||
printf 'echo "📝 Capturing git metadata after commit..."\n'
|
||||
printf '\n'
|
||||
printf '# Cross-platform temp directory detection\n'
|
||||
printf 'if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then\n'
|
||||
printf ' TEMP_DIR="${TEMP:-/tmp}"\n'
|
||||
printf 'else\n'
|
||||
printf ' TEMP_DIR="/tmp"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf '# Ensure metadata directory exists\n'
|
||||
printf 'mkdir -p "$TEMP_DIR/git-metadata"\n'
|
||||
printf '\n'
|
||||
printf '# Capture current git state\n'
|
||||
printf 'git branch --show-current > "$TEMP_DIR/git-metadata/current-branch" 2>/dev/null || printf "main" > "$TEMP_DIR/git-metadata/current-branch"\n'
|
||||
printf 'git rev-parse HEAD > "$TEMP_DIR/git-metadata/commit-hash" 2>/dev/null || printf "no-commits" > "$TEMP_DIR/git-metadata/commit-hash"\n'
|
||||
printf 'git remote get-url origin > "$TEMP_DIR/git-metadata/remote-url" 2>/dev/null || printf "no-remote" > "$TEMP_DIR/git-metadata/remote-url"\n'
|
||||
printf '\n'
|
||||
printf '# Log the commit for development tracking\n'
|
||||
printf 'printf "%%s: Commit %%s on branch %%s\\n" "$(date)" "$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")" "$(git branch --show-current 2>/dev/null || echo "unknown")" >> "$TEMP_DIR/git-metadata/commit-log"\n'
|
||||
printf '\n'
|
||||
printf 'echo "✅ Git metadata updated"\n'
|
||||
} > .git/hooks/post-commit
|
||||
|
||||
# Ensure metadata directory exists
|
||||
mkdir -p /tmp/git-metadata
|
||||
# Create pre-push hook for quality checks using printf
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Pre-push hook for basic quality checks\n'
|
||||
printf 'echo "🔍 Running pre-push quality checks..."\n'
|
||||
printf '\n'
|
||||
printf '# Check if package.json exists and run tests\n'
|
||||
printf 'if [ -f "package.json" ]; then\n'
|
||||
printf ' echo "📦 Found Node.js project, checking scripts..."\n'
|
||||
printf ' if npm run --silent test --if-present 2>/dev/null; then\n'
|
||||
printf ' echo "✅ Tests passed"\n'
|
||||
printf ' else\n'
|
||||
printf ' echo "⚠️ Tests not found or failed - pushing anyway"\n'
|
||||
printf ' fi\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf '# Check if requirements.txt or pyproject.toml exists\n'
|
||||
printf 'if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then\n'
|
||||
printf ' echo "🐍 Found Python project..."\n'
|
||||
printf ' # Could add Python linting here\n'
|
||||
printf ' echo "✅ Python project checks passed"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf '# Check for large files (cross-platform compatible)\n'
|
||||
printf 'echo "📁 Checking for large files..."\n'
|
||||
printf 'if command -v find >/dev/null 2>&1; then\n'
|
||||
printf ' large_files=$(find . -type f -size +100M 2>/dev/null | head -5)\n'
|
||||
printf ' if [ ! -z "$large_files" ]; then\n'
|
||||
printf ' echo "⚠️ Large files detected:"\n'
|
||||
printf ' printf "%%s\\n" "$large_files"\n'
|
||||
printf ' echo "Consider using Git LFS for large files"\n'
|
||||
printf ' fi\n'
|
||||
printf 'else\n'
|
||||
printf ' echo "⚠️ find command not available, skipping large file check"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf 'echo "✅ Pre-push checks completed"\n'
|
||||
} > .git/hooks/pre-push
|
||||
|
||||
# Capture current git state
|
||||
git branch --show-current > /tmp/git-metadata/current-branch 2>/dev/null || echo "main" > /tmp/git-metadata/current-branch
|
||||
git rev-parse HEAD > /tmp/git-metadata/commit-hash 2>/dev/null || echo "no-commits" > /tmp/git-metadata/commit-hash
|
||||
git remote get-url origin > /tmp/git-metadata/remote-url 2>/dev/null || echo "no-remote" > /tmp/git-metadata/remote-url
|
||||
# Make hooks executable (cross-platform compatible)
|
||||
if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "cygwin" && "$OSTYPE" != "win32" ]]; then
|
||||
chmod +x .git/hooks/post-commit
|
||||
chmod +x .git/hooks/pre-push
|
||||
else
|
||||
# On Windows, Git Bash should handle executable permissions automatically
|
||||
echo "🔧 Git hooks created (Windows will handle executable permissions)"
|
||||
fi
|
||||
|
||||
# Log the commit for development tracking
|
||||
echo "$(date): Commit $(git rev-parse --short HEAD) on branch $(git branch --show-current)" >> /tmp/git-metadata/commit-log
|
||||
|
||||
echo "✅ Git metadata updated"
|
||||
POST_COMMIT_END
|
||||
|
||||
# Make post-commit hook executable
|
||||
chmod +x .git/hooks/post-commit
|
||||
|
||||
# Create pre-push hook for quality checks
|
||||
cat > .git/hooks/pre-push << 'PRE_PUSH_END'
|
||||
#!/bin/bash
|
||||
# Pre-push hook for basic quality checks
|
||||
echo "🔍 Running pre-push quality checks..."
|
||||
|
||||
# Check if package.json exists and run tests
|
||||
if [ -f "package.json" ]; then
|
||||
echo "📦 Found Node.js project, checking scripts..."
|
||||
if npm run --silent test --if-present; then
|
||||
echo "✅ Tests passed"
|
||||
else
|
||||
echo "⚠️ Tests not found or failed - pushing anyway"
|
||||
# Set proper ownership (Unix-like systems only)
|
||||
if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "cygwin" && "$OSTYPE" != "win32" ]]; then
|
||||
if command -v chown >/dev/null 2>&1 && [ "$USER_NAME" != "$(whoami)" ]; then
|
||||
chown -R "$USER_NAME:$USER_NAME" .git/hooks 2>/dev/null || {
|
||||
echo "⚠️ Could not set ownership - you may need to run with appropriate permissions"
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if requirements.txt or pyproject.toml exists
|
||||
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
|
||||
echo "🐍 Found Python project..."
|
||||
# Could add Python linting here
|
||||
echo "✅ Python project checks passed"
|
||||
# Create a helper script for viewing git metadata
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Helper script to view captured git metadata\n'
|
||||
printf '\n'
|
||||
printf '# Cross-platform temp directory detection\n'
|
||||
printf 'if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then\n'
|
||||
printf ' TEMP_DIR="${TEMP:-/tmp}"\n'
|
||||
printf 'else\n'
|
||||
printf ' TEMP_DIR="/tmp"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf 'METADATA_DIR="$TEMP_DIR/git-metadata"\n'
|
||||
printf '\n'
|
||||
printf 'echo "📊 Git Metadata Summary"\n'
|
||||
printf 'echo "====================="\n'
|
||||
printf '\n'
|
||||
printf 'if [ -d "$METADATA_DIR" ]; then\n'
|
||||
printf ' if [ -f "$METADATA_DIR/current-branch" ]; then\n'
|
||||
printf ' printf "Current Branch: %%s\\n" "$(cat "$METADATA_DIR/current-branch")"\n'
|
||||
printf ' fi\n'
|
||||
printf ' \n'
|
||||
printf ' if [ -f "$METADATA_DIR/commit-hash" ]; then\n'
|
||||
printf ' printf "Latest Commit: %%s\\n" "$(cat "$METADATA_DIR/commit-hash")"\n'
|
||||
printf ' fi\n'
|
||||
printf ' \n'
|
||||
printf ' if [ -f "$METADATA_DIR/remote-url" ]; then\n'
|
||||
printf ' printf "Remote URL: %%s\\n" "$(cat "$METADATA_DIR/remote-url")"\n'
|
||||
printf ' fi\n'
|
||||
printf ' \n'
|
||||
printf ' if [ -f "$METADATA_DIR/commit-log" ]; then\n'
|
||||
printf ' echo ""\n'
|
||||
printf ' echo "Recent Commits:"\n'
|
||||
printf ' tail -5 "$METADATA_DIR/commit-log" 2>/dev/null || echo "No commit log available"\n'
|
||||
printf ' fi\n'
|
||||
printf 'else\n'
|
||||
printf ' echo "No git metadata found. Make a commit to generate metadata."\n'
|
||||
printf 'fi\n'
|
||||
} > .git/hooks/show-metadata
|
||||
|
||||
# Make metadata viewer executable
|
||||
if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "cygwin" && "$OSTYPE" != "win32" ]]; then
|
||||
chmod +x .git/hooks/show-metadata
|
||||
fi
|
||||
|
||||
# Check for large files
|
||||
echo "📁 Checking for large files..."
|
||||
large_files=$(find . -type f -size +100M 2>/dev/null | head -5)
|
||||
if [ ! -z "$large_files" ]; then
|
||||
echo "⚠️ Large files detected:"
|
||||
echo "$large_files"
|
||||
echo "Consider using Git LFS for large files"
|
||||
fi
|
||||
|
||||
echo "✅ Pre-push checks completed"
|
||||
PRE_PUSH_END
|
||||
|
||||
# Make pre-push hook executable
|
||||
chmod +x .git/hooks/pre-push
|
||||
|
||||
# Set proper ownership for the coder user
|
||||
chown -R coder:coder .git/hooks
|
||||
|
||||
echo "✅ Git hooks and metadata capture configured"
|
||||
echo "📝 Git metadata will be automatically captured on commits"
|
||||
echo "🔍 Pre-push quality checks will run before each push"
|
||||
echo "🔍 Pre-push quality checks will run before each push"
|
||||
echo "💡 Run '.git/hooks/show-metadata' to view captured git metadata"
|
||||
echo "💡 Metadata is stored in: $TEMP_DIR/git-metadata/"
|
||||
@@ -1,66 +1,280 @@
|
||||
#!/bin/bash
|
||||
# Convert CRLF to LF if present (handles Windows line endings)
|
||||
if command -v dos2unix >/dev/null 2>&1; then
|
||||
dos2unix "$0" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "🌊 Setting up Windsurf IDE support..."
|
||||
|
||||
# Cross-platform user and directory detection
|
||||
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
|
||||
HOME_DIR="${USERPROFILE:-$HOME}"
|
||||
USER_NAME="${USERNAME:-${USER:-coder}}"
|
||||
WINDSURF_DIR="$HOME_DIR/.windsurf"
|
||||
else
|
||||
HOME_DIR="${HOME:-/home/coder}"
|
||||
USER_NAME="${USER:-coder}"
|
||||
WINDSURF_DIR="$HOME_DIR/.windsurf"
|
||||
fi
|
||||
|
||||
# Create Windsurf configuration directories
|
||||
mkdir -p /home/coder/.windsurf/data/User
|
||||
mkdir -p /home/coder/.windsurf/extensions
|
||||
mkdir -p "$WINDSURF_DIR/data/User"
|
||||
mkdir -p "$WINDSURF_DIR/extensions"
|
||||
|
||||
# Create optimized Windsurf settings
|
||||
cat > /home/coder/.windsurf/data/User/settings.json << 'WINDSURF_SETTINGS_END'
|
||||
# Create optimized Windsurf settings using printf to ensure LF line endings
|
||||
{
|
||||
"workbench.colorTheme": "Windsurf Dark",
|
||||
"editor.fontSize": 14,
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": true,
|
||||
"source.organizeImports": true
|
||||
},
|
||||
"files.autoSave": "afterDelay",
|
||||
"files.autoSaveDelay": 1000,
|
||||
"terminal.integrated.fontSize": 13,
|
||||
"git.enableSmartCommit": true,
|
||||
"git.confirmSync": false,
|
||||
"python.defaultInterpreterPath": "/home/coder/.venv/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": false,
|
||||
"python.linting.flake8Enabled": true,
|
||||
"typescript.preferences.includePackageJsonAutoImports": "auto",
|
||||
"javascript.preferences.includePackageJsonAutoImports": "auto",
|
||||
"windsurf.ai.enabled": true,
|
||||
"windsurf.ai.showInEditorContextMenu": true,
|
||||
"windsurf.chat.enabled": true,
|
||||
"windsurf.codeCompletion.enabled": true
|
||||
}
|
||||
WINDSURF_SETTINGS_END
|
||||
printf '{\n'
|
||||
printf ' "workbench.colorTheme": "Windsurf Dark",\n'
|
||||
printf ' "editor.fontSize": 14,\n'
|
||||
printf ' "editor.tabSize": 2,\n'
|
||||
printf ' "editor.insertSpaces": true,\n'
|
||||
printf ' "editor.formatOnSave": true,\n'
|
||||
printf ' "editor.codeActionsOnSave": {\n'
|
||||
printf ' "source.fixAll": true,\n'
|
||||
printf ' "source.organizeImports": true\n'
|
||||
printf ' },\n'
|
||||
printf ' "files.autoSave": "afterDelay",\n'
|
||||
printf ' "files.autoSaveDelay": 1000,\n'
|
||||
printf ' "terminal.integrated.fontSize": 13,\n'
|
||||
printf ' "git.enableSmartCommit": true,\n'
|
||||
printf ' "git.confirmSync": false,\n'
|
||||
printf ' "python.defaultInterpreterPath": "%s/.venv/bin/python",\n' "$HOME_DIR"
|
||||
printf ' "python.linting.enabled": true,\n'
|
||||
printf ' "python.linting.pylintEnabled": false,\n'
|
||||
printf ' "python.linting.flake8Enabled": true,\n'
|
||||
printf ' "typescript.preferences.includePackageJsonAutoImports": "auto",\n'
|
||||
printf ' "javascript.preferences.includePackageJsonAutoImports": "auto",\n'
|
||||
printf ' "windsurf.ai.enabled": true,\n'
|
||||
printf ' "windsurf.ai.showInEditorContextMenu": true,\n'
|
||||
printf ' "windsurf.chat.enabled": true,\n'
|
||||
printf ' "windsurf.codeCompletion.enabled": true\n'
|
||||
printf '}\n'
|
||||
} > "$WINDSURF_DIR/data/User/settings.json"
|
||||
|
||||
# Create development keybindings
|
||||
cat > /home/coder/.windsurf/data/User/keybindings.json << 'WINDSURF_KEYS_END'
|
||||
[
|
||||
{
|
||||
"key": "ctrl+shift+a",
|
||||
"command": "windsurf.chat.open"
|
||||
},
|
||||
{
|
||||
"key": "ctrl+shift+c",
|
||||
"command": "windsurf.ai.generateCode"
|
||||
},
|
||||
{
|
||||
"key": "ctrl+shift+r",
|
||||
"command": "windsurf.ai.refactorSelection"
|
||||
},
|
||||
{
|
||||
"key": "ctrl+shift+e",
|
||||
"command": "windsurf.ai.explainCode"
|
||||
}
|
||||
]
|
||||
WINDSURF_KEYS_END
|
||||
# Create development keybindings using printf
|
||||
{
|
||||
printf '[\n'
|
||||
printf ' {\n'
|
||||
printf ' "key": "ctrl+shift+a",\n'
|
||||
printf ' "command": "windsurf.chat.open"\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "key": "ctrl+shift+c",\n'
|
||||
printf ' "command": "windsurf.ai.generateCode"\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "key": "ctrl+shift+r",\n'
|
||||
printf ' "command": "windsurf.ai.refactorSelection"\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "key": "ctrl+shift+e",\n'
|
||||
printf ' "command": "windsurf.ai.explainCode"\n'
|
||||
printf ' }\n'
|
||||
printf ']\n'
|
||||
} > "$WINDSURF_DIR/data/User/keybindings.json"
|
||||
|
||||
# Set proper ownership
|
||||
chown -R coder:coder /home/coder/.windsurf
|
||||
# Create development tasks configuration for Windsurf
|
||||
{
|
||||
printf '{\n'
|
||||
printf ' "version": "2.0.0",\n'
|
||||
printf ' "tasks": [\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Dev Server",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "npm run dev",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' },\n'
|
||||
printf ' "problemMatcher": []\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Python Dev Server",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "uvicorn main:app --reload --host 0.0.0.0 --port 8000",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' },\n'
|
||||
printf ' "problemMatcher": []\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "AI Code Review",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "echo",\n'
|
||||
printf ' "args": ["Use Ctrl+Shift+R to refactor selection with Windsurf AI"],\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' }\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "label": "Install Dependencies",\n'
|
||||
printf ' "type": "shell",\n'
|
||||
printf ' "command": "npm install",\n'
|
||||
printf ' "group": "build",\n'
|
||||
printf ' "presentation": {\n'
|
||||
printf ' "echo": true,\n'
|
||||
printf ' "reveal": "always",\n'
|
||||
printf ' "focus": false,\n'
|
||||
printf ' "panel": "new"\n'
|
||||
printf ' }\n'
|
||||
printf ' }\n'
|
||||
printf ' ]\n'
|
||||
printf '}\n'
|
||||
} > "$WINDSURF_DIR/data/User/tasks.json"
|
||||
|
||||
# Create useful code snippets for Windsurf
|
||||
mkdir -p "$WINDSURF_DIR/data/User/snippets"
|
||||
{
|
||||
printf '{\n'
|
||||
printf ' "Windsurf AI Comment": {\n'
|
||||
printf ' "prefix": "ai-comment",\n'
|
||||
printf ' "body": [\n'
|
||||
printf ' "// AI-assisted code: ${1:description}",\n'
|
||||
printf ' "// Generated with Windsurf AI on $(date)"\n'
|
||||
printf ' ],\n'
|
||||
printf ' "description": "Add AI assistance comment"\n'
|
||||
printf ' },\n'
|
||||
printf ' "FastAPI with AI Comments": {\n'
|
||||
printf ' "prefix": "fastapi-ai",\n'
|
||||
printf ' "body": [\n'
|
||||
printf ' "# AI-enhanced FastAPI application",\n'
|
||||
printf ' "from fastapi import FastAPI",\n'
|
||||
printf ' "from fastapi.middleware.cors import CORSMiddleware",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "app = FastAPI(",\n'
|
||||
printf ' " title=\\"${1:AI-Enhanced API}\\",",\n'
|
||||
printf ' " description=\\"API built with Windsurf AI assistance\\",",\n'
|
||||
printf ' " version=\\"0.1.0\\"",\n'
|
||||
printf ' ")",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "# AI-suggested CORS configuration",\n'
|
||||
printf ' "app.add_middleware(",\n'
|
||||
printf ' " CORSMiddleware,",\n'
|
||||
printf ' " allow_origins=[\\"*\\"],",\n'
|
||||
printf ' " allow_credentials=True,",\n'
|
||||
printf ' " allow_methods=[\\"*\\"],",\n'
|
||||
printf ' " allow_headers=[\\"*\\"],",\n'
|
||||
printf ' ")",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "@app.get(\\"\/\\")\\",\n'
|
||||
printf ' "async def root():",\n'
|
||||
printf ' " return {\\"message\\": \\"${2:Hello from AI-enhanced API}\\"}"\n'
|
||||
printf ' ],\n'
|
||||
printf ' "description": "AI-enhanced FastAPI template"\n'
|
||||
printf ' },\n'
|
||||
printf ' "React Component with AI": {\n'
|
||||
printf ' "prefix": "react-ai",\n'
|
||||
printf ' "body": [\n'
|
||||
printf ' "// AI-enhanced React component",\n'
|
||||
printf ' "import React, { useState, useEffect } from '\''react'\'';",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "interface ${1:Component}Props {",\n'
|
||||
printf ' " // AI-suggested props",\n'
|
||||
printf ' " title?: string;",\n'
|
||||
printf ' "}",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "const ${1:Component}: React.FC<${1:Component}Props> = ({ title = '\''${2:Default Title}'\'' }) => {",\n'
|
||||
printf ' " const [state, setState] = useState<string>('\'\'');",\n'
|
||||
printf ' "",\n'
|
||||
printf ' " // AI-suggested useEffect",\n'
|
||||
printf ' " useEffect(() => {",\n'
|
||||
printf ' " // Component initialization",\n'
|
||||
printf ' " }, []);",\n'
|
||||
printf ' "",\n'
|
||||
printf ' " return (",\n'
|
||||
printf ' " <div>",\n'
|
||||
printf ' " <h1>{title}</h1>",\n'
|
||||
printf ' " {/* AI-enhanced component content */}",\n'
|
||||
printf ' " </div>",\n'
|
||||
printf ' " );",\n'
|
||||
printf ' "};",\n'
|
||||
printf ' "",\n'
|
||||
printf ' "export default ${1:Component};"\n'
|
||||
printf ' ],\n'
|
||||
printf ' "description": "AI-enhanced React component template"\n'
|
||||
printf ' }\n'
|
||||
printf '}\n'
|
||||
} > "$WINDSURF_DIR/data/User/snippets/windsurf-ai.code-snippets"
|
||||
|
||||
# Create Windsurf-specific launch configuration
|
||||
{
|
||||
printf '{\n'
|
||||
printf ' "version": "0.2.0",\n'
|
||||
printf ' "configurations": [\n'
|
||||
printf ' {\n'
|
||||
printf ' "name": "Debug Node.js with AI",\n'
|
||||
printf ' "type": "node",\n'
|
||||
printf ' "request": "launch",\n'
|
||||
printf ' "program": "${workspaceFolder}/index.js",\n'
|
||||
printf ' "console": "integratedTerminal",\n'
|
||||
printf ' "internalConsoleOptions": "neverOpen"\n'
|
||||
printf ' },\n'
|
||||
printf ' {\n'
|
||||
printf ' "name": "Debug Python with AI",\n'
|
||||
printf ' "type": "python",\n'
|
||||
printf ' "request": "launch",\n'
|
||||
printf ' "program": "${workspaceFolder}/main.py",\n'
|
||||
printf ' "console": "integratedTerminal",\n'
|
||||
printf ' "python": "%s/.venv/bin/python"\n' "$HOME_DIR"
|
||||
printf ' }\n'
|
||||
printf ' ]\n'
|
||||
printf '}\n'
|
||||
} > "$WINDSURF_DIR/data/User/launch.json"
|
||||
|
||||
# Set proper ownership (Unix-like systems only)
|
||||
if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "cygwin" && "$OSTYPE" != "win32" ]]; then
|
||||
if command -v chown >/dev/null 2>&1; then
|
||||
chown -R "$USER_NAME:$USER_NAME" "$WINDSURF_DIR" 2>/dev/null || {
|
||||
echo "⚠️ Could not set ownership - you may need to run with appropriate permissions"
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create Windsurf AI helper script
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Windsurf AI Helper Commands\n'
|
||||
printf 'echo "🌊 Windsurf AI Assistant Helper"\n'
|
||||
printf 'echo "============================"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "AI Features:"\n'
|
||||
printf 'echo " Ctrl+Shift+A # Open AI Chat"\n'
|
||||
printf 'echo " Ctrl+Shift+C # Generate Code with AI"\n'
|
||||
printf 'echo " Ctrl+Shift+R # Refactor Selection with AI"\n'
|
||||
printf 'echo " Ctrl+Shift+E # Explain Code with AI"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "AI-Enhanced Snippets:"\n'
|
||||
printf 'echo " ai-comment # Add AI assistance comment"\n'
|
||||
printf 'echo " fastapi-ai # FastAPI with AI comments"\n'
|
||||
printf 'echo " react-ai # React component with AI"\n'
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "Configuration Location:"\n'
|
||||
printf 'echo " Settings: %s/data/User/settings.json"\n' "$WINDSURF_DIR"
|
||||
printf 'echo " Keybindings: %s/data/User/keybindings.json"\n' "$WINDSURF_DIR"
|
||||
printf 'echo " Snippets: %s/data/User/snippets/"\n' "$WINDSURF_DIR"
|
||||
printf 'echo ""\n'
|
||||
printf 'echo "💡 Windsurf AI is enabled with optimized settings for development"\n'
|
||||
} > "$WINDSURF_DIR/windsurf-help"
|
||||
|
||||
# Make helper script executable (Unix-like systems only)
|
||||
if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "cygwin" && "$OSTYPE" != "win32" ]]; then
|
||||
chmod +x "$WINDSURF_DIR/windsurf-help"
|
||||
fi
|
||||
|
||||
echo "✅ Windsurf IDE support configured"
|
||||
echo "🌊 Windsurf AI features enabled with optimized settings"
|
||||
echo "⌨️ Keyboard shortcuts: Ctrl+Shift+A (chat), Ctrl+Shift+C (generate), Ctrl+Shift+R (refactor)"
|
||||
echo "⌨️ Keyboard shortcuts: Ctrl+Shift+A (chat), Ctrl+Shift+C (generate), Ctrl+Shift+R (refactor)"
|
||||
echo "📁 Configuration stored in: $WINDSURF_DIR/"
|
||||
echo "💡 Run '$WINDSURF_DIR/windsurf-help' for quick reference"
|
||||
@@ -1,43 +1,120 @@
|
||||
#!/bin/bash
|
||||
# Convert CRLF to LF if present (handles Windows line endings)
|
||||
if command -v dos2unix >/dev/null 2>&1; then
|
||||
dos2unix "$0" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "🚀 Initializing development environment as user: $(whoami)"
|
||||
|
||||
# =============================================================================
|
||||
# Create coder user if it doesn't exist
|
||||
# Cross-platform system detection and configuration
|
||||
# =============================================================================
|
||||
if ! id -u coder >/dev/null 2>&1; then
|
||||
echo "👤 Creating coder user..."
|
||||
useradd -m -s /bin/bash -u 1000 coder
|
||||
usermod -aG sudo coder
|
||||
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
detect_system() {
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
SYSTEM="debian"
|
||||
PKG_MANAGER="apt-get"
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
SYSTEM="rhel"
|
||||
PKG_MANAGER="yum"
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
SYSTEM="arch"
|
||||
PKG_MANAGER="pacman"
|
||||
else
|
||||
SYSTEM="linux"
|
||||
PKG_MANAGER="unknown"
|
||||
fi
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
SYSTEM="macos"
|
||||
PKG_MANAGER="brew"
|
||||
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
|
||||
SYSTEM="windows"
|
||||
PKG_MANAGER="choco"
|
||||
else
|
||||
SYSTEM="unknown"
|
||||
PKG_MANAGER="unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
detect_system
|
||||
|
||||
# Cross-platform directory and user detection
|
||||
if [[ "$SYSTEM" == "windows" ]]; then
|
||||
HOME_DIR="${USERPROFILE:-$HOME}"
|
||||
USER_NAME="${USERNAME:-${USER:-coder}}"
|
||||
WORKSPACES_DIR="$HOME_DIR/workspaces"
|
||||
TEMP_DIR="${TEMP:-/tmp}"
|
||||
BIN_DIR="$HOME_DIR/bin"
|
||||
CONFIG_DIR="$HOME_DIR/.config"
|
||||
else
|
||||
HOME_DIR="${HOME:-/home/coder}"
|
||||
USER_NAME="${USER:-coder}"
|
||||
WORKSPACES_DIR="/workspaces"
|
||||
TEMP_DIR="/tmp"
|
||||
BIN_DIR="$HOME_DIR/bin"
|
||||
CONFIG_DIR="$HOME_DIR/.config"
|
||||
fi
|
||||
|
||||
# Set default versions if not provided
|
||||
NODE_VERSION="${NODE_VERSION:-20}"
|
||||
PYTHON_VERSION="${PYTHON_VERSION:-3.11}"
|
||||
GIT_AUTHOR_NAME="${GIT_AUTHOR_NAME:-Developer}"
|
||||
GIT_AUTHOR_EMAIL="${GIT_AUTHOR_EMAIL:-dev@example.com}"
|
||||
ENABLE_SERVICES="${ENABLE_SERVICES:-false}"
|
||||
|
||||
# =============================================================================
|
||||
# Create user and directories (Unix-like systems only)
|
||||
# =============================================================================
|
||||
if [[ "$SYSTEM" != "windows" && "$SYSTEM" != "macos" ]]; then
|
||||
if ! id -u "$USER_NAME" >/dev/null 2>&1; then
|
||||
echo "👤 Creating $USER_NAME user..."
|
||||
if [[ "$EUID" -eq 0 ]]; then
|
||||
useradd -m -s /bin/bash -u 1000 "$USER_NAME" 2>/dev/null || {
|
||||
echo "⚠️ Could not create user $USER_NAME"
|
||||
}
|
||||
if command -v usermod >/dev/null 2>&1; then
|
||||
usermod -aG sudo "$USER_NAME" 2>/dev/null || true
|
||||
fi
|
||||
if [[ -f "/etc/sudoers" ]]; then
|
||||
echo "$USER_NAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Not running as root, skipping user creation"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Create necessary directories
|
||||
# =============================================================================
|
||||
echo "📁 Creating user directories..."
|
||||
mkdir -p /home/coder/bin
|
||||
mkdir -p /home/coder/.local/bin
|
||||
mkdir -p /home/coder/.config
|
||||
mkdir -p /tmp/git-metadata
|
||||
mkdir -p /workspaces
|
||||
mkdir -p "$BIN_DIR"
|
||||
mkdir -p "$HOME_DIR/.local/bin"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
mkdir -p "$TEMP_DIR/git-metadata"
|
||||
mkdir -p "$WORKSPACES_DIR"
|
||||
|
||||
# Ensure proper ownership
|
||||
chown -R coder:coder /home/coder /workspaces
|
||||
# Ensure proper ownership (Unix-like systems only)
|
||||
if [[ "$SYSTEM" != "windows" ]] && command -v chown >/dev/null 2>&1; then
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && [[ "$EUID" -eq 0 ]]; then
|
||||
chown -R "$USER_NAME:$USER_NAME" "$HOME_DIR" "$WORKSPACES_DIR" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Switch to coder user for remaining operations
|
||||
# Environment setup
|
||||
# =============================================================================
|
||||
echo "🔄 Switching to coder user context..."
|
||||
export HOME=/home/coder
|
||||
export USER=coder
|
||||
echo "🔄 Setting up environment context..."
|
||||
export HOME="$HOME_DIR"
|
||||
export USER="$USER_NAME"
|
||||
|
||||
# =============================================================================
|
||||
# Git Configuration
|
||||
# =============================================================================
|
||||
echo "⚙️ Configuring Git..."
|
||||
git config --global user.name "${GIT_AUTHOR_NAME}"
|
||||
git config --global user.email "${GIT_AUTHOR_EMAIL}"
|
||||
git config --global user.name "$GIT_AUTHOR_NAME"
|
||||
git config --global user.email "$GIT_AUTHOR_EMAIL"
|
||||
git config --global commit.gpgsign false
|
||||
git config --global tag.gpgsign false
|
||||
git config --global init.defaultBranch main
|
||||
@@ -45,184 +122,286 @@ git config --global pull.rebase false
|
||||
|
||||
# Capture and log git information
|
||||
echo "📝 Capturing Git metadata..."
|
||||
cd /workspaces
|
||||
cd "$WORKSPACES_DIR"
|
||||
if [ -d ".git" ]; then
|
||||
git branch --show-current > /tmp/git-metadata/current-branch 2>/dev/null || echo "main" > /tmp/git-metadata/current-branch
|
||||
git rev-parse HEAD > /tmp/git-metadata/commit-hash 2>/dev/null || echo "no-commits" > /tmp/git-metadata/commit-hash
|
||||
git remote get-url origin > /tmp/git-metadata/remote-url 2>/dev/null || echo "no-remote" > /tmp/git-metadata/remote-url
|
||||
git branch --show-current > "$TEMP_DIR/git-metadata/current-branch" 2>/dev/null || printf "main" > "$TEMP_DIR/git-metadata/current-branch"
|
||||
git rev-parse HEAD > "$TEMP_DIR/git-metadata/commit-hash" 2>/dev/null || printf "no-commits" > "$TEMP_DIR/git-metadata/commit-hash"
|
||||
git remote get-url origin > "$TEMP_DIR/git-metadata/remote-url" 2>/dev/null || printf "no-remote" > "$TEMP_DIR/git-metadata/remote-url"
|
||||
else
|
||||
echo "no-repo" > /tmp/git-metadata/current-branch
|
||||
echo "no-repo" > /tmp/git-metadata/commit-hash
|
||||
echo "no-repo" > /tmp/git-metadata/remote-url
|
||||
printf "no-repo" > "$TEMP_DIR/git-metadata/current-branch"
|
||||
printf "no-repo" > "$TEMP_DIR/git-metadata/commit-hash"
|
||||
printf "no-repo" > "$TEMP_DIR/git-metadata/remote-url"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# System Package Updates and Installation
|
||||
# =============================================================================
|
||||
echo "📦 Installing system packages..."
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y make tree jq curl wget unzip build-essential postgresql-client redis-tools
|
||||
install_system_packages() {
|
||||
echo "📦 Installing system packages..."
|
||||
case "$SYSTEM" in
|
||||
"debian")
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq 2>/dev/null || true
|
||||
apt-get install -y make tree jq curl wget unzip build-essential 2>/dev/null || {
|
||||
echo "⚠️ Some packages failed to install"
|
||||
}
|
||||
if [[ "$ENABLE_SERVICES" == "true" ]]; then
|
||||
apt-get install -y postgresql-client redis-tools 2>/dev/null || true
|
||||
fi
|
||||
;;
|
||||
"rhel")
|
||||
yum update -y 2>/dev/null || dnf update -y 2>/dev/null || true
|
||||
yum groupinstall -y "Development Tools" 2>/dev/null || dnf groupinstall -y "Development Tools" 2>/dev/null || true
|
||||
yum install -y make tree jq curl wget unzip 2>/dev/null || dnf install -y make tree jq curl wget unzip 2>/dev/null || true
|
||||
;;
|
||||
"macos")
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
brew install make tree jq curl wget unzip 2>/dev/null || true
|
||||
else
|
||||
echo "⚠️ Homebrew not found. Please install build tools manually."
|
||||
fi
|
||||
;;
|
||||
"windows")
|
||||
if command -v choco >/dev/null 2>&1; then
|
||||
choco install -y make tree jq curl wget unzip 2>/dev/null || true
|
||||
elif command -v winget >/dev/null 2>&1; then
|
||||
winget install make tree jq curl wget unzip 2>/dev/null || true
|
||||
else
|
||||
echo "⚠️ Package manager not found. Please install build tools manually."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ Unknown system. Please install build tools manually."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ "$EUID" -eq 0 ]] || [[ "$SYSTEM" == "macos" ]] || [[ "$SYSTEM" == "windows" ]]; then
|
||||
install_system_packages
|
||||
else
|
||||
echo "⚠️ Not running with appropriate privileges, skipping system package installation"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Node.js and npm Setup (as coder user)
|
||||
# Node.js and npm Setup
|
||||
# =============================================================================
|
||||
echo "🟢 Setting up Node.js and npm..."
|
||||
|
||||
# Create Node.js setup script
|
||||
cat > /tmp/node_setup.sh << 'NODE_SCRIPT_END'
|
||||
#!/bin/bash
|
||||
if ! command -v nvm &> /dev/null; then
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||||
export NVM_DIR="/home/coder/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Node.js setup script\n'
|
||||
printf 'if ! command -v nvm >/dev/null 2>&1; then\n'
|
||||
printf ' curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash 2>/dev/null || {\n'
|
||||
printf ' echo "⚠️ Failed to install nvm"\n'
|
||||
printf ' exit 1\n'
|
||||
printf ' }\n'
|
||||
printf ' export NVM_DIR="%s/.nvm"\n' "$HOME_DIR"
|
||||
printf ' [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"\n'
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf 'export NVM_DIR="%s/.nvm"\n' "$HOME_DIR"
|
||||
printf '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"\n'
|
||||
printf 'nvm install %s 2>/dev/null || echo "⚠️ Failed to install Node.js %s"\n' "$NODE_VERSION" "$NODE_VERSION"
|
||||
printf 'nvm use %s 2>/dev/null || true\n' "$NODE_VERSION"
|
||||
printf 'nvm alias default %s 2>/dev/null || true\n' "$NODE_VERSION"
|
||||
printf '\n'
|
||||
printf 'echo "📦 Installing npm packages..."\n'
|
||||
printf 'for package in repomix create-next-app nodemon concurrently @types/node typescript eslint prettier; do\n'
|
||||
printf ' npm install -g "$package" 2>/dev/null || echo "⚠️ Failed to install $package"\n'
|
||||
printf 'done\n'
|
||||
} > "$TEMP_DIR/node_setup.sh"
|
||||
|
||||
chmod +x "$TEMP_DIR/node_setup.sh"
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "$TEMP_DIR/node_setup.sh" 2>/dev/null || bash "$TEMP_DIR/node_setup.sh"
|
||||
else
|
||||
bash "$TEMP_DIR/node_setup.sh"
|
||||
fi
|
||||
|
||||
export NVM_DIR="/home/coder/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
||||
nvm install ${NODE_VERSION}
|
||||
nvm use ${NODE_VERSION}
|
||||
nvm alias default ${NODE_VERSION}
|
||||
|
||||
echo "📦 Installing npm packages..."
|
||||
npm install -g repomix create-next-app nodemon concurrently @types/node typescript eslint prettier
|
||||
npm install -g create-next-app@latest
|
||||
NODE_SCRIPT_END
|
||||
|
||||
chmod +x /tmp/node_setup.sh
|
||||
su - coder -c "/tmp/node_setup.sh"
|
||||
rm /tmp/node_setup.sh
|
||||
rm -f "$TEMP_DIR/node_setup.sh"
|
||||
|
||||
# =============================================================================
|
||||
# Python Setup with uv (as coder user)
|
||||
# Python Setup with uv
|
||||
# =============================================================================
|
||||
echo "🐍 Setting up Python and uv..."
|
||||
|
||||
# Install Python version
|
||||
apt-get install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-dev python${PYTHON_VERSION}-venv
|
||||
# Install Python version (Linux only)
|
||||
if [[ "$SYSTEM" == "debian" ]] && [[ "$EUID" -eq 0 ]]; then
|
||||
apt-get install -y "python$PYTHON_VERSION" "python$PYTHON_VERSION-dev" "python$PYTHON_VERSION-venv" 2>/dev/null || {
|
||||
echo "⚠️ Failed to install Python $PYTHON_VERSION"
|
||||
}
|
||||
fi
|
||||
|
||||
# Create Python setup script
|
||||
cat > /tmp/python_setup.sh << 'PYTHON_SCRIPT_END'
|
||||
#!/bin/bash
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
export PATH="/home/coder/.cargo/bin:$PATH"
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Python setup script\n'
|
||||
printf 'curl -LsSf https://astral.sh/uv/install.sh | sh 2>/dev/null || {\n'
|
||||
printf ' echo "⚠️ Failed to install uv"\n'
|
||||
printf ' exit 1\n'
|
||||
printf '}\n'
|
||||
printf 'export PATH="%s/.cargo/bin:$PATH"\n' "$HOME_DIR"
|
||||
printf '\n'
|
||||
printf 'echo "📦 Installing Python packages with uv..."\n'
|
||||
printf 'for package in fastapi uvicorn requests pandas numpy psycopg2-binary redis qdrant-client python-dotenv; do\n'
|
||||
printf ' uv tool install "$package" 2>/dev/null || echo "⚠️ Failed to install $package"\n'
|
||||
printf 'done\n'
|
||||
printf '\n'
|
||||
printf 'uv venv "%s/.venv" --python=%s 2>/dev/null || echo "⚠️ Failed to create venv"\n' "$HOME_DIR" "$PYTHON_VERSION"
|
||||
printf '\n'
|
||||
printf '# Add venv activation to shell config\n'
|
||||
printf 'SHELL_RC="%s/.bashrc"\n' "$HOME_DIR"
|
||||
printf 'if [[ "$SHELL" == *"zsh"* && -f "%s/.zshrc" ]]; then\n' "$HOME_DIR"
|
||||
printf ' SHELL_RC="%s/.zshrc"\n' "$HOME_DIR"
|
||||
printf 'fi\n'
|
||||
printf 'if ! grep -q "source %s/.venv/bin/activate" "$SHELL_RC" 2>/dev/null; then\n' "$HOME_DIR"
|
||||
printf ' printf "source %s/.venv/bin/activate\\n" >> "$SHELL_RC"\n' "$HOME_DIR"
|
||||
printf 'fi\n'
|
||||
} > "$TEMP_DIR/python_setup.sh"
|
||||
|
||||
echo "📦 Installing Python packages with uv..."
|
||||
for package in fastapi uvicorn requests pandas numpy psycopg2-binary redis qdrant-client python-dotenv; do
|
||||
uv tool install $package || echo "Failed to install $package"
|
||||
done
|
||||
|
||||
uv venv /home/coder/.venv --python=${PYTHON_VERSION}
|
||||
echo 'source /home/coder/.venv/bin/activate' >> /home/coder/.bashrc
|
||||
PYTHON_SCRIPT_END
|
||||
|
||||
chmod +x /tmp/python_setup.sh
|
||||
su - coder -c "/tmp/python_setup.sh"
|
||||
rm /tmp/python_setup.sh
|
||||
chmod +x "$TEMP_DIR/python_setup.sh"
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "$TEMP_DIR/python_setup.sh" 2>/dev/null || bash "$TEMP_DIR/python_setup.sh"
|
||||
else
|
||||
bash "$TEMP_DIR/python_setup.sh"
|
||||
fi
|
||||
rm -f "$TEMP_DIR/python_setup.sh"
|
||||
|
||||
# =============================================================================
|
||||
# Rust and Cargo Setup (as coder user)
|
||||
# Rust and Cargo Setup
|
||||
# =============================================================================
|
||||
echo "🦀 Installing Rust and Cargo..."
|
||||
|
||||
# Create Rust setup script
|
||||
cat > /tmp/rust_setup.sh << 'RUST_SCRIPT_END'
|
||||
#!/bin/bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
||||
source "/home/coder/.cargo/env"
|
||||
echo 'export PATH="/home/coder/.cargo/bin:$PATH"' >> /home/coder/.bashrc
|
||||
cargo install cargo-watch cargo-edit cargo-audit
|
||||
RUST_SCRIPT_END
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Rust setup script\n'
|
||||
printf 'curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable 2>/dev/null || {\n'
|
||||
printf ' echo "⚠️ Failed to install Rust"\n'
|
||||
printf ' exit 1\n'
|
||||
printf '}\n'
|
||||
printf 'source "%s/.cargo/env"\n' "$HOME_DIR"
|
||||
printf '\n'
|
||||
printf '# Add cargo to shell config\n'
|
||||
printf 'SHELL_RC="%s/.bashrc"\n' "$HOME_DIR"
|
||||
printf 'if [[ "$SHELL" == *"zsh"* && -f "%s/.zshrc" ]]; then\n' "$HOME_DIR"
|
||||
printf ' SHELL_RC="%s/.zshrc"\n' "$HOME_DIR"
|
||||
printf 'fi\n'
|
||||
printf 'if ! grep -q "export PATH=.*cargo.*bin" "$SHELL_RC" 2>/dev/null; then\n'
|
||||
printf ' printf "export PATH=\\"%s/.cargo/bin:$PATH\\"\\n" >> "$SHELL_RC"\n' "$HOME_DIR"
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf 'cargo install cargo-watch cargo-edit cargo-audit 2>/dev/null || echo "⚠️ Failed to install some cargo tools"\n'
|
||||
} > "$TEMP_DIR/rust_setup.sh"
|
||||
|
||||
chmod +x /tmp/rust_setup.sh
|
||||
su - coder -c "/tmp/rust_setup.sh"
|
||||
rm /tmp/rust_setup.sh
|
||||
chmod +x "$TEMP_DIR/rust_setup.sh"
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "$TEMP_DIR/rust_setup.sh" 2>/dev/null || bash "$TEMP_DIR/rust_setup.sh"
|
||||
else
|
||||
bash "$TEMP_DIR/rust_setup.sh"
|
||||
fi
|
||||
rm -f "$TEMP_DIR/rust_setup.sh"
|
||||
|
||||
# =============================================================================
|
||||
# repomix Installation (as coder user)
|
||||
# repomix Installation
|
||||
# =============================================================================
|
||||
echo "📁 Installing repomix..."
|
||||
su - coder -c "npm install -g repomix"
|
||||
if command -v npm >/dev/null 2>&1; then
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "npm install -g repomix 2>/dev/null || echo '⚠️ Failed to install repomix'"
|
||||
else
|
||||
npm install -g repomix 2>/dev/null || echo "⚠️ Failed to install repomix"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ npm not available, skipping repomix installation"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Shell Configuration (as coder user)
|
||||
# Shell Configuration
|
||||
# =============================================================================
|
||||
echo "🐚 Setting up shell environment..."
|
||||
|
||||
# Create devinfo script
|
||||
cat > /tmp/devinfo_script.sh << 'DEVINFO_SCRIPT_END'
|
||||
#!/bin/bash
|
||||
mkdir -p /home/coder/bin
|
||||
cat > /home/coder/bin/devinfo << 'DEVINFO_END'
|
||||
#!/bin/bash
|
||||
echo '🚀 Development Environment Info'
|
||||
echo '==============================='
|
||||
echo ''
|
||||
echo '🔧 Installed Tools:'
|
||||
echo ' Node.js: '$(node --version 2>/dev/null || echo 'Not found')
|
||||
echo ' npm: '$(npm --version 2>/dev/null || echo 'Not found')
|
||||
echo ' Python: '$(python${PYTHON_VERSION} --version 2>/dev/null || echo 'Not found')
|
||||
echo ' uv: '$(uv --version 2>/dev/null || echo 'Not found')
|
||||
echo ' Rust: '$(rustc --version 2>/dev/null || echo 'Not found')
|
||||
echo ' Cargo: '$(cargo --version 2>/dev/null || echo 'Not found')
|
||||
echo ' repomix: '$(repomix --version 2>/dev/null || echo 'Not found')
|
||||
echo ''
|
||||
echo '🗄️ Database Services:'
|
||||
if [ "${ENABLE_SERVICES}" = "true" ]; then
|
||||
echo ' PostgreSQL: '${POSTGRES_URL}
|
||||
echo ' Redis: '${REDIS_URL}
|
||||
echo ' Qdrant: '${QDRANT_URL}
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Development environment info script\n'
|
||||
printf 'mkdir -p "%s"\n' "$BIN_DIR"
|
||||
printf '{\n'
|
||||
printf ' printf "#!/bin/bash\\n"\n'
|
||||
printf ' printf "echo '\''🚀 Development Environment Info'\''\\n"\n'
|
||||
printf ' printf "echo '\''==============================='\''\\n"\n'
|
||||
printf ' printf "echo \\'\\'\\n"\n'
|
||||
printf ' printf "echo '\''🔧 Installed Tools:'\''\\n"\n'
|
||||
printf ' printf "echo '\'' Node.js: '\''\\$(node --version 2>/dev/null || echo '\''Not found'\'')\\n"\n'
|
||||
printf ' printf "echo '\'' npm: '\''\\$(npm --version 2>/dev/null || echo '\''Not found'\'')\\n"\n'
|
||||
printf ' printf "echo '\'' Python: '\''\\$(python%s --version 2>/dev/null || echo '\''Not found'\'')\\n"\n' "$PYTHON_VERSION"
|
||||
printf ' printf "echo '\'' uv: '\''\\$(uv --version 2>/dev/null || echo '\''Not found'\'')\\n"\n'
|
||||
printf ' printf "echo '\'' Rust: '\''\\$(rustc --version 2>/dev/null || echo '\''Not found'\'')\\n"\n'
|
||||
printf ' printf "echo '\'' Cargo: '\''\\$(cargo --version 2>/dev/null || echo '\''Not found'\'')\\n"\n'
|
||||
printf ' printf "echo '\'' repomix: '\''\\$(repomix --version 2>/dev/null || echo '\''Not found'\'')\\n"\n'
|
||||
printf ' printf "echo \\'\\'\\n"\n'
|
||||
printf ' printf "echo '\''🗄️ Database Services:'\''\\n"\n'
|
||||
printf ' printf "if [ \\"%s\\" = \\"true\\" ]; then\\n" "%s"\n' "$ENABLE_SERVICES" "$ENABLE_SERVICES"
|
||||
printf ' printf " echo '\'' PostgreSQL: '\''\\${POSTGRES_URL:-Not configured}\\n"\n'
|
||||
printf ' printf " echo '\'' Redis: '\''\\${REDIS_URL:-Not configured}\\n"\n'
|
||||
printf ' printf " echo '\'' Qdrant: '\''\\${QDRANT_URL:-Not configured}\\n"\n'
|
||||
printf ' printf "else\\n"\n'
|
||||
printf ' printf " echo '\'' Services disabled'\''\\n"\n'
|
||||
printf ' printf "fi\\n"\n'
|
||||
printf ' printf "echo \\'\\'\\n"\n'
|
||||
printf ' printf "echo '\''📝 Git Metadata:'\''\\n"\n'
|
||||
printf ' printf "if [ -f %s/git-metadata/current-branch ]; then\\n" "%s"\n' "$TEMP_DIR" "$TEMP_DIR"
|
||||
printf ' printf " echo '\'' Branch: '\''\\$(cat %s/git-metadata/current-branch)\\n" "%s"\n' "$TEMP_DIR" "$TEMP_DIR"
|
||||
printf ' printf " echo '\'' Commit: '\''\\$(cat %s/git-metadata/commit-hash)\\n" "%s"\n' "$TEMP_DIR" "$TEMP_DIR"
|
||||
printf ' printf " echo '\'' Remote: '\''\\$(cat %s/git-metadata/remote-url)\\n" "%s"\n' "$TEMP_DIR" "$TEMP_DIR"
|
||||
printf ' printf "fi\\n"\n'
|
||||
printf '} > "%s/devinfo"\n' "$BIN_DIR"
|
||||
printf 'chmod +x "%s/devinfo"\n' "$BIN_DIR"
|
||||
} > "$TEMP_DIR/devinfo_script.sh"
|
||||
|
||||
chmod +x "$TEMP_DIR/devinfo_script.sh"
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "$TEMP_DIR/devinfo_script.sh" 2>/dev/null || bash "$TEMP_DIR/devinfo_script.sh"
|
||||
else
|
||||
echo ' Services disabled'
|
||||
bash "$TEMP_DIR/devinfo_script.sh"
|
||||
fi
|
||||
echo ''
|
||||
echo '📝 Git Metadata:'
|
||||
if [ -f /tmp/git-metadata/current-branch ]; then
|
||||
echo ' Branch: '$(cat /tmp/git-metadata/current-branch)
|
||||
echo ' Commit: '$(cat /tmp/git-metadata/commit-hash)
|
||||
echo ' Remote: '$(cat /tmp/git-metadata/remote-url)
|
||||
rm -f "$TEMP_DIR/devinfo_script.sh"
|
||||
|
||||
# Create shell aliases
|
||||
{
|
||||
printf '#!/bin/bash\n'
|
||||
printf '# Shell configuration script\n'
|
||||
printf 'SHELL_RC="%s/.bashrc"\n' "$HOME_DIR"
|
||||
printf 'if [[ "$SHELL" == *"zsh"* && -f "%s/.zshrc" ]]; then\n' "$HOME_DIR"
|
||||
printf ' SHELL_RC="%s/.zshrc"\n' "$HOME_DIR"
|
||||
printf 'fi\n'
|
||||
printf '\n'
|
||||
printf 'if ! grep -q "# Development Environment Aliases" "$SHELL_RC" 2>/dev/null; then\n'
|
||||
printf ' printf "\\n# Development Environment Aliases\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias ll='\''ls -alF'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias la='\''ls -A'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias l='\''ls -CF'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias gs='\''git status'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias gp='\''git push'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias gc='\''git commit'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias gco='\''git checkout'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias gb='\''git branch'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias devinfo='\''%s/devinfo'\''\\n" >> "$SHELL_RC"\n' "$BIN_DIR"
|
||||
printf ' printf "alias pip='\''uv pip'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias python='\''python%s'\''\\n" >> "$SHELL_RC"\n' "$PYTHON_VERSION"
|
||||
printf ' if command -v docker >/dev/null 2>&1; then\n'
|
||||
printf ' printf "alias dps='\''docker ps'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias dimg='\''docker images'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' printf "alias dlog='\''docker logs'\''\\n" >> "$SHELL_RC"\n'
|
||||
printf ' fi\n'
|
||||
printf ' printf "\\n" >> "$SHELL_RC"\n'
|
||||
printf 'fi\n'
|
||||
} > "$TEMP_DIR/bashrc_setup.sh"
|
||||
|
||||
chmod +x "$TEMP_DIR/bashrc_setup.sh"
|
||||
if [[ "$USER_NAME" != "$(whoami)" ]] && command -v su >/dev/null 2>&1; then
|
||||
su - "$USER_NAME" -c "$TEMP_DIR/bashrc_setup.sh" 2>/dev/null || bash "$TEMP_DIR/bashrc_setup.sh"
|
||||
else
|
||||
bash "$TEMP_DIR/bashrc_setup.sh"
|
||||
fi
|
||||
DEVINFO_END
|
||||
chmod +x /home/coder/bin/devinfo
|
||||
DEVINFO_SCRIPT_END
|
||||
|
||||
chmod +x /tmp/devinfo_script.sh
|
||||
su - coder -c "/tmp/devinfo_script.sh"
|
||||
rm /tmp/devinfo_script.sh
|
||||
|
||||
# Create bashrc aliases script
|
||||
cat > /tmp/bashrc_setup.sh << 'BASHRC_SCRIPT_END'
|
||||
#!/bin/bash
|
||||
cat >> /home/coder/.bashrc << 'BASHRC_END'
|
||||
|
||||
# Development Environment Aliases
|
||||
alias ll='ls -alF'
|
||||
alias la='ls -A'
|
||||
alias l='ls -CF'
|
||||
alias gs='git status'
|
||||
alias gp='git push'
|
||||
alias gc='git commit'
|
||||
alias gco='git checkout'
|
||||
alias gb='git branch'
|
||||
|
||||
# Development workflow shortcuts
|
||||
alias devinfo='/home/coder/bin/devinfo'
|
||||
|
||||
# Package managers
|
||||
alias pip='uv pip'
|
||||
alias python='python${PYTHON_VERSION}'
|
||||
|
||||
# Docker shortcuts
|
||||
alias dps='docker ps'
|
||||
alias dimg='docker images'
|
||||
alias dlog='docker logs'
|
||||
|
||||
BASHRC_END
|
||||
BASHRC_SCRIPT_END
|
||||
|
||||
chmod +x /tmp/bashrc_setup.sh
|
||||
su - coder -c "/tmp/bashrc_setup.sh"
|
||||
rm /tmp/bashrc_setup.sh
|
||||
rm -f "$TEMP_DIR/bashrc_setup.sh"
|
||||
|
||||
# =============================================================================
|
||||
# Final Environment Setup
|
||||
@@ -230,14 +409,15 @@ rm /tmp/bashrc_setup.sh
|
||||
echo "✅ Development environment initialization complete!"
|
||||
echo ""
|
||||
echo "🎉 Available tools:"
|
||||
echo " - Node.js ${NODE_VERSION} with npm packages"
|
||||
echo " - Python ${PYTHON_VERSION} with uv package manager"
|
||||
printf " - Node.js %s with npm packages\n" "$NODE_VERSION"
|
||||
printf " - Python %s with uv package manager\n" "$PYTHON_VERSION"
|
||||
echo " - Rust with Cargo"
|
||||
echo " - repomix for repository packaging"
|
||||
echo " - make, tree, and other build tools"
|
||||
if [ "${ENABLE_SERVICES}" = "true" ]; then
|
||||
echo " - PostgreSQL, Redis, Qdrant databases"
|
||||
if [ "$ENABLE_SERVICES" = "true" ]; then
|
||||
echo " - PostgreSQL, Redis, Qdrant databases"
|
||||
fi
|
||||
echo ""
|
||||
echo "🔧 Run 'devinfo' for detailed environment information"
|
||||
echo "🚀 Ready for development!"
|
||||
echo "🚀 Ready for development!"
|
||||
echo "💡 Restart your shell or source your shell config to use new aliases"
|
||||
@@ -12,8 +12,10 @@ environment = "dev"
|
||||
# =============================================================================
|
||||
# Docker Configuration
|
||||
# =============================================================================
|
||||
docker_socket = ""
|
||||
devcontainer_image = "mcr.microsoft.com/devcontainers/universal:2-linux"
|
||||
docker_socket = ""
|
||||
# devcontainer_image is deprecated, using devcontainer_repo_url instead
|
||||
devcontainer_repo_url = "http://git.lab/vasceannie/code-tools.git"
|
||||
envbuilder_cache_repo = "local" # Set to your registry URL for faster builds, e.g. "ghcr.io/username/cache"
|
||||
|
||||
# =============================================================================
|
||||
# Development Tool Versions
|
||||
|
||||
@@ -40,11 +40,23 @@ variable "docker_socket" {
|
||||
}
|
||||
|
||||
variable "devcontainer_image" {
|
||||
description = "Development container image with all required tools pre-installed"
|
||||
description = "Development container image with all required tools pre-installed (deprecated - use devcontainer_repo_url)"
|
||||
type = string
|
||||
default = "mcr.microsoft.com/devcontainers/universal:2-linux"
|
||||
}
|
||||
|
||||
variable "devcontainer_repo_url" {
|
||||
description = "Git repository URL containing the devcontainer configuration"
|
||||
type = string
|
||||
default = "http://git.lab/vasceannie/code-tools.git"
|
||||
}
|
||||
|
||||
variable "envbuilder_cache_repo" {
|
||||
description = "Docker registry to use for caching envbuilder layers (e.g., 'ghcr.io/username/cache')"
|
||||
type = string
|
||||
default = "local"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Development Tool Versions
|
||||
# =============================================================================
|
||||
|
||||
@@ -31,17 +31,12 @@ resource "coder_agent" "main" {
|
||||
"ENABLE_SERVICES" = tostring(data.coder_parameter.enable_services.value)
|
||||
# Security: Block file transfer commands to prevent data exfiltration
|
||||
"CODER_AGENT_BLOCK_FILE_TRANSFER" = var.block_file_transfer ? "1" : ""
|
||||
# Repository to clone on startup
|
||||
"CODER_WORKSPACE_REPO" = local.repo_url != "custom" ? local.repo_url : ""
|
||||
}
|
||||
|
||||
# Reference bind-mounted startup script plus service port forwarding
|
||||
startup_script = <<-EOT
|
||||
bash /home/coder/resources/tf/scripts/workspace-setup.sh
|
||||
|
||||
# Register JetBrains Gateway backend location if enabled
|
||||
if [ "${data.coder_parameter.enable_jetbrains.value}" = "true" ] && [ -d ~/JetBrains ]; then
|
||||
~/JetBrains/*/bin/remote-dev-server.sh registerBackendLocationForGateway 2>/dev/null || echo "JetBrains Gateway registration skipped"
|
||||
fi
|
||||
EOT
|
||||
startup_script = "#!/bin/sh\necho 'Starting workspace...'"
|
||||
|
||||
# Performance and resource monitoring
|
||||
metadata {
|
||||
|
||||
Reference in New Issue
Block a user