@alanbem/dclaude 0.0.11 → 0.0.12

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 +53 -0
  2. package/dclaude +101 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -151,6 +151,21 @@ dclaude chrome # Launch Chrome with DevTools
151
151
  dclaude # Claude can now interact with the browser
152
152
  ```
153
153
 
154
+ ### iTerm2 Shell Integration
155
+
156
+ If you use iTerm2 on macOS, dclaude automatically enables [iTerm2 Shell Integration](https://iterm2.com/documentation-shell-integration.html):
157
+
158
+ - **Click URLs in output** - Opens in your Mac's browser
159
+ - **imgcat** - Display images inline in terminal
160
+ - **it2copy** - Copy to Mac clipboard from inside container
161
+ - **Marks** - Navigate between command prompts
162
+
163
+ This only activates when running in iTerm2. To disable:
164
+
165
+ ```bash
166
+ DCLAUDE_ITERM2=false dclaude
167
+ ```
168
+
154
169
  ### System Context
155
170
 
156
171
  dclaude automatically tells Claude about its container environment so it can give better suggestions:
@@ -175,10 +190,12 @@ DCLAUDE_SYSTEM_CONTEXT=false dclaude
175
190
  | `DCLAUDE_NAMESPACE` | (none) | Namespace for isolated credentials/config |
176
191
  | `DCLAUDE_NETWORK` | `auto` | Network mode: `auto`, `host`, `bridge` |
177
192
  | `DCLAUDE_GIT_AUTH` | `auto` | SSH auth: `auto`, `agent-forwarding`, `key-mount`, `none` |
193
+ | `DCLAUDE_MOUNT_ROOT` | (working dir) | Mount parent directory for sibling access |
178
194
  | `DCLAUDE_DEBUG` | `false` | Enable debug output |
179
195
  | `DCLAUDE_QUIET` | `false` | Suppress info messages |
180
196
  | `DCLAUDE_NO_UPDATE` | `false` | Skip image update check |
181
197
  | `DCLAUDE_SYSTEM_CONTEXT` | `true` | Inform Claude about container environment |
198
+ | `DCLAUDE_ITERM2` | `true` | Enable iTerm2 shell integration (only affects iTerm2) |
182
199
 
183
200
  ## Configuration File
184
201
 
@@ -200,6 +217,7 @@ dclaude walks up the directory tree to find `.dclaude` files. Any dclaude sessio
200
217
  | `NAMESPACE` | Isolate credentials/config (see Namespace Isolation) |
201
218
  | `NETWORK` | Network mode (`host`, `bridge`) |
202
219
  | `GIT_AUTH` | Git auth mode |
220
+ | `MOUNT_ROOT` | Mount directory (relative to config file, or absolute path) |
203
221
  | `DEBUG` | Enable debug output (`true`, `false`) |
204
222
  | `CHROME_PORT` | Chrome DevTools port |
205
223
 
@@ -238,6 +256,41 @@ Each namespace gets its own:
238
256
  - Git configuration
239
257
  - Container instance
240
258
 
259
+ ## Mount Root (Parent Directory Access)
260
+
261
+ By default, dclaude only mounts the current working directory. Use `MOUNT_ROOT` to mount a parent directory, enabling access to sibling directories.
262
+
263
+ **Use case:** You're working in a subdirectory but need access to related projects:
264
+
265
+ ```text
266
+ /Users/alan/projects/mycompany/
267
+ ├── shared-libs/ # Common libraries
268
+ ├── api-service/ # API backend
269
+ ├── web-app/ # Frontend
270
+ └── infrastructure/
271
+ └── terraform/ # ← You're here, but need access to siblings
272
+ ```
273
+
274
+ **Option 1: Using `.dclaude` file (recommended)**
275
+ ```bash
276
+ # Create config at the directory you want as mount root
277
+ echo "MOUNT_ROOT=." > ~/projects/mycompany/.dclaude
278
+
279
+ # Relative paths are resolved from config file's directory
280
+ echo "MOUNT_ROOT=.." > ~/projects/mycompany/subdir/.dclaude # mounts mycompany/
281
+ ```
282
+
283
+ **Option 2: Using environment variable**
284
+ ```bash
285
+ # Relative path (from working directory)
286
+ DCLAUDE_MOUNT_ROOT=../.. dclaude
287
+
288
+ # Absolute path
289
+ DCLAUDE_MOUNT_ROOT=/Users/alan/projects/mycompany dclaude
290
+ ```
291
+
292
+ Now Claude can see and work with all sibling directories while your working directory remains `terraform/`.
293
+
241
294
  ## Networking
242
295
 
243
296
  dclaude auto-detects the best networking mode:
package/dclaude CHANGED
@@ -27,6 +27,7 @@ CHROME_FLAGS="${DCLAUDE_CHROME_FLAGS:-}"
27
27
  # - DCLAUDE_GIT_AUTH (git auth mode)
28
28
  # - DCLAUDE_DEBUG (enable debug output)
29
29
  # - DCLAUDE_CHROME_PORT (chrome devtools port)
30
+ # - DCLAUDE_MOUNT_ROOT (mount a parent directory instead of working directory)
30
31
 
31
32
  # Colors for output (only if terminal supports it)
32
33
  if [[ -t 1 ]]; then
@@ -122,6 +123,18 @@ load_config_file() {
122
123
  CHROME_PORT)
123
124
  [[ -z "${DCLAUDE_CHROME_PORT:-}" ]] && DCLAUDE_CHROME_PORT="$value"
124
125
  ;;
126
+ MOUNT_ROOT)
127
+ if [[ -z "${DCLAUDE_MOUNT_ROOT:-}" ]]; then
128
+ # Resolve relative paths relative to config file's directory
129
+ if [[ "$value" != /* ]]; then
130
+ local config_dir
131
+ config_dir=$(dirname "$config_file")
132
+ DCLAUDE_MOUNT_ROOT=$(cd "$config_dir" && cd "$value" 2>/dev/null && pwd)
133
+ else
134
+ DCLAUDE_MOUNT_ROOT="$value"
135
+ fi
136
+ fi
137
+ ;;
125
138
  esac
126
139
  fi
127
140
  done < "$config_file"
@@ -147,6 +160,7 @@ if [[ -n "$DCLAUDE_CONFIG_FILE" ]]; then
147
160
  [[ -n "${DCLAUDE_NETWORK:-}" ]] && debug " NETWORK=$DCLAUDE_NETWORK"
148
161
  [[ -n "${DCLAUDE_GIT_AUTH:-}" ]] && debug " GIT_AUTH=$DCLAUDE_GIT_AUTH"
149
162
  [[ -n "${DCLAUDE_CHROME_PORT:-}" ]] && debug " CHROME_PORT=$DCLAUDE_CHROME_PORT"
163
+ [[ -n "${DCLAUDE_MOUNT_ROOT:-}" ]] && debug " MOUNT_ROOT=$DCLAUDE_MOUNT_ROOT"
150
164
  fi
151
165
  fi
152
166
 
@@ -577,6 +591,55 @@ get_host_path() {
577
591
  echo "$host_path"
578
592
  }
579
593
 
594
+ # Compute mount root path from DCLAUDE_MOUNT_ROOT
595
+ # Supports: absolute paths, relative paths (../, ../../, etc.)
596
+ # Returns: Absolute path to mount root, or HOST_PATH if not set
597
+ get_mount_root() {
598
+ local host_path="$1"
599
+ local mount_root="${DCLAUDE_MOUNT_ROOT:-}"
600
+
601
+ # If not set, use host path (current behavior)
602
+ if [[ -z "$mount_root" ]]; then
603
+ echo "$host_path"
604
+ return 0
605
+ fi
606
+
607
+ local resolved_root
608
+
609
+ # Handle relative paths (resolve relative to host_path)
610
+ if [[ "$mount_root" != /* ]]; then
611
+ # Relative path - resolve it
612
+ resolved_root=$(cd "$host_path" && cd "$mount_root" 2>/dev/null && pwd) || {
613
+ error "Mount root path not accessible: $mount_root (relative to $host_path)"
614
+ exit 1
615
+ }
616
+ else
617
+ # Absolute path - use directly
618
+ resolved_root="$mount_root"
619
+ fi
620
+
621
+ # Validate mount root exists
622
+ if [[ ! -d "$resolved_root" ]]; then
623
+ error "Mount root directory does not exist: $resolved_root"
624
+ exit 1
625
+ fi
626
+
627
+ # Validate that host_path is under mount_root
628
+ # Use realpath to normalize paths for comparison
629
+ local real_host real_root
630
+ real_host=$(cd "$host_path" && pwd -P)
631
+ real_root=$(cd "$resolved_root" && pwd -P)
632
+
633
+ if [[ "$real_host" != "$real_root" && "$real_host" != "$real_root"/* ]]; then
634
+ error "Working directory is not under mount root"
635
+ error " Working directory: $real_host"
636
+ error " Mount root: $real_root"
637
+ exit 1
638
+ fi
639
+
640
+ echo "$resolved_root"
641
+ }
642
+
580
643
  # Generate deterministic container name from path (and namespace if set)
581
644
  get_container_name() {
582
645
  local path="${1:-$HOST_PATH}"
@@ -976,6 +1039,9 @@ main() {
976
1039
 
977
1040
  info "Verifying environment..."
978
1041
  debug "Host path: $HOST_PATH"
1042
+ if [[ "$MOUNT_ROOT" != "$HOST_PATH" ]]; then
1043
+ debug "Mount root: $MOUNT_ROOT"
1044
+ fi
979
1045
 
980
1046
  # Check prerequisites
981
1047
  check_docker
@@ -1108,6 +1174,9 @@ main() {
1108
1174
  debug " SYSTEM_CONTEXT=$ENABLE_SYSTEM_CONTEXT"
1109
1175
  debug " IMAGE=$IMAGE"
1110
1176
  debug " HOST_PATH=$HOST_PATH"
1177
+ if [[ "$MOUNT_ROOT" != "$HOST_PATH" ]]; then
1178
+ debug " MOUNT_ROOT=$MOUNT_ROOT"
1179
+ fi
1111
1180
  debug " PLATFORM=$platform"
1112
1181
  fi
1113
1182
 
@@ -1145,6 +1214,16 @@ main() {
1145
1214
  done
1146
1215
  fi
1147
1216
 
1217
+ # Ensure SSH proxy is running if container uses agent forwarding (macOS)
1218
+ if [[ "$platform" == "darwin" ]]; then
1219
+ local container_ssh_sock
1220
+ container_ssh_sock=$(docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' "$container_name" 2>/dev/null | grep "^SSH_AUTH_SOCK=" | cut -d= -f2)
1221
+ if [[ "$container_ssh_sock" == "/tmp/ssh-proxy/agent" ]]; then
1222
+ debug "Container uses SSH agent forwarding, ensuring proxy is running"
1223
+ setup_ssh_proxy_container
1224
+ fi
1225
+ fi
1226
+
1148
1227
  # Check if interactive (TTY available) and not in print mode
1149
1228
  if [[ -n "$tty_flags" ]] && ! should_skip_tmux "${claude_args[@]}" "$@"; then
1150
1229
  # Interactive and not print mode - use tmux for session management
@@ -1163,6 +1242,7 @@ main() {
1163
1242
  [[ -n "${TERM_PROGRAM_VERSION:-}" ]] && exec_env_args+=(-e "TERM_PROGRAM_VERSION=${TERM_PROGRAM_VERSION}")
1164
1243
  [[ -n "${TERM_SESSION_ID:-}" ]] && exec_env_args+=(-e "TERM_SESSION_ID=${TERM_SESSION_ID}")
1165
1244
  [[ -n "${COLORTERM:-}" ]] && exec_env_args+=(-e "COLORTERM=${COLORTERM}")
1245
+ [[ -n "${DCLAUDE_ITERM2:-}" ]] && exec_env_args+=(-e "DCLAUDE_ITERM2=${DCLAUDE_ITERM2}")
1166
1246
 
1167
1247
  debug "Creating new tmux session running Claude"
1168
1248
  debug "Claude args count: ${#claude_args[@]}, user args: $*"
@@ -1200,11 +1280,11 @@ main() {
1200
1280
  claude_volume=$(get_volume_name)
1201
1281
 
1202
1282
  DOCKER_ARGS+=(
1203
- # Mount current directory
1204
- -v "${HOST_PATH}:${HOST_PATH}"
1283
+ # Mount directory tree (mount root allows access to parent directories)
1284
+ -v "${MOUNT_ROOT}:${MOUNT_ROOT}"
1205
1285
  # Mount persistent Claude configuration volume
1206
1286
  -v "${claude_volume}:/home/claude/.claude"
1207
- # Set working directory
1287
+ # Set working directory (within the mounted tree)
1208
1288
  -w "${HOST_PATH}"
1209
1289
  # Network mode
1210
1290
  --network="$network_mode"
@@ -1240,6 +1320,11 @@ main() {
1240
1320
  DOCKER_ARGS+=(-e "COLORTERM=${COLORTERM}")
1241
1321
  fi
1242
1322
 
1323
+ # Pass through iTerm2 integration opt-out if set
1324
+ if [[ -n "${DCLAUDE_ITERM2:-}" ]]; then
1325
+ DOCKER_ARGS+=(-e "DCLAUDE_ITERM2=${DCLAUDE_ITERM2}")
1326
+ fi
1327
+
1243
1328
  # Mount Docker socket if detected (detection done earlier for system context)
1244
1329
  if [[ -n "$DOCKER_SOCKET" ]] && [[ -S "$DOCKER_SOCKET" ]]; then
1245
1330
  DOCKER_ARGS+=(-v "${DOCKER_SOCKET}:/var/run/docker.sock")
@@ -1310,6 +1395,7 @@ main() {
1310
1395
  [[ -n "${TERM_PROGRAM_VERSION:-}" ]] && exec_env_args+=(-e "TERM_PROGRAM_VERSION=${TERM_PROGRAM_VERSION}")
1311
1396
  [[ -n "${TERM_SESSION_ID:-}" ]] && exec_env_args+=(-e "TERM_SESSION_ID=${TERM_SESSION_ID}")
1312
1397
  [[ -n "${COLORTERM:-}" ]] && exec_env_args+=(-e "COLORTERM=${COLORTERM}")
1398
+ [[ -n "${DCLAUDE_ITERM2:-}" ]] && exec_env_args+=(-e "DCLAUDE_ITERM2=${DCLAUDE_ITERM2}")
1313
1399
 
1314
1400
  debug "Creating new tmux session running Claude"
1315
1401
  debug "Claude args count: ${#claude_args[@]}, user args: $*"
@@ -1458,6 +1544,7 @@ cmd_attach() {
1458
1544
  [[ -n "${TERM_PROGRAM_VERSION:-}" ]] && exec_env_args+=(-e "TERM_PROGRAM_VERSION=${TERM_PROGRAM_VERSION}")
1459
1545
  [[ -n "${TERM_SESSION_ID:-}" ]] && exec_env_args+=(-e "TERM_SESSION_ID=${TERM_SESSION_ID}")
1460
1546
  [[ -n "${COLORTERM:-}" ]] && exec_env_args+=(-e "COLORTERM=${COLORTERM}")
1547
+ [[ -n "${DCLAUDE_ITERM2:-}" ]] && exec_env_args+=(-e "DCLAUDE_ITERM2=${DCLAUDE_ITERM2}")
1461
1548
 
1462
1549
  # Attach to existing session
1463
1550
  info "Attaching to session: $session_name"
@@ -1514,7 +1601,7 @@ cmd_chrome() {
1514
1601
  fi
1515
1602
 
1516
1603
  # 2. Setup profile directory
1517
- local profile_dir="$HOST_PATH/.dclaude/chrome/profiles/$CHROME_PROFILE"
1604
+ local profile_dir="$HOST_PATH/.dclaude.d/chrome/profiles/$CHROME_PROFILE"
1518
1605
  mkdir -p "$profile_dir"
1519
1606
  debug "Profile directory: $profile_dir"
1520
1607
 
@@ -1989,8 +2076,9 @@ cmd_git() {
1989
2076
  exit 0
1990
2077
  }
1991
2078
 
1992
- # Initialize HOST_PATH once for all commands
2079
+ # Initialize HOST_PATH and MOUNT_ROOT once for all commands
1993
2080
  HOST_PATH=$(get_host_path)
2081
+ MOUNT_ROOT=$(get_mount_root "$HOST_PATH")
1994
2082
 
1995
2083
  # Handle subcommands
1996
2084
  if [[ $# -gt 0 ]]; then
@@ -2067,6 +2155,7 @@ Environment Variables:
2067
2155
  DCLAUDE_NAMESPACE Namespace for isolated credentials/config
2068
2156
  DCLAUDE_GIT_AUTH SSH auth for Git: auto, agent-forwarding, key-mount, none
2069
2157
  DCLAUDE_NETWORK Network mode: auto, host, bridge
2158
+ DCLAUDE_MOUNT_ROOT Mount parent directory (absolute or relative path)
2070
2159
  DCLAUDE_DOCKER_SOCKET Override Docker socket path
2071
2160
  DCLAUDE_TMUX_SESSION Custom tmux session name (default: claude-TIMESTAMP)
2072
2161
  DCLAUDE_CHROME_BIN Chrome executable path (auto-detected if not set)
@@ -2079,6 +2168,8 @@ Configuration File (.dclaude):
2079
2168
  NAMESPACE=mycompany
2080
2169
  NETWORK=host
2081
2170
  DEBUG=true
2171
+ MOUNT_ROOT=. # Mount config file's directory
2172
+ MOUNT_ROOT=.. # Mount parent of config file's directory
2082
2173
  dclaude walks up the directory tree to find .dclaude files.
2083
2174
  Environment variables override .dclaude settings.
2084
2175
 
@@ -2102,6 +2193,11 @@ Examples:
2102
2193
  DCLAUDE_NAMESPACE=mycompany dclaude
2103
2194
  # Or create .dclaude file: echo "NAMESPACE=mycompany" > ~/projects/mycompany/.dclaude
2104
2195
 
2196
+ # Mount parent directory to access sibling directories
2197
+ DCLAUDE_MOUNT_ROOT=.. dclaude # Relative path
2198
+ DCLAUDE_MOUNT_ROOT=/Users/alan/projects dclaude # Absolute path
2199
+ # Or in .dclaude file: MOUNT_ROOT=..
2200
+
2105
2201
  # Update image and restart container
2106
2202
  dclaude pull # Pull latest image
2107
2203
  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.11",
3
+ "version": "0.0.12",
4
4
  "description": "Dockerized Claude Code CLI launcher with MCP support",
5
5
  "main": "dclaude",
6
6
  "bin": {