@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.
- package/README.md +0 -11
- package/dclaude +118 -137
- 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
|
|
423
|
-
local
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
930
|
-
if [[
|
|
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
|
-
|
|
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=$
|
|
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 [[
|
|
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
|
|
1990
|
+
# Authenticate GitHub CLI (persists until container is removed)
|
|
2010
1991
|
dclaude gh
|
|
2011
1992
|
|
|
2012
1993
|
# Open bash shell in running container
|