mirror of
https://github.com/textcortex/claude-code-sandbox.git
synced 2025-08-04 10:59:28 +00:00
Checkpoint
This commit is contained in:
parent
24c2a98caf
commit
c7e37a0830
4 changed files with 56 additions and 29 deletions
|
@ -34,16 +34,25 @@ WORKDIR /workspace
|
|||
|
||||
# Create a wrapper script for git that prevents branch switching
|
||||
RUN echo '#!/bin/bash\n\
|
||||
if [[ "$1" == "checkout" ]] && [[ "$2" != "-b" ]] && [[ "$*" != *"--"* ]]; then\n\
|
||||
echo "Error: Branch switching is disabled in claude-sandbox"\n\
|
||||
echo "You can only create new branches with git checkout -b"\n\
|
||||
exit 1\n\
|
||||
fi\n\
|
||||
if [[ "$1" == "switch" ]]; then\n\
|
||||
echo "Error: Branch switching is disabled in claude-sandbox"\n\
|
||||
exit 1\n\
|
||||
fi\n\
|
||||
/usr/bin/git "$@"' > /usr/local/bin/git-wrapper && \
|
||||
# Allow the initial branch creation\n\
|
||||
if [ ! -f /tmp/.branch-created ]; then\n\
|
||||
/usr/bin/git.real "$@"\n\
|
||||
if [[ "$1" == "checkout" ]] && [[ "$2" == "-b" ]]; then\n\
|
||||
touch /tmp/.branch-created\n\
|
||||
fi\n\
|
||||
else\n\
|
||||
# After initial branch creation, prevent switching\n\
|
||||
if [[ "$1" == "checkout" ]] && [[ "$2" != "-b" ]] && [[ "$*" != *"--"* ]]; then\n\
|
||||
echo "Error: Branch switching is disabled in claude-sandbox"\n\
|
||||
echo "You can only create new branches with git checkout -b"\n\
|
||||
exit 1\n\
|
||||
fi\n\
|
||||
if [[ "$1" == "switch" ]]; then\n\
|
||||
echo "Error: Branch switching is disabled in claude-sandbox"\n\
|
||||
exit 1\n\
|
||||
fi\n\
|
||||
/usr/bin/git.real "$@"\n\
|
||||
fi' > /usr/local/bin/git-wrapper && \
|
||||
chmod +x /usr/local/bin/git-wrapper && \
|
||||
mv /usr/bin/git /usr/bin/git.real && \
|
||||
ln -s /usr/local/bin/git-wrapper /usr/bin/git
|
||||
|
|
|
@ -28,10 +28,12 @@ Claude-sandbox is a tool that runs Claude Code as an interactive agent inside Do
|
|||
- Git configuration
|
||||
|
||||
#### 4. **Git Workflow**
|
||||
- Container automatically starts on a new branch (never on main)
|
||||
- **IMPORTANT**: Branch switching happens INSIDE the container, not on the host
|
||||
- Host repository remains on its current branch
|
||||
- Container automatically creates and switches to a new branch internally
|
||||
- Branch naming: `claude/[timestamp]`
|
||||
- Claude can make commits but cannot switch branches
|
||||
- Git wrapper prevents branch switching operations
|
||||
- Claude can make commits but cannot switch branches after initial creation
|
||||
- Git wrapper prevents branch switching operations within container
|
||||
|
||||
#### 5. **Change Detection & Review**
|
||||
- Real-time monitoring for new commits
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Docker from 'dockerode';
|
||||
import path from 'path';
|
||||
import { SandboxConfig, Credentials } from './types';
|
||||
import chalk from 'chalk';
|
||||
|
||||
export class ContainerManager {
|
||||
private docker: Docker;
|
||||
|
@ -29,6 +30,15 @@ export class ContainerManager {
|
|||
private async ensureImage(): Promise<void> {
|
||||
const imageName = this.config.dockerImage || 'claude-sandbox:latest';
|
||||
|
||||
// Check if image already exists
|
||||
try {
|
||||
await this.docker.getImage(imageName).inspect();
|
||||
console.log(chalk.green(`✓ Using existing image: ${imageName}`));
|
||||
return;
|
||||
} catch (error) {
|
||||
console.log(chalk.blue(`Building image: ${imageName}...`));
|
||||
}
|
||||
|
||||
// Check if we need to build from Dockerfile
|
||||
if (this.config.dockerfile) {
|
||||
await this.buildImage(this.config.dockerfile, imageName);
|
||||
|
@ -71,11 +81,24 @@ WORKDIR /workspace
|
|||
|
||||
# Create a wrapper script for git that prevents branch switching
|
||||
RUN echo '#!/bin/bash\\n\\
|
||||
if [[ "$1" == "checkout" ]] && [[ "$2" != "-b" ]]; then\\n\\
|
||||
echo "Branch switching is disabled in claude-sandbox"\\n\\
|
||||
exit 1\\n\\
|
||||
fi\\n\\
|
||||
/usr/bin/git "$@"' > /usr/local/bin/git && \\
|
||||
# Allow the initial branch creation\\n\\
|
||||
if [ ! -f /tmp/.branch-created ]; then\\n\\
|
||||
/usr/bin/git "$@"\\n\\
|
||||
if [[ "$1" == "checkout" ]] && [[ "$2" == "-b" ]]; then\\n\\
|
||||
touch /tmp/.branch-created\\n\\
|
||||
fi\\n\\
|
||||
else\\n\\
|
||||
# After initial branch creation, prevent switching\\n\\
|
||||
if [[ "$1" == "checkout" ]] && [[ "$2" != "-b" ]]; then\\n\\
|
||||
echo "Branch switching is disabled in claude-sandbox"\\n\\
|
||||
exit 1\\n\\
|
||||
fi\\n\\
|
||||
if [[ "$1" == "switch" ]]; then\\n\\
|
||||
echo "Branch switching is disabled in claude-sandbox"\\n\\
|
||||
exit 1\\n\\
|
||||
fi\\n\\
|
||||
/usr/bin/git "$@"\\n\\
|
||||
fi' > /usr/local/bin/git && \\
|
||||
chmod +x /usr/local/bin/git
|
||||
|
||||
# Set up entrypoint
|
||||
|
@ -143,7 +166,7 @@ ENTRYPOINT ["/bin/bash", "-c"]
|
|||
NetworkMode: 'bridge',
|
||||
},
|
||||
WorkingDir: '/workspace',
|
||||
Cmd: [`cd /workspace && git checkout ${branchName} && claude --dangerously-skip-permissions`],
|
||||
Cmd: [`cd /workspace && git checkout -b ${branchName} && claude --dangerously-skip-permissions`],
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
|
|
13
src/index.ts
13
src/index.ts
|
@ -32,9 +32,9 @@ export class ClaudeSandbox {
|
|||
// Verify we're in a git repository
|
||||
await this.verifyGitRepo();
|
||||
|
||||
// Create new branch
|
||||
const branchName = await this.createBranch();
|
||||
console.log(chalk.green(`✓ Created branch: ${branchName}`));
|
||||
// Generate branch name (but don't switch yet)
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
|
||||
const branchName = `claude/${timestamp}-${Date.now()}`;
|
||||
|
||||
// Discover credentials
|
||||
const credentials = await this.credentialManager.discover();
|
||||
|
@ -74,13 +74,6 @@ export class ClaudeSandbox {
|
|||
}
|
||||
}
|
||||
|
||||
private async createBranch(): Promise<string> {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
|
||||
const branchName = `claude/${timestamp}-${Date.now()}`;
|
||||
|
||||
await this.git.checkout(['-b', branchName]);
|
||||
return branchName;
|
||||
}
|
||||
|
||||
private async prepareContainer(branchName: string, credentials: any): Promise<any> {
|
||||
const workDir = process.cwd();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue