create-claude-docker 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 create-claude-docker contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # create-claude-docker
2
+
3
+ Create Docker-based Claude Code development environment with **Z.AI GLM-4.7** support.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/create-claude-docker.svg)](https://www.npmjs.com/package/create-claude-docker)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - 🐳 **Docker-based**: Isolated environment for each project
11
+ - 🔑 **Auto-configured**: API key injection on container start
12
+ - 🤖 **Z.AI GLM-4.7**: Pre-configured for Z.AI's Claude-compatible models
13
+ - 👤 **Non-root user**: Supports `--dangerously-skip-permissions` flag
14
+ - 🛠️ **Default agents**: Pre-configured specialized agents (backend, frontend, debugging, etc.)
15
+
16
+ ## Quick Start
17
+
18
+ ### Create a new project with npx
19
+
20
+ ```bash
21
+ # Interactive mode
22
+ npx create-claude-docker my-project
23
+
24
+ # With options
25
+ npx create-claude-docker my-project --description "My AI project" --author "Your Name"
26
+ ```
27
+
28
+ ### CLI Options
29
+
30
+ | Option | Alias | Description |
31
+ |--------|-------|-------------|
32
+ | `--description` | `-d` | Project description |
33
+ | `--author` | `-a` | Author name |
34
+
35
+ ### After creation
36
+
37
+ ```bash
38
+ cd my-project
39
+
40
+ # Add your Z.AI API key
41
+ nano .env
42
+
43
+ # Build and start
44
+ npm run docker:build
45
+ npm run docker:up
46
+
47
+ # Run Claude Code
48
+ npm run claude:unsafe
49
+ ```
50
+
51
+ ## Manual Setup (Alternative)
52
+
53
+ ### Option 2: Using Z.AI GLM-4.7 Models
54
+
55
+ Z.AI provides GLM-4.7 models that are compatible with Claude Code through an Anthropic-compatible API endpoint.
56
+
57
+ 1. **Get Z.AI API key:**
58
+ - Visit: https://z.ai/manage-apikey/apikey-list
59
+ - Or: https://open.bigmodel.cn/
60
+ - Sign up and get your API key
61
+
62
+ 2. **Configure environment:**
63
+ ```bash
64
+ cp .env.example .env
65
+ # Edit .env and set your Z.AI API key:
66
+ ZAI_API_KEY=your-zai-api-key-here
67
+ ```
68
+
69
+ 3. **Build and start:**
70
+ ```bash
71
+ npm run docker:build
72
+ npm run docker:up
73
+ ```
74
+
75
+ The container will **automatically configure** Claude Code with your API key on startup. You should see:
76
+ ```
77
+ 🚀 Starting Claude Code container...
78
+ 🔧 Configuring Claude Code settings...
79
+ ✅ Claude Code configured with Z.AI API key
80
+ 📋 Current settings.json:
81
+ ...
82
+ ```
83
+
84
+ 4. **Run Claude Code:**
85
+ ```bash
86
+ npm run claude:unsafe
87
+ ```
88
+
89
+ 5. **Verify configuration:**
90
+ Once inside Claude Code, run `/status` to check the current model in use.
91
+ You should see `glm-4.7` as the active model.
92
+
93
+ ## Switching Between Models
94
+
95
+ ### To switch from GLM-4.7 back to Anthropic Claude:
96
+
97
+ 1. Edit `.env` and set `ANTHROPIC_API_KEY` to your Anthropic key
98
+ 2. Remove or edit `.claude/settings.json` to remove the GLM model configuration
99
+ 3. Restart the container:
100
+ ```bash
101
+ npm run docker:down
102
+ npm run docker:up
103
+ ```
104
+
105
+ ### To customize model selection:
106
+
107
+ Edit `./claude-data/settings.json` (created on first run) or `.claude/settings.json`:
108
+
109
+ ```json
110
+ {
111
+ "env": {
112
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-3-5-haiku-20241022",
113
+ "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-3-5-sonnet-20241022",
114
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-3-5-sonnet-20241022"
115
+ }
116
+ }
117
+ ```
118
+
119
+ ## Available Commands
120
+
121
+ | Command | Description |
122
+ |---------|-------------|
123
+ | `npm run docker:build` | Build Docker image |
124
+ | `npm run docker:up` | Start container in background |
125
+ | `npm run docker:down` | Stop and remove container |
126
+ | `npm run docker:logs` | View container logs |
127
+ | `npm run docker:shell` | Open bash shell in container |
128
+ | `npm run claude` | Run Claude Code (normal mode) |
129
+ | `npm run claude:unsafe` | Run Claude Code with --dangerously-skip-permissions |
130
+
131
+ ## Project Structure
132
+
133
+ ```
134
+ .
135
+ ├── .docker/
136
+ │ └── Dockerfile # Docker image definition
137
+ ├── .claude/
138
+ │ ├── settings.json # Default GLM-4.7 model configuration
139
+ │ └── agents/ # Default agent configurations
140
+ │ ├── backend-node-pro.md
141
+ │ ├── ui-architect.md
142
+ │ ├── debugging-expert.md
143
+ │ ├── architecture-reviewer.md
144
+ │ └── technical-writer.md
145
+ ├── .env.example # Environment variables template
146
+ ├── docker-compose.yml # Docker Compose configuration
147
+ ├── package.json # NPM scripts
148
+ ├── claude-data/ # Claude Code config (auto-created, overrides .claude/)
149
+ └── README.md # This file
150
+ ```
151
+
152
+ ## Default Agents
153
+
154
+ The boilerplate includes pre-configured specialized agents:
155
+
156
+ | Agent | Purpose | Model |
157
+ |-------|---------|-------|
158
+ | `backend-node-pro` | Backend Node.js development (API clients, workers, Firebase) | Opus/GLM-4.7 |
159
+ | `ui-architect` | Frontend/React design (components, styling, UX) | Opus/GLM-4.7 |
160
+ | `debugging-expert` | Debugging complex issues and root cause analysis | Opus/GLM-4.7 |
161
+ | `architecture-reviewer` | System design evaluation and architectural decisions | Sonnet/GLM-4.7 |
162
+ | `technical-writer` | Documentation, API references, guides | Sonnet/GLM-4.7 |
163
+
164
+ ## Configuration
165
+
166
+ ### Non-Root User
167
+
168
+ The container runs as user `claude` (UID 2000) to satisfy Claude Code's security requirements when using `--dangerously-skip-permissions`.
169
+
170
+ ### Environment Variables
171
+
172
+ Create a `.env` file from `.env.example`:
173
+
174
+ ```bash
175
+ # Option 1: Anthropic Claude
176
+ ANTHROPIC_API_KEY=sk-ant-xxxxx
177
+
178
+ # Option 2: Z.AI GLM-4.7 (uses ZAI_API_KEY, overrides ANTHROPIC_API_KEY)
179
+ ZAI_API_KEY=your-zai-api-key-here
180
+ ```
181
+
182
+ ### Default Configuration
183
+
184
+ The container **automatically generates** `settings.json` on every startup using your API key from `.env`.
185
+
186
+ - **API key injection**: The entrypoint script reads `ZAI_API_KEY` (or `ANTHROPIC_API_KEY`) and creates a properly configured `settings.json`
187
+ - **Agents**: Pre-defined agent configurations from `.claude/agents/` are copied on first run
188
+ - **Persistence**: Settings are stored in `./claude-data/` volume
189
+
190
+ **Important:** Changes to `./claude-data/settings.json` will be overwritten on container restart. To persist custom settings, modify `.docker/entrypoint.sh`.
191
+
192
+ ### Git Integration
193
+
194
+ Your host's `.gitconfig` is mounted read-only at `/home/claude/.gitconfig`, so commits in the container will be signed with your credentials.
195
+
196
+ ## Manual Docker Commands
197
+
198
+ If you prefer running Docker commands directly:
199
+
200
+ ```bash
201
+ # Build and start
202
+ docker compose up -d --build
203
+
204
+ # Enter container
205
+ docker compose exec claude bash
206
+
207
+ # Run claude directly
208
+ docker compose exec claude claude --dangerously-skip-permissions
209
+
210
+ # Stop
211
+ docker compose down
212
+ ```
213
+
214
+ ## Tips
215
+
216
+ 1. **First setup**: Run `npm run docker:build && npm run docker:up` before first use
217
+ 2. **Persistent config**: Claude Code settings stored in `./claude-data/` (gitignore this)
218
+ 3. **Shared gitconfig**: Commits use your host's git identity
219
+ 4. **Workspace**: Project mounted at `/workspace` in container
220
+ 5. **GLM-4.7 users**: The default `settings.json` is pre-configured for GLM-4.7. Just set your Z.AI API key in `.env`
221
+ 6. **Reset config**: Delete `./claude-data/` and restart to revert to default configuration
222
+ 7. **Custom agents**: Add new `.md` files to `.claude/agents/` or `./claude-data/agents/` before building
223
+
224
+ ### Multi-line Prompts in Docker Container
225
+
226
+ The `/terminal-setup` command doesn't work in Docker containers (detected as `xterm`). Use these alternatives:
227
+
228
+ | Method | How to use |
229
+ |--------|------------|
230
+ | **Ctrl+J** | Press `Ctrl+J` to insert a new line (recommended) |
231
+ | **Backslash** | Type `\` before pressing Enter to continue on next line |
232
+
233
+ Example with backslash:
234
+ ```
235
+ > This is line one\
236
+ and this continues on line two\
237
+ and line three
238
+ ```
239
+
240
+ ## Troubleshooting
241
+
242
+ ### GLM-4.7 Configuration Not Working
243
+
244
+ 1. **Check API key**: Ensure `ZAI_API_KEY` or `ANTHROPIC_API_KEY` is set in your `.env` file
245
+ 2. **Check container logs** to verify settings were generated:
246
+ ```bash
247
+ npm run docker:logs
248
+ # Should show: ✅ Claude Code configured with Z.AI API key
249
+ ```
250
+ 3. **Verify settings.json**: Run `/status` in Claude Code to see current model
251
+ 4. **Debug inside container**:
252
+ ```bash
253
+ npm run docker:shell
254
+ cat ~/.claude/settings.json
255
+ ```
256
+ 5. **Rebuild and restart** (if API key changed):
257
+ ```bash
258
+ npm run docker:down
259
+ npm run docker:up
260
+ ```
261
+
262
+ ### Permission Denied Errors
263
+
264
+ The container runs as non-root user `claude` (UID 2000). If you encounter permission issues:
265
+
266
+ 1. **Check file ownership**: Ensure your project files are accessible by UID 2000
267
+ 2. **Adjust UID**: Modify the UID in Dockerfile if needed (currently 2000)
268
+
269
+ ## Project Structure
270
+
271
+ ```
272
+ create-claude-docker/
273
+ ├── bin/
274
+ │ └── create.js # CLI entry point
275
+ ├── template/ # Boilerplate files copied to new projects
276
+ │ ├── .docker/
277
+ │ │ ├── Dockerfile
278
+ │ │ └── entrypoint.sh
279
+ │ ├── .claude/
280
+ │ │ ├── settings.json
281
+ │ │ └── agents/
282
+ │ ├── .env.example
283
+ │ ├── .gitignore
284
+ │ ├── docker-compose.yml
285
+ │ └── README.md
286
+ ├── package.json
287
+ └── README.md
288
+ ```
289
+
290
+ ## Publishing to npm
291
+
292
+ To publish this package to npm:
293
+
294
+ ```bash
295
+ # Login to npm
296
+ npm login
297
+
298
+ # Update version
299
+ npm version patch # or minor, major
300
+
301
+ # Publish
302
+ npm publish
303
+ ```
304
+
305
+ After publishing, users can create new projects with:
306
+
307
+ ```bash
308
+ npx create-claude-docker my-awesome-project
309
+ ```
310
+
311
+ ## Development
312
+
313
+ To test the CLI locally:
314
+
315
+ ```bash
316
+ # From the repository root
317
+ node bin/create.js test-project
318
+
319
+ # Or link globally
320
+ npm link
321
+ create-claude-docker test-project
322
+ ```
323
+
324
+ ## License
325
+
326
+ MIT
package/bin/create.js ADDED
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * create-claude-docker CLI
5
+ * Creates a new Claude Code Docker project from template
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+ const { execSync } = require('child_process');
12
+
13
+ // ANSI colors
14
+ const colors = {
15
+ reset: '\x1b[0m',
16
+ bright: '\x1b[1m',
17
+ green: '\x1b[32m',
18
+ cyan: '\x1b[36m',
19
+ yellow: '\x1b[33m',
20
+ red: '\x1b[31m',
21
+ dim: '\x1b[2m',
22
+ };
23
+
24
+ const log = {
25
+ info: (msg) => console.log(`${colors.cyan}ℹ${colors.reset} ${msg}`),
26
+ success: (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`),
27
+ warn: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
28
+ error: (msg) => console.log(`${colors.red}✗${colors.reset} ${msg}`),
29
+ step: (msg) => console.log(`${colors.dim} ${msg}${colors.reset}`),
30
+ };
31
+
32
+ const rl = readline.createInterface({
33
+ input: process.stdin,
34
+ output: process.stdout,
35
+ });
36
+
37
+ function ask(question, defaultValue = '') {
38
+ const defaultHint = defaultValue ? ` ${colors.dim}(${defaultValue})${colors.reset}` : '';
39
+ return new Promise((resolve) => {
40
+ rl.question(`${question}${defaultHint}: `, (answer) => {
41
+ resolve(answer.trim() || defaultValue);
42
+ });
43
+ });
44
+ }
45
+
46
+ function copyRecursive(src, dest, replacements = {}) {
47
+ const stats = fs.statSync(src);
48
+
49
+ if (stats.isDirectory()) {
50
+ fs.mkdirSync(dest, { recursive: true });
51
+ const files = fs.readdirSync(src);
52
+ for (const file of files) {
53
+ copyRecursive(path.join(src, file), path.join(dest, file), replacements);
54
+ }
55
+ } else {
56
+ let content = fs.readFileSync(src, 'utf8');
57
+
58
+ // Apply replacements for text files
59
+ if (!isBinaryFile(src)) {
60
+ for (const [key, value] of Object.entries(replacements)) {
61
+ content = content.replace(new RegExp(key, 'g'), value);
62
+ }
63
+ }
64
+
65
+ fs.writeFileSync(dest, content);
66
+ }
67
+ }
68
+
69
+ function isBinaryFile(filePath) {
70
+ const binaryExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.ico', '.woff', '.woff2', '.ttf', '.eot'];
71
+ return binaryExtensions.some(ext => filePath.endsWith(ext));
72
+ }
73
+
74
+ function toKebabCase(str) {
75
+ return str
76
+ .toLowerCase()
77
+ .replace(/[^a-z0-9]+/g, '-')
78
+ .replace(/^-|-$/g, '');
79
+ }
80
+
81
+ async function main() {
82
+ console.log(`
83
+ ${colors.bright}${colors.cyan}╔═══════════════════════════════════════════════════════════╗
84
+ ║ create-claude-docker ║
85
+ ║ Docker-based Claude Code development environment ║
86
+ ╚═══════════════════════════════════════════════════════════╝${colors.reset}
87
+ `);
88
+
89
+ // Get project name from args or prompt
90
+ let projectName = process.argv[2];
91
+ let description = '';
92
+ let author = '';
93
+
94
+ // Parse CLI arguments
95
+ const args = process.argv.slice(2);
96
+ const descIndex = args.findIndex(a => a === '--description' || a === '-d');
97
+ if (descIndex !== -1 && args[descIndex + 1]) {
98
+ description = args[descIndex + 1];
99
+ args.splice(descIndex, 2);
100
+ }
101
+
102
+ const authorIndex = args.findIndex(a => a === '--author' || a === '-a');
103
+ if (authorIndex !== -1 && args[authorIndex + 1]) {
104
+ author = args[authorIndex + 1];
105
+ args.splice(authorIndex, 2);
106
+ }
107
+
108
+ projectName = args[0];
109
+
110
+ // Interactive prompts if not provided
111
+ if (!projectName) {
112
+ projectName = await ask('Project name', 'my-claude-project');
113
+ }
114
+
115
+ projectName = toKebabCase(projectName);
116
+
117
+ if (!description) {
118
+ description = await ask('Description', 'A Claude Code Docker project');
119
+ }
120
+
121
+ if (!author) {
122
+ try {
123
+ author = execSync('git config user.name', { encoding: 'utf8' }).trim();
124
+ } catch {
125
+ author = '';
126
+ }
127
+ author = await ask('Author', author);
128
+ }
129
+
130
+ rl.close();
131
+
132
+ const targetDir = path.resolve(process.cwd(), projectName);
133
+ const templateDir = path.join(__dirname, '..', 'template');
134
+
135
+ // Check if directory exists
136
+ if (fs.existsSync(targetDir)) {
137
+ log.error(`Directory "${projectName}" already exists!`);
138
+ process.exit(1);
139
+ }
140
+
141
+ console.log('');
142
+ log.info(`Creating project "${projectName}"...`);
143
+
144
+ // Create project directory
145
+ fs.mkdirSync(targetDir, { recursive: true });
146
+ log.step('Created project directory');
147
+
148
+ // Copy template files
149
+ copyRecursive(templateDir, targetDir);
150
+ log.step('Copied template files');
151
+
152
+ // Generate package.json
153
+ const packageJson = {
154
+ name: projectName,
155
+ version: '1.0.0',
156
+ description: description,
157
+ author: author,
158
+ scripts: {
159
+ 'docker:build': 'docker compose build',
160
+ 'docker:up': 'docker compose up -d',
161
+ 'docker:down': 'docker compose down',
162
+ 'docker:logs': 'docker compose logs -f',
163
+ 'docker:shell': 'docker compose exec claude bash',
164
+ 'claude': 'docker compose exec claude claude',
165
+ 'claude:unsafe': 'docker compose exec claude claude --dangerously-skip-permissions',
166
+ },
167
+ keywords: ['claude-code', 'docker', 'anthropic', 'z-ai', 'glm-4'],
168
+ };
169
+
170
+ fs.writeFileSync(
171
+ path.join(targetDir, 'package.json'),
172
+ JSON.stringify(packageJson, null, 2) + '\n'
173
+ );
174
+ log.step('Generated package.json');
175
+
176
+ // Create .env from .env.example
177
+ const envExamplePath = path.join(targetDir, '.env.example');
178
+ const envPath = path.join(targetDir, '.env');
179
+ if (fs.existsSync(envExamplePath)) {
180
+ fs.copyFileSync(envExamplePath, envPath);
181
+ log.step('Created .env from .env.example');
182
+ }
183
+
184
+ // Rename gitignore.template to .gitignore (npm pack ignores .gitignore files)
185
+ const gitignoreTemplate = path.join(targetDir, 'gitignore.template');
186
+ const gitignorePath = path.join(targetDir, '.gitignore');
187
+ if (fs.existsSync(gitignoreTemplate)) {
188
+ fs.renameSync(gitignoreTemplate, gitignorePath);
189
+ log.step('Created .gitignore');
190
+ }
191
+
192
+ // Initialize git (optional)
193
+ try {
194
+ execSync('git init', { cwd: targetDir, stdio: 'ignore' });
195
+ execSync('git add .', { cwd: targetDir, stdio: 'ignore' });
196
+ log.step('Initialized git repository');
197
+ } catch {
198
+ log.warn('Could not initialize git repository');
199
+ }
200
+
201
+ console.log('');
202
+ log.success(`Project "${projectName}" created successfully!`);
203
+
204
+ console.log(`
205
+ ${colors.bright}Next steps:${colors.reset}
206
+
207
+ ${colors.cyan}cd ${projectName}${colors.reset}
208
+
209
+ ${colors.dim}# Add your Z.AI API key${colors.reset}
210
+ ${colors.cyan}nano .env${colors.reset}
211
+
212
+ ${colors.dim}# Build and start the container${colors.reset}
213
+ ${colors.cyan}npm run docker:build${colors.reset}
214
+ ${colors.cyan}npm run docker:up${colors.reset}
215
+
216
+ ${colors.dim}# Run Claude Code${colors.reset}
217
+ ${colors.cyan}npm run claude:unsafe${colors.reset}
218
+
219
+ ${colors.dim}Documentation: https://github.com/fishinthenet/create-claude-docker${colors.reset}
220
+ `);
221
+ }
222
+
223
+ main().catch((err) => {
224
+ log.error(err.message);
225
+ process.exit(1);
226
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "create-claude-docker",
3
+ "version": "1.0.1",
4
+ "description": "Create Docker-based Claude Code development environment with Z.AI GLM-4.7 support",
5
+ "author": "Szymon <szymon@fishinthenet.com>",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/fishinthenet/create-claude-docker.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/fishinthenet/create-claude-docker/issues"
13
+ },
14
+ "homepage": "https://github.com/fishinthenet/create-claude-docker#readme",
15
+ "bin": {
16
+ "create-claude-docker": "./bin/create.js"
17
+ },
18
+ "files": [
19
+ "bin",
20
+ "template"
21
+ ],
22
+ "keywords": [
23
+ "claude-code",
24
+ "docker",
25
+ "anthropic",
26
+ "z-ai",
27
+ "glm-4",
28
+ "boilerplate",
29
+ "create",
30
+ "cli"
31
+ ],
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "scripts": {
36
+ "docker:build": "docker compose build",
37
+ "docker:up": "docker compose up -d",
38
+ "docker:down": "docker compose down",
39
+ "docker:logs": "docker compose logs -f",
40
+ "docker:shell": "docker compose exec claude bash",
41
+ "claude": "docker compose exec claude claude",
42
+ "claude:unsafe": "docker compose exec claude claude --dangerously-skip-permissions",
43
+ "test": "node bin/create.js --help"
44
+ }
45
+ }