Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "peerbot-integration",
"version": "1.0.0",
"name": "Peerbot Worker Integration",
"description": "Adds Peerbot worker packages and Claude Code CLI to devcontainer environment",
"documentationURL": "https://github.com/buremba/peerbot",
"options": {
"version": {
"type": "string",
"default": "latest",
"description": "Version of Claude Code CLI to install"
}
},
"installsAfter": ["ghcr.io/devcontainers/features/common-utils"],
"postCreateCommand": [
"npm install -g @anthropic-ai/claude-code",
"npm install -g /app/packages/worker",
"npm install -g /app/packages/shared"
]
}
31 changes: 31 additions & 0 deletions .devcontainer-features/peerbot-integration/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

set -e

# Peerbot Integration Feature Installation Script

echo "Installing Peerbot Worker Integration..."

# Install Claude Code CLI globally
echo "Installing Claude Code CLI..."
npm install -g "@anthropic-ai/claude-code@${VERSION:-latest}"

# Verify installation
if ! command -v claude >/dev/null 2>&1; then
echo "❌ Error: Claude CLI installation failed"
exit 1
fi

# Setup git configuration for peerbot workers
echo "Configuring git for Peerbot workers..."
git config --global user.name "Claude Code Worker" 2>/dev/null || true
git config --global user.email "claude-code-worker@noreply.github.com" 2>/dev/null || true
git config --global init.defaultBranch main 2>/dev/null || true
git config --global pull.rebase false 2>/dev/null || true
git config --global safe.directory '*' 2>/dev/null || true

# Create peerbot directories
mkdir -p /app/packages
mkdir -p /home/${_REMOTE_USER:-vscode}/.claude

echo "✅ Peerbot Integration feature installed successfully"
16 changes: 7 additions & 9 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,36 +113,34 @@ graph TB

### How Conversations Continue
1. **Persistent Volume**: Single 10GB PVC shared across all workers
2. **User Isolation**: Each user gets `/workspace/user-{username}/` directory
3. **Claude Sessions**: All conversation history stored in `.claude/` subdirectory
2. **User Isolation**: Each user gets `/workspace/user-{username}/` directory
3. **Claude Sessions**: Global session data stored in `/workspace/.claude-sessions/` and symlinked to `~/.claude`
4. **Auto-Resume**: Workers use `claude --resume <session-id>` to continue conversations
5. **No Data Loss**: Data persists even when worker pods terminate
5. **No Data Loss**: Both project data and Claude sessions persist across worker pod restarts

### Background Process Management
Workers include a background process management MCP server.

### Directory Structure
```
/workspace/ # PVC mount point (K8s) or local workspaces dir (Docker)
├── .claude-sessions/ # Claude CLI global session data (symlinked from ~/.claude)
│ ├── projects/ # Project contexts across all threads
│ ├── sessions/ # Conversation history for all sessions
│ └── settings.mcp.json # MCP server configuration
├── U095ZLHKP98/ # Per-userId directory
│ ├── 1756492073.980799/ # Per-thread workspace (threadId/timestamp)
│ │ ├── .git/ # Cloned repository
│ │ ├── .claude/ # Claude session data (auto-resume support)
│ │ │ ├── projects/ # Project context
│ │ │ └── sessions/ # Conversation history
│ │ └── [project files] # User's code from repository
│ └── 1756491379.629309/ # Another thread workspace
│ ├── .git/
│ ├── .claude/
│ └── [project files]
└── U09513HH1N1/ # Another user's workspace
├── 1756479858.121779/ # Thread-specific workspace
│ ├── .git/
│ ├── .claude/
│ └── [project files]
└── 1756491388.020389/ # Another thread workspace
├── .git/
├── .claude/
└── [project files]
```

Expand Down
114 changes: 0 additions & 114 deletions Dockerfile.worker

This file was deleted.

19 changes: 6 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ setup:
@echo "🚀 Starting PeerBot development setup..."
@./bin/setup-slack.sh

# Start local development
dev: build-worker
# Start local development
dev:
@if [ ! -f .env ]; then \
echo "❌ .env file not found!"; \
echo ""; \
Expand All @@ -28,9 +28,8 @@ dev: build-worker
fi
@echo "🚀 Starting local development mode..."
@echo " This will:"
@echo " - Build worker Docker image"
@echo " - Start orchestrator and dispatcher with hot reload"
@echo " - Use Docker containers for workers"
@echo " - Use devcontainer-built images for workers (built on demand)"
@echo ""
@if grep -q "DEPLOYMENT_MODE=" .env 2>/dev/null; then \
DEPLOYMENT_MODE=$$(grep "DEPLOYMENT_MODE=" .env | cut -d'=' -f2); \
Expand All @@ -55,16 +54,10 @@ dev: build-worker
bun --watch packages/orchestrator/src/index.ts & \
bun --watch packages/dispatcher/src/index.ts

# Build worker image for Docker mode
# Build base worker image for development (optional fallback)
build-worker:
@echo "🔨 Building worker Docker image..."
@if [ "$$NODE_ENV" = "development" ]; then \
echo "📦 Building development image with volume mounts..."; \
docker build -f Dockerfile.worker.dev -t peerbot-worker:latest .; \
else \
echo "📦 Building production image..."; \
docker build -f Dockerfile.worker -t peerbot-worker:latest .; \
fi
@echo "ℹ️ Worker images are now built dynamically using devcontainers"
@echo " Base images will be built on-demand when workers are created"

# Catch-all target to prevent errors when passing arguments
%:
Expand Down
53 changes: 53 additions & 0 deletions packages/dispatcher/src/queue/slack-thread-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ interface ThreadResponsePayload {
originalMessageTs?: string; // User's original message timestamp for reactions
gitBranch?: string; // Current git branch for Edit button URLs
botResponseTs?: string; // Bot's response message timestamp for updates
envChanges?: boolean; // Flag indicating environment was modified
modifiedFiles?: string[]; // Files changed (e.g. [".devcontainer/devcontainer.json"])
currentCommit?: string; // Current git HEAD after changes
repositoryUrl?: string; // Repository URL for rebuild context
}

/**
Expand Down Expand Up @@ -340,6 +344,12 @@ export class ThreadResponseConsumer {
await this.handleError(data, isFirstResponse, botMessageTs);
}

// Handle environment changes - forward rebuild request to orchestrator
if (data.envChanges && data.currentCommit && data.repositoryUrl) {
logger.info(`Environment change detected for thread ${data.threadTs}: ${data.modifiedFiles?.join(', ')}`);
await this.handleEnvironmentChange(data);
}

// Log completion
if (data.isDone) {
logger.info(`Thread processing completed for message ${data.messageId}`);
Expand Down Expand Up @@ -602,6 +612,49 @@ export class ThreadResponseConsumer {
}
}

/**
* Handle environment change by forwarding rebuild request to orchestrator
*/
private async handleEnvironmentChange(data: ThreadResponsePayload): Promise<void> {
try {
// Create rebuild request message for orchestrator
const rebuildRequest = {
type: 'rebuild_request',
threadId: data.threadTs,
userId: data.userId,
channelId: data.channelId,
repositoryUrl: data.repositoryUrl,
commitId: data.currentCommit,
modifiedFiles: data.modifiedFiles,
originalMessageTs: data.originalMessageTs,
platformMetadata: {
teamId: '', // Will be filled in by dispatcher if needed
repositoryUrl: data.repositoryUrl,
botResponseTs: data.botResponseTs,
originalMessageTs: data.originalMessageTs
},
timestamp: Date.now()
};

// Send rebuild request to orchestrator via messages queue
const jobId = await this.pgBoss.send('messages', rebuildRequest, {
retryLimit: 3,
retryDelay: 5000,
priority: 5 // High priority for rebuild requests
});

if (jobId) {
logger.info(`Sent rebuild request to orchestrator: job ${jobId} for thread ${data.threadTs}`);
} else {
logger.error(`Failed to send rebuild request for thread ${data.threadTs}: pgBoss returned null`);
}

} catch (error) {
logger.error(`Failed to handle environment change for thread ${data.threadTs}:`, error);
// Don't throw - environment changes are not critical to message processing
}
}

/**
* Check if consumer is running and healthy
*/
Expand Down
1 change: 1 addition & 0 deletions packages/orchestrator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"test": "bun test"
},
"dependencies": {
"@devcontainers/cli": "^0.60.0",
"@kubernetes/client-node": "^0.21.0",
"@sentry/node": "^10.6.0",
"dockerode": "^4.0.7",
Expand Down
Loading
Loading