@alanbem/dclaude 0.0.9 → 0.0.10

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.
Files changed (3) hide show
  1. package/README.md +72 -0
  2. package/dclaude +178 -48
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -172,6 +172,7 @@ DCLAUDE_SYSTEM_CONTEXT=false dclaude
172
172
  |----------|---------|-------------|
173
173
  | `DCLAUDE_RM` | `false` | Remove container on exit (ephemeral mode) |
174
174
  | `DCLAUDE_TAG` | `latest` | Docker image tag |
175
+ | `DCLAUDE_NAMESPACE` | (none) | Namespace for isolated credentials/config |
175
176
  | `DCLAUDE_NETWORK` | `auto` | Network mode: `auto`, `host`, `bridge` |
176
177
  | `DCLAUDE_GIT_AUTH` | `auto` | SSH auth: `auto`, `agent-forwarding`, `key-mount`, `none` |
177
178
  | `DCLAUDE_DEBUG` | `false` | Enable debug output |
@@ -179,6 +180,64 @@ DCLAUDE_SYSTEM_CONTEXT=false dclaude
179
180
  | `DCLAUDE_NO_UPDATE` | `false` | Skip image update check |
180
181
  | `DCLAUDE_SYSTEM_CONTEXT` | `true` | Inform Claude about container environment |
181
182
 
183
+ ## Configuration File
184
+
185
+ Create a `.dclaude` file at your project root to configure dclaude for that directory tree:
186
+
187
+ ```bash
188
+ # ~/projects/mycompany/.dclaude
189
+ NAMESPACE=mycompany
190
+ NETWORK=host
191
+ DEBUG=true
192
+ ```
193
+
194
+ dclaude walks up the directory tree to find `.dclaude` files. Any dclaude session started from that directory or any subdirectory will use these settings.
195
+
196
+ **Supported variables:**
197
+
198
+ | Variable | Description |
199
+ |----------|-------------|
200
+ | `NAMESPACE` | Isolate credentials/config (see Namespace Isolation) |
201
+ | `NETWORK` | Network mode (`host`, `bridge`) |
202
+ | `GIT_AUTH` | Git auth mode |
203
+ | `DEBUG` | Enable debug output (`true`, `false`) |
204
+ | `CHROME_PORT` | Chrome DevTools port |
205
+
206
+ **Precedence:** Environment variables override `.dclaude` file settings.
207
+
208
+ ## Namespace Isolation
209
+
210
+ Use namespaces to maintain completely separate environments with different credentials and settings.
211
+
212
+ **Use case:** You have both a personal Anthropic subscription and a company subscription. You want to keep them completely separate.
213
+
214
+ **Option 1: Using `.dclaude` file (recommended)**
215
+ ```bash
216
+ # Create config at company project root
217
+ echo "NAMESPACE=mycompany" > ~/projects/mycompany/.dclaude
218
+
219
+ # Now any dclaude in that tree uses company credentials
220
+ cd ~/projects/mycompany/api/src
221
+ dclaude # Uses mycompany namespace automatically
222
+ ```
223
+
224
+ **Option 2: Using environment variable**
225
+ ```bash
226
+ DCLAUDE_NAMESPACE=mycompany dclaude
227
+ ```
228
+
229
+ **Option 3: Shell alias**
230
+ ```bash
231
+ # Add to ~/.bashrc or ~/.zshrc
232
+ alias dclaude-work='DCLAUDE_NAMESPACE=mycompany dclaude'
233
+ ```
234
+
235
+ Each namespace gets its own:
236
+ - Claude credentials and API key
237
+ - Claude settings and preferences
238
+ - Git configuration
239
+ - Container instance
240
+
182
241
  ## Networking
183
242
 
184
243
  dclaude auto-detects the best networking mode:
@@ -259,6 +318,19 @@ ssh-add ~/.ssh/id_ed25519
259
318
  dclaude exec brew install <tool> # This persists
260
319
  ```
261
320
 
321
+ **Directories appear empty inside container? (OrbStack)**
322
+
323
+ This is a [known OrbStack 2.0.x bug](https://github.com/orbstack/orbstack/issues/2103) where VirtioFS caches stale directory entries. Directories that existed before upgrading to OrbStack 2.0 may appear empty inside the container.
324
+
325
+ ```bash
326
+ # Fix: rename the directory to clear the cache
327
+ mv problematic-dir problematic-dir.tmp && mv problematic-dir.tmp problematic-dir
328
+
329
+ # Or restart OrbStack completely (clears all caches)
330
+ ```
331
+
332
+ Upgrading to the latest OrbStack version may also help.
333
+
262
334
  ## Project Structure
263
335
 
264
336
  ```text
package/dclaude CHANGED
@@ -4,25 +4,30 @@
4
4
 
5
5
  set -euo pipefail
6
6
 
7
- # Configuration
7
+ # Early configuration (before config file loading)
8
8
  readonly IMAGE_NAME="${DCLAUDE_REGISTRY:-docker.io}/alanbem/dclaude"
9
9
  readonly IMAGE_TAG="${DCLAUDE_TAG:-latest}"
10
10
  readonly IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
11
11
  readonly VOLUME_PREFIX="dclaude"
12
- readonly DEBUG="${DCLAUDE_DEBUG:-false}"
13
12
  readonly QUIET="${DCLAUDE_QUIET:-false}"
14
13
  readonly REMOVE_CONTAINER="${DCLAUDE_RM:-false}"
14
+ readonly ENABLE_SYSTEM_CONTEXT="${DCLAUDE_SYSTEM_CONTEXT:-true}" # Inform Claude about dclaude environment
15
+
15
16
  # Docker socket will be detected dynamically unless overridden
16
17
  DOCKER_SOCKET="${DCLAUDE_DOCKER_SOCKET:-}"
17
- readonly GIT_AUTH_MODE="${DCLAUDE_GIT_AUTH:-auto}" # auto, agent-forwarding, key-mount, none
18
- readonly ENABLE_SYSTEM_CONTEXT="${DCLAUDE_SYSTEM_CONTEXT:-true}" # Inform Claude about dclaude environment
19
18
 
20
- # Chrome configuration (not readonly to allow --port flag override)
19
+ # Chrome configuration (not readonly to allow --port flag and config file override)
21
20
  CHROME_PROFILE="${DCLAUDE_CHROME_PROFILE:-claude}"
22
- CHROME_PORT="${DCLAUDE_CHROME_PORT:-9222}"
23
21
  CHROME_BIN="${DCLAUDE_CHROME_BIN:-}"
24
22
  CHROME_FLAGS="${DCLAUDE_CHROME_FLAGS:-}"
25
23
 
24
+ # Variables that can be set via .dclaude config file (declared after config loading)
25
+ # - DCLAUDE_NAMESPACE (namespace for volume/container isolation)
26
+ # - DCLAUDE_NETWORK (network mode: host/bridge)
27
+ # - DCLAUDE_GIT_AUTH (git auth mode)
28
+ # - DCLAUDE_DEBUG (enable debug output)
29
+ # - DCLAUDE_CHROME_PORT (chrome devtools port)
30
+
26
31
  # Colors for output (only if terminal supports it)
27
32
  if [[ -t 1 ]]; then
28
33
  readonly RED='\033[0;31m'
@@ -68,17 +73,83 @@ debug() {
68
73
  fi
69
74
  }
70
75
 
71
- # Reset terminal mouse mode after tmux exits
72
- # Prevents iTerm2 warnings about mouse reporting being left on
73
- reset_terminal_mouse() {
74
- # Disable all mouse reporting modes:
75
- # ?1000 - X10 mouse reporting
76
- # ?1002 - Cell motion mouse tracking
77
- # ?1003 - All motion mouse tracking
78
- # ?1006 - SGR extended mouse reporting
79
- printf '\033[?1000l\033[?1002l\033[?1003l\033[?1006l'
76
+ # Find .dclaude config file by walking up directory tree
77
+ find_config_file() {
78
+ local dir="$PWD"
79
+ while [[ "$dir" != "/" ]]; do
80
+ if [[ -f "$dir/.dclaude" ]]; then
81
+ echo "$dir/.dclaude"
82
+ return 0
83
+ fi
84
+ dir=$(dirname "$dir")
85
+ done
86
+ return 1
80
87
  }
81
88
 
89
+ # Load .dclaude config file (env vars take precedence)
90
+ load_config_file() {
91
+ local config_file="$1"
92
+
93
+ while IFS= read -r line || [[ -n "$line" ]]; do
94
+ # Skip comments and empty lines
95
+ [[ "$line" =~ ^[[:space:]]*# ]] && continue
96
+ [[ -z "${line// }" ]] && continue
97
+
98
+ # Parse key=value
99
+ if [[ "$line" =~ ^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*=[[:space:]]*(.*)$ ]]; then
100
+ local key="${BASH_REMATCH[1]}"
101
+ local value="${BASH_REMATCH[2]}"
102
+ # Trim quotes if present
103
+ value="${value#\"}"
104
+ value="${value%\"}"
105
+ value="${value#\'}"
106
+ value="${value%\'}"
107
+
108
+ # Only set if env var not already set (env var takes precedence)
109
+ case "$key" in
110
+ NAMESPACE)
111
+ [[ -z "${DCLAUDE_NAMESPACE:-}" ]] && DCLAUDE_NAMESPACE="$value"
112
+ ;;
113
+ NETWORK)
114
+ [[ -z "${DCLAUDE_NETWORK:-}" ]] && DCLAUDE_NETWORK="$value"
115
+ ;;
116
+ GIT_AUTH)
117
+ [[ -z "${DCLAUDE_GIT_AUTH:-}" ]] && DCLAUDE_GIT_AUTH="$value"
118
+ ;;
119
+ DEBUG)
120
+ [[ -z "${DCLAUDE_DEBUG:-}" ]] && DCLAUDE_DEBUG="$value"
121
+ ;;
122
+ CHROME_PORT)
123
+ [[ -z "${DCLAUDE_CHROME_PORT:-}" ]] && DCLAUDE_CHROME_PORT="$value"
124
+ ;;
125
+ esac
126
+ fi
127
+ done < "$config_file"
128
+ }
129
+
130
+ # Load config file if found (must happen early, before readonly declarations)
131
+ DCLAUDE_CONFIG_FILE=""
132
+ if DCLAUDE_CONFIG_FILE=$(find_config_file); then
133
+ load_config_file "$DCLAUDE_CONFIG_FILE"
134
+ fi
135
+
136
+ # Now set readonly variables that may have been loaded from config file
137
+ readonly DEBUG="${DCLAUDE_DEBUG:-false}"
138
+ readonly GIT_AUTH_MODE="${DCLAUDE_GIT_AUTH:-auto}" # auto, agent-forwarding, key-mount, none
139
+ readonly NAMESPACE="${DCLAUDE_NAMESPACE:-}"
140
+ CHROME_PORT="${DCLAUDE_CHROME_PORT:-9222}"
141
+
142
+ # Show config file if loaded (always at info level, details at debug)
143
+ if [[ -n "$DCLAUDE_CONFIG_FILE" ]]; then
144
+ info "Using config: $DCLAUDE_CONFIG_FILE"
145
+ if [[ "$DEBUG" == "true" ]]; then
146
+ [[ -n "$NAMESPACE" ]] && debug " NAMESPACE=$NAMESPACE"
147
+ [[ -n "${DCLAUDE_NETWORK:-}" ]] && debug " NETWORK=$DCLAUDE_NETWORK"
148
+ [[ -n "${DCLAUDE_GIT_AUTH:-}" ]] && debug " GIT_AUTH=$DCLAUDE_GIT_AUTH"
149
+ [[ -n "${DCLAUDE_CHROME_PORT:-}" ]] && debug " CHROME_PORT=$DCLAUDE_CHROME_PORT"
150
+ fi
151
+ fi
152
+
82
153
  # Detect platform
83
154
  detect_platform() {
84
155
  case "$(uname -s)" in
@@ -416,10 +487,20 @@ detect_network_capability() {
416
487
  echo "$test_result"
417
488
  }
418
489
 
490
+ # Get volume name (includes namespace if set)
491
+ get_volume_name() {
492
+ if [[ -n "$NAMESPACE" ]]; then
493
+ echo "${VOLUME_PREFIX}-${NAMESPACE}-claude"
494
+ else
495
+ echo "${VOLUME_PREFIX}-claude"
496
+ fi
497
+ }
498
+
419
499
  # Create Docker volumes if they don't exist
420
500
  create_volumes() {
421
501
  # Create essential volume for Claude CLI persistence
422
- local volume="${VOLUME_PREFIX}-claude"
502
+ local volume
503
+ volume=$(get_volume_name)
423
504
 
424
505
  if ! docker volume inspect "$volume" &> /dev/null; then
425
506
  info "Creating volume: $volume"
@@ -496,12 +577,17 @@ get_host_path() {
496
577
  echo "$host_path"
497
578
  }
498
579
 
499
- # Generate deterministic container name from path
580
+ # Generate deterministic container name from path (and namespace if set)
500
581
  get_container_name() {
501
582
  local path="${1:-$HOST_PATH}"
583
+ local hash_input="${NAMESPACE}:${path}"
502
584
  local path_hash
503
- path_hash=$(echo -n "$path" | md5sum 2>/dev/null | cut -d' ' -f1 || echo -n "$path" | md5 | cut -d' ' -f1)
504
- echo "dclaude-${path_hash:0:12}"
585
+ path_hash=$(echo -n "$hash_input" | md5sum 2>/dev/null | cut -d' ' -f1 || echo -n "$hash_input" | md5 | cut -d' ' -f1)
586
+ if [[ -n "$NAMESPACE" ]]; then
587
+ echo "dclaude-${NAMESPACE}-${path_hash:0:8}"
588
+ else
589
+ echo "dclaude-${path_hash:0:12}"
590
+ fi
505
591
  }
506
592
 
507
593
  # Generate system context prompt for Claude
@@ -678,10 +764,30 @@ When suggesting commands or file operations, you can treat this environment as i
678
764
  EOF
679
765
  }
680
766
 
767
+ # Get SSH proxy container/volume names (includes namespace if set)
768
+ get_ssh_proxy_container_name() {
769
+ if [[ -n "$NAMESPACE" ]]; then
770
+ echo "dclaude-${NAMESPACE}-ssh-proxy-$(id -u)"
771
+ else
772
+ echo "dclaude-ssh-proxy-$(id -u)"
773
+ fi
774
+ }
775
+
776
+ get_ssh_proxy_volume_name() {
777
+ if [[ -n "$NAMESPACE" ]]; then
778
+ echo "dclaude-${NAMESPACE}-ssh-proxy"
779
+ else
780
+ echo "dclaude-ssh-proxy"
781
+ fi
782
+ }
783
+
681
784
  # Handle SSH authentication based on DCLAUDE_GIT_AUTH mode
682
785
  # Setup SSH proxy container for macOS
683
786
  setup_ssh_proxy_container() {
684
- local proxy_container="dclaude-ssh-proxy-$(id -u)"
787
+ local proxy_container
788
+ local proxy_volume
789
+ proxy_container=$(get_ssh_proxy_container_name)
790
+ proxy_volume=$(get_ssh_proxy_volume_name)
685
791
 
686
792
  # Check if proxy container already exists and is running
687
793
  if docker ps -q -f name="^${proxy_container}$" 2>/dev/null | grep -q .; then
@@ -704,7 +810,7 @@ setup_ssh_proxy_container() {
704
810
  docker run -d \
705
811
  --name "$proxy_container" \
706
812
  -v "/run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock:ro" \
707
- -v "dclaude-ssh-proxy:/tmp/ssh-proxy" \
813
+ -v "${proxy_volume}:/tmp/ssh-proxy" \
708
814
  --rm \
709
815
  alpine:3.19 sh -c '
710
816
  # Install socat
@@ -775,10 +881,12 @@ handle_git_auth() {
775
881
  setup_ssh_proxy_container
776
882
 
777
883
  # Now mount the proxied socket from the shared volume
778
- docker_args+=(-v "dclaude-ssh-proxy:/tmp/ssh-proxy:ro"
884
+ local ssh_proxy_vol
885
+ ssh_proxy_vol=$(get_ssh_proxy_volume_name)
886
+ docker_args+=(-v "${ssh_proxy_vol}:/tmp/ssh-proxy:ro"
779
887
  -e "SSH_AUTH_SOCK=/tmp/ssh-proxy/agent")
780
888
  info "SSH agent forwarding enabled via proxy container"
781
- debug "Mounted SSH proxy volume: dclaude-ssh-proxy:/tmp/ssh-proxy"
889
+ debug "Mounted SSH proxy volume: ${ssh_proxy_vol}:/tmp/ssh-proxy"
782
890
  ;;
783
891
  windows)
784
892
  warning "SSH agent forwarding not fully supported on Windows"
@@ -858,6 +966,7 @@ is_print_mode() {
858
966
  return 1
859
967
  }
860
968
 
969
+
861
970
  # Main execution
862
971
  main() {
863
972
  # No argument parsing - pass everything through to Claude
@@ -986,12 +1095,30 @@ main() {
986
1095
  debug "System context disabled (DCLAUDE_SYSTEM_CONTEXT=$ENABLE_SYSTEM_CONTEXT)"
987
1096
  fi
988
1097
 
1098
+ # Final environment summary (all variables now resolved)
1099
+ if [[ "$DEBUG" == "true" ]]; then
1100
+ debug "Resolved environment:"
1101
+ debug " NAMESPACE=${NAMESPACE:-<not set>}"
1102
+ debug " NETWORK_MODE=$network_mode"
1103
+ debug " GIT_AUTH=$resolved_git_auth"
1104
+ debug " DOCKER_SOCKET=${DOCKER_SOCKET:-<not found>}"
1105
+ debug " CHROME_PORT=${CHROME_PORT:-9222}"
1106
+ debug " SYSTEM_CONTEXT=$ENABLE_SYSTEM_CONTEXT"
1107
+ debug " IMAGE=$IMAGE"
1108
+ debug " HOST_PATH=$HOST_PATH"
1109
+ debug " PLATFORM=$platform"
1110
+ fi
1111
+
989
1112
  # Generate container name based on path (for reuse when DCLAUDE_RM=false)
990
1113
  local container_name=""
991
1114
  if [[ "$REMOVE_CONTAINER" == "false" ]]; then
992
1115
  # Create deterministic name from path hash
993
1116
  container_name=$(get_container_name "$HOST_PATH")
994
- debug "Container name: $container_name (path: $HOST_PATH)"
1117
+ if [[ -n "$NAMESPACE" ]]; then
1118
+ debug "Container name: $container_name (namespace: $NAMESPACE, path: $HOST_PATH)"
1119
+ else
1120
+ debug "Container name: $container_name (path: $HOST_PATH)"
1121
+ fi
995
1122
 
996
1123
  # Check if container already exists
997
1124
  if docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then
@@ -1034,18 +1161,12 @@ main() {
1034
1161
  [[ -n "${TERM_PROGRAM_VERSION:-}" ]] && exec_env_args+=(-e "TERM_PROGRAM_VERSION=${TERM_PROGRAM_VERSION}")
1035
1162
  [[ -n "${TERM_SESSION_ID:-}" ]] && exec_env_args+=(-e "TERM_SESSION_ID=${TERM_SESSION_ID}")
1036
1163
  [[ -n "${COLORTERM:-}" ]] && exec_env_args+=(-e "COLORTERM=${COLORTERM}")
1037
- # Internal env vars for tmux status bar display
1038
- exec_env_args+=(-e "_DCLAUDE_NET=${network_mode}")
1039
- exec_env_args+=(-e "_DCLAUDE_TAG=${DCLAUDE_TAG:-latest}")
1040
- exec_env_args+=(-e "_DCLAUDE_SESSION=${DCLAUDE_TMUX_SESSION:-auto}")
1041
1164
 
1042
1165
  debug "Creating new tmux session running Claude"
1043
1166
  debug "Claude args count: ${#claude_args[@]}, user args: $*"
1044
1167
  info "Starting new Claude session..."
1045
1168
  docker exec -it -u claude "${exec_env_args[@]}" "$container_name" tmux -f /home/claude/.tmux.conf new-session -s "$tmux_session" claude "${claude_args[@]}" "$@"
1046
- local tmux_exit=$?
1047
- reset_terminal_mouse
1048
- exit $tmux_exit
1169
+ exit $?
1049
1170
  else
1050
1171
  # Non-interactive or print mode - run claude directly without tmux
1051
1172
  debug "Non-interactive or print mode, running Claude directly (no tmux)"
@@ -1072,11 +1193,15 @@ main() {
1072
1193
  # Persistent containers run in background and shouldn't have TTY/stdin attached
1073
1194
 
1074
1195
 
1196
+ # Get namespaced volume name
1197
+ local claude_volume
1198
+ claude_volume=$(get_volume_name)
1199
+
1075
1200
  DOCKER_ARGS+=(
1076
1201
  # Mount current directory
1077
1202
  -v "${HOST_PATH}:${HOST_PATH}"
1078
1203
  # Mount persistent Claude configuration volume
1079
- -v "${VOLUME_PREFIX}-claude:/home/claude/.claude"
1204
+ -v "${claude_volume}:/home/claude/.claude"
1080
1205
  # Set working directory
1081
1206
  -w "${HOST_PATH}"
1082
1207
  # Network mode
@@ -1183,18 +1308,12 @@ main() {
1183
1308
  [[ -n "${TERM_PROGRAM_VERSION:-}" ]] && exec_env_args+=(-e "TERM_PROGRAM_VERSION=${TERM_PROGRAM_VERSION}")
1184
1309
  [[ -n "${TERM_SESSION_ID:-}" ]] && exec_env_args+=(-e "TERM_SESSION_ID=${TERM_SESSION_ID}")
1185
1310
  [[ -n "${COLORTERM:-}" ]] && exec_env_args+=(-e "COLORTERM=${COLORTERM}")
1186
- # Internal env vars for tmux status bar display
1187
- exec_env_args+=(-e "_DCLAUDE_NET=${network_mode}")
1188
- exec_env_args+=(-e "_DCLAUDE_TAG=${DCLAUDE_TAG:-latest}")
1189
- exec_env_args+=(-e "_DCLAUDE_SESSION=${DCLAUDE_TMUX_SESSION:-auto}")
1190
1311
 
1191
1312
  debug "Creating new tmux session running Claude"
1192
1313
  debug "Claude args count: ${#claude_args[@]}, user args: $*"
1193
1314
  info "Starting new Claude session..."
1194
1315
  docker exec -it -u claude "${exec_env_args[@]}" "$container_name" tmux -f /home/claude/.tmux.conf new-session -s "$tmux_session" claude "${claude_args[@]}" "$@"
1195
- local tmux_exit=$?
1196
- reset_terminal_mouse
1197
- exit $tmux_exit
1316
+ exit $?
1198
1317
  else
1199
1318
  # Non-interactive or print mode - run claude directly without tmux
1200
1319
  debug "Non-interactive or print mode, running Claude directly (no tmux)"
@@ -1341,9 +1460,7 @@ cmd_attach() {
1341
1460
  # Attach to existing session
1342
1461
  info "Attaching to session: $session_name"
1343
1462
  docker exec -it -u claude "${exec_env_args[@]}" "$container_name" tmux -f /home/claude/.tmux.conf attach-session -t "$session_name"
1344
- local tmux_exit=$?
1345
- reset_terminal_mouse
1346
- exit $tmux_exit
1463
+ exit $?
1347
1464
  }
1348
1465
 
1349
1466
  # Subcommand: launch Chrome with DevTools and ensure MCP configured
@@ -1532,16 +1649,16 @@ cmd_update() {
1532
1649
  fi
1533
1650
 
1534
1651
  info "Updating Claude CLI..."
1535
- local npm_output
1536
- if npm_output=$(docker exec -u claude "$container_name" npm update -g @anthropic-ai/claude-code 2>&1); then
1652
+ local update_output
1653
+ if update_output=$(docker exec -u claude "$container_name" claude update 2>&1); then
1537
1654
  # Show command and output together, indented to align with "Debug: " prefix
1538
- debug "npm update -g @anthropic-ai/claude-code
1539
- $(echo "$npm_output" | sed 's/^/ /')"
1655
+ debug "claude update
1656
+ $(echo "$update_output" | sed 's/^/ /')"
1540
1657
  local new_version=$(docker exec -u claude "$container_name" claude --version 2>/dev/null | head -1)
1541
1658
  success "Claude CLI updated: $new_version"
1542
1659
  else
1543
- debug "npm update -g @anthropic-ai/claude-code
1544
- $(echo "$npm_output" | sed 's/^/ /')"
1660
+ debug "claude update
1661
+ $(echo "$update_output" | sed 's/^/ /')"
1545
1662
  error "Failed to update Claude CLI"
1546
1663
  exit 1
1547
1664
  fi
@@ -1945,6 +2062,7 @@ Environment Variables:
1945
2062
  DCLAUDE_TAG Docker image tag (default: latest)
1946
2063
  DCLAUDE_RM Remove container on exit (default: false)
1947
2064
  DCLAUDE_DEBUG Enable debug output (default: false)
2065
+ DCLAUDE_NAMESPACE Namespace for isolated credentials/config
1948
2066
  DCLAUDE_GIT_AUTH SSH auth for Git: auto, agent-forwarding, key-mount, none
1949
2067
  DCLAUDE_NETWORK Network mode: auto, host, bridge
1950
2068
  DCLAUDE_DOCKER_SOCKET Override Docker socket path
@@ -1954,6 +2072,14 @@ Environment Variables:
1954
2072
  DCLAUDE_CHROME_PORT Chrome debugging port (default: 9222)
1955
2073
  DCLAUDE_CHROME_FLAGS Additional Chrome flags (default: empty)
1956
2074
 
2075
+ Configuration File (.dclaude):
2076
+ Create a .dclaude file at project root to configure dclaude for that tree:
2077
+ NAMESPACE=mycompany
2078
+ NETWORK=host
2079
+ DEBUG=true
2080
+ dclaude walks up the directory tree to find .dclaude files.
2081
+ Environment variables override .dclaude settings.
2082
+
1957
2083
  Examples:
1958
2084
  # Start new Claude session (auto-generated session name)
1959
2085
  dclaude
@@ -1970,6 +2096,10 @@ Examples:
1970
2096
  # Start with ephemeral container (removed on exit)
1971
2097
  DCLAUDE_RM=true dclaude
1972
2098
 
2099
+ # Use namespace for isolated credentials (personal vs company)
2100
+ DCLAUDE_NAMESPACE=mycompany dclaude
2101
+ # Or create .dclaude file: echo "NAMESPACE=mycompany" > ~/projects/mycompany/.dclaude
2102
+
1973
2103
  # Update image and restart container
1974
2104
  dclaude pull # Pull latest image
1975
2105
  dclaude update # Update Claude CLI in container
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alanbem/dclaude",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Dockerized Claude Code CLI launcher with MCP support",
5
5
  "main": "dclaude",
6
6
  "bin": {