Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e740431
Fix Anthropic model configuration for moltbot gateway
Feb 3, 2026
859d057
Add Claude Max OAuth support and Brave Search integration
Feb 4, 2026
58522a8
Fix Telegram plugin enablement and OpenClaw config paths
Feb 4, 2026
2812419
Add Claude Max OAuth support and automated health checks
Feb 4, 2026
f7a4877
Fix gateway startup - minimal working config
Feb 5, 2026
dff8b95
Enable Telegram bot via environment variable
Feb 5, 2026
023cc72
Add persistent storage for OpenClaw data
Feb 5, 2026
16919cc
Fix R2 sync hanging by using timeout cp instead of rsync
Feb 5, 2026
689a408
Set Claude Sonnet 4.5 as default model
Feb 6, 2026
25ef40d
Add performance, reliability, and feature improvements
Feb 6, 2026
ed47733
Fix model config format - use object instead of string
Feb 6, 2026
5130201
Fix config order - write after R2 restore
Feb 6, 2026
18a8737
Add auto-clone GitHub repo on container startup
Feb 6, 2026
53e09d9
Add Telegram owner auto-allowlist to skip pairing on startup
Feb 7, 2026
9d99e4b
Add gateway auto-recovery restart loop and GitHub token fallback
Feb 7, 2026
2fde828
Fix git remote URL not updated on pull after token rotation
Feb 7, 2026
610d5b1
Auto-restore cron jobs after gateway startup
Feb 7, 2026
44a66c7
Symlink all repo contents to workspace, not just .md files
Feb 7, 2026
f89f47c
Fix model config: set claude-sonnet-4-5 after doctor runs
Feb 7, 2026
4cb5e58
Add autonomous web research skill with Serper API
Feb 8, 2026
1bbc650
Clear stale session lock files before gateway startup
Feb 8, 2026
324d181
Add process guard: kill stale instances before gateway startup
Feb 8, 2026
9943a16
Fix auto-study cron registration with correct openclaw CLI syntax
Feb 8, 2026
6fe5d31
Add automatic cron job recovery to scheduled handler
Feb 10, 2026
4811a7e
Optimize token usage: trim SKILL.md files, reduce cron frequency
Feb 10, 2026
7d24969
Fix channel plugins not auto-enabling after container restart
Feb 10, 2026
9031ee1
Fix zombie process accumulation and optimize token usage
Feb 11, 2026
7a40b0d
Add context pruning config, merge personality files, remove verbose l…
Feb 11, 2026
b4de66b
Add brain memory consolidation system with daily/weekly crons
Feb 11, 2026
cf8fb3d
Cleanup: deduplicate logic, update models, remove redundant R2 sync
Feb 11, 2026
d64536f
Register Haiku model in OpenClaw config on startup
Feb 11, 2026
b31230e
Add self-modifying agent system with tiered memory
Feb 12, 2026
643a6df
Add Google Calendar integration with auto-sync and availability checking
Feb 13, 2026
af7836f
Improve reliability: restart resilience, parallel startup, health mon…
Feb 13, 2026
19e0b59
Add NODE_PATH env var for global npm module resolution in container
Feb 13, 2026
5107eb9
Add read-page.js for browser-based web page reading
Feb 13, 2026
65269bc
Fix cron auto-restoration: replace nc with Node.js port check and rem…
Feb 14, 2026
256f9a4
Switch AI model from Claude to GitHub Copilot GPT-5 Mini
Feb 19, 2026
1dad59d
Add git credential helper for GITHUB_PAT to fix workspace push 403
Feb 19, 2026
74eaec0
Merge upstream origin/main: rclone R2, openclaw upgrade, AI Gateway
Feb 19, 2026
fc7bade
Revert workflow changes to avoid PAT scope requirement
Feb 19, 2026
50134be
Add inter-agent communication system (Layer 1 + Layer 2)
Feb 19, 2026
0ca22b8
Add Google Calendar credential file fallback and revert OpenAI model …
Feb 20, 2026
e4c68f7
Add Gmail read-only inbox integration for astin@hashed.com
Feb 21, 2026
5f9ddce
feat: add OpenClaw security hardening, memory search, and personality…
Feb 21, 2026
d548d55
Add lean HEARTBEAT.md and protect critical bootstrap files from agent…
Feb 21, 2026
7531591
Fix HEARTBEAT cron check to include operator token auth
Feb 21, 2026
f3d6be5
fix: sync inbox on-demand when user asks about email
Feb 21, 2026
1d4b2f8
feat: add pristine skills overlay, CDP browser creds, and browser TOO…
Feb 21, 2026
f73b953
Add browser instructions to CLAUDE.md — use CDP scripts, not built-in…
Feb 21, 2026
e5dad28
Add CLAUDE.md browser injection fallback in startup script
Feb 22, 2026
a26b144
Disable built-in browser tool via tools.deny config
Feb 22, 2026
f88b900
Add portfolio research cron, kimchi monitor, and fix cron auth
Feb 22, 2026
6a89dc3
Add GITHUB_REPO_SUBDIR support for scoped memory storage
Feb 22, 2026
07b077f
Add Notion API key support for agent integration
Feb 22, 2026
3cb2b90
Inject Notion API instructions into TOOLS.md on startup
Feb 23, 2026
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
198 changes: 1 addition & 197 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ on:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
unit:
test:
runs-on: ubuntu-latest

steps:
Expand All @@ -23,203 +22,8 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Format check
run: npm run format:check

- name: Type check
run: npm run typecheck

- name: Run tests
run: npm test

e2e:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: write
pull-requests: write

strategy:
fail-fast: false
matrix:
config:
- name: base
env: {}
- name: telegram
env:
TELEGRAM_BOT_TOKEN: "fake-telegram-bot-token-for-e2e"
TELEGRAM_DM_POLICY: "pairing"
- name: discord
env:
DISCORD_BOT_TOKEN: "fake-discord-bot-token-for-e2e"
DISCORD_DM_POLICY: "pairing"
- name: workers-ai
env:
CF_AI_GATEWAY_MODEL: "workers-ai/@cf/openai/gpt-oss-120b"

name: e2e (${{ matrix.config.name }})

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Install Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_wrapper: false

- name: Install system dependencies
run: sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg imagemagick bc

- name: Install cctr
uses: taiki-e/install-action@v2
with:
tool: cctr

- name: Install plwr
uses: taiki-e/install-action@v2
with:
tool: plwr@0.7.2

- name: Install Playwright browsers
run: npm install -g playwright && npx playwright install --with-deps chromium

- name: Run E2E tests (${{ matrix.config.name }})
id: e2e
continue-on-error: true
env:
# Cloud infrastructure credentials (from repo secrets with E2E_ prefix)
CLOUDFLARE_API_TOKEN: ${{ secrets.E2E_CLOUDFLARE_API_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.E2E_CF_ACCOUNT_ID }}
WORKERS_SUBDOMAIN: ${{ secrets.E2E_WORKERS_SUBDOMAIN }}
CF_ACCESS_TEAM_DOMAIN: ${{ secrets.E2E_CF_ACCESS_TEAM_DOMAIN }}
R2_ACCESS_KEY_ID: ${{ secrets.E2E_R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.E2E_R2_SECRET_ACCESS_KEY }}
# AI provider — Cloudflare AI Gateway (preferred)
CLOUDFLARE_AI_GATEWAY_API_KEY: ${{ secrets.CLOUDFLARE_AI_GATEWAY_API_KEY }}
CF_AI_GATEWAY_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
CF_AI_GATEWAY_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_GATEWAY_ID }}
# AI provider — legacy (still supported)
AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }}
AI_GATEWAY_BASE_URL: ${{ secrets.AI_GATEWAY_BASE_URL }}
# Unique test run ID for parallel isolation
E2E_TEST_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.config.name }}
# Matrix-specific config
TELEGRAM_BOT_TOKEN: ${{ matrix.config.env.TELEGRAM_BOT_TOKEN }}
TELEGRAM_DM_POLICY: ${{ matrix.config.env.TELEGRAM_DM_POLICY }}
DISCORD_BOT_TOKEN: ${{ matrix.config.env.DISCORD_BOT_TOKEN }}
DISCORD_DM_POLICY: ${{ matrix.config.env.DISCORD_DM_POLICY }}
CF_AI_GATEWAY_MODEL: ${{ matrix.config.env.CF_AI_GATEWAY_MODEL }}
run: cctr -vv test/e2e

- name: Generate video thumbnail
id: video
if: always()
run: |
if ls /tmp/moltworker-e2e-videos/*.mp4 1>/dev/null 2>&1; then
for mp4 in /tmp/moltworker-e2e-videos/*.mp4; do
thumb="${mp4%.mp4}.png"

# Extract middle frame as thumbnail
duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$mp4")
midpoint=$(echo "$duration / 2" | bc -l)
ffmpeg -y -ss "$midpoint" -i "$mp4" -vframes 1 -update 1 -q:v 2 "$thumb"

# Add play button overlay
width=$(identify -format '%w' "$thumb")
height=$(identify -format '%h' "$thumb")
cx=$((width / 2))
cy=$((height / 2))
convert "$thumb" \
-fill 'rgba(0,0,0,0.6)' -draw "circle ${cx},${cy} $((cx+50)),${cy}" \
-fill 'white' -draw "polygon $((cx-15)),$((cy-25)) $((cx-15)),$((cy+25)) $((cx+30)),${cy}" \
"$thumb"

echo "video_path=$mp4" >> $GITHUB_OUTPUT
echo "video_name=$(basename $mp4)" >> $GITHUB_OUTPUT
echo "thumb_path=$thumb" >> $GITHUB_OUTPUT
echo "thumb_name=$(basename $thumb)" >> $GITHUB_OUTPUT
done
echo "has_video=true" >> $GITHUB_OUTPUT
else
echo "has_video=false" >> $GITHUB_OUTPUT
fi

- name: Prepare video for upload
id: prepare
if: always() && steps.video.outputs.has_video == 'true'
run: |
mkdir -p /tmp/e2e-video-upload/videos/${{ github.run_id }}-${{ matrix.config.name }}
cp "${{ steps.video.outputs.video_path }}" /tmp/e2e-video-upload/videos/${{ github.run_id }}-${{ matrix.config.name }}/
cp "${{ steps.video.outputs.thumb_path }}" /tmp/e2e-video-upload/videos/${{ github.run_id }}-${{ matrix.config.name }}/
echo "video_url=https://github.com/${{ github.repository }}/raw/e2e-artifacts-${{ matrix.config.name }}/videos/${{ github.run_id }}-${{ matrix.config.name }}/${{ steps.video.outputs.video_name }}" >> $GITHUB_OUTPUT
echo "thumb_url=https://github.com/${{ github.repository }}/raw/e2e-artifacts-${{ matrix.config.name }}/videos/${{ github.run_id }}-${{ matrix.config.name }}/${{ steps.video.outputs.thumb_name }}" >> $GITHUB_OUTPUT

- name: Upload video to e2e-artifacts branch
if: always() && steps.video.outputs.has_video == 'true'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: /tmp/e2e-video-upload
publish_branch: e2e-artifacts-${{ matrix.config.name }}
keep_files: true

- name: Delete old video comments
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const marker = '<!-- e2e-video-${{ matrix.config.name }} -->';
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
for (const comment of comments) {
if (comment.body.includes(marker)) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
});
}
}

- name: Comment on PR with video
if: always() && github.event_name == 'pull_request' && steps.prepare.outputs.video_url
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
<!-- e2e-video-${{ matrix.config.name }} -->
## E2E Test Recording (${{ matrix.config.name }})

${{ steps.e2e.outcome == 'success' && '✅ Tests passed' || '❌ Tests failed' }}

[![E2E Test Video](${{ steps.prepare.outputs.thumb_url }})](${{ steps.prepare.outputs.video_url }})

- name: Add video link to summary
if: always()
run: |
echo "## E2E Test Recording" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.video.outputs.has_video }}" == "true" ]; then
echo "📹 [Download video](${{ steps.prepare.outputs.video_url }})" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ No video recording found" >> $GITHUB_STEP_SUMMARY
fi

- name: Fail if E2E tests failed
if: steps.e2e.outcome == 'failure'
run: exit 1
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ Thumbs.db
# Docker build artifacts
*.tar

# Local Claude settings
.claude/

# Clawdbot runtime config (contains tokens)
clawdbot/
.clawdhub/

# Custom skills (user-specific)
skills/prompt-guard/

# Veta agent memory
.veta/

Expand All @@ -60,4 +70,4 @@ test/e2e/.dev.vars
.wrangler-e2e-*.jsonc

# npm config
.npmrc
.npmrc
Loading