sandboxbox 3.0.74 → 3.0.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-sandbox/plugins/marketplaces/anentrypoint-glootie-cc/package-lock.json +1334 -114
- package/.claude-sandbox/plugins/marketplaces/anentrypoint-glootie-cc/package.json +1 -1
- package/.mcp.json +9 -0
- package/CHANGELOG.md +22 -14
- package/CLAUDE.md +9 -2
- package/Dockerfile +19 -10
- package/cli.js +17 -5
- package/package.json +5 -2
- package/utils/commands/claude.js +13 -10
- package/utils/commands/container.js +30 -3
- package/utils/mcp-server.js +121 -0
- package/utils/sandbox.js +61 -0
- package/utils/ui.js +1 -0
package/.mcp.json
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [3.0.75] - 2025-11-13
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
6
|
+
- MCP server mode: Run sandboxbox as an MCP server with `npx sandboxbox mcp`
|
|
7
|
+
- `sandboxbox_run` MCP tool: Execute prompts in isolated sandboxbox environments via MCP protocol
|
|
8
|
+
- `.mcp.json` configuration file for easy Claude Code integration
|
|
9
|
+
- Fetch polyfill in container: undici package installed globally with automatic polyfill via NODE_OPTIONS
|
|
10
|
+
- Build command implementation: `npx sandboxbox build` to rebuild container images
|
|
11
|
+
- Plugin registry files: installed_plugins.json and known_marketplaces.json in .claude-sandbox/
|
|
12
|
+
- Automatic path rewriting for all plugin configuration files during sandbox creation
|
|
11
13
|
|
|
12
14
|
### Changed
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
15
|
+
- Container claude wrapper uses NODE_OPTIONS to inject fetch polyfill automatically
|
|
16
|
+
- Removed enabledPlugins from .claude-sandbox/settings.json (controlled by config.json)
|
|
17
|
+
- Updated cli.js to support 'mcp' command
|
|
18
|
+
- Added @modelcontextprotocol/sdk and undici dependencies
|
|
19
|
+
- Dockerfile creates fetch-init.mjs for global fetch availability
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- Fetch API not available in container: Added undici polyfill loaded via NODE_OPTIONS
|
|
23
|
+
- Plugin paths now correctly rewritten in installed_plugins.json and known_marketplaces.json
|
|
24
|
+
- Build command now functional with proper podman integration
|
|
25
|
+
|
|
26
|
+
### Removed
|
|
27
|
+
- Manual MCP server configurations from settings.json (delegated to plugin's .mcp.json)
|
|
28
|
+
- Firewall script from Dockerfile (not essential for core functionality)
|
|
21
29
|
|
|
22
30
|
## [3.0.64] - 2025-10-27
|
|
23
31
|
|
package/CLAUDE.md
CHANGED
|
@@ -78,8 +78,15 @@ if (process.platform === 'win32') {
|
|
|
78
78
|
1. Copy project to temporary directory (including .git)
|
|
79
79
|
2. Mount temporary directory as /workspace in container
|
|
80
80
|
3. Run commands in isolated environment
|
|
81
|
-
4.
|
|
82
|
-
5.
|
|
81
|
+
4. Auto-commit and push changes to host repository
|
|
82
|
+
5. Clean up temporary directory on exit
|
|
83
|
+
|
|
84
|
+
### Auto-Commit & Push (v3.0.76+)
|
|
85
|
+
- Cleanup function automatically detects uncommitted changes
|
|
86
|
+
- Auto-commits with timestamped message: "sandboxbox auto-commit: {ISO timestamp}"
|
|
87
|
+
- Auto-pushes to host repository before sandbox cleanup
|
|
88
|
+
- Changes persist automatically without manual git operations
|
|
89
|
+
- Graceful error handling - cleanup continues even if git operations fail
|
|
83
90
|
|
|
84
91
|
### Pattern
|
|
85
92
|
```javascript
|
package/Dockerfile
CHANGED
|
@@ -78,18 +78,27 @@ RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/
|
|
|
78
78
|
-a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
|
|
79
79
|
-x
|
|
80
80
|
|
|
81
|
-
# Install Claude
|
|
82
|
-
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}
|
|
83
|
-
|
|
84
|
-
# Install playwright deps (commented out due to build issues)
|
|
85
|
-
# RUN npx --yes playwright install-deps
|
|
81
|
+
# Install Claude and dependencies
|
|
82
|
+
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION} undici
|
|
86
83
|
|
|
87
84
|
RUN npm i -g @playwright/mcp
|
|
88
85
|
|
|
89
|
-
#
|
|
90
|
-
COPY init-firewall.sh /usr/local/bin/
|
|
86
|
+
# Switch to root to create wrapper scripts
|
|
91
87
|
USER root
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
|
|
89
|
+
# Create fetch polyfill init script
|
|
90
|
+
RUN echo 'import { fetch, Headers, Request, Response } from "undici";\n\
|
|
91
|
+
globalThis.fetch = fetch;\n\
|
|
92
|
+
globalThis.Headers = Headers;\n\
|
|
93
|
+
globalThis.Request = Request;\n\
|
|
94
|
+
globalThis.Response = Response;\n\
|
|
95
|
+
' > /usr/local/lib/fetch-init.mjs
|
|
96
|
+
|
|
97
|
+
# Create wrapper script that uses the init
|
|
98
|
+
RUN echo '#!/bin/bash\n\
|
|
99
|
+
NODE_OPTIONS="--import=/usr/local/lib/fetch-init.mjs" exec /home/node/.local/bin/claude "$@"\n\
|
|
100
|
+
' > /usr/local/bin/claude-with-fetch && \
|
|
101
|
+
chmod +x /usr/local/bin/claude-with-fetch && \
|
|
102
|
+
ln -sf /usr/local/bin/claude-with-fetch /usr/local/share/npm-global/bin/claude
|
|
103
|
+
|
|
95
104
|
USER node
|
package/cli.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* SandboxBox CLI - Process Containment Sandbox
|
|
5
|
-
* Lightweight process isolation for CLI tools
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
3
|
import { resolve } from 'path';
|
|
9
4
|
import { color } from './utils/colors.js';
|
|
10
5
|
import { showBanner, showHelp } from './utils/ui.js';
|
|
@@ -76,6 +71,23 @@ async function main() {
|
|
|
76
71
|
if (!versionCommand()) process.exit(1);
|
|
77
72
|
break;
|
|
78
73
|
|
|
74
|
+
case 'mcp':
|
|
75
|
+
const { spawn } = await import('child_process');
|
|
76
|
+
const { fileURLToPath } = await import('url');
|
|
77
|
+
const { dirname } = await import('path');
|
|
78
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
79
|
+
const __dirname = dirname(__filename);
|
|
80
|
+
const mcpServerPath = resolve(__dirname, 'utils', 'mcp-server.js');
|
|
81
|
+
|
|
82
|
+
const mcpProcess = spawn('node', [mcpServerPath], {
|
|
83
|
+
stdio: 'inherit'
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
mcpProcess.on('exit', (code) => {
|
|
87
|
+
process.exit(code || 0);
|
|
88
|
+
});
|
|
89
|
+
break;
|
|
90
|
+
|
|
79
91
|
default:
|
|
80
92
|
console.log(color('red', `❌ Unknown command: ${command}`));
|
|
81
93
|
console.log(color('yellow', 'Use --help for usage information'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sandboxbox",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.76",
|
|
4
4
|
"description": "Lightweight process containment sandbox for CLI tools - Playwright, Claude Code, and more. Pure Node.js, no dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cli.js",
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
],
|
|
30
30
|
"author": "",
|
|
31
31
|
"license": "MIT",
|
|
32
|
-
"dependencies": {
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.21.1",
|
|
34
|
+
"undici": "^7.16.0"
|
|
35
|
+
},
|
|
33
36
|
"repository": {
|
|
34
37
|
"type": "git",
|
|
35
38
|
"url": "git+https://github.com/AnEntrypoint/sandboxbox.git"
|
package/utils/commands/claude.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
+
import { fetch } from 'undici';
|
|
2
|
+
if (!globalThis.fetch) {
|
|
3
|
+
globalThis.fetch = fetch;
|
|
4
|
+
}
|
|
5
|
+
|
|
1
6
|
import { existsSync, writeFileSync, appendFileSync } from 'fs';
|
|
2
7
|
import { resolve, join } from 'path';
|
|
3
8
|
import { spawn, execSync } from 'child_process';
|
|
4
9
|
import { color } from '../colors.js';
|
|
5
10
|
import { createSandbox, createSandboxEnv } from '../sandbox.js';
|
|
6
|
-
// ClaudeOptimizer disabled to preserve bundled hooks
|
|
7
|
-
// import { ClaudeOptimizer } from '../claude-optimizer.js';
|
|
8
11
|
import { SystemOptimizer } from '../system-optimizer.js';
|
|
9
12
|
|
|
10
|
-
// Console output configuration
|
|
11
13
|
const MAX_CONSOLE_LINES = parseInt(process.env.SANDBOX_MAX_CONSOLE_LINES) || 5;
|
|
12
14
|
const MAX_LOG_ENTRY_LENGTH = parseInt(process.env.SANDBOX_MAX_LOG_LENGTH) || 200;
|
|
13
15
|
const ENABLE_FILE_LOGGING = process.env.SANDBOX_ENABLE_FILE_LOGGING === 'true';
|
|
14
16
|
const VERBOSE_OUTPUT = process.env.SANDBOX_VERBOSE === 'true' || process.argv.includes('--verbose');
|
|
15
17
|
global.toolCallLog = [];
|
|
16
18
|
global.logFileHandle = null;
|
|
17
|
-
global.pendingToolCalls = new Map();
|
|
18
|
-
global.conversationalBuffer = '';
|
|
19
|
-
|
|
20
|
-
// Helper function to extract tool metadata without showing actual content
|
|
19
|
+
global.pendingToolCalls = new Map();
|
|
20
|
+
global.conversationalBuffer = '';
|
|
21
21
|
function extractToolMetadata(toolUse) {
|
|
22
22
|
const metadata = {
|
|
23
23
|
name: toolUse.name || 'unknown',
|
|
@@ -316,10 +316,13 @@ ${prompt}`;
|
|
|
316
316
|
// Environment is now properly configured with same permissions as run command
|
|
317
317
|
|
|
318
318
|
const proc = spawn('claude', claudeArgs, {
|
|
319
|
-
cwd: workspacePath,
|
|
320
|
-
env:
|
|
319
|
+
cwd: workspacePath,
|
|
320
|
+
env: {
|
|
321
|
+
...env,
|
|
322
|
+
NODE_OPTIONS: '--import=/usr/local/lib/fetch-init.mjs'
|
|
323
|
+
},
|
|
321
324
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
322
|
-
shell: false,
|
|
325
|
+
shell: false,
|
|
323
326
|
detached: false
|
|
324
327
|
});
|
|
325
328
|
|
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
|
-
import { resolve, join } from 'path';
|
|
2
|
+
import { resolve, join, dirname } from 'path';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
3
4
|
import { color } from '../colors.js';
|
|
4
5
|
import { createSandbox, createSandboxEnv, runInSandbox } from '../sandbox.js';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
5
10
|
|
|
6
11
|
export function buildCommand(dockerfilePath) {
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
const repoRoot = resolve(__dirname, '..', '..');
|
|
13
|
+
const dockerfile = dockerfilePath || join(repoRoot, 'Dockerfile');
|
|
14
|
+
|
|
15
|
+
if (!existsSync(dockerfile)) {
|
|
16
|
+
console.log(color('red', `❌ Dockerfile not found: ${dockerfile}`));
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log(color('cyan', `📦 Building sandboxbox container from ${dockerfile}...`));
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const buildContext = dirname(dockerfile);
|
|
24
|
+
|
|
25
|
+
execSync(`podman build -t sandboxbox:latest -f "${dockerfile}" "${buildContext}"`, {
|
|
26
|
+
stdio: 'inherit',
|
|
27
|
+
shell: process.platform === 'win32'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log(color('green', '✅ Container built successfully!'));
|
|
31
|
+
return true;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.log(color('red', `❌ Build failed: ${error.message}`));
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
9
36
|
}
|
|
10
37
|
|
|
11
38
|
export async function runCommand(projectDir, cmd) {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname, resolve } from 'path';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const server = new Server(
|
|
14
|
+
{
|
|
15
|
+
name: 'sandboxbox',
|
|
16
|
+
version: '1.0.0',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
capabilities: {
|
|
20
|
+
tools: {},
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
26
|
+
return {
|
|
27
|
+
tools: [
|
|
28
|
+
{
|
|
29
|
+
name: 'sandboxbox_run',
|
|
30
|
+
description: 'Execute a prompt in an isolated sandboxbox environment. Runs Claude Code with the given prompt in a temporary containerized workspace.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
prompt: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'The prompt to execute in the sandboxbox environment',
|
|
37
|
+
},
|
|
38
|
+
directory: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'The directory to run in (defaults to current directory)',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ['prompt'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
51
|
+
if (request.params.name !== 'sandboxbox_run') {
|
|
52
|
+
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const { prompt, directory } = request.params.arguments;
|
|
56
|
+
|
|
57
|
+
if (!prompt || typeof prompt !== 'string') {
|
|
58
|
+
throw new Error('prompt is required and must be a string');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const targetDir = directory || process.cwd();
|
|
62
|
+
const cliPath = resolve(__dirname, '..', 'cli.js');
|
|
63
|
+
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const args = ['claude', targetDir, prompt];
|
|
66
|
+
const child = spawn('node', [cliPath, ...args], {
|
|
67
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
68
|
+
env: { ...process.env, SANDBOX_VERBOSE: 'false' }
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
let stdout = '';
|
|
72
|
+
let stderr = '';
|
|
73
|
+
|
|
74
|
+
child.stdout.on('data', (data) => {
|
|
75
|
+
stdout += data.toString();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
child.stderr.on('data', (data) => {
|
|
79
|
+
stderr += data.toString();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
child.on('close', (code) => {
|
|
83
|
+
if (code !== 0) {
|
|
84
|
+
resolve({
|
|
85
|
+
content: [{
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: `Error (exit code ${code}):\n${stderr || stdout}`,
|
|
88
|
+
}],
|
|
89
|
+
isError: true,
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
resolve({
|
|
93
|
+
content: [{
|
|
94
|
+
type: 'text',
|
|
95
|
+
text: stdout || 'Command completed successfully',
|
|
96
|
+
}],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
child.on('error', (error) => {
|
|
102
|
+
resolve({
|
|
103
|
+
content: [{
|
|
104
|
+
type: 'text',
|
|
105
|
+
text: `Error: ${error.message}`,
|
|
106
|
+
}],
|
|
107
|
+
isError: true,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
async function main() {
|
|
114
|
+
const transport = new StdioServerTransport();
|
|
115
|
+
await server.connect(transport);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
main().catch((error) => {
|
|
119
|
+
console.error('Server error:', error);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
});
|
package/utils/sandbox.js
CHANGED
|
@@ -325,6 +325,66 @@ node_modules/
|
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
const cleanup = () => {
|
|
328
|
+
const VERBOSE_OUTPUT = process.env.SANDBOX_VERBOSE === 'true' || process.argv.includes('--verbose');
|
|
329
|
+
|
|
330
|
+
// Push any committed changes back to host before cleanup
|
|
331
|
+
try {
|
|
332
|
+
// Check if there are any uncommitted changes
|
|
333
|
+
const status = execSync(`git status --porcelain`, {
|
|
334
|
+
cwd: workspaceDir,
|
|
335
|
+
encoding: 'utf8',
|
|
336
|
+
stdio: 'pipe'
|
|
337
|
+
}).trim();
|
|
338
|
+
|
|
339
|
+
if (status) {
|
|
340
|
+
// Add all changes
|
|
341
|
+
execSync(`git add -A`, {
|
|
342
|
+
cwd: workspaceDir,
|
|
343
|
+
stdio: 'pipe',
|
|
344
|
+
shell: true
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Commit with timestamp
|
|
348
|
+
const commitMessage = `sandboxbox auto-commit: ${new Date().toISOString()}
|
|
349
|
+
|
|
350
|
+
🤖 Generated with SandboxBox
|
|
351
|
+
Changes made during sandboxbox session`;
|
|
352
|
+
|
|
353
|
+
execSync(`git commit -m "${commitMessage}"`, {
|
|
354
|
+
cwd: workspaceDir,
|
|
355
|
+
stdio: 'pipe',
|
|
356
|
+
shell: true
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
if (VERBOSE_OUTPUT) {
|
|
360
|
+
console.log('✅ Committed sandbox changes');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Push to host repository (origin points to host)
|
|
365
|
+
try {
|
|
366
|
+
execSync(`git push origin HEAD`, {
|
|
367
|
+
cwd: workspaceDir,
|
|
368
|
+
stdio: 'pipe',
|
|
369
|
+
shell: true
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
if (VERBOSE_OUTPUT) {
|
|
373
|
+
console.log('✅ Pushed changes to host repository');
|
|
374
|
+
}
|
|
375
|
+
} catch (pushError) {
|
|
376
|
+
// Push might fail if there are no changes or network issues
|
|
377
|
+
if (VERBOSE_OUTPUT) {
|
|
378
|
+
console.log('⚠️ Could not push to host repository');
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
// Don't fail cleanup if git operations fail
|
|
383
|
+
if (VERBOSE_OUTPUT) {
|
|
384
|
+
console.log(`⚠️ Git sync failed: ${error.message}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
328
388
|
// Close any log files that might be open
|
|
329
389
|
if (global.logFileHandle) {
|
|
330
390
|
try {
|
|
@@ -334,6 +394,7 @@ node_modules/
|
|
|
334
394
|
// Don't fail on log cleanup
|
|
335
395
|
}
|
|
336
396
|
}
|
|
397
|
+
|
|
337
398
|
rmSync(sandboxDir, { recursive: true, force: true });
|
|
338
399
|
};
|
|
339
400
|
|
package/utils/ui.js
CHANGED
|
@@ -18,6 +18,7 @@ export function showHelp() {
|
|
|
18
18
|
console.log(' run <project-dir> [cmd] Run project in container');
|
|
19
19
|
console.log(' shell <project-dir> Start interactive shell');
|
|
20
20
|
console.log(' claude <project-dir> [prompt] [--host] [--headless] Start Claude Code with Git integration');
|
|
21
|
+
console.log(' mcp Start as MCP server (stdio transport)');
|
|
21
22
|
console.log(' version Show version information');
|
|
22
23
|
console.log('');
|
|
23
24
|
console.log(color('yellow', 'Claude Command Options:'));
|