gigaclaw 1.4.0
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/LICENSE +26 -0
- package/README.md +237 -0
- package/api/CLAUDE.md +19 -0
- package/api/index.js +265 -0
- package/bin/cli.js +823 -0
- package/bin/local.sh +85 -0
- package/bin/postinstall.js +63 -0
- package/config/index.js +26 -0
- package/config/instrumentation.js +62 -0
- package/drizzle/0000_initial.sql +52 -0
- package/drizzle/0001_nostalgic_sersi.sql +11 -0
- package/drizzle/0002_black_daimon_hellstrom.sql +19 -0
- package/drizzle/0003_rename_code_workspaces.sql +5 -0
- package/drizzle/meta/0000_snapshot.json +321 -0
- package/drizzle/meta/0001_snapshot.json +390 -0
- package/drizzle/meta/0002_snapshot.json +411 -0
- package/drizzle/meta/0003_snapshot.json +419 -0
- package/drizzle/meta/_journal.json +34 -0
- package/lib/actions.js +44 -0
- package/lib/ai/agent.js +86 -0
- package/lib/ai/index.js +342 -0
- package/lib/ai/model.js +180 -0
- package/lib/ai/tools.js +269 -0
- package/lib/ai/web-search.js +42 -0
- package/lib/auth/actions.js +28 -0
- package/lib/auth/config.js +27 -0
- package/lib/auth/edge-config.js +27 -0
- package/lib/auth/index.js +27 -0
- package/lib/auth/middleware.js +62 -0
- package/lib/channels/base.js +56 -0
- package/lib/channels/index.js +15 -0
- package/lib/channels/telegram.js +148 -0
- package/lib/chat/actions.js +579 -0
- package/lib/chat/api.js +140 -0
- package/lib/chat/components/app-sidebar.js +213 -0
- package/lib/chat/components/app-sidebar.jsx +279 -0
- package/lib/chat/components/chat-header.js +192 -0
- package/lib/chat/components/chat-header.jsx +223 -0
- package/lib/chat/components/chat-input.js +236 -0
- package/lib/chat/components/chat-input.jsx +249 -0
- package/lib/chat/components/chat-nav-context.js +11 -0
- package/lib/chat/components/chat-nav-context.jsx +11 -0
- package/lib/chat/components/chat-page.js +99 -0
- package/lib/chat/components/chat-page.jsx +121 -0
- package/lib/chat/components/chat.js +153 -0
- package/lib/chat/components/chat.jsx +199 -0
- package/lib/chat/components/chats-page.js +367 -0
- package/lib/chat/components/chats-page.jsx +394 -0
- package/lib/chat/components/code-mode-toggle.js +132 -0
- package/lib/chat/components/code-mode-toggle.jsx +163 -0
- package/lib/chat/components/crons-page.js +172 -0
- package/lib/chat/components/crons-page.jsx +244 -0
- package/lib/chat/components/greeting.js +11 -0
- package/lib/chat/components/greeting.jsx +16 -0
- package/lib/chat/components/icons.js +805 -0
- package/lib/chat/components/icons.jsx +751 -0
- package/lib/chat/components/index.js +20 -0
- package/lib/chat/components/message.js +363 -0
- package/lib/chat/components/message.jsx +422 -0
- package/lib/chat/components/messages.js +65 -0
- package/lib/chat/components/messages.jsx +74 -0
- package/lib/chat/components/notifications-page.js +56 -0
- package/lib/chat/components/notifications-page.jsx +87 -0
- package/lib/chat/components/page-layout.js +21 -0
- package/lib/chat/components/page-layout.jsx +28 -0
- package/lib/chat/components/pull-requests-page.js +103 -0
- package/lib/chat/components/pull-requests-page.jsx +113 -0
- package/lib/chat/components/settings-layout.js +39 -0
- package/lib/chat/components/settings-layout.jsx +53 -0
- package/lib/chat/components/settings-secrets-page.js +216 -0
- package/lib/chat/components/settings-secrets-page.jsx +264 -0
- package/lib/chat/components/sidebar-history-item.js +138 -0
- package/lib/chat/components/sidebar-history-item.jsx +119 -0
- package/lib/chat/components/sidebar-history.js +167 -0
- package/lib/chat/components/sidebar-history.jsx +220 -0
- package/lib/chat/components/sidebar-user-nav.js +61 -0
- package/lib/chat/components/sidebar-user-nav.jsx +77 -0
- package/lib/chat/components/swarm-page.js +157 -0
- package/lib/chat/components/swarm-page.jsx +210 -0
- package/lib/chat/components/tool-call.js +89 -0
- package/lib/chat/components/tool-call.jsx +107 -0
- package/lib/chat/components/triggers-page.js +153 -0
- package/lib/chat/components/triggers-page.jsx +221 -0
- package/lib/chat/components/ui/combobox.js +98 -0
- package/lib/chat/components/ui/combobox.jsx +114 -0
- package/lib/chat/components/ui/confirm-dialog.js +53 -0
- package/lib/chat/components/ui/confirm-dialog.jsx +57 -0
- package/lib/chat/components/ui/dropdown-menu.js +194 -0
- package/lib/chat/components/ui/dropdown-menu.jsx +215 -0
- package/lib/chat/components/ui/rename-dialog.js +78 -0
- package/lib/chat/components/ui/rename-dialog.jsx +74 -0
- package/lib/chat/components/ui/scroll-area.js +13 -0
- package/lib/chat/components/ui/scroll-area.jsx +17 -0
- package/lib/chat/components/ui/separator.js +21 -0
- package/lib/chat/components/ui/separator.jsx +18 -0
- package/lib/chat/components/ui/sheet.js +75 -0
- package/lib/chat/components/ui/sheet.jsx +95 -0
- package/lib/chat/components/ui/sidebar.js +228 -0
- package/lib/chat/components/ui/sidebar.jsx +246 -0
- package/lib/chat/components/ui/tooltip.js +56 -0
- package/lib/chat/components/ui/tooltip.jsx +66 -0
- package/lib/chat/components/upgrade-dialog.js +151 -0
- package/lib/chat/components/upgrade-dialog.jsx +170 -0
- package/lib/chat/utils.js +11 -0
- package/lib/code/actions.js +153 -0
- package/lib/code/code-page.js +22 -0
- package/lib/code/code-page.jsx +25 -0
- package/lib/code/index.js +1 -0
- package/lib/code/terminal-view.js +201 -0
- package/lib/code/terminal-view.jsx +224 -0
- package/lib/code/ws-proxy.js +80 -0
- package/lib/cron.js +246 -0
- package/lib/db/api-keys.js +163 -0
- package/lib/db/chats.js +168 -0
- package/lib/db/code-workspaces.js +110 -0
- package/lib/db/index.js +52 -0
- package/lib/db/notifications.js +99 -0
- package/lib/db/schema.js +66 -0
- package/lib/db/update-check.js +96 -0
- package/lib/db/users.js +89 -0
- package/lib/paths.js +42 -0
- package/lib/tools/create-job.js +97 -0
- package/lib/tools/docker.js +146 -0
- package/lib/tools/github.js +271 -0
- package/lib/tools/openai.js +35 -0
- package/lib/tools/telegram.js +292 -0
- package/lib/triggers.js +104 -0
- package/lib/utils/render-md.js +111 -0
- package/package.json +118 -0
- package/setup/lib/auth.mjs +81 -0
- package/setup/lib/env.mjs +21 -0
- package/setup/lib/fs-utils.mjs +20 -0
- package/setup/lib/github.mjs +149 -0
- package/setup/lib/prerequisites.mjs +155 -0
- package/setup/lib/prompts.mjs +267 -0
- package/setup/lib/providers.mjs +105 -0
- package/setup/lib/sync.mjs +125 -0
- package/setup/lib/targets.mjs +45 -0
- package/setup/lib/telegram-verify.mjs +63 -0
- package/setup/lib/telegram.mjs +76 -0
- package/setup/setup-cloud.mjs +833 -0
- package/setup/setup-local.mjs +377 -0
- package/setup/setup-telegram.mjs +265 -0
- package/setup/setup.mjs +87 -0
- package/templates/.dockerignore +5 -0
- package/templates/.env.example +104 -0
- package/templates/.github/workflows/auto-merge.yml +117 -0
- package/templates/.github/workflows/notify-job-failed.yml +64 -0
- package/templates/.github/workflows/notify-pr-complete.yml +119 -0
- package/templates/.github/workflows/rebuild-event-handler.yml +121 -0
- package/templates/.github/workflows/run-job.yml +89 -0
- package/templates/.github/workflows/upgrade-event-handler.yml +62 -0
- package/templates/.gitignore.template +45 -0
- package/templates/.pi/extensions/env-sanitizer/index.ts +48 -0
- package/templates/.pi/extensions/env-sanitizer/package.json +5 -0
- package/templates/CLAUDE.md +29 -0
- package/templates/CLAUDE.md.template +308 -0
- package/templates/app/api/[...gigaclaw]/route.js +1 -0
- package/templates/app/api/auth/[...nextauth]/route.js +1 -0
- package/templates/app/chat/[chatId]/page.js +9 -0
- package/templates/app/chats/page.js +7 -0
- package/templates/app/code/[codeWorkspaceId]/page.js +9 -0
- package/templates/app/components/ascii-logo.jsx +12 -0
- package/templates/app/components/login-form.jsx +92 -0
- package/templates/app/components/setup-form.jsx +82 -0
- package/templates/app/components/theme-provider.jsx +11 -0
- package/templates/app/components/theme-toggle.jsx +38 -0
- package/templates/app/components/ui/button.jsx +21 -0
- package/templates/app/components/ui/card.jsx +23 -0
- package/templates/app/components/ui/input.jsx +10 -0
- package/templates/app/components/ui/label.jsx +10 -0
- package/templates/app/crons/page.js +5 -0
- package/templates/app/globals.css +90 -0
- package/templates/app/layout.js +33 -0
- package/templates/app/login/page.js +15 -0
- package/templates/app/notifications/page.js +7 -0
- package/templates/app/page.js +7 -0
- package/templates/app/pull-requests/page.js +7 -0
- package/templates/app/settings/crons/page.js +5 -0
- package/templates/app/settings/layout.js +7 -0
- package/templates/app/settings/page.js +5 -0
- package/templates/app/settings/secrets/page.js +5 -0
- package/templates/app/settings/triggers/page.js +5 -0
- package/templates/app/stream/chat/route.js +1 -0
- package/templates/app/swarm/page.js +7 -0
- package/templates/app/triggers/page.js +5 -0
- package/templates/config/CODE_PLANNING.md +14 -0
- package/templates/config/CRONS.json +56 -0
- package/templates/config/HEARTBEAT.md +3 -0
- package/templates/config/JOB_AGENT.md +30 -0
- package/templates/config/JOB_PLANNING.md +240 -0
- package/templates/config/JOB_SUMMARY.md +130 -0
- package/templates/config/SKILL_BUILDING_GUIDE.md +96 -0
- package/templates/config/SOUL.md +48 -0
- package/templates/config/TRIGGERS.json +58 -0
- package/templates/config/WEB_SEARCH_AVAILABLE.md +5 -0
- package/templates/config/WEB_SEARCH_UNAVAILABLE.md +3 -0
- package/templates/docker/claude-code-job/Dockerfile +34 -0
- package/templates/docker/claude-code-job/entrypoint.sh +149 -0
- package/templates/docker/claude-code-workspace/.tmux.conf +5 -0
- package/templates/docker/claude-code-workspace/Dockerfile +61 -0
- package/templates/docker/claude-code-workspace/entrypoint.sh +51 -0
- package/templates/docker/event-handler/Dockerfile +20 -0
- package/templates/docker/event-handler/ecosystem.config.cjs +7 -0
- package/templates/docker/pi-coding-agent-job/Dockerfile +51 -0
- package/templates/docker/pi-coding-agent-job/entrypoint.sh +164 -0
- package/templates/docker-compose.local.yml +78 -0
- package/templates/docker-compose.yml +64 -0
- package/templates/instrumentation.js +6 -0
- package/templates/middleware.js +23 -0
- package/templates/next.config.mjs +3 -0
- package/templates/postcss.config.mjs +5 -0
- package/templates/public/favicon.ico +0 -0
- package/templates/server.js +25 -0
- package/templates/skills/LICENSE +21 -0
- package/templates/skills/README.md +119 -0
- package/templates/skills/brave-search/SKILL.md +79 -0
- package/templates/skills/brave-search/content.js +86 -0
- package/templates/skills/brave-search/package-lock.json +621 -0
- package/templates/skills/brave-search/package.json +14 -0
- package/templates/skills/brave-search/search.js +199 -0
- package/templates/skills/browser-tools/SKILL.md +196 -0
- package/templates/skills/browser-tools/browser-content.js +103 -0
- package/templates/skills/browser-tools/browser-cookies.js +35 -0
- package/templates/skills/browser-tools/browser-eval.js +53 -0
- package/templates/skills/browser-tools/browser-hn-scraper.js +108 -0
- package/templates/skills/browser-tools/browser-nav.js +44 -0
- package/templates/skills/browser-tools/browser-pick.js +162 -0
- package/templates/skills/browser-tools/browser-screenshot.js +34 -0
- package/templates/skills/browser-tools/browser-start.js +87 -0
- package/templates/skills/browser-tools/package-lock.json +2556 -0
- package/templates/skills/browser-tools/package.json +19 -0
- package/templates/skills/google-docs/SKILL.md +23 -0
- package/templates/skills/google-docs/create.sh +69 -0
- package/templates/skills/google-drive/SKILL.md +47 -0
- package/templates/skills/google-drive/delete.sh +47 -0
- package/templates/skills/google-drive/download.sh +50 -0
- package/templates/skills/google-drive/list.sh +41 -0
- package/templates/skills/google-drive/upload.sh +76 -0
- package/templates/skills/kie-ai/SKILL.md +38 -0
- package/templates/skills/kie-ai/generate-image.sh +77 -0
- package/templates/skills/kie-ai/generate-video.sh +69 -0
- package/templates/skills/llm-secrets/SKILL.md +34 -0
- package/templates/skills/llm-secrets/llm-secrets.js +33 -0
- package/templates/skills/modify-self/SKILL.md +12 -0
- package/templates/skills/youtube-transcript/SKILL.md +41 -0
- package/templates/skills/youtube-transcript/package-lock.json +24 -0
- package/templates/skills/youtube-transcript/package.json +8 -0
- package/templates/skills/youtube-transcript/transcript.js +84 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Extract job ID from branch name (job/uuid -> uuid), fallback to random UUID
|
|
5
|
+
if [[ "$BRANCH" == job/* ]]; then
|
|
6
|
+
JOB_ID="${BRANCH#job/}"
|
|
7
|
+
else
|
|
8
|
+
JOB_ID=$(cat /proc/sys/kernel/random/uuid)
|
|
9
|
+
fi
|
|
10
|
+
echo "Job ID: ${JOB_ID}"
|
|
11
|
+
|
|
12
|
+
# Export SECRETS (JSON) as flat env vars (GH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, etc.)
|
|
13
|
+
if [ -n "$SECRETS" ]; then
|
|
14
|
+
eval $(echo "$SECRETS" | jq -r 'to_entries | .[] | "export \(.key)=\(.value | @sh)"')
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Export LLM_SECRETS (JSON) as flat env vars
|
|
18
|
+
if [ -n "$LLM_SECRETS" ]; then
|
|
19
|
+
eval $(echo "$LLM_SECRETS" | jq -r 'to_entries | .[] | "export \(.key)=\(.value | @sh)"')
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Unset ANTHROPIC_API_KEY so Claude Code uses the OAuth token.
|
|
23
|
+
# If both are set, Claude Code prioritizes API key (billing to API credits)
|
|
24
|
+
# which defeats the purpose. The API key is for the event handler, not here.
|
|
25
|
+
unset ANTHROPIC_API_KEY
|
|
26
|
+
|
|
27
|
+
# Git setup - derive identity from GitHub token
|
|
28
|
+
gh auth setup-git
|
|
29
|
+
GH_USER_JSON=$(gh api user -q '{name: .name, login: .login, email: .email, id: .id}')
|
|
30
|
+
GH_USER_NAME=$(echo "$GH_USER_JSON" | jq -r '.name // .login')
|
|
31
|
+
GH_USER_EMAIL=$(echo "$GH_USER_JSON" | jq -r '.email // "\(.id)+\(.login)@users.noreply.github.com"')
|
|
32
|
+
git config --global user.name "$GH_USER_NAME"
|
|
33
|
+
git config --global user.email "$GH_USER_EMAIL"
|
|
34
|
+
|
|
35
|
+
# Clone branch
|
|
36
|
+
if [ -n "$REPO_URL" ]; then
|
|
37
|
+
git clone --single-branch --branch "$BRANCH" --depth 1 "$REPO_URL" /job
|
|
38
|
+
else
|
|
39
|
+
echo "No REPO_URL provided"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
cd /job
|
|
43
|
+
|
|
44
|
+
# Install npm deps for active skills (native deps need correct Linux arch)
|
|
45
|
+
for skill_dir in /job/skills/active/*/; do
|
|
46
|
+
if [ -f "${skill_dir}package.json" ]; then
|
|
47
|
+
echo "Installing skill deps: $(basename "$skill_dir")"
|
|
48
|
+
(cd "$skill_dir" && npm install --omit=dev --no-package-lock)
|
|
49
|
+
fi
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
# Start Chrome if puppeteer installed it (needed by browser-tools skill)
|
|
53
|
+
CHROME_PID=""
|
|
54
|
+
CHROME_BIN=$(find /home/agent/.cache/puppeteer -name "chrome" -type f 2>/dev/null | head -1)
|
|
55
|
+
if [ -n "$CHROME_BIN" ]; then
|
|
56
|
+
$CHROME_BIN --headless --no-sandbox --disable-gpu --remote-debugging-port=9222 2>/dev/null &
|
|
57
|
+
CHROME_PID=$!
|
|
58
|
+
sleep 2
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Setup logs
|
|
62
|
+
LOG_DIR="/job/logs/${JOB_ID}"
|
|
63
|
+
mkdir -p "${LOG_DIR}"
|
|
64
|
+
|
|
65
|
+
# Build system prompt from config MD files
|
|
66
|
+
SYSTEM_PROMPT_FILE="${LOG_DIR}/system-prompt.md"
|
|
67
|
+
SYSTEM_FILES=("SOUL.md" "JOB_AGENT.md")
|
|
68
|
+
> "$SYSTEM_PROMPT_FILE"
|
|
69
|
+
for i in "${!SYSTEM_FILES[@]}"; do
|
|
70
|
+
cat "/job/config/${SYSTEM_FILES[$i]}" >> "$SYSTEM_PROMPT_FILE"
|
|
71
|
+
if [ "$i" -lt $((${#SYSTEM_FILES[@]} - 1)) ]; then
|
|
72
|
+
echo -e "\n\n" >> "$SYSTEM_PROMPT_FILE"
|
|
73
|
+
fi
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
# Resolve {{datetime}} variable in system prompt
|
|
77
|
+
sed -i "s/{{datetime}}/$(date -u +"%Y-%m-%dT%H:%M:%SZ")/g" "$SYSTEM_PROMPT_FILE"
|
|
78
|
+
|
|
79
|
+
# Read job metadata from job.config.json
|
|
80
|
+
JOB_CONFIG="/job/logs/${JOB_ID}/job.config.json"
|
|
81
|
+
TITLE=$(jq -r '.title // empty' "$JOB_CONFIG")
|
|
82
|
+
JOB_DESCRIPTION=$(jq -r '.job // empty' "$JOB_CONFIG")
|
|
83
|
+
|
|
84
|
+
PROMPT="
|
|
85
|
+
|
|
86
|
+
# Your Job
|
|
87
|
+
|
|
88
|
+
${JOB_DESCRIPTION}"
|
|
89
|
+
|
|
90
|
+
# Build --model flag if LLM_MODEL is set
|
|
91
|
+
MODEL_FLAG=""
|
|
92
|
+
if [ -n "$LLM_MODEL" ]; then
|
|
93
|
+
MODEL_FLAG="--model $LLM_MODEL"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Run Claude Code — capture exit code instead of letting set -e kill the script
|
|
97
|
+
# stream-json gives the full conversation trace (thinking, tool calls, results)
|
|
98
|
+
# similar to Pi's .jsonl session logs
|
|
99
|
+
set +e
|
|
100
|
+
claude -p "$PROMPT" \
|
|
101
|
+
$MODEL_FLAG \
|
|
102
|
+
--append-system-prompt-file "$SYSTEM_PROMPT_FILE" \
|
|
103
|
+
--dangerously-skip-permissions \
|
|
104
|
+
--verbose \
|
|
105
|
+
--output-format stream-json \
|
|
106
|
+
> "${LOG_DIR}/claude-session.jsonl" 2>"${LOG_DIR}/claude-stderr.log"
|
|
107
|
+
AGENT_EXIT=$?
|
|
108
|
+
|
|
109
|
+
# Commit based on outcome
|
|
110
|
+
if [ $AGENT_EXIT -ne 0 ]; then
|
|
111
|
+
# Claude Code failed — only commit session logs, not partial code changes
|
|
112
|
+
git reset || true
|
|
113
|
+
git add -f "${LOG_DIR}"
|
|
114
|
+
git commit -m "🤖 Agent Job: ${TITLE} (failed)" || true
|
|
115
|
+
else
|
|
116
|
+
# Claude Code succeeded — commit everything
|
|
117
|
+
git add -A
|
|
118
|
+
git add -f "${LOG_DIR}"
|
|
119
|
+
git commit -m "🤖 Agent Job: ${TITLE}" || true
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
git push origin
|
|
123
|
+
|
|
124
|
+
# Capture log commit SHA, then remove logs so they don't merge into main
|
|
125
|
+
LOG_SHA=$(git rev-parse HEAD)
|
|
126
|
+
git rm -rf "${LOG_DIR}"
|
|
127
|
+
git commit -m "done." || true
|
|
128
|
+
git push origin
|
|
129
|
+
set -e
|
|
130
|
+
|
|
131
|
+
# Cleanup Chrome
|
|
132
|
+
if [ -n "$CHROME_PID" ]; then
|
|
133
|
+
kill $CHROME_PID 2>/dev/null || true
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Create PR with log permalink (auto-merge handled by GitHub Actions workflow)
|
|
137
|
+
REPO_SLUG=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
138
|
+
LOG_URL="https://github.com/${REPO_SLUG}/tree/${LOG_SHA}/logs/${JOB_ID}"
|
|
139
|
+
gh pr create --title "🤖 Agent Job: ${TITLE}" \
|
|
140
|
+
--body "📋 [View Job Logs](${LOG_URL})"$'\n\n---\n\n'"${JOB_DESCRIPTION}" \
|
|
141
|
+
--base main || true
|
|
142
|
+
|
|
143
|
+
# Re-raise failure so the workflow reports it
|
|
144
|
+
if [ $AGENT_EXIT -ne 0 ]; then
|
|
145
|
+
echo "Claude Code exited with code ${AGENT_EXIT}"
|
|
146
|
+
exit $AGENT_EXIT
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
echo "Done. Job ID: ${JOB_ID}"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
FROM ubuntu:24.04
|
|
2
|
+
|
|
3
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
4
|
+
|
|
5
|
+
# System packages
|
|
6
|
+
RUN apt-get update && apt-get install -y \
|
|
7
|
+
tmux \
|
|
8
|
+
git \
|
|
9
|
+
curl \
|
|
10
|
+
jq \
|
|
11
|
+
build-essential \
|
|
12
|
+
locales \
|
|
13
|
+
fonts-noto-color-emoji \
|
|
14
|
+
fonts-symbola \
|
|
15
|
+
ca-certificates \
|
|
16
|
+
gnupg \
|
|
17
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
18
|
+
|
|
19
|
+
# Locale
|
|
20
|
+
RUN locale-gen en_US.UTF-8
|
|
21
|
+
ENV LANG=en_US.UTF-8
|
|
22
|
+
ENV LC_ALL=en_US.UTF-8
|
|
23
|
+
ENV LC_CTYPE=en_US.UTF-8
|
|
24
|
+
|
|
25
|
+
# GitHub CLI
|
|
26
|
+
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
|
27
|
+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
|
28
|
+
&& apt-get update && apt-get install -y gh \
|
|
29
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
30
|
+
|
|
31
|
+
# ttyd (web terminal)
|
|
32
|
+
RUN curl -fsSL -o /usr/local/bin/ttyd https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64 \
|
|
33
|
+
&& chmod +x /usr/local/bin/ttyd
|
|
34
|
+
|
|
35
|
+
# Node.js 22
|
|
36
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
|
37
|
+
&& apt-get install -y nodejs \
|
|
38
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
39
|
+
|
|
40
|
+
# Claude Code
|
|
41
|
+
RUN npm install -g @anthropic-ai/claude-code
|
|
42
|
+
|
|
43
|
+
# Non-root user
|
|
44
|
+
RUN useradd -m -s /bin/bash claude-code \
|
|
45
|
+
&& mkdir -p /home/claude-code/workspace \
|
|
46
|
+
&& chown claude-code:claude-code /home/claude-code/workspace
|
|
47
|
+
|
|
48
|
+
COPY .tmux.conf /home/claude-code/.tmux.conf
|
|
49
|
+
RUN chown claude-code:claude-code /home/claude-code/.tmux.conf
|
|
50
|
+
|
|
51
|
+
COPY entrypoint.sh /entrypoint.sh
|
|
52
|
+
RUN chmod +x /entrypoint.sh
|
|
53
|
+
|
|
54
|
+
USER claude-code
|
|
55
|
+
WORKDIR /home/claude-code/workspace
|
|
56
|
+
|
|
57
|
+
ENV REPO=""
|
|
58
|
+
ENV BRANCH=main
|
|
59
|
+
ENV PORT=7681
|
|
60
|
+
|
|
61
|
+
ENTRYPOINT ["/entrypoint.sh"]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Git setup - derive identity from GitHub token
|
|
5
|
+
gh auth setup-git
|
|
6
|
+
GH_USER_JSON=$(gh api user -q '{name: .name, login: .login, email: .email, id: .id}')
|
|
7
|
+
GH_USER_NAME=$(echo "$GH_USER_JSON" | jq -r '.name // .login')
|
|
8
|
+
GH_USER_EMAIL=$(echo "$GH_USER_JSON" | jq -r '.email // "\(.id)+\(.login)@users.noreply.github.com"')
|
|
9
|
+
git config --global user.name "$GH_USER_NAME"
|
|
10
|
+
git config --global user.email "$GH_USER_EMAIL"
|
|
11
|
+
|
|
12
|
+
# Clone repo (skip if already cloned — enables docker restart)
|
|
13
|
+
if [ -n "$REPO" ] && [ ! -d "/home/claude-code/workspace/.git" ]; then
|
|
14
|
+
git clone --branch "$BRANCH" "https://github.com/$REPO" /home/claude-code/workspace
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
cd /home/claude-code/workspace
|
|
18
|
+
WORKSPACE_DIR=$(pwd)
|
|
19
|
+
|
|
20
|
+
# Claude Code auth — use OAuth token, not API key
|
|
21
|
+
unset ANTHROPIC_API_KEY
|
|
22
|
+
export CLAUDE_CODE_OAUTH_TOKEN="${CLAUDE_CODE_OAUTH_TOKEN}"
|
|
23
|
+
|
|
24
|
+
# Skip onboarding and trust dialogs
|
|
25
|
+
mkdir -p ~/.claude
|
|
26
|
+
cat > ~/.claude/settings.json << 'EOF'
|
|
27
|
+
{
|
|
28
|
+
"theme": "dark",
|
|
29
|
+
"hasTrustDialogAccepted": true,
|
|
30
|
+
"skipDangerousModePermissionPrompt": true
|
|
31
|
+
}
|
|
32
|
+
EOF
|
|
33
|
+
|
|
34
|
+
cat > ~/.claude.json << ENDJSON
|
|
35
|
+
{
|
|
36
|
+
"hasCompletedOnboarding": true,
|
|
37
|
+
"projects": {
|
|
38
|
+
"${WORKSPACE_DIR}": {
|
|
39
|
+
"allowedTools": [],
|
|
40
|
+
"hasTrustDialogAccepted": true,
|
|
41
|
+
"hasTrustDialogHooksAccepted": true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
ENDJSON
|
|
46
|
+
|
|
47
|
+
# Start Claude Code in a tmux session
|
|
48
|
+
tmux -u new-session -d -s claude 'claude --dangerously-skip-permissions'
|
|
49
|
+
|
|
50
|
+
# Start ttyd in foreground (PID 1) — serves tmux over WebSocket
|
|
51
|
+
exec ttyd --writable -p "${PORT:-7681}" tmux attach -t claude
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
FROM node:22-bookworm-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y curl git python3 make g++ && \
|
|
4
|
+
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
5
|
+
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
|
|
6
|
+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
|
7
|
+
| tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \
|
|
8
|
+
apt-get update && apt-get install -y gh && \
|
|
9
|
+
rm -rf /var/lib/apt/lists/*
|
|
10
|
+
RUN npm install -g pm2
|
|
11
|
+
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY package.json package-lock.json* ./
|
|
14
|
+
RUN npm install --omit=dev && \
|
|
15
|
+
npm install --no-save gigabot@$(node -p "require('./package.json').version")
|
|
16
|
+
|
|
17
|
+
COPY /templates/docker/event-handler/ecosystem.config.cjs /opt/ecosystem.config.cjs
|
|
18
|
+
|
|
19
|
+
EXPOSE 80
|
|
20
|
+
CMD ["pm2-runtime", "/opt/ecosystem.config.cjs"]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
FROM node:22-bookworm-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y \
|
|
4
|
+
git \
|
|
5
|
+
jq \
|
|
6
|
+
curl \
|
|
7
|
+
procps \
|
|
8
|
+
# Chrome/Chromium dependencies
|
|
9
|
+
libnss3 \
|
|
10
|
+
libnspr4 \
|
|
11
|
+
libatk1.0-0 \
|
|
12
|
+
libatk-bridge2.0-0 \
|
|
13
|
+
libcups2 \
|
|
14
|
+
libdrm2 \
|
|
15
|
+
libdbus-1-3 \
|
|
16
|
+
libxkbcommon0 \
|
|
17
|
+
libatspi2.0-0 \
|
|
18
|
+
libxcomposite1 \
|
|
19
|
+
libxdamage1 \
|
|
20
|
+
libxfixes3 \
|
|
21
|
+
libxrandr2 \
|
|
22
|
+
libgbm1 \
|
|
23
|
+
libasound2 \
|
|
24
|
+
libpango-1.0-0 \
|
|
25
|
+
libcairo2 \
|
|
26
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
27
|
+
|
|
28
|
+
# Install GitHub CLI
|
|
29
|
+
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
|
30
|
+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
|
31
|
+
&& apt-get update && apt-get install -y gh \
|
|
32
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
33
|
+
|
|
34
|
+
RUN npm install -g @mariozechner/pi-coding-agent
|
|
35
|
+
|
|
36
|
+
# Create a non-root user and give it ownership of /job.
|
|
37
|
+
RUN useradd -m -s /bin/bash agent \
|
|
38
|
+
&& mkdir -p /job \
|
|
39
|
+
&& chown agent:agent /job
|
|
40
|
+
|
|
41
|
+
# Create Pi config directory (extension loaded from repo at runtime)
|
|
42
|
+
RUN mkdir -p /home/agent/.pi/agent \
|
|
43
|
+
&& chown -R agent:agent /home/agent/.pi
|
|
44
|
+
|
|
45
|
+
COPY entrypoint.sh /entrypoint.sh
|
|
46
|
+
RUN chmod +x /entrypoint.sh
|
|
47
|
+
|
|
48
|
+
USER agent
|
|
49
|
+
WORKDIR /job
|
|
50
|
+
|
|
51
|
+
ENTRYPOINT ["/entrypoint.sh"]
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Extract job ID from branch name (job/uuid -> uuid), fallback to random UUID
|
|
5
|
+
if [[ "$BRANCH" == job/* ]]; then
|
|
6
|
+
JOB_ID="${BRANCH#job/}"
|
|
7
|
+
else
|
|
8
|
+
JOB_ID=$(cat /proc/sys/kernel/random/uuid)
|
|
9
|
+
fi
|
|
10
|
+
echo "Job ID: ${JOB_ID}"
|
|
11
|
+
|
|
12
|
+
# Export SECRETS (JSON) as flat env vars (GH_TOKEN, ANTHROPIC_API_KEY, etc.)
|
|
13
|
+
# These are filtered from LLM's bash subprocess by env-sanitizer extension
|
|
14
|
+
if [ -n "$SECRETS" ]; then
|
|
15
|
+
eval $(echo "$SECRETS" | jq -r 'to_entries | .[] | "export \(.key)=\(.value | @sh)"')
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Export LLM_SECRETS (JSON) as flat env vars
|
|
19
|
+
# These are NOT filtered - LLM can access these (browser logins, skill API keys, etc.)
|
|
20
|
+
if [ -n "$LLM_SECRETS" ]; then
|
|
21
|
+
eval $(echo "$LLM_SECRETS" | jq -r 'to_entries | .[] | "export \(.key)=\(.value | @sh)"')
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Git setup - derive identity from GitHub token
|
|
25
|
+
gh auth setup-git
|
|
26
|
+
GH_USER_JSON=$(gh api user -q '{name: .name, login: .login, email: .email, id: .id}')
|
|
27
|
+
GH_USER_NAME=$(echo "$GH_USER_JSON" | jq -r '.name // .login')
|
|
28
|
+
GH_USER_EMAIL=$(echo "$GH_USER_JSON" | jq -r '.email // "\(.id)+\(.login)@users.noreply.github.com"')
|
|
29
|
+
git config --global user.name "$GH_USER_NAME"
|
|
30
|
+
git config --global user.email "$GH_USER_EMAIL"
|
|
31
|
+
|
|
32
|
+
# Clone branch
|
|
33
|
+
if [ -n "$REPO_URL" ]; then
|
|
34
|
+
git clone --single-branch --branch "$BRANCH" --depth 1 "$REPO_URL" /job
|
|
35
|
+
else
|
|
36
|
+
echo "No REPO_URL provided"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
cd /job
|
|
40
|
+
|
|
41
|
+
# Install npm deps for active skills (native deps need correct Linux arch)
|
|
42
|
+
for skill_dir in /job/skills/active/*/; do
|
|
43
|
+
if [ -f "${skill_dir}package.json" ]; then
|
|
44
|
+
echo "Installing skill deps: $(basename "$skill_dir")"
|
|
45
|
+
(cd "$skill_dir" && npm install --omit=dev --no-package-lock)
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
# Start Chrome if available (installed by browser-tools skill via Puppeteer)
|
|
50
|
+
CHROME_PID=""
|
|
51
|
+
CHROME_BIN=$(find /home/agent/.cache/puppeteer -name "chrome" -type f 2>/dev/null | head -1)
|
|
52
|
+
if [ -n "$CHROME_BIN" ]; then
|
|
53
|
+
$CHROME_BIN --headless --no-sandbox --disable-gpu --remote-debugging-port=9222 2>/dev/null &
|
|
54
|
+
CHROME_PID=$!
|
|
55
|
+
sleep 2
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Setup logs
|
|
59
|
+
LOG_DIR="/job/logs/${JOB_ID}"
|
|
60
|
+
mkdir -p "${LOG_DIR}"
|
|
61
|
+
|
|
62
|
+
# 1. Build system prompt from config MD files
|
|
63
|
+
SYSTEM_FILES=("SOUL.md" "JOB_AGENT.md")
|
|
64
|
+
> /job/.pi/SYSTEM.md
|
|
65
|
+
for i in "${!SYSTEM_FILES[@]}"; do
|
|
66
|
+
cat "/job/config/${SYSTEM_FILES[$i]}" >> /job/.pi/SYSTEM.md
|
|
67
|
+
if [ "$i" -lt $((${#SYSTEM_FILES[@]} - 1)) ]; then
|
|
68
|
+
echo -e "\n\n" >> /job/.pi/SYSTEM.md
|
|
69
|
+
fi
|
|
70
|
+
done
|
|
71
|
+
|
|
72
|
+
# Resolve {{datetime}} variable in SYSTEM.md
|
|
73
|
+
sed -i "s/{{datetime}}/$(date -u +"%Y-%m-%dT%H:%M:%SZ")/g" /job/.pi/SYSTEM.md
|
|
74
|
+
|
|
75
|
+
# Read job metadata from job.config.json
|
|
76
|
+
JOB_CONFIG="/job/logs/${JOB_ID}/job.config.json"
|
|
77
|
+
TITLE=$(jq -r '.title // empty' "$JOB_CONFIG")
|
|
78
|
+
JOB_DESCRIPTION=$(jq -r '.job // empty' "$JOB_CONFIG")
|
|
79
|
+
|
|
80
|
+
PROMPT="
|
|
81
|
+
|
|
82
|
+
# Your Job
|
|
83
|
+
|
|
84
|
+
${JOB_DESCRIPTION}"
|
|
85
|
+
|
|
86
|
+
LLM_PROVIDER="${LLM_PROVIDER:-anthropic}"
|
|
87
|
+
|
|
88
|
+
MODEL_FLAGS="--provider $LLM_PROVIDER"
|
|
89
|
+
if [ -n "$LLM_MODEL" ]; then
|
|
90
|
+
MODEL_FLAGS="$MODEL_FLAGS --model $LLM_MODEL"
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# Generate models.json for custom provider (OpenAI-compatible endpoints like Ollama)
|
|
94
|
+
if [ "$LLM_PROVIDER" = "custom" ] && [ -n "$OPENAI_BASE_URL" ]; then
|
|
95
|
+
# If no API key was provided, set a dummy so Pi doesn't send empty auth
|
|
96
|
+
if [ -z "$CUSTOM_API_KEY" ]; then
|
|
97
|
+
export CUSTOM_API_KEY="not-needed"
|
|
98
|
+
fi
|
|
99
|
+
cat > /home/agent/.pi/agent/models.json <<MODELS
|
|
100
|
+
{
|
|
101
|
+
"providers": {
|
|
102
|
+
"custom": {
|
|
103
|
+
"baseUrl": "$OPENAI_BASE_URL",
|
|
104
|
+
"api": "openai-completions",
|
|
105
|
+
"apiKey": "CUSTOM_API_KEY",
|
|
106
|
+
"models": [{ "id": "$LLM_MODEL" }]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
MODELS
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Copy custom models.json to PI's global config if present in repo (overrides generated)
|
|
114
|
+
if [ -f "/job/.pi/agent/models.json" ]; then
|
|
115
|
+
mkdir -p /home/agent/.pi/agent
|
|
116
|
+
cp /job/.pi/agent/models.json /home/agent/.pi/agent/models.json
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# Run Pi — capture exit code instead of letting set -e kill the script
|
|
120
|
+
set +e
|
|
121
|
+
pi $MODEL_FLAGS -p "$PROMPT" --session-dir "${LOG_DIR}"
|
|
122
|
+
PI_EXIT=$?
|
|
123
|
+
|
|
124
|
+
# 2. Commit based on outcome
|
|
125
|
+
if [ $PI_EXIT -ne 0 ]; then
|
|
126
|
+
# Pi failed — only commit session logs, not partial code changes
|
|
127
|
+
git reset || true
|
|
128
|
+
git add -f "${LOG_DIR}"
|
|
129
|
+
git commit -m "🤖 Agent Job: ${TITLE} (failed)" || true
|
|
130
|
+
else
|
|
131
|
+
# Pi succeeded — commit everything
|
|
132
|
+
git add -A
|
|
133
|
+
git add -f "${LOG_DIR}"
|
|
134
|
+
git commit -m "🤖 Agent Job: ${TITLE}" || true
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
git push origin
|
|
138
|
+
|
|
139
|
+
# Capture log commit SHA, then remove logs so they don't merge into main
|
|
140
|
+
LOG_SHA=$(git rev-parse HEAD)
|
|
141
|
+
git rm -rf "${LOG_DIR}"
|
|
142
|
+
git commit -m "done." || true
|
|
143
|
+
git push origin
|
|
144
|
+
set -e
|
|
145
|
+
|
|
146
|
+
# Create PR with log permalink (auto-merge handled by GitHub Actions workflow)
|
|
147
|
+
REPO_SLUG=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
148
|
+
LOG_URL="https://github.com/${REPO_SLUG}/tree/${LOG_SHA}/logs/${JOB_ID}"
|
|
149
|
+
gh pr create --title "🤖 Agent Job: ${TITLE}" \
|
|
150
|
+
--body "📋 [View Job Logs](${LOG_URL})"$'\n\n---\n\n'"${JOB_DESCRIPTION}" \
|
|
151
|
+
--base main || true
|
|
152
|
+
|
|
153
|
+
# Cleanup
|
|
154
|
+
if [ -n "$CHROME_PID" ]; then
|
|
155
|
+
kill $CHROME_PID 2>/dev/null || true
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Re-raise Pi's failure so the workflow reports it
|
|
159
|
+
if [ $PI_EXIT -ne 0 ]; then
|
|
160
|
+
echo "Pi exited with code ${PI_EXIT}"
|
|
161
|
+
exit $PI_EXIT
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
echo "Done. Job ID: ${JOB_ID}"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# GigaClaw — Local Mode (docker-compose.local.yml)
|
|
2
|
+
# Runs GigaClaw 100% offline using Ollama for LLM inference.
|
|
3
|
+
# No GitHub, no ngrok, no Telegram required.
|
|
4
|
+
#
|
|
5
|
+
# Prerequisites:
|
|
6
|
+
# 1. Install Ollama: https://ollama.com/download
|
|
7
|
+
# 2. Pull a model: ollama pull llama3.1:8b
|
|
8
|
+
# 3. Start Ollama: ollama serve
|
|
9
|
+
#
|
|
10
|
+
# Start GigaClaw:
|
|
11
|
+
# docker compose -f docker-compose.local.yml up -d
|
|
12
|
+
#
|
|
13
|
+
# Access the web interface at: http://localhost:3000
|
|
14
|
+
#
|
|
15
|
+
# ─── NOTE ────────────────────────────────────────────────────────────────────
|
|
16
|
+
# This compose file builds GigaClaw from your local source code using the
|
|
17
|
+
# official Node.js image. No private Docker registry or login is required.
|
|
18
|
+
# First build: ~2-3 minutes. Subsequent starts: instant.
|
|
19
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
services:
|
|
22
|
+
gigaclaw:
|
|
23
|
+
container_name: gigaclaw-local
|
|
24
|
+
# Build from local source — no private registry or docker login required
|
|
25
|
+
build:
|
|
26
|
+
context: .
|
|
27
|
+
dockerfile_inline: |
|
|
28
|
+
FROM node:20-alpine
|
|
29
|
+
WORKDIR /app
|
|
30
|
+
COPY package*.json ./
|
|
31
|
+
RUN npm ci
|
|
32
|
+
COPY . .
|
|
33
|
+
EXPOSE 3000
|
|
34
|
+
ENV NODE_ENV=development
|
|
35
|
+
CMD ["npm", "run", "dev"]
|
|
36
|
+
ports:
|
|
37
|
+
- "3000:3000"
|
|
38
|
+
volumes:
|
|
39
|
+
# Mount source for hot-reload in dev mode
|
|
40
|
+
- .:/app
|
|
41
|
+
- /app/node_modules
|
|
42
|
+
# Persist the SQLite database across container restarts
|
|
43
|
+
- gigaclaw-data:/app/data
|
|
44
|
+
environment:
|
|
45
|
+
# Ollama runs on the host machine — Docker reaches it via host.docker.internal
|
|
46
|
+
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
|
|
47
|
+
- NODE_ENV=development
|
|
48
|
+
env_file:
|
|
49
|
+
- .env
|
|
50
|
+
extra_hosts:
|
|
51
|
+
# Ensures host.docker.internal resolves on Linux (already works on macOS/Windows)
|
|
52
|
+
- "host.docker.internal:host-gateway"
|
|
53
|
+
stop_grace_period: 30s
|
|
54
|
+
healthcheck:
|
|
55
|
+
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/ping"]
|
|
56
|
+
interval: 15s
|
|
57
|
+
timeout: 5s
|
|
58
|
+
retries: 3
|
|
59
|
+
start_period: 60s
|
|
60
|
+
restart: unless-stopped
|
|
61
|
+
|
|
62
|
+
# Optional: self-hosted push notifications over LAN (no internet required)
|
|
63
|
+
# Enable with: docker compose -f docker-compose.local.yml --profile notifications up -d
|
|
64
|
+
ntfy:
|
|
65
|
+
image: binwiederhier/ntfy
|
|
66
|
+
container_name: gigaclaw-ntfy
|
|
67
|
+
ports:
|
|
68
|
+
- "8080:80"
|
|
69
|
+
command: serve --base-url http://localhost:8080
|
|
70
|
+
volumes:
|
|
71
|
+
- ntfy-data:/var/cache/ntfy
|
|
72
|
+
profiles:
|
|
73
|
+
- notifications
|
|
74
|
+
restart: unless-stopped
|
|
75
|
+
|
|
76
|
+
volumes:
|
|
77
|
+
gigaclaw-data:
|
|
78
|
+
ntfy-data:
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
services:
|
|
2
|
+
traefik:
|
|
3
|
+
image: traefik:v3
|
|
4
|
+
command:
|
|
5
|
+
- --providers.docker=true
|
|
6
|
+
- --providers.docker.exposedByDefault=false
|
|
7
|
+
- --entrypoints.web.address=:80
|
|
8
|
+
- --entrypoints.websecure.address=:443
|
|
9
|
+
## Uncomment the following lines to enable TLS via Let's Encrypt
|
|
10
|
+
## (requires LETSENCRYPT_EMAIL in .env):
|
|
11
|
+
# - --entrypoints.web.http.redirections.entrypoint.to=websecure
|
|
12
|
+
# - --entrypoints.web.http.redirections.entrypoint.scheme=https
|
|
13
|
+
# - --certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}
|
|
14
|
+
# - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
|
15
|
+
# - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
|
|
16
|
+
ports:
|
|
17
|
+
- "80:80"
|
|
18
|
+
- "443:443"
|
|
19
|
+
volumes:
|
|
20
|
+
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
21
|
+
- traefik_certs:/letsencrypt
|
|
22
|
+
restart: unless-stopped
|
|
23
|
+
|
|
24
|
+
event-handler:
|
|
25
|
+
container_name: gigaclaw-event-handler
|
|
26
|
+
image: ${EVENT_HANDLER_IMAGE_URL:-gignaati/gigaclaw:event-handler-${GIGACLAW_VERSION:-latest}}
|
|
27
|
+
volumes:
|
|
28
|
+
- .:/app
|
|
29
|
+
- /app/node_modules
|
|
30
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
31
|
+
labels:
|
|
32
|
+
- traefik.enable=true
|
|
33
|
+
# Set APP_HOSTNAME in .env to the domain from APP_URL (e.g., mybot.example.com)
|
|
34
|
+
- traefik.http.routers.event-handler.rule=Host(`${APP_HOSTNAME}`)
|
|
35
|
+
- traefik.http.routers.event-handler.entrypoints=web
|
|
36
|
+
- traefik.http.services.event-handler.loadbalancer.server.port=80
|
|
37
|
+
## Uncomment the following lines to enable TLS via Let's Encrypt:
|
|
38
|
+
# - traefik.http.routers.event-handler.entrypoints=websecure
|
|
39
|
+
# - traefik.http.routers.event-handler.tls.certresolver=letsencrypt
|
|
40
|
+
stop_grace_period: 120s
|
|
41
|
+
healthcheck:
|
|
42
|
+
test: ["CMD", "curl", "-f", "http://localhost:80/api/ping"]
|
|
43
|
+
interval: 10s
|
|
44
|
+
timeout: 3s
|
|
45
|
+
retries: 3
|
|
46
|
+
start_period: 30s
|
|
47
|
+
restart: unless-stopped
|
|
48
|
+
|
|
49
|
+
runner:
|
|
50
|
+
image: myoung34/github-runner:latest
|
|
51
|
+
deploy:
|
|
52
|
+
replicas: ${RUNNER_REPLICAS:-2}
|
|
53
|
+
environment:
|
|
54
|
+
REPO_URL: https://github.com/${GH_OWNER}/${GH_REPO}
|
|
55
|
+
ACCESS_TOKEN: ${GH_TOKEN}
|
|
56
|
+
RUNNER_SCOPE: repo
|
|
57
|
+
LABELS: self-hosted
|
|
58
|
+
volumes:
|
|
59
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
60
|
+
- .:/project:ro
|
|
61
|
+
restart: unless-stopped
|
|
62
|
+
|
|
63
|
+
volumes:
|
|
64
|
+
traefik_certs:
|