mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
chore: update Docker configuration and entrypoint script
- Enhanced .dockerignore to exclude additional build outputs and dependencies. - Modified dev.mjs and start.mjs to change Docker container startup behavior, removing the --build flag to preserve volumes. - Updated docker-compose.yml to add a new volume for persisting Claude CLI OAuth session keys. - Introduced docker-entrypoint.sh to fix permissions on the Claude CLI config directory. - Adjusted Dockerfile to include the entrypoint script and ensure proper user permissions. These changes improve the Docker setup and streamline the development workflow.
This commit is contained in:
@@ -1 +1,19 @@
|
|||||||
|
# Dependencies
|
||||||
node_modules/
|
node_modules/
|
||||||
|
**/node_modules/
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
dist/
|
||||||
|
**/dist/
|
||||||
|
dist-electron/
|
||||||
|
**/dist-electron/
|
||||||
|
build/
|
||||||
|
**/build/
|
||||||
|
.next/
|
||||||
|
**/.next/
|
||||||
|
.nuxt/
|
||||||
|
**/.nuxt/
|
||||||
|
out/
|
||||||
|
**/out/
|
||||||
|
.cache/
|
||||||
|
**/.cache/
|
||||||
22
Dockerfile
22
Dockerfile
@@ -53,8 +53,8 @@ RUN npm run build:packages && npm run build --workspace=apps/server
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
FROM node:22-alpine AS server
|
FROM node:22-alpine AS server
|
||||||
|
|
||||||
# Install git, curl, bash (for terminal), and GitHub CLI (pinned version, multi-arch)
|
# Install git, curl, bash (for terminal), su-exec (for user switching), and GitHub CLI (pinned version, multi-arch)
|
||||||
RUN apk add --no-cache git curl bash && \
|
RUN apk add --no-cache git curl bash su-exec && \
|
||||||
GH_VERSION="2.63.2" && \
|
GH_VERSION="2.63.2" && \
|
||||||
ARCH=$(uname -m) && \
|
ARCH=$(uname -m) && \
|
||||||
case "$ARCH" in \
|
case "$ARCH" in \
|
||||||
@@ -72,9 +72,11 @@ RUN npm install -g @anthropic-ai/claude-code
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Create non-root user
|
# Create non-root user with home directory
|
||||||
RUN addgroup -g 1001 -S automaker && \
|
RUN addgroup -g 1001 -S automaker && \
|
||||||
adduser -S automaker -u 1001
|
adduser -S automaker -u 1001 -h /home/automaker && \
|
||||||
|
mkdir -p /home/automaker && \
|
||||||
|
chown automaker:automaker /home/automaker
|
||||||
|
|
||||||
# Copy root package.json (needed for workspace resolution)
|
# Copy root package.json (needed for workspace resolution)
|
||||||
COPY --from=server-builder /app/package*.json ./
|
COPY --from=server-builder /app/package*.json ./
|
||||||
@@ -98,12 +100,17 @@ RUN git config --system --add safe.directory '*' && \
|
|||||||
# Use gh as credential helper (works with GH_TOKEN env var)
|
# Use gh as credential helper (works with GH_TOKEN env var)
|
||||||
git config --system credential.helper '!gh auth git-credential'
|
git config --system credential.helper '!gh auth git-credential'
|
||||||
|
|
||||||
# Switch to non-root user
|
# Copy entrypoint script for fixing permissions on mounted volumes
|
||||||
USER automaker
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
# Note: We stay as root here so entrypoint can fix permissions
|
||||||
|
# The entrypoint script will switch to automaker user before running the command
|
||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
ENV PORT=3008
|
ENV PORT=3008
|
||||||
ENV DATA_DIR=/data
|
ENV DATA_DIR=/data
|
||||||
|
ENV HOME=/home/automaker
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
EXPOSE 3008
|
EXPOSE 3008
|
||||||
@@ -112,6 +119,9 @@ EXPOSE 3008
|
|||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
CMD curl -f http://localhost:3008/api/health || exit 1
|
CMD curl -f http://localhost:3008/api/health || exit 1
|
||||||
|
|
||||||
|
# Use entrypoint to fix permissions before starting
|
||||||
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
CMD ["node", "apps/server/dist/index.js"]
|
CMD ["node", "apps/server/dist/index.js"]
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,28 @@ import { createLogger } from '@automaker/utils/logger';
|
|||||||
import { getHttpApiClient } from './http-api-client';
|
import { getHttpApiClient } from './http-api-client';
|
||||||
import { getElectronAPI } from './electron';
|
import { getElectronAPI } from './electron';
|
||||||
import { getItem, setItem } from './storage';
|
import { getItem, setItem } from './storage';
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
const logger = createLogger('WorkspaceConfig');
|
const logger = createLogger('WorkspaceConfig');
|
||||||
|
|
||||||
const LAST_PROJECT_DIR_KEY = 'automaker:lastProjectDir';
|
const LAST_PROJECT_DIR_KEY = 'automaker:lastProjectDir';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browser-compatible path join utility
|
||||||
|
* Works in both Node.js and browser environments
|
||||||
|
*/
|
||||||
|
function joinPath(...parts: string[]): string {
|
||||||
|
// Remove empty parts and normalize separators
|
||||||
|
const normalized = parts
|
||||||
|
.filter((p) => p)
|
||||||
|
.map((p) => p.replace(/\\/g, '/'))
|
||||||
|
.join('/')
|
||||||
|
.replace(/\/+/g, '/'); // Remove duplicate slashes
|
||||||
|
|
||||||
|
// Preserve leading slash if first part had it
|
||||||
|
const hasLeadingSlash = parts[0]?.startsWith('/');
|
||||||
|
return hasLeadingSlash ? '/' + normalized.replace(/^\//, '') : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default Documents/Automaker directory path
|
* Gets the default Documents/Automaker directory path
|
||||||
* @returns Promise resolving to Documents/Automaker path, or null if unavailable
|
* @returns Promise resolving to Documents/Automaker path, or null if unavailable
|
||||||
@@ -21,7 +37,7 @@ async function getDefaultDocumentsPath(): Promise<string | null> {
|
|||||||
try {
|
try {
|
||||||
const api = getElectronAPI();
|
const api = getElectronAPI();
|
||||||
const documentsPath = await api.getPath('documents');
|
const documentsPath = await api.getPath('documents');
|
||||||
return path.join(documentsPath, 'Automaker');
|
return joinPath(documentsPath, 'Automaker');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to get documents path:', error);
|
logger.error('Failed to get documents path:', error);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
9
dev.mjs
9
dev.mjs
@@ -172,7 +172,9 @@ async function main() {
|
|||||||
} else if (choice === '3') {
|
} else if (choice === '3') {
|
||||||
console.log('');
|
console.log('');
|
||||||
log('Launching Docker Container (Isolated Mode)...', 'blue');
|
log('Launching Docker Container (Isolated Mode)...', 'blue');
|
||||||
log('Building and starting Docker containers...', 'yellow');
|
log('Starting Docker containers...', 'yellow');
|
||||||
|
log('Note: Containers will only rebuild if images are missing.', 'yellow');
|
||||||
|
log('To force a rebuild, run: docker compose up --build', 'yellow');
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// Check if ANTHROPIC_API_KEY is set
|
// Check if ANTHROPIC_API_KEY is set
|
||||||
@@ -183,8 +185,9 @@ async function main() {
|
|||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build and start containers with docker-compose
|
// Start containers with docker-compose (without --build to preserve volumes)
|
||||||
processes.docker = crossSpawn('docker', ['compose', 'up', '--build'], {
|
// Images will only be built if they don't exist
|
||||||
|
processes.docker = crossSpawn('docker', ['compose', 'up'], {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
cwd: __dirname,
|
cwd: __dirname,
|
||||||
env: {
|
env: {
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ services:
|
|||||||
# This volume persists data between restarts but is container-managed
|
# This volume persists data between restarts but is container-managed
|
||||||
- automaker-data:/data
|
- automaker-data:/data
|
||||||
|
|
||||||
|
# Persist Claude CLI OAuth session keys across container restarts
|
||||||
|
# This allows 'claude login' authentication to persist between restarts
|
||||||
|
- automaker-claude-config:/home/automaker/.claude
|
||||||
|
|
||||||
# NO host directory mounts - container cannot access your laptop files
|
# NO host directory mounts - container cannot access your laptop files
|
||||||
# If you need to work on a project, create it INSIDE the container
|
# If you need to work on a project, create it INSIDE the container
|
||||||
# or use a separate docker-compose override file
|
# or use a separate docker-compose override file
|
||||||
@@ -72,3 +76,8 @@ volumes:
|
|||||||
automaker-data:
|
automaker-data:
|
||||||
name: automaker-data
|
name: automaker-data
|
||||||
# Named volume - completely isolated from host filesystem
|
# Named volume - completely isolated from host filesystem
|
||||||
|
|
||||||
|
automaker-claude-config:
|
||||||
|
name: automaker-claude-config
|
||||||
|
# Named volume for Claude CLI OAuth session keys and configuration
|
||||||
|
# Persists authentication across container restarts
|
||||||
|
|||||||
19
docker-entrypoint.sh
Executable file
19
docker-entrypoint.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Fix permissions on Claude CLI config directory if it exists
|
||||||
|
# This handles the case where a volume is mounted and owned by root
|
||||||
|
if [ -d "/home/automaker/.claude" ]; then
|
||||||
|
chown -R automaker:automaker /home/automaker/.claude
|
||||||
|
chmod -R 755 /home/automaker/.claude
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure the directory exists with correct permissions if volume is empty
|
||||||
|
if [ ! -d "/home/automaker/.claude" ]; then
|
||||||
|
mkdir -p /home/automaker/.claude
|
||||||
|
chown automaker:automaker /home/automaker/.claude
|
||||||
|
chmod 755 /home/automaker/.claude
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Switch to automaker user and execute the command
|
||||||
|
exec su-exec automaker "$@"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"dev:electron:wsl": "npm run build:packages && npm run _dev:electron:wsl",
|
"dev:electron:wsl": "npm run build:packages && npm run _dev:electron:wsl",
|
||||||
"dev:electron:wsl:gpu": "npm run build:packages && npm run _dev:electron:wsl:gpu",
|
"dev:electron:wsl:gpu": "npm run build:packages && npm run _dev:electron:wsl:gpu",
|
||||||
"dev:server": "npm run build:packages && npm run _dev:server",
|
"dev:server": "npm run build:packages && npm run _dev:server",
|
||||||
"dev:docker": "docker compose up --build",
|
"dev:docker": "docker compose up",
|
||||||
"dev:full": "npm run build:packages && concurrently \"npm run _dev:server\" \"npm run _dev:web\"",
|
"dev:full": "npm run build:packages && concurrently \"npm run _dev:server\" \"npm run _dev:web\"",
|
||||||
"build": "npm run build:packages && npm run build --workspace=apps/ui",
|
"build": "npm run build:packages && npm run build --workspace=apps/ui",
|
||||||
"build:packages": "npm run build -w @automaker/types && npm run build -w @automaker/platform && npm run build -w @automaker/utils && npm run build -w @automaker/prompts -w @automaker/model-resolver -w @automaker/dependency-resolver && npm run build -w @automaker/git-utils",
|
"build:packages": "npm run build -w @automaker/types && npm run build -w @automaker/platform && npm run build -w @automaker/utils && npm run build -w @automaker/prompts -w @automaker/model-resolver -w @automaker/dependency-resolver && npm run build -w @automaker/git-utils",
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ async function main() {
|
|||||||
} else if (choice === '3') {
|
} else if (choice === '3') {
|
||||||
console.log('');
|
console.log('');
|
||||||
log('Launching Docker Container (Isolated Mode)...', 'blue');
|
log('Launching Docker Container (Isolated Mode)...', 'blue');
|
||||||
log('Building and starting Docker containers...', 'yellow');
|
log('Starting Docker containers...', 'yellow');
|
||||||
|
log('Note: Containers will only rebuild if images are missing.', 'yellow');
|
||||||
|
log('To force a rebuild, run: docker compose up --build', 'yellow');
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// Check if ANTHROPIC_API_KEY is set
|
// Check if ANTHROPIC_API_KEY is set
|
||||||
@@ -242,8 +244,9 @@ async function main() {
|
|||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build and start containers with docker-compose
|
// Start containers with docker-compose (without --build to preserve volumes)
|
||||||
processes.docker = crossSpawn('docker', ['compose', 'up', '--build'], {
|
// Images will only be built if they don't exist
|
||||||
|
processes.docker = crossSpawn('docker', ['compose', 'up'], {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
cwd: __dirname,
|
cwd: __dirname,
|
||||||
env: {
|
env: {
|
||||||
|
|||||||
Reference in New Issue
Block a user