@alanbem/dclaude 0.0.3 → 0.0.5

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 +0 -11
  2. package/dclaude +118 -137
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -151,16 +151,6 @@ dclaude chrome # Launch Chrome with DevTools
151
151
  dclaude # Claude can now interact with the browser
152
152
  ```
153
153
 
154
- ### Config Mounting
155
-
156
- Mount your host configs for seamless tool integration:
157
-
158
- ```bash
159
- DCLAUDE_MOUNT_CONFIGS=true dclaude
160
- ```
161
-
162
- This mounts (read-only): `.docker/`, `.gitconfig`, `.config/gh/`, `.npmrc`
163
-
164
154
  ### System Context
165
155
 
166
156
  dclaude automatically tells Claude about its container environment so it can give better suggestions:
@@ -184,7 +174,6 @@ DCLAUDE_SYSTEM_CONTEXT=false dclaude
184
174
  | `DCLAUDE_TAG` | `latest` | Docker image tag |
185
175
  | `DCLAUDE_NETWORK` | `auto` | Network mode: `auto`, `host`, `bridge` |
186
176
  | `DCLAUDE_GIT_AUTH` | `auto` | SSH auth: `auto`, `agent-forwarding`, `key-mount`, `none` |
187
- | `DCLAUDE_MOUNT_CONFIGS` | `false` | Mount host config files |
188
177
  | `DCLAUDE_DEBUG` | `false` | Enable debug output |
189
178
  | `DCLAUDE_QUIET` | `false` | Suppress info messages |
190
179
  | `DCLAUDE_NO_UPDATE` | `false` | Skip image update check |
package/dclaude CHANGED
@@ -14,7 +14,6 @@ readonly QUIET="${DCLAUDE_QUIET:-false}"
14
14
  readonly REMOVE_CONTAINER="${DCLAUDE_RM:-false}"
15
15
  # Docker socket will be detected dynamically unless overridden
16
16
  DOCKER_SOCKET="${DCLAUDE_DOCKER_SOCKET:-}"
17
- readonly MOUNT_CONFIGS="${DCLAUDE_MOUNT_CONFIGS:-false}"
18
17
  readonly GIT_AUTH_MODE="${DCLAUDE_GIT_AUTH:-auto}" # auto, agent-forwarding, key-mount, none
19
18
  readonly ENABLE_SYSTEM_CONTEXT="${DCLAUDE_SYSTEM_CONTEXT:-true}" # Inform Claude about dclaude environment
20
19
 
@@ -419,21 +418,19 @@ detect_network_capability() {
419
418
 
420
419
  # Create Docker volumes if they don't exist
421
420
  create_volumes() {
422
- # Create essential volumes for persistence
423
- local volumes=("${VOLUME_PREFIX}-claude" "${VOLUME_PREFIX}-config")
424
-
425
- for volume in "${volumes[@]}"; do
426
- if ! docker volume inspect "$volume" &> /dev/null; then
427
- info "Creating volume: $volume"
428
- if ! docker volume create "$volume" > /dev/null; then
429
- error "Failed to create volume: $volume"
430
- exit 1
431
- fi
432
- debug "Volume created successfully: $volume"
433
- else
434
- debug "Volume exists: $volume"
421
+ # Create essential volume for Claude CLI persistence
422
+ local volume="${VOLUME_PREFIX}-claude"
423
+
424
+ if ! docker volume inspect "$volume" &> /dev/null; then
425
+ info "Creating volume: $volume"
426
+ if ! docker volume create "$volume" > /dev/null; then
427
+ error "Failed to create volume: $volume"
428
+ exit 1
435
429
  fi
436
- done
430
+ debug "Volume created successfully: $volume"
431
+ else
432
+ debug "Volume exists: $volume"
433
+ fi
437
434
  }
438
435
 
439
436
  # Pull or update the Docker image
@@ -736,14 +733,6 @@ handle_git_auth() {
736
733
  local docker_args=()
737
734
  local git_auth_mode="${GIT_AUTH_MODE}"
738
735
 
739
- # If config mounting is enabled and git auth mode is auto, prefer key-mount for consistency
740
- if [[ "$MOUNT_CONFIGS" == "true" ]] && [[ "$git_auth_mode" == "auto" ]]; then
741
- if [[ -d "${HOME}/.ssh" ]] && [[ -r "${HOME}/.ssh" ]]; then
742
- git_auth_mode="key-mount"
743
- debug "Git auth: key-mount (DCLAUDE_MOUNT_CONFIGS=true prefers key mounting)"
744
- fi
745
- fi
746
-
747
736
  # Auto-detect best method if set to auto
748
737
  if [[ "$git_auth_mode" == "auto" ]]; then
749
738
  if [[ -n "${SSH_AUTH_SOCK:-}" ]] && [[ -S "${SSH_AUTH_SOCK}" ]]; then
@@ -827,112 +816,23 @@ handle_git_auth() {
827
816
  fi
828
817
  }
829
818
 
830
- # Mount configuration directories from host
831
- mount_host_configs() {
832
- local docker_args=()
833
- local mounted_count=0
834
-
835
- if [[ "$MOUNT_CONFIGS" != "true" ]]; then
836
- debug "Config mounting disabled (DCLAUDE_MOUNT_CONFIGS=$MOUNT_CONFIGS)"
837
- return 0
838
- fi
839
-
840
- info "Mounting host configurations (read-only)"
841
- debug "SSH authentication handled separately via DCLAUDE_GIT_AUTH"
842
-
843
- # Docker configuration (docker-cli installed)
844
- # Default to true when master switch is enabled
845
- if [[ "${DCLAUDE_MOUNT_DOCKER:-true}" == "true" ]] && [[ -d "${HOME}/.docker" ]]; then
846
- if [[ -r "${HOME}/.docker" ]]; then
847
- docker_args+=(-v "${HOME}/.docker:/home/claude/.docker:ro")
848
- debug "Mounting Docker config: ${HOME}/.docker"
849
- ((mounted_count++))
850
- else
851
- warning "Docker config exists but is not readable: ${HOME}/.docker"
852
- fi
853
- elif [[ "${DCLAUDE_MOUNT_DOCKER:-true}" == "true" ]]; then
854
- debug "Docker config not found: ${HOME}/.docker"
855
- fi
856
-
857
- # GitHub CLI configuration (github-cli installed)
858
- # Default to true when master switch is enabled
859
- if [[ "${DCLAUDE_MOUNT_GH:-true}" == "true" ]] && [[ -d "${HOME}/.config/gh" ]]; then
860
- if [[ -r "${HOME}/.config/gh" ]]; then
861
- docker_args+=(-v "${HOME}/.config/gh:/home/claude/.config/gh:ro")
862
- debug "Mounting GitHub CLI config: ${HOME}/.config/gh"
863
- ((mounted_count++))
864
- else
865
- warning "GitHub CLI config exists but is not readable: ${HOME}/.config/gh"
866
- fi
867
- elif [[ "${DCLAUDE_MOUNT_GH:-true}" == "true" ]]; then
868
- debug "GitHub CLI config not found: ${HOME}/.config/gh"
869
- fi
870
-
871
- # Git configuration (git installed)
872
- # Default to true when master switch is enabled
873
- if [[ "${DCLAUDE_MOUNT_GIT:-true}" == "true" ]] && [[ -f "${HOME}/.gitconfig" ]]; then
874
- if [[ -r "${HOME}/.gitconfig" ]]; then
875
- docker_args+=(-v "${HOME}/.gitconfig:/home/claude/.gitconfig:ro")
876
- debug "Mounting Git config: ${HOME}/.gitconfig"
877
- ((mounted_count++))
878
- else
879
- warning "Git config exists but is not readable: ${HOME}/.gitconfig"
880
- fi
881
- elif [[ "${DCLAUDE_MOUNT_GIT:-true}" == "true" ]]; then
882
- debug "Git config not found: ${HOME}/.gitconfig"
883
- fi
884
-
885
- # NPM configuration (npm installed)
886
- # Default to true when master switch is enabled
887
- if [[ "${DCLAUDE_MOUNT_NPM:-true}" == "true" ]] && [[ -f "${HOME}/.npmrc" ]]; then
888
- if [[ -r "${HOME}/.npmrc" ]]; then
889
- docker_args+=(-v "${HOME}/.npmrc:/home/claude/.npmrc:ro")
890
- debug "Mounting NPM config: ${HOME}/.npmrc"
891
- ((mounted_count++))
892
- else
893
- warning "NPM config exists but is not readable: ${HOME}/.npmrc"
894
- fi
895
- elif [[ "${DCLAUDE_MOUNT_NPM:-true}" == "true" ]]; then
896
- debug "NPM config not found: ${HOME}/.npmrc"
897
- fi
898
-
899
- # Note: AWS CLI, gcloud, kubectl are NOT installed in the container
900
- # These configs will not be mounted unless those tools are added to Dockerfile
901
-
902
- # Security warning with details
903
- if [[ $mounted_count -gt 0 ]]; then
904
- warning "Mounted $mounted_count configuration directories (read-only)"
905
- warning "Security: The following sensitive data is now accessible in the container:"
906
- # SSH is now handled separately, don't warn here
907
- if [[ "${DCLAUDE_MOUNT_DOCKER:-true}" == "true" ]] && [[ -d "${HOME}/.docker" ]] && [[ -r "${HOME}/.docker" ]]; then
908
- warning " - Docker registry authentication tokens"
909
- fi
910
- if [[ "${DCLAUDE_MOUNT_GH:-true}" == "true" ]] && [[ -d "${HOME}/.config/gh" ]] && [[ -r "${HOME}/.config/gh" ]]; then
911
- warning " - GitHub CLI authentication tokens"
912
- fi
913
- if [[ "${DCLAUDE_MOUNT_NPM:-true}" == "true" ]] && [[ -f "${HOME}/.npmrc" ]] && [[ -r "${HOME}/.npmrc" ]]; then
914
- warning " - NPM registry authentication tokens"
915
- fi
916
- warning "Only use in trusted environments!"
917
- fi
918
-
919
- # Print arguments separated by null characters for safe parsing (only if we have args)
920
- if [[ ${#docker_args[@]} -gt 0 ]]; then
921
- printf '%s\0' "${docker_args[@]}"
922
- fi
923
- }
924
-
925
819
  # Detect TTY availability and return appropriate Docker flags
820
+ # Detect TTY status early (before any subshells)
821
+ # Must be done at script top-level since $() subshells don't inherit TTY
822
+ STDIN_IS_TTY=false
823
+ STDOUT_IS_TTY=false
824
+ [[ -t 0 ]] && STDIN_IS_TTY=true
825
+ [[ -t 1 ]] && STDOUT_IS_TTY=true
826
+
926
827
  detect_tty_flags() {
927
828
  local tty_flags=""
928
829
 
929
- # Check if stdin is a TTY
930
- if [[ -t 0 ]]; then
830
+ # Use pre-detected TTY status (can't detect inside subshell)
831
+ if [[ "$STDIN_IS_TTY" == "true" ]]; then
931
832
  tty_flags="-i"
932
833
  fi
933
834
 
934
- # Check if stdout is a TTY
935
- if [[ -t 1 ]]; then
835
+ if [[ "$STDOUT_IS_TTY" == "true" ]]; then
936
836
  tty_flags="${tty_flags} -t"
937
837
  fi
938
838
 
@@ -940,7 +840,7 @@ detect_tty_flags() {
940
840
  tty_flags=$(echo $tty_flags | xargs)
941
841
 
942
842
  if [[ "$DEBUG" == "true" ]]; then
943
- debug "TTY detection: stdin=$(test -t 0 && echo yes || echo no), stdout=$(test -t 1 && echo yes || echo no)"
843
+ debug "TTY detection: stdin=$STDIN_IS_TTY, stdout=$STDOUT_IS_TTY"
944
844
  debug "TTY flags: ${tty_flags:-none}"
945
845
  fi
946
846
 
@@ -1054,10 +954,7 @@ main() {
1054
954
  local resolved_git_auth="$GIT_AUTH_MODE"
1055
955
  if [[ "$GIT_AUTH_MODE" == "auto" ]]; then
1056
956
  # Same auto-detection logic as handle_git_auth()
1057
- if [[ "$MOUNT_CONFIGS" == "true" ]] && [[ -d "${HOME}/.ssh" ]] && [[ -r "${HOME}/.ssh" ]]; then
1058
- resolved_git_auth="key-mount"
1059
- debug "Git auth resolved: key-mount (DCLAUDE_MOUNT_CONFIGS=true)"
1060
- elif [[ -n "${SSH_AUTH_SOCK:-}" ]] && [[ -S "${SSH_AUTH_SOCK}" ]]; then
957
+ if [[ -n "${SSH_AUTH_SOCK:-}" ]] && [[ -S "${SSH_AUTH_SOCK}" ]]; then
1061
958
  resolved_git_auth="agent-forwarding"
1062
959
  debug "Git auth resolved: agent-forwarding (active agent detected)"
1063
960
  elif [[ -d "${HOME}/.ssh" ]] && [[ -r "${HOME}/.ssh" ]]; then
@@ -1180,8 +1077,6 @@ main() {
1180
1077
  -v "${HOST_PATH}:${HOST_PATH}"
1181
1078
  # Mount persistent Claude configuration volume
1182
1079
  -v "${VOLUME_PREFIX}-claude:/home/claude/.claude"
1183
- # Mount persistent config volume (gh, etc.)
1184
- -v "${VOLUME_PREFIX}-config:/home/claude/.config"
1185
1080
  # Set working directory
1186
1081
  -w "${HOST_PATH}"
1187
1082
  # Network mode
@@ -1234,12 +1129,6 @@ main() {
1234
1129
  [[ -n "$ssh_arg" ]] && DOCKER_ARGS+=("$ssh_arg")
1235
1130
  done < <(handle_git_auth)
1236
1131
 
1237
- # Mount host configurations if enabled
1238
- # Use process substitution to preserve null bytes
1239
- while IFS= read -r -d '' config_arg; do
1240
- [[ -n "$config_arg" ]] && DOCKER_ARGS+=("$config_arg")
1241
- done < <(mount_host_configs)
1242
-
1243
1132
  # Add any additional environment variables
1244
1133
  if [[ -n "${CLAUDE_MODEL:-}" ]]; then
1245
1134
  DOCKER_ARGS+=(-e "CLAUDE_MODEL=${CLAUDE_MODEL}")
@@ -1893,6 +1782,94 @@ cmd_rm() {
1893
1782
  exit 0
1894
1783
  }
1895
1784
 
1785
+ # Subcommand: configure git identity
1786
+ cmd_git() {
1787
+ local container_name=$(get_container_name "$HOST_PATH")
1788
+
1789
+ # Check if container exists
1790
+ if ! docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then
1791
+ error "No container found for this directory"
1792
+ info "Run 'dclaude' first to create a container"
1793
+ exit 1
1794
+ fi
1795
+
1796
+ # Check if container is running
1797
+ local container_status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null)
1798
+ if [[ "$container_status" != "running" ]]; then
1799
+ if [[ "$container_status" == "exited" ]]; then
1800
+ info "Starting container: $container_name"
1801
+ docker start "$container_name" >/dev/null
1802
+ sleep 1
1803
+ else
1804
+ error "Container $container_name is in unexpected state: $container_status"
1805
+ exit 1
1806
+ fi
1807
+ fi
1808
+
1809
+ # Check if git config already exists
1810
+ local existing_name existing_email
1811
+ existing_name=$(docker exec -u claude "$container_name" git config --global user.name 2>/dev/null || echo "")
1812
+ existing_email=$(docker exec -u claude "$container_name" git config --global user.email 2>/dev/null || echo "")
1813
+
1814
+ echo ""
1815
+ echo "Git Configuration"
1816
+ echo "─────────────────"
1817
+
1818
+ if [[ -n "$existing_name" && -n "$existing_email" ]]; then
1819
+ echo "Current config:"
1820
+ echo " Name: $existing_name"
1821
+ echo " Email: $existing_email"
1822
+ echo ""
1823
+ read -p "Update? [y/N]: " update
1824
+ if [[ "$update" != "y" && "$update" != "Y" ]]; then
1825
+ exit 0
1826
+ fi
1827
+ fi
1828
+
1829
+ # Try to get from host
1830
+ local host_name host_email
1831
+ host_name=$(git config --global user.name 2>/dev/null || echo "")
1832
+ host_email=$(git config --global user.email 2>/dev/null || echo "")
1833
+
1834
+ local name="" email=""
1835
+
1836
+ if [[ -n "$host_name" && -n "$host_email" ]]; then
1837
+ echo "Found on host:"
1838
+ echo " Name: $host_name"
1839
+ echo " Email: $host_email"
1840
+ echo ""
1841
+ read -p "Copy to container? [Y/n]: " copy
1842
+ if [[ "$copy" != "n" && "$copy" != "N" ]]; then
1843
+ name="$host_name"
1844
+ email="$host_email"
1845
+ fi
1846
+ fi
1847
+
1848
+ # Prompt if not copying from host
1849
+ if [[ -z "$name" ]]; then
1850
+ if [[ -z "$host_name" && -z "$host_email" ]]; then
1851
+ echo "No git config found on host."
1852
+ echo ""
1853
+ fi
1854
+ read -p "Enter your name: " name
1855
+ read -p "Enter your email: " email
1856
+ fi
1857
+
1858
+ # Validate
1859
+ if [[ -z "$name" || -z "$email" ]]; then
1860
+ error "Name and email are required"
1861
+ exit 1
1862
+ fi
1863
+
1864
+ # Save to container
1865
+ docker exec -u claude "$container_name" git config --global user.name "$name"
1866
+ docker exec -u claude "$container_name" git config --global user.email "$email"
1867
+
1868
+ echo ""
1869
+ success "Git config saved"
1870
+ exit 0
1871
+ }
1872
+
1896
1873
  # Initialize HOST_PATH once for all commands
1897
1874
  HOST_PATH=$(get_host_path)
1898
1875
 
@@ -1940,6 +1917,10 @@ if [[ $# -gt 0 ]]; then
1940
1917
  shift
1941
1918
  cmd_ssh "$@"
1942
1919
  ;;
1920
+ git)
1921
+ shift
1922
+ cmd_git "$@"
1923
+ ;;
1943
1924
  --help|-h|help)
1944
1925
  cat << 'EOF'
1945
1926
  dclaude - Dockerized Claude Code Launcher
@@ -1953,6 +1934,7 @@ Usage:
1953
1934
  dclaude stop Stop container for current directory
1954
1935
  dclaude rm [-f] Remove container for current directory
1955
1936
  dclaude ssh Start SSH server for remote access
1937
+ dclaude git Configure git identity (name/email)
1956
1938
  dclaude chrome [options] Launch Chrome with DevTools and MCP integration
1957
1939
  dclaude gh Authenticate GitHub CLI (runs gh auth login)
1958
1940
  dclaude exec [command] Execute command in container (default: bash)
@@ -1963,7 +1945,6 @@ Environment Variables:
1963
1945
  DCLAUDE_TAG Docker image tag (default: latest)
1964
1946
  DCLAUDE_RM Remove container on exit (default: false)
1965
1947
  DCLAUDE_DEBUG Enable debug output (default: false)
1966
- DCLAUDE_MOUNT_CONFIGS Mount host configs (default: false)
1967
1948
  DCLAUDE_GIT_AUTH SSH auth for Git: auto, agent-forwarding, key-mount, none
1968
1949
  DCLAUDE_NETWORK Network mode: auto, host, bridge
1969
1950
  DCLAUDE_DOCKER_SOCKET Override Docker socket path
@@ -2006,7 +1987,7 @@ Examples:
2006
1987
  dclaude chrome --setup-only # Just create .mcp.json, don't launch
2007
1988
  DCLAUDE_CHROME_PROFILE=testing dclaude chrome # Use different profile
2008
1989
 
2009
- # Authenticate GitHub CLI (persists in dclaude-config volume)
1990
+ # Authenticate GitHub CLI (persists until container is removed)
2010
1991
  dclaude gh
2011
1992
 
2012
1993
  # Open bash shell in running container
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alanbem/dclaude",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Dockerized Claude Code CLI launcher with MCP support",
5
5
  "main": "dclaude",
6
6
  "bin": {