plonecli 7.0a4__tar.gz → 7.0.0b2__tar.gz

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 (92) hide show
  1. plonecli-7.0.0b2/.claude/statusline-command.sh +36 -0
  2. plonecli-7.0.0b2/.devcontainer/Dockerfile +102 -0
  3. plonecli-7.0.0b2/.devcontainer/devcontainer.json +59 -0
  4. plonecli-7.0.0b2/.devcontainer/init-firewall.sh +163 -0
  5. plonecli-7.0.0b2/.devcontainer/setup-claude.sh +33 -0
  6. plonecli-7.0.0b2/.editorconfig +21 -0
  7. plonecli-7.0.0b2/.github/ISSUE_TEMPLATE.md +15 -0
  8. plonecli-7.0.0b2/.github/workflows/python-package.yml +40 -0
  9. plonecli-7.0.0b2/.gitignore +83 -0
  10. plonecli-7.0.0b2/.readthedocs.yaml +35 -0
  11. plonecli-7.0.0b2/AUTHORS.md +9 -0
  12. plonecli-7.0a4/CHANGES.rst → plonecli-7.0.0b2/CHANGES.md +78 -71
  13. plonecli-7.0.0b2/CLAUDE.md +2 -0
  14. plonecli-7.0a4/CONTRIBUTING.rst → plonecli-7.0.0b2/CONTRIBUTING.md +42 -44
  15. plonecli-7.0.0b2/PKG-INFO +475 -0
  16. plonecli-7.0.0b2/README.md +432 -0
  17. plonecli-7.0.0b2/ROADMAP.md +138 -0
  18. plonecli-7.0.0b2/devcontainer.sh +49 -0
  19. plonecli-7.0.0b2/docs/.gitignore +3 -0
  20. plonecli-7.0.0b2/docs/authors.md +2 -0
  21. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/conf.py +5 -2
  22. plonecli-7.0.0b2/docs/contributing.md +2 -0
  23. plonecli-7.0.0b2/docs/history.md +2 -0
  24. plonecli-7.0.0b2/docs/index.md +11 -0
  25. plonecli-7.0.0b2/docs/installation.md +81 -0
  26. plonecli-7.0.0b2/docs/readme.md +2 -0
  27. plonecli-7.0.0b2/jsconfig.json +24 -0
  28. plonecli-7.0.0b2/plonecli/__init__.py +1 -0
  29. plonecli-7.0.0b2/plonecli/cli.py +361 -0
  30. plonecli-7.0.0b2/plonecli/config.py +127 -0
  31. {plonecli-7.0a4 → plonecli-7.0.0b2}/plonecli/exceptions.py +6 -8
  32. plonecli-7.0.0b2/plonecli/plone_versions.py +122 -0
  33. plonecli-7.0.0b2/plonecli/project.py +160 -0
  34. plonecli-7.0.0b2/plonecli/registry.py +205 -0
  35. plonecli-7.0.0b2/plonecli/templates.py +165 -0
  36. plonecli-7.0.0b2/plonecli/updater.py +98 -0
  37. plonecli-7.0.0b2/plonecli.md +125 -0
  38. plonecli-7.0.0b2/pyproject.toml +69 -0
  39. plonecli-7.0.0b2/tests/conftest.py +1 -0
  40. plonecli-7.0.0b2/tests/test_config.py +152 -0
  41. plonecli-7.0.0b2/tests/test_plonecli.py +235 -0
  42. plonecli-7.0.0b2/tests/test_project.py +151 -0
  43. plonecli-7.0.0b2/tests/test_registry.py +290 -0
  44. plonecli-7.0.0b2/tests/test_templates.py +105 -0
  45. plonecli-7.0.0b2/tests/test_theme_barceloneta_integration.py +112 -0
  46. plonecli-7.0.0b2/tests/test_updater.py +95 -0
  47. plonecli-7.0.0b2/tox.ini +42 -0
  48. plonecli-7.0.0b2/uv.lock +1228 -0
  49. plonecli-7.0a4/AUTHORS.rst +0 -13
  50. plonecli-7.0a4/PKG-INFO +0 -693
  51. plonecli-7.0a4/README.rst +0 -373
  52. plonecli-7.0a4/docs/authors.rst +0 -1
  53. plonecli-7.0a4/docs/contributing.rst +0 -1
  54. plonecli-7.0a4/docs/history.rst +0 -1
  55. plonecli-7.0a4/docs/index.rst +0 -14
  56. plonecli-7.0a4/docs/installation.rst +0 -50
  57. plonecli-7.0a4/docs/readme.rst +0 -1
  58. plonecli-7.0a4/plonecli/__init__.py +0 -9
  59. plonecli-7.0a4/plonecli/cli.py +0 -293
  60. plonecli-7.0a4/plonecli/configure_mrbob/.mrbob.ini +0 -64
  61. plonecli-7.0a4/plonecli/configure_mrbob.py +0 -230
  62. plonecli-7.0a4/plonecli/registry.py +0 -167
  63. plonecli-7.0a4/plonecli.egg-info/PKG-INFO +0 -693
  64. plonecli-7.0a4/plonecli.egg-info/SOURCES.txt +0 -47
  65. plonecli-7.0a4/plonecli.egg-info/dependency_links.txt +0 -1
  66. plonecli-7.0a4/plonecli.egg-info/entry_points.txt +0 -2
  67. plonecli-7.0a4/plonecli.egg-info/not-zip-safe +0 -1
  68. plonecli-7.0a4/plonecli.egg-info/requires.txt +0 -14
  69. plonecli-7.0a4/plonecli.egg-info/top_level.txt +0 -1
  70. plonecli-7.0a4/plonecli.rst +0 -139
  71. plonecli-7.0a4/plonecli_autocomplete.sh +0 -8
  72. plonecli-7.0a4/setup.cfg +0 -72
  73. plonecli-7.0a4/setup.py +0 -40
  74. plonecli-7.0a4/tests/conftest.py +0 -11
  75. plonecli-7.0a4/tests/test_configure_mrbob.py +0 -226
  76. plonecli-7.0a4/tests/test_plonecli.py +0 -234
  77. plonecli-7.0a4/tests/test_registry.py +0 -108
  78. plonecli-7.0a4/tox.ini +0 -149
  79. {plonecli-7.0a4 → plonecli-7.0.0b2}/LICENSE +0 -0
  80. {plonecli-7.0a4 → plonecli-7.0.0b2}/MANIFEST.in +0 -0
  81. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/Makefile +0 -0
  82. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/make.bat +0 -0
  83. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plone_cli_logo.png +0 -0
  84. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plone_cli_logo.svg +0 -0
  85. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plonecli_add_content_type_optimized.gif +0 -0
  86. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plonecli_add_theme_optimized.gif +0 -0
  87. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plonecli_add_vocabulary_optimized.gif +0 -0
  88. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plonecli_build_optimized.gif +0 -0
  89. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plonecli_create_addon_optimized.gif +0 -0
  90. {plonecli-7.0a4 → plonecli-7.0.0b2}/docs/plonecli_serve_optimized.gif +0 -0
  91. {plonecli-7.0a4 → plonecli-7.0.0b2}/requirements.txt +0 -0
  92. {plonecli-7.0a4 → plonecli-7.0.0b2}/tests/__init__.py +0 -0
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+ input=$(cat)
3
+
4
+ model=$(echo "$input" | jq -r '.model.display_name // "unknown model"')
5
+ output_style=$(echo "$input" | jq -r '.output_style.name // empty')
6
+ used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
7
+ remaining_pct=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')
8
+
9
+ # Build status parts
10
+ parts=()
11
+
12
+ # Model
13
+ parts+=("$model")
14
+
15
+ # Context window
16
+ if [ -n "$used_pct" ] && [ -n "$remaining_pct" ]; then
17
+ ctx=$(printf "ctx: %.0f%% used / %.0f%% left" "$used_pct" "$remaining_pct")
18
+ parts+=("$ctx")
19
+ fi
20
+
21
+ # Output style / thinking
22
+ if [ -n "$output_style" ] && [ "$output_style" != "default" ]; then
23
+ parts+=("style: $output_style")
24
+ fi
25
+
26
+ # Join with separator
27
+ result=""
28
+ for part in "${parts[@]}"; do
29
+ if [ -z "$result" ]; then
30
+ result="$part"
31
+ else
32
+ result="$result | $part"
33
+ fi
34
+ done
35
+
36
+ echo "$result"
@@ -0,0 +1,102 @@
1
+ FROM node:20
2
+
3
+ ARG TZ
4
+ ENV TZ="$TZ"
5
+
6
+ # Install basic development tools, iptables/ipset, and chromium
7
+ RUN apt-get update && apt-get install -y --no-install-recommends \
8
+ less \
9
+ git \
10
+ procps \
11
+ sudo \
12
+ fzf \
13
+ zsh \
14
+ man-db \
15
+ unzip \
16
+ gnupg2 \
17
+ gh \
18
+ iptables \
19
+ ipset \
20
+ iproute2 \
21
+ dnsutils \
22
+ aggregate \
23
+ jq \
24
+ nano \
25
+ vim \
26
+ chromium \
27
+ python3 \
28
+ python3-venv \
29
+ && apt-get clean && rm -rf /var/lib/apt/lists/*
30
+
31
+ # Ensure default node user has access to /usr/local/share
32
+ RUN mkdir -p /usr/local/share/npm-global && \
33
+ chown -R node:node /usr/local/share
34
+
35
+ ARG USERNAME=node
36
+
37
+ # Persist bash history.
38
+ RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
39
+ && mkdir /commandhistory \
40
+ && touch /commandhistory/.bash_history \
41
+ && chown -R $USERNAME /commandhistory
42
+
43
+ # Set `DEVCONTAINER` environment variable to help with orientation
44
+ ENV DEVCONTAINER=true
45
+
46
+ # Create workspace and config directories and set permissions
47
+ RUN mkdir -p /workspace /home/node/.claude && \
48
+ chown -R node:node /workspace /home/node/.claude
49
+
50
+ WORKDIR /workspace
51
+
52
+ ARG GIT_DELTA_VERSION=0.18.2
53
+ RUN ARCH=$(dpkg --print-architecture) && \
54
+ wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
55
+ sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
56
+ rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"
57
+
58
+ # Set up non-root user
59
+ USER node
60
+
61
+ # Install global packages
62
+ ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global
63
+ ENV PATH=$HOME/.local/bin:$PATH:/usr/local/share/npm-global/bin
64
+
65
+ # Set the default shell to zsh rather than sh
66
+ ENV SHELL=/bin/zsh
67
+
68
+ # Set the default editor and visual
69
+ ENV EDITOR=nano
70
+ ENV VISUAL=nano
71
+
72
+ # Default powerline10k theme
73
+ ARG ZSH_IN_DOCKER_VERSION=1.2.0
74
+ RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \
75
+ -p git \
76
+ -p fzf \
77
+ -a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \
78
+ -a "source /usr/share/doc/fzf/examples/completion.zsh" \
79
+ -a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
80
+ -x
81
+
82
+ # Copy and set up firewall and Claude setup scripts
83
+ COPY init-firewall.sh /usr/local/bin/
84
+ COPY setup-claude.sh /usr/local/bin/
85
+ USER root
86
+ RUN chmod +x /usr/local/bin/init-firewall.sh /usr/local/bin/setup-claude.sh && \
87
+ echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \
88
+ chmod 0440 /etc/sudoers.d/node-firewall
89
+
90
+ # Chromium flags for running in container
91
+ ENV CHROME_PATH=/usr/bin/chromium
92
+ ENV CHROMIUM_FLAGS="--no-sandbox --disable-gpu --disable-dev-shm-usage"
93
+
94
+ USER node
95
+
96
+ # Install UV package manager
97
+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh
98
+
99
+ # Install Claude Code (native) and OpenCode into ~/.local/bin (persisted in image)
100
+ RUN mkdir -p "$HOME/.local/bin" && \
101
+ curl -fsSL https://claude.ai/install.sh | bash && \
102
+ curl -fsSL https://opencode.ai/install | bash
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "Claude Code Sandbox",
3
+ "build": {
4
+ "dockerfile": "Dockerfile",
5
+ "args": {
6
+ "TZ": "${localEnv:TZ:America/Los_Angeles}",
7
+ "GIT_DELTA_VERSION": "0.18.2",
8
+ "ZSH_IN_DOCKER_VERSION": "1.2.0"
9
+ }
10
+ },
11
+
12
+ "runArgs": ["--cap-add=NET_ADMIN", "--cap-add=NET_RAW"],
13
+ "customizations": {
14
+ "vscode": {
15
+ "extensions": [
16
+ "anthropic.claude-code",
17
+ "dbaeumer.vscode-eslint",
18
+ "esbenp.prettier-vscode",
19
+ "eamodio.gitlens",
20
+ "ms-python.python"
21
+ ],
22
+ "settings": {
23
+ "editor.formatOnSave": true,
24
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
25
+ "editor.codeActionsOnSave": {
26
+ "source.fixAll.eslint": "explicit"
27
+ },
28
+ "terminal.integrated.defaultProfile.linux": "zsh",
29
+ "terminal.integrated.profiles.linux": {
30
+ "bash": {
31
+ "path": "bash",
32
+ "icon": "terminal-bash"
33
+ },
34
+ "zsh": {
35
+ "path": "zsh"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ },
41
+ "remoteUser": "node",
42
+ "mounts": [
43
+ "source=claude-code-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
44
+ "source=claude-code-config-${devcontainerId},target=/home/node/.claude,type=volume",
45
+ "source=${localEnv:HOME}/develop/plone/src/copier-templates,target=/home/node/develop/plone/src/copier-templates,type=bind,consistency=delegated",
46
+ "source=${localEnv:HOME}/.copier-templates/plone-copier-templates,target=/home/node/.copier-templates/plone-copier-templates,type=bind,readonly"
47
+ ],
48
+ "containerEnv": {
49
+ "CLAUDE_CONFIG_DIR": "/home/node/.claude",
50
+ "POWERLEVEL9K_DISABLE_GITSTATUS": "true",
51
+ "CHROME_PATH": "/usr/bin/chromium",
52
+ "PUPPETEER_EXECUTABLE_PATH": "/usr/bin/chromium"
53
+ },
54
+ "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
55
+ "workspaceFolder": "/workspace",
56
+ "postCreateCommand": "/usr/local/bin/setup-claude.sh",
57
+ "postStartCommand": "sudo /usr/local/bin/init-firewall.sh",
58
+ "waitFor": "postStartCommand"
59
+ }
@@ -0,0 +1,163 @@
1
+ #!/bin/bash
2
+ set -euo pipefail # Exit on error, undefined vars, and pipeline failures
3
+ IFS=$'\n\t' # Stricter word splitting
4
+ # Extract Docker DNS info BEFORE any flushing
5
+ DOCKER_DNS_RULES=$(iptables-save -t nat | grep "127\.0\.0\.11" || true)
6
+
7
+ # Flush existing rules and delete existing ipsets
8
+ iptables -F
9
+ iptables -X
10
+ iptables -t nat -F
11
+ iptables -t nat -X
12
+ iptables -t mangle -F
13
+ iptables -t mangle -X
14
+ ipset destroy allowed-domains 2>/dev/null || true
15
+
16
+ # Selectively restore ONLY internal Docker DNS resolution
17
+ if [ -n "$DOCKER_DNS_RULES" ]; then
18
+ echo "Restoring Docker DNS rules..."
19
+ iptables -t nat -N DOCKER_OUTPUT 2>/dev/null || true
20
+ iptables -t nat -N DOCKER_POSTROUTING 2>/dev/null || true
21
+ echo "$DOCKER_DNS_RULES" | xargs -L 1 iptables -t nat
22
+ else
23
+ echo "No Docker DNS rules to restore"
24
+ fi
25
+
26
+ # First allow DNS and localhost before any restrictions
27
+ # Allow outbound DNS
28
+ iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
29
+ # Allow inbound DNS responses
30
+ iptables -A INPUT -p udp --sport 53 -j ACCEPT
31
+ # Allow outbound SSH
32
+ iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
33
+ # Allow inbound SSH responses
34
+ iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
35
+ # Allow localhost
36
+ iptables -A INPUT -i lo -j ACCEPT
37
+ iptables -A OUTPUT -o lo -j ACCEPT
38
+
39
+ # Create ipset with CIDR support
40
+ ipset create allowed-domains hash:net
41
+
42
+ # Fetch GitHub meta information and aggregate + add their IP ranges
43
+ echo "Fetching GitHub IP ranges..."
44
+ gh_ranges=$(curl -s https://api.github.com/meta)
45
+ if [ -z "$gh_ranges" ]; then
46
+ echo "ERROR: Failed to fetch GitHub IP ranges"
47
+ exit 1
48
+ fi
49
+
50
+ if ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; then
51
+ echo "ERROR: GitHub API response missing required fields"
52
+ exit 1
53
+ fi
54
+
55
+ echo "Processing GitHub IPs..."
56
+ while read -r cidr; do
57
+ if [[ ! "$cidr" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
58
+ echo "ERROR: Invalid CIDR range from GitHub meta: $cidr"
59
+ exit 1
60
+ fi
61
+ echo "Adding GitHub range $cidr"
62
+ ipset add allowed-domains "$cidr" 2>/dev/null || true
63
+ done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | aggregate -q)
64
+
65
+ # Resolve and add other allowed domains
66
+ for domain in \
67
+ "registry.npmjs.org" \
68
+ "api.anthropic.com" \
69
+ "claude.ai" \
70
+ "sentry.io" \
71
+ "statsig.anthropic.com" \
72
+ "statsig.com" \
73
+ "marketplace.visualstudio.com" \
74
+ "vscode.blob.core.windows.net" \
75
+ "update.code.visualstudio.com" \
76
+ "opencode.ai"; do
77
+ echo "Resolving $domain..."
78
+ ips=$(dig +noall +answer A "$domain" | awk '$4 == "A" {print $5}')
79
+ if [ -z "$ips" ]; then
80
+ echo "ERROR: Failed to resolve $domain"
81
+ exit 1
82
+ fi
83
+
84
+ while read -r ip; do
85
+ if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
86
+ echo "ERROR: Invalid IP from DNS for $domain: $ip"
87
+ exit 1
88
+ fi
89
+ echo "Adding $ip for $domain"
90
+ ipset add allowed-domains "$ip" 2>/dev/null || true
91
+ done < <(echo "$ips")
92
+ done
93
+
94
+ # PyPI (for UV package installation)
95
+ for domain in \
96
+ "pypi.org" \
97
+ "files.pythonhosted.org" \
98
+ "dist.plone.org"; do
99
+ echo "Resolving $domain..."
100
+ ips=$(dig +noall +answer A "$domain" | awk '$4 == "A" {print $5}')
101
+ if [ -z "$ips" ]; then
102
+ echo "ERROR: Failed to resolve $domain"
103
+ exit 1
104
+ fi
105
+
106
+ while read -r ip; do
107
+ if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
108
+ echo "ERROR: Invalid IP from DNS for $domain: $ip"
109
+ exit 1
110
+ fi
111
+ echo "Adding $ip for $domain"
112
+ ipset add allowed-domains "$ip" 2>/dev/null || true
113
+ done < <(echo "$ips")
114
+ done
115
+
116
+ # Get host IP from default route
117
+ HOST_IP=$(ip route | grep default | cut -d" " -f3)
118
+ if [ -z "$HOST_IP" ]; then
119
+ echo "ERROR: Failed to detect host IP"
120
+ exit 1
121
+ fi
122
+
123
+ HOST_NETWORK=$(echo "$HOST_IP" | sed "s/\.[0-9]*$/.0\/24/")
124
+ echo "Host network detected as: $HOST_NETWORK"
125
+
126
+ # Set up remaining iptables rules
127
+ iptables -A INPUT -s "$HOST_NETWORK" -j ACCEPT
128
+ iptables -A OUTPUT -d "$HOST_NETWORK" -j ACCEPT
129
+
130
+ # Set default policies to DROP first
131
+ iptables -P INPUT DROP
132
+ iptables -P FORWARD DROP
133
+ iptables -P OUTPUT DROP
134
+
135
+ # First allow established connections for already approved traffic
136
+ iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
137
+ iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
138
+
139
+ # Then allow only specific outbound traffic to allowed domains
140
+ iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT
141
+
142
+ # Explicitly REJECT all other outbound traffic for immediate feedback
143
+ iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited
144
+
145
+ echo "Firewall configuration complete"
146
+ echo "Verifying firewall rules..."
147
+
148
+ # Verify blocked traffic using a direct IP (1.1.1.1) to avoid DNS issues
149
+ # (container DNS may resolve blocked domains to 127.0.0.1, bypassing the firewall)
150
+ if curl --connect-timeout 5 -s -o /dev/null https://1.1.1.1 2>/dev/null; then
151
+ echo "ERROR: Firewall verification failed - was able to reach https://1.1.1.1"
152
+ exit 1
153
+ else
154
+ echo "Firewall verification passed - unable to reach https://1.1.1.1 as expected"
155
+ fi
156
+
157
+ # Verify GitHub API access
158
+ if ! curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; then
159
+ echo "ERROR: Firewall verification failed - unable to reach https://api.github.com"
160
+ exit 1
161
+ else
162
+ echo "Firewall verification passed - able to reach https://api.github.com as expected"
163
+ fi
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # Claude Code and OpenCode are installed into the image via the Dockerfile.
5
+ # This script only handles per-container configuration that depends on the
6
+ # mounted ~/.claude volume.
7
+
8
+ export PATH="$HOME/.local/bin:$PATH"
9
+
10
+ if command -v claude &>/dev/null; then
11
+ echo "Configuring Chrome DevTools MCP server..."
12
+ claude mcp remove chrome-devtools 2>/dev/null || true
13
+ claude mcp add chrome-devtools -- npx -y chrome-devtools-mcp@latest
14
+ else
15
+ echo "WARNING: claude CLI not found, skipping MCP configuration"
16
+ fi
17
+
18
+ echo "Enabling remote control for all sessions..."
19
+ mkdir -p ~/.claude
20
+ SETTINGS_FILE="$HOME/.claude/settings.json"
21
+ if [ -f "$SETTINGS_FILE" ]; then
22
+ # Merge preferRemoteControl into existing settings using node (available in the container)
23
+ node -e "
24
+ const fs = require('fs');
25
+ const s = JSON.parse(fs.readFileSync('$SETTINGS_FILE', 'utf8'));
26
+ s.preferRemoteControl = true;
27
+ fs.writeFileSync('$SETTINGS_FILE', JSON.stringify(s, null, 2));
28
+ "
29
+ else
30
+ echo '{"preferRemoteControl": true}' > "$SETTINGS_FILE"
31
+ fi
32
+
33
+ echo "Claude Code and OpenCode setup complete."
@@ -0,0 +1,21 @@
1
+ # http://editorconfig.org
2
+
3
+ root = true
4
+
5
+ [*]
6
+ indent_style = space
7
+ indent_size = 4
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+ charset = utf-8
11
+ end_of_line = lf
12
+
13
+ [*.bat]
14
+ indent_style = tab
15
+ end_of_line = crlf
16
+
17
+ [LICENSE]
18
+ insert_final_newline = false
19
+
20
+ [Makefile]
21
+ indent_style = tab
@@ -0,0 +1,15 @@
1
+ * Plone CLI version:
2
+ * Python version:
3
+ * Operating System:
4
+
5
+ ### Description
6
+
7
+ Describe what you were trying to get done.
8
+ Tell us what happened, what went wrong, and what you expected to happen.
9
+
10
+ ### What I Did
11
+
12
+ ```
13
+ Paste the command(s) you ran and the output.
14
+ If there was a crash, please include the traceback here.
15
+ ```
@@ -0,0 +1,40 @@
1
+ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2
+ # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3
+
4
+ name: Python package
5
+
6
+ on:
7
+ push:
8
+ branches: [master]
9
+ pull_request:
10
+ branches: [master]
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v2
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v2
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+ - name: Install dependencies
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install flake8 pytest
30
+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
31
+ pip install -e .[test]
32
+ - name: Lint with flake8
33
+ run: |
34
+ # stop the build if there are Python syntax errors or undefined names
35
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
36
+ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
37
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
38
+ - name: Test with pytest
39
+ run: |
40
+ pytest
@@ -0,0 +1,83 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ bin/
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ env/
19
+ include/
20
+ lib/
21
+ lib64/
22
+ man/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+ pip-selfcheck.json
40
+
41
+ # Unit test / coverage reports
42
+ htmlcov/
43
+ .tox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *,cover
50
+ .hypothesis/
51
+
52
+ # Translations
53
+ *.mo
54
+ *.pot
55
+
56
+ # Django stuff:
57
+ *.log
58
+
59
+ # Sphinx documentation
60
+ docs/_build/
61
+
62
+ # PyBuilder
63
+ target/
64
+
65
+ # pyenv python configuration file
66
+ .python-version
67
+ /plonecli.sublime-project
68
+ /plonecli.sublime-workspace
69
+ /tmp
70
+ /local
71
+ /src/*
72
+ /.vscode/settings.json
73
+ /.pytest_cache
74
+ /tmpdist
75
+ /_build
76
+ /venv
77
+ pyvenv.cfg
78
+
79
+ .settings/
80
+ .*project
81
+ /bak_pyproject.toml
82
+ /docs/venv
83
+ /.claude/settings.local.json
@@ -0,0 +1,35 @@
1
+ # Read the Docs configuration file for Sphinx projects
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3
+
4
+ # Required
5
+ version: 2
6
+
7
+ # Set the OS, Python version and other tools you might need
8
+ build:
9
+ os: ubuntu-22.04
10
+ tools:
11
+ python: "3.12"
12
+ # You can also specify other tool versions:
13
+ # nodejs: "20"
14
+ # rust: "1.70"
15
+ # golang: "1.20"
16
+
17
+ # Build documentation in the "docs/" directory with Sphinx
18
+ sphinx:
19
+ configuration: docs/conf.py
20
+ # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
21
+ # builder: "dirhtml"
22
+ # Fail on all warnings to avoid broken references
23
+ # fail_on_warning: true
24
+
25
+ # Optionally build your docs in additional formats such as PDF and ePub
26
+ formats:
27
+ - pdf
28
+ - epub
29
+
30
+ # Optional but recommended, declare the Python requirements required
31
+ # to build your documentation
32
+ # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
33
+ python:
34
+ install:
35
+ - requirements: requirements.txt
@@ -0,0 +1,9 @@
1
+ # Credits
2
+
3
+ ## Development Lead
4
+
5
+ * Maik Derstappen <md@derico.de>
6
+
7
+ ## Contributors
8
+
9
+ * Thomas Massmann