Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "intercept",
"command": "python -c \"import sys,json; d=json.load(sys.stdin); p=d.get('file_path',''); blocked=['.env','secrets','.git/']; sys.exit(1) if any(x in p for x in blocked) else sys.exit(0)\""

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Embedding Python logic directly in JSON strings makes it hard to read, test, and maintain. While this command is simple enough, it sets a precedent. For more complex logic, it's better to move it to a separate script file (e.g., scripts/pre-tool-use-check.py) and invoke that script from the hook. This improves readability and makes the hook's behavior easier to manage in the long term.

}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python -c \"import sys,json; d=json.load(sys.stdin); p=d.get('file_path',''); exec('import subprocess; r=subprocess.run([sys.executable,\\\"-m\\\",\\\"py_compile\\\",p],capture_output=True,text=True); print(r.stderr) if r.returncode else print(\\\"Syntax OK: \\\"+p)') if p.endswith('.py') else print('Skipped (not Python)')\""

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The python command for the PostToolUse hook has a syntax error and is unnecessarily complex. The exec(...) if ... else ... construct is not valid Python because exec is a statement, not an expression. This will cause the hook to fail with a SyntaxError.

Additionally, using exec here is a code smell and makes the command very difficult to read and maintain. The logic can be written directly without it.

I recommend simplifying the command and using a standard if/else structure. For better long-term maintainability, consider moving this logic into a separate script file.

Suggested change
"command": "python -c \"import sys,json; d=json.load(sys.stdin); p=d.get('file_path',''); exec('import subprocess; r=subprocess.run([sys.executable,\\\"-m\\\",\\\"py_compile\\\",p],capture_output=True,text=True); print(r.stderr) if r.returncode else print(\\\"Syntax OK: \\\"+p)') if p.endswith('.py') else print('Skipped (not Python)')\""
"command": "python -c \"import sys, json, subprocess; d = json.load(sys.stdin); p = d.get('file_path', '');\nif p.endswith('.py'):\n r = subprocess.run([sys.executable, '-m', 'py_compile', p], capture_output=True, text=True)\n if r.returncode == 0:\n print(f'Syntax OK: {p}')\n else:\n print(r.stderr, file=sys.stderr)\nelse:\n print('Skipped (not Python)')\""

}
]
}
]
}
}
39 changes: 39 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ClawCloud Auto-Login

Automated ClawCloud keep-alive via GitHub Actions + Playwright.

## Commands

```bash
# Install dependencies
pip install playwright requests pynacl
playwright install chromium
playwright install-deps

# Run locally
python scripts/auto_login.py
```

## Architecture

- `scripts/auto_login.py` — Single-file automation script (Playwright browser automation)
- `.github/workflows/keep-alive.yml` — Cron job (every 5 days, UTC 01:00)
- `.claude/settings.json` — Claude Code hooks

## Key Classes (auto_login.py)

- `Telegram` — Bot notifications and 2FA code retrieval via `/code` command
- `SecretUpdater` — Auto-updates GitHub Secrets via API (requires PyNaCl)
- `AutoLogin` — Main login flow: ClawCloud → GitHub OAuth → region detection → keepalive

## Required Secrets

`GH_USERNAME`, `GH_PASSWORD`, `GH_SESSION`, `TG_BOT_TOKEN`, `TG_CHAT_ID`, `REPO_TOKEN`

## Gotchas

- All credentials come from GitHub Actions secrets / environment variables — never hardcode
- The script uses anti-detection measures (custom user agent, webdriver override)
- `GH_SESSION` cookie auto-updates on successful login if `REPO_TOKEN` is set
- Region is auto-detected from redirect URL after OAuth (e.g. `ap-southeast-1.console.claw.cloud`)
- 2FA supports both GitHub Mobile approval and TOTP via Telegram `/code 123456`