thepopebot 1.2.74-beta.9 → 1.2.75-beta.1
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 +37 -38
- package/api/CLAUDE.md +8 -5
- package/api/index.js +185 -25
- package/bin/CLAUDE.md +37 -0
- package/bin/cli.js +9 -73
- package/bin/docker-build.js +94 -32
- package/bin/managed-paths.js +6 -0
- package/bin/sync.js +177 -78
- package/config/CLAUDE.md +19 -9
- package/config/instrumentation.js +8 -4
- package/drizzle/0016_majestic_metal_master.sql +1 -0
- package/drizzle/0017_smart_trauma.sql +1 -0
- package/drizzle/0018_aberrant_vertigo.sql +1 -0
- package/drizzle/0019_slimy_midnight.sql +1 -0
- package/drizzle/0020_natural_fabian_cortez.sql +1 -0
- package/drizzle/meta/0016_snapshot.json +616 -0
- package/drizzle/meta/0017_snapshot.json +624 -0
- package/drizzle/meta/0018_snapshot.json +632 -0
- package/drizzle/meta/0019_snapshot.json +640 -0
- package/drizzle/meta/0020_snapshot.json +632 -0
- package/drizzle/meta/_journal.json +35 -0
- package/lib/CLAUDE.md +2 -2
- package/lib/actions.js +4 -4
- package/lib/ai/CLAUDE.md +40 -17
- package/lib/ai/agent.js +33 -64
- package/lib/ai/headless-stream.js +55 -93
- package/lib/ai/index.js +116 -88
- package/lib/ai/line-mappers.js +393 -0
- package/lib/ai/model.js +43 -5
- package/lib/ai/tools.js +109 -309
- package/lib/auth/CLAUDE.md +8 -0
- package/lib/auth/components/login-form.js +1 -1
- package/lib/auth/components/login-form.jsx +1 -1
- package/lib/auth/components/setup-form.js +50 -1
- package/lib/auth/components/setup-form.jsx +57 -2
- package/lib/auth/middleware.js +1 -1
- package/lib/chat/CLAUDE.md +53 -0
- package/lib/chat/actions.js +472 -32
- package/lib/chat/api.js +340 -6
- package/lib/chat/components/CLAUDE.md +145 -0
- package/lib/chat/components/app-sidebar.js +11 -13
- package/lib/chat/components/app-sidebar.jsx +14 -17
- package/lib/chat/components/chat-header.js +15 -6
- package/lib/chat/components/chat-header.jsx +27 -8
- package/lib/chat/components/chat-input.js +142 -23
- package/lib/chat/components/chat-input.jsx +134 -27
- package/lib/chat/components/chat-page.js +10 -4
- package/lib/chat/components/chat-page.jsx +53 -45
- package/lib/chat/components/chat.js +254 -67
- package/lib/chat/components/chat.jsx +275 -81
- package/lib/chat/components/chats-page.js +32 -5
- package/lib/chat/components/chats-page.jsx +45 -6
- package/lib/chat/components/code-mode-toggle.js +311 -162
- package/lib/chat/components/code-mode-toggle.jsx +349 -198
- package/lib/chat/components/containers-page.js +542 -0
- package/lib/chat/components/containers-page.jsx +710 -0
- package/lib/chat/components/diff-viewer.js +138 -0
- package/lib/chat/components/diff-viewer.jsx +158 -0
- package/lib/chat/components/icons.js +88 -0
- package/lib/chat/components/icons.jsx +82 -0
- package/lib/chat/components/index.js +6 -4
- package/lib/chat/components/message.js +107 -27
- package/lib/chat/components/message.jsx +128 -30
- package/lib/chat/components/notifications-page.js +1 -1
- package/lib/chat/components/notifications-page.jsx +1 -1
- package/lib/chat/components/profile-page.js +1 -1
- package/lib/chat/components/profile-page.jsx +1 -1
- package/lib/chat/components/runners-page.js +1 -1
- package/lib/chat/components/runners-page.jsx +1 -1
- package/lib/chat/components/settings-chat-page.js +458 -311
- package/lib/chat/components/settings-chat-page.jsx +412 -272
- package/lib/chat/components/settings-coding-agents-page.js +767 -0
- package/lib/chat/components/settings-coding-agents-page.jsx +940 -0
- package/lib/chat/components/settings-general-page.js +189 -29
- package/lib/chat/components/settings-general-page.jsx +178 -14
- package/lib/chat/components/settings-github-page.js +103 -475
- package/lib/chat/components/settings-github-page.jsx +96 -462
- package/lib/chat/components/settings-jobs-page.js +585 -0
- package/lib/chat/components/settings-jobs-page.jsx +684 -0
- package/lib/chat/components/settings-layout.js +5 -6
- package/lib/chat/components/settings-layout.jsx +5 -6
- package/lib/chat/components/settings-secrets-layout.js +15 -6
- package/lib/chat/components/settings-secrets-layout.jsx +16 -6
- package/lib/chat/components/settings-secrets-page.js +23 -189
- package/lib/chat/components/settings-secrets-page.jsx +20 -195
- package/lib/chat/components/settings-shared.js +328 -0
- package/lib/chat/components/settings-shared.jsx +339 -0
- package/lib/chat/components/settings-users-page.js +22 -58
- package/lib/chat/components/settings-users-page.jsx +19 -57
- package/lib/chat/components/sidebar-history-item.js +5 -2
- package/lib/chat/components/sidebar-history-item.jsx +7 -2
- package/lib/chat/components/sidebar-history.js +9 -10
- package/lib/chat/components/sidebar-history.jsx +10 -10
- package/lib/chat/components/tool-call.js +2 -2
- package/lib/chat/components/tool-call.jsx +2 -2
- package/lib/chat/components/ui/combobox.js +12 -8
- package/lib/chat/components/ui/combobox.jsx +17 -9
- package/lib/chat/components/ui/dropdown-menu.js +52 -26
- package/lib/chat/components/ui/dropdown-menu.jsx +40 -18
- package/lib/chat/components/upgrade-dialog.js +3 -3
- package/lib/chat/components/upgrade-dialog.jsx +3 -3
- package/lib/chat/components/voice-bars.js +2 -2
- package/lib/chat/components/voice-bars.jsx +2 -2
- package/lib/cluster/CLAUDE.md +1 -1
- package/lib/cluster/actions.js +2 -2
- package/lib/cluster/components/cluster-console-page.js +3 -3
- package/lib/cluster/components/cluster-console-page.jsx +3 -3
- package/lib/cluster/components/cluster-logs-page.js +7 -37
- package/lib/cluster/components/cluster-logs-page.jsx +7 -40
- package/lib/cluster/components/cluster-page.js +82 -17
- package/lib/cluster/components/cluster-page.jsx +77 -16
- package/lib/cluster/components/clusters-page.js +13 -1
- package/lib/cluster/components/clusters-page.jsx +17 -3
- package/lib/cluster/execute.js +6 -3
- package/lib/cluster/runtime.js +2 -1
- package/lib/cluster/stream.js +22 -34
- package/lib/code/CLAUDE.md +13 -1
- package/lib/code/actions.js +741 -151
- package/lib/code/code-page.js +266 -105
- package/lib/code/code-page.jsx +281 -113
- package/lib/code/editor-view.js +662 -0
- package/lib/code/editor-view.jsx +749 -0
- package/lib/code/port-forwards.js +152 -0
- package/lib/code/terminal-sessions.js +4 -1
- package/lib/code/terminal-view.js +450 -35
- package/lib/code/terminal-view.jsx +437 -30
- package/lib/config.js +57 -15
- package/lib/containers/CLAUDE.md +9 -0
- package/lib/containers/logs.js +178 -0
- package/lib/containers/stream.js +72 -0
- package/lib/cron.js +1 -1
- package/lib/db/CLAUDE.md +36 -3
- package/lib/db/api-keys.js +73 -14
- package/lib/db/chats.js +3 -1
- package/lib/db/clusters.js +1 -0
- package/lib/db/code-workspaces.js +27 -3
- package/lib/db/config.js +172 -11
- package/lib/db/index.js +16 -6
- package/lib/db/oauth-tokens.js +157 -0
- package/lib/db/schema.js +4 -1
- package/lib/llm-providers.js +93 -10
- package/lib/maintenance.js +35 -0
- package/lib/oauth/helper.js +92 -0
- package/lib/oauth/providers.js +35 -0
- package/lib/paths.js +7 -9
- package/lib/tools/CLAUDE.md +7 -3
- package/lib/tools/create-agent-job.js +140 -0
- package/lib/tools/docker.js +548 -73
- package/lib/tools/github.js +40 -71
- package/lib/utils/random-name.js +58 -0
- package/lib/utils/render-md.js +2 -13
- package/lib/voice/use-voice-input.js +8 -3
- package/package.json +13 -1
- package/setup/CLAUDE.md +32 -0
- package/setup/lib/providers.mjs +11 -0
- package/setup/lib/targets.mjs +2 -1
- package/setup/setup.mjs +64 -460
- package/templates/.env.example +3 -0
- package/templates/.github/workflows/CLAUDE.md.template +16 -0
- package/templates/.github/workflows/auto-merge.yml +1 -1
- package/templates/.github/workflows/notify-pr-complete.yml +8 -8
- package/templates/.github/workflows/rebuild-event-handler.yml +9 -5
- package/templates/.github/workflows/upgrade-event-handler.yml +1 -1
- package/templates/.gitignore.template +9 -10
- package/templates/CLAUDE.md +1 -1
- package/templates/CLAUDE.md.template +130 -74
- package/templates/README.md +75 -0
- package/templates/config/CLAUDE.md.template +40 -0
- package/templates/config/agent-chat/SYSTEM.md +76 -0
- package/templates/config/code-chat/SYSTEM.md +10 -0
- package/templates/config/litellm/main.yaml +6 -0
- package/templates/cron/.gitkeep +0 -0
- package/templates/cron/CLAUDE.md.template +24 -0
- package/templates/docker-compose.custom.yml +2 -1
- package/templates/docker-compose.litellm.yml +82 -0
- package/templates/docker-compose.yml +2 -1
- package/templates/docs/CLAUDE.md.template +12 -0
- package/templates/docs/CLI.md +59 -0
- package/templates/docs/CLUSTERS.md +151 -0
- package/templates/docs/CONFIGURATION.md +181 -0
- package/templates/docs/CRONS_AND_TRIGGERS.md +132 -0
- package/templates/docs/GETTING_STARTED.md +64 -0
- package/templates/docs/SECURITY.md +61 -0
- package/templates/docs/SKILLS.md +113 -0
- package/templates/docs/UPGRADING.md +92 -0
- package/templates/logs/.gitkeep +0 -0
- package/templates/skills/CLAUDE.md.template +109 -0
- package/templates/skills/README.md +0 -2
- package/templates/skills/agent-job-secrets/SKILL.md +25 -0
- package/templates/skills/agent-job-secrets/agent-job-secrets.js +66 -0
- package/templates/skills/playwright-cli/SKILL.md +294 -0
- package/templates/triggers/.gitkeep +0 -0
- package/templates/triggers/CLAUDE.md.template +41 -0
- package/lib/ai/web-search.js +0 -44
- package/lib/chat/components/features-context.js +0 -14
- package/lib/chat/components/features-context.jsx +0 -13
- package/lib/tools/create-job.js +0 -97
- package/templates/.github/workflows/notify-job-failed.yml +0 -64
- package/templates/.github/workflows/run-job.yml +0 -89
- package/templates/config/CODE_PLANNING.md +0 -14
- package/templates/config/JOB_PLANNING.md +0 -240
- package/templates/config/SKILL_BUILDING_GUIDE.md +0 -96
- package/templates/config/WEB_SEARCH_AVAILABLE.md +0 -5
- package/templates/config/WEB_SEARCH_UNAVAILABLE.md +0 -3
- package/templates/skills/brave-search/SKILL.md +0 -79
- package/templates/skills/brave-search/content.js +0 -86
- package/templates/skills/brave-search/package-lock.json +0 -621
- package/templates/skills/brave-search/package.json +0 -14
- package/templates/skills/brave-search/search.js +0 -199
- package/templates/skills/browser-tools/SKILL.md +0 -196
- package/templates/skills/browser-tools/browser-content.js +0 -103
- package/templates/skills/browser-tools/browser-cookies.js +0 -35
- package/templates/skills/browser-tools/browser-eval.js +0 -53
- package/templates/skills/browser-tools/browser-hn-scraper.js +0 -108
- package/templates/skills/browser-tools/browser-nav.js +0 -44
- package/templates/skills/browser-tools/browser-pick.js +0 -162
- package/templates/skills/browser-tools/browser-screenshot.js +0 -34
- package/templates/skills/browser-tools/browser-start.js +0 -87
- package/templates/skills/browser-tools/package-lock.json +0 -2556
- package/templates/skills/browser-tools/package.json +0 -19
- package/templates/skills/google-docs/SKILL.md +0 -23
- package/templates/skills/google-docs/create.sh +0 -69
- package/templates/skills/google-drive/SKILL.md +0 -47
- package/templates/skills/google-drive/delete.sh +0 -47
- package/templates/skills/google-drive/download.sh +0 -50
- package/templates/skills/google-drive/list.sh +0 -41
- package/templates/skills/google-drive/upload.sh +0 -76
- package/templates/skills/kie-ai/SKILL.md +0 -38
- package/templates/skills/kie-ai/generate-image.sh +0 -77
- package/templates/skills/kie-ai/generate-video.sh +0 -69
- package/templates/skills/llm-secrets/SKILL.md +0 -34
- package/templates/skills/llm-secrets/llm-secrets.js +0 -33
- package/templates/skills/modify-self/SKILL.md +0 -12
- package/templates/skills/youtube-transcript/SKILL.md +0 -41
- package/templates/skills/youtube-transcript/package-lock.json +0 -24
- package/templates/skills/youtube-transcript/package.json +0 -8
- package/templates/skills/youtube-transcript/transcript.js +0 -84
- /package/lib/{cluster → chat}/components/code-log-view.js +0 -0
- /package/lib/{cluster → chat}/components/code-log-view.jsx +0 -0
- /package/templates/config/{JOB_AGENT.md → agent-job/AGENT_JOB.md} +0 -0
- /package/templates/config/{SOUL.md → agent-job/SOUL.md} +0 -0
- /package/templates/config/{JOB_SUMMARY.md → agent-job/SUMMARY.md} +0 -0
- /package/templates/config/{CLUSTER_ROLE_PROMPT.md → cluster/ROLE.md} +0 -0
- /package/templates/config/{CLUSTER_SYSTEM_PROMPT.md → cluster/SYSTEM.md} +0 -0
package/README.md
CHANGED
|
@@ -22,36 +22,36 @@ Build autonomous AI agents that work for you 24/7, individually or in teams.
|
|
|
22
22
|
│ │
|
|
23
23
|
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
24
24
|
│ │ Event Handler │ ──1──► │ GitHub │ │
|
|
25
|
-
│ │
|
|
26
|
-
│ └────────▲────────┘
|
|
27
|
-
│ │
|
|
28
|
-
│ │
|
|
29
|
-
│ │
|
|
30
|
-
│
|
|
31
|
-
│
|
|
32
|
-
│
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
│ │
|
|
36
|
-
│ │
|
|
37
|
-
│ │
|
|
38
|
-
│
|
|
39
|
-
│
|
|
40
|
-
│
|
|
41
|
-
│
|
|
42
|
-
│
|
|
43
|
-
│ │
|
|
44
|
-
│ │
|
|
45
|
-
│ │
|
|
46
|
-
│ │
|
|
47
|
-
│ 5 (notify-pr-complete.yml
|
|
48
|
-
│ │
|
|
49
|
-
│
|
|
25
|
+
│ │ (creates branch)│ │(agent-job/* br) │ │
|
|
26
|
+
│ └────────▲────────┘ └─────────────────┘ │
|
|
27
|
+
│ │ │
|
|
28
|
+
│ │ 2 (launches Docker container locally) │
|
|
29
|
+
│ │ │
|
|
30
|
+
│ ▼ │
|
|
31
|
+
│ ┌─────────────────┐ │
|
|
32
|
+
│ │ Docker Agent │ │
|
|
33
|
+
│ │ (coding agent) │ │
|
|
34
|
+
│ └────────┬────────┘ │
|
|
35
|
+
│ │ │
|
|
36
|
+
│ │ 3 (commits, pushes, creates PR) │
|
|
37
|
+
│ │ │
|
|
38
|
+
│ ▼ │
|
|
39
|
+
│ ┌─────────────────┐ │
|
|
40
|
+
│ │ GitHub │ │
|
|
41
|
+
│ │ (PR opened) │ │
|
|
42
|
+
│ └────────┬────────┘ │
|
|
43
|
+
│ │ │
|
|
44
|
+
│ │ 4a (auto-merge.yml) │
|
|
45
|
+
│ │ 4b (rebuild-event-handler.yml) │
|
|
46
|
+
│ │ │
|
|
47
|
+
│ 5 (notify-pr-complete.yml → │
|
|
48
|
+
│ │ webhook to event handler) │
|
|
49
|
+
│ └──────────────────────────► Event Handler │
|
|
50
50
|
│ │
|
|
51
51
|
└──────────────────────────────────────────────────────────────────────┘
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
You interact with your bot via the web chat interface or Telegram (optional). The Event Handler creates
|
|
54
|
+
You interact with your bot via the web chat interface or Telegram (optional). The Event Handler creates an agent-job branch and launches a Docker container locally with the coding agent. The agent does the work, commits the results, pushes, and opens a PR. Auto-merge handles the rest. You get a notification when it's done.
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -94,19 +94,18 @@ npm run setup
|
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
The wizard walks you through everything:
|
|
97
|
-
- Checks prerequisites (Node.js, Git, GitHub CLI)
|
|
97
|
+
- Checks prerequisites (Node.js, Git, GitHub CLI, Docker)
|
|
98
98
|
- Creates a GitHub repository and pushes your initial commit
|
|
99
99
|
- Creates a GitHub Personal Access Token (scoped to your repo)
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
- Builds the project and starts Docker for you
|
|
100
|
+
- Configures your public URL and webhook secret
|
|
101
|
+
- Syncs settings to `.env`, database, and GitHub secrets/variables
|
|
102
|
+
- Starts Docker for you
|
|
104
103
|
|
|
105
104
|
**That's it.** Visit your APP_URL when the wizard finishes.
|
|
106
105
|
|
|
107
106
|
- **Web Chat**: Visit your APP_URL to chat with your agent, create jobs, upload files
|
|
108
107
|
- **Telegram** (optional): Run `npm run setup-telegram` to connect a Telegram bot
|
|
109
|
-
- **Webhook**: Send a POST to `/api/create-job` with your API key to create jobs programmatically
|
|
108
|
+
- **Webhook**: Send a POST to `/api/create-agent-job` with your API key to create jobs programmatically
|
|
110
109
|
- **Cron**: Edit `config/CRONS.json` to schedule recurring jobs
|
|
111
110
|
|
|
112
111
|
### Chat vs Agent LLM
|
|
@@ -135,7 +134,7 @@ claude setup-token
|
|
|
135
134
|
|
|
136
135
|
Paste the token (starts with `sk-ant-oat01-`) into the setup wizard. Your agent jobs will now run through your subscription. Note that usage counts toward your Claude.ai limits, and you still need an API key for the chat side.
|
|
137
136
|
|
|
138
|
-
See [
|
|
137
|
+
See [Coding Agents](docs/CODING_AGENTS.md) for details on all five agent backends.
|
|
139
138
|
|
|
140
139
|
> **Local installs**: Your server needs to be reachable from the internet for GitHub webhooks and Telegram. On a VPS/cloud server, your APP_URL is just your domain. For local development, use [ngrok](https://ngrok.com) (`ngrok http 80`) or port forwarding to expose your machine.
|
|
141
140
|
>
|
|
@@ -187,9 +186,9 @@ See [Security](docs/SECURITY.md) for full details on what's exposed, the risks,
|
|
|
187
186
|
|
|
188
187
|
## Different Models
|
|
189
188
|
|
|
190
|
-
|
|
189
|
+
thepopebot supports 9 built-in LLM providers (Anthropic, OpenAI, Google, DeepSeek, MiniMax, Mistral, xAI, Kimi, OpenRouter) plus custom OpenAI-compatible endpoints. The chat layer and coding agents are independent — use Claude for interactive chat and a different model for code tasks, or run everything on a single provider.
|
|
191
190
|
|
|
192
|
-
See [Different Models](docs/RUNNING_DIFFERENT_MODELS.md) for the full
|
|
191
|
+
See [Different Models](docs/RUNNING_DIFFERENT_MODELS.md) for the full provider reference, admin UI configuration, per-job overrides, and custom provider setup.
|
|
193
192
|
|
|
194
193
|
---
|
|
195
194
|
|
|
@@ -199,13 +198,13 @@ See [Different Models](docs/RUNNING_DIFFERENT_MODELS.md) for the full guide: Eve
|
|
|
199
198
|
|----------|-------------|
|
|
200
199
|
| [Architecture](docs/ARCHITECTURE.md) | Two-layer design, file structure, API endpoints, GitHub Actions, Docker agent |
|
|
201
200
|
| [CLI Reference](docs/CLI.md) | `init`, managed vs user files, template conventions, all CLI commands |
|
|
202
|
-
| [Configuration](docs/CONFIGURATION.md) |
|
|
201
|
+
| [Configuration](docs/CONFIGURATION.md) | Admin UI, DB-backed config, infrastructure variables, GitHub secrets, Docker Compose |
|
|
203
202
|
| [Customization](docs/CUSTOMIZATION.md) | Personality, skills, operating system files, using your bot, security details |
|
|
204
203
|
| [Chat Integrations](docs/CHAT_INTEGRATIONS.md) | Web chat, Telegram, adding new channels |
|
|
205
|
-
| [Different Models](docs/RUNNING_DIFFERENT_MODELS.md) |
|
|
204
|
+
| [Different Models](docs/RUNNING_DIFFERENT_MODELS.md) | 9 built-in LLM providers, chat vs coding agent config, per-job overrides, custom providers |
|
|
206
205
|
| [Auto-Merge](docs/AUTO_MERGE.md) | Auto-merge controls, ALLOWED_PATHS configuration |
|
|
207
206
|
| [Deployment](docs/DEPLOYMENT.md) | VPS setup, Docker Compose, HTTPS with Let's Encrypt |
|
|
208
|
-
| [
|
|
207
|
+
| [Coding Agents](docs/CODING_AGENTS.md) | 5 coding agent backends, OAuth tokens, LiteLLM proxy, per-agent config |
|
|
209
208
|
| [How to Build Skills](docs/HOW_TO_BUILD_SKILLS.md) | Guide to building and activating agent skills |
|
|
210
209
|
| [Pre-Release](docs/PRE_RELEASE.md) | Installing beta/alpha builds |
|
|
211
210
|
| [Code Workspaces](docs/CODE_WORKSPACES.md) | Interactive Docker containers with in-browser terminal |
|
package/api/CLAUDE.md
CHANGED
|
@@ -10,21 +10,24 @@ Auth flow: `x-api-key` header -> `verifyApiKey()` -> database lookup (hashed, ti
|
|
|
10
10
|
|
|
11
11
|
## Do NOT use these routes for browser UI
|
|
12
12
|
|
|
13
|
-
Browser-facing
|
|
13
|
+
Browser-facing data fetching uses **fetch route handlers** colocated with pages (`route.js` files in `web/app/`). These check `auth()` session — never use `/api` routes from the browser. Server actions (`'use server'`) are used only for **mutations** (rename, delete, star, config updates) — never for data fetching (causes page refresh issues). Handler implementations live in `lib/chat/api.js`; route files are thin re-exports.
|
|
14
14
|
|
|
15
15
|
| Caller | Mechanism | Auth |
|
|
16
16
|
|--------|-----------|------|
|
|
17
17
|
| External (cURL, GitHub Actions, Telegram) | `/api` route | `x-api-key` header |
|
|
18
|
-
| Browser UI (data
|
|
19
|
-
| Browser UI (
|
|
18
|
+
| Browser UI (data fetching) | Fetch route handler colocated with page | `auth()` session |
|
|
19
|
+
| Browser UI (mutations) | Server action | `requireAuth()` session |
|
|
20
|
+
| Browser UI (streaming) | `/stream/chat`, `/stream/containers`, `/stream/cluster/*/logs` | `auth()` session |
|
|
20
21
|
|
|
21
22
|
## Routes
|
|
22
23
|
|
|
23
24
|
| Method | Path | Auth | Handler |
|
|
24
25
|
|--------|------|------|---------|
|
|
25
26
|
| GET | `/api/ping` | None | Health check |
|
|
26
|
-
| POST | `/api/create-job` | `x-api-key` | Create agent job |
|
|
27
|
-
| GET | `/api/
|
|
27
|
+
| POST | `/api/create-agent-job` | `x-api-key` | Create agent job |
|
|
28
|
+
| GET | `/api/get-agent-job-secret` | `x-api-key` | Get an agent job secret; oauth2 credentials return only the access_token (auto-refreshed) |
|
|
29
|
+
| POST | `/api/set-agent-job-secret` | `x-api-key` | Set/update an agent job secret (for agents to persist rotated credentials) |
|
|
30
|
+
| GET | `/api/agent-jobs/status` | `x-api-key` | Agent job status (query: `?agent_job_id=`) |
|
|
28
31
|
| POST | `/api/telegram/webhook` | Telegram webhook secret | Telegram message handler |
|
|
29
32
|
| POST | `/api/telegram/register` | `x-api-key` | Register bot token + webhook URL |
|
|
30
33
|
| POST | `/api/github/webhook` | GitHub webhook secret | GitHub event handler |
|
package/api/index.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { createHash, timingSafeEqual } from 'crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { createAgentJob } from '../lib/tools/create-agent-job.js';
|
|
3
3
|
import { setWebhook } from '../lib/tools/telegram.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getAgentJobStatus, fetchAgentJobLog } from '../lib/tools/github.js';
|
|
5
5
|
import { getTelegramAdapter } from '../lib/channels/index.js';
|
|
6
|
-
import { chat,
|
|
6
|
+
import { chat, summarizeAgentJob } from '../lib/ai/index.js';
|
|
7
7
|
import { createNotification } from '../lib/db/notifications.js';
|
|
8
8
|
import { loadTriggers } from '../lib/triggers.js';
|
|
9
9
|
import { verifyApiKey } from '../lib/db/api-keys.js';
|
|
10
10
|
import { getConfig } from '../lib/config.js';
|
|
11
|
+
import { parseOAuthState, exchangeCodeForToken } from '../lib/oauth/helper.js';
|
|
12
|
+
import { setAgentJobSecret } from '../lib/db/config.js';
|
|
13
|
+
|
|
14
|
+
// ── Per-key lock for OAuth token refresh ────────────────────────────
|
|
15
|
+
const _refreshLocks = new Map();
|
|
11
16
|
|
|
12
17
|
// Bot token — resolved from DB/env, can be overridden by /telegram/register
|
|
13
18
|
let telegramBotToken = null;
|
|
@@ -31,7 +36,7 @@ function getFireTriggers() {
|
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
// Routes that have their own authentication
|
|
34
|
-
const PUBLIC_ROUTES = ['/telegram/webhook', '/github/webhook', '/ping'];
|
|
39
|
+
const PUBLIC_ROUTES = ['/telegram/webhook', '/github/webhook', '/ping', '/oauth/callback'];
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Timing-safe string comparison.
|
|
@@ -71,31 +76,112 @@ function checkAuth(routePath, request) {
|
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
/**
|
|
74
|
-
* Extract job ID from branch name (e.g., "job/abc123" -> "abc123")
|
|
79
|
+
* Extract agent job ID from branch name (e.g., "agent-job/abc123" -> "abc123")
|
|
75
80
|
*/
|
|
76
|
-
function
|
|
77
|
-
if (!branchName
|
|
78
|
-
return branchName.slice(
|
|
81
|
+
function extractAgentJobId(branchName) {
|
|
82
|
+
if (!branchName) return null;
|
|
83
|
+
if (branchName.startsWith('agent-job/')) return branchName.slice(10);
|
|
84
|
+
// Backwards compatibility with old job/ prefix
|
|
85
|
+
if (branchName.startsWith('job/')) return branchName.slice(4);
|
|
86
|
+
return null;
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
82
90
|
// Route handlers
|
|
83
91
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
84
92
|
|
|
85
|
-
async function
|
|
93
|
+
async function handleCreateAgentJob(request) {
|
|
86
94
|
const body = await request.json();
|
|
87
95
|
const { job } = body;
|
|
88
96
|
if (!job) return Response.json({ error: 'Missing job field' }, { status: 400 });
|
|
89
97
|
|
|
90
98
|
try {
|
|
91
|
-
const result = await
|
|
99
|
+
const result = await createAgentJob(job, {
|
|
100
|
+
llmModel: body.llm_model,
|
|
101
|
+
agentBackend: body.agent_backend,
|
|
102
|
+
});
|
|
92
103
|
return Response.json(result);
|
|
93
104
|
} catch (err) {
|
|
94
105
|
console.error(err);
|
|
95
|
-
return Response.json({ error: 'Failed to create job' }, { status: 500 });
|
|
106
|
+
return Response.json({ error: 'Failed to create agent job' }, { status: 500 });
|
|
96
107
|
}
|
|
97
108
|
}
|
|
98
109
|
|
|
110
|
+
async function handleGetAgentSecret(request) {
|
|
111
|
+
const record = verifyApiKey(request.headers.get('x-api-key'));
|
|
112
|
+
if (record.type !== 'agent_job_api_key') {
|
|
113
|
+
return Response.json({ error: 'Forbidden' }, { status: 403 });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const key = new URL(request.url).searchParams.get('key');
|
|
117
|
+
if (!key) return Response.json({ error: 'Missing key' }, { status: 400 });
|
|
118
|
+
|
|
119
|
+
const { getAgentJobSecretRaw, setAgentJobSecret: saveSecret } = await import('../lib/db/config.js');
|
|
120
|
+
const raw = getAgentJobSecretRaw(key);
|
|
121
|
+
if (!raw) return Response.json({ error: 'Not found' }, { status: 404 });
|
|
122
|
+
|
|
123
|
+
let parsed;
|
|
124
|
+
try {
|
|
125
|
+
parsed = JSON.parse(raw);
|
|
126
|
+
} catch {
|
|
127
|
+
// Plain string
|
|
128
|
+
return Response.json({ value: raw });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (parsed.type === 'oauth2') {
|
|
132
|
+
// Serialize refresh per key — prevents concurrent requests from racing on token rotation
|
|
133
|
+
if (!_refreshLocks.has(key)) _refreshLocks.set(key, Promise.resolve());
|
|
134
|
+
let release;
|
|
135
|
+
const gate = new Promise((r) => { release = r; });
|
|
136
|
+
const prev = _refreshLocks.get(key);
|
|
137
|
+
_refreshLocks.set(key, gate);
|
|
138
|
+
await prev;
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
// Re-read after acquiring lock — previous request may have already refreshed
|
|
142
|
+
const freshRaw = getAgentJobSecretRaw(key);
|
|
143
|
+
const freshParsed = freshRaw ? JSON.parse(freshRaw) : parsed;
|
|
144
|
+
|
|
145
|
+
const { refreshOAuthToken } = await import('../lib/oauth/helper.js');
|
|
146
|
+
const newToken = await refreshOAuthToken({
|
|
147
|
+
refreshToken: freshParsed.token.refresh_token,
|
|
148
|
+
clientId: freshParsed.clientId,
|
|
149
|
+
clientSecret: freshParsed.clientSecret,
|
|
150
|
+
tokenUrl: freshParsed.tokenUrl,
|
|
151
|
+
});
|
|
152
|
+
// Persist updated token (refresh token may have rotated)
|
|
153
|
+
saveSecret(key, JSON.stringify({ ...freshParsed, token: { ...freshParsed.token, ...newToken } }), 'refresh');
|
|
154
|
+
return Response.json({ value: newToken.access_token });
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.error(`[secrets] OAuth refresh failed for "${key}":`, err.message);
|
|
157
|
+
return Response.json({ error: `OAuth refresh failed: ${err.message}` }, { status: 502 });
|
|
158
|
+
} finally {
|
|
159
|
+
release();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (parsed.type === 'oauth_token') {
|
|
163
|
+
return Response.json({ value: JSON.stringify(parsed.token) });
|
|
164
|
+
}
|
|
165
|
+
// Unknown structured value — return raw
|
|
166
|
+
return Response.json({ value: raw });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function handleSetAgentSecret(request) {
|
|
170
|
+
const record = verifyApiKey(request.headers.get('x-api-key'));
|
|
171
|
+
if (record.type !== 'agent_job_api_key') {
|
|
172
|
+
return Response.json({ error: 'Forbidden' }, { status: 403 });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const body = await request.json();
|
|
176
|
+
const { key, value } = body;
|
|
177
|
+
if (!key || typeof value !== 'string') {
|
|
178
|
+
return Response.json({ error: 'Missing key or value' }, { status: 400 });
|
|
179
|
+
}
|
|
180
|
+
const { setAgentJobSecret } = await import('../lib/db/config.js');
|
|
181
|
+
setAgentJobSecret(key, value, 'agent');
|
|
182
|
+
return Response.json({ success: true });
|
|
183
|
+
}
|
|
184
|
+
|
|
99
185
|
async function handleTelegramRegister(request) {
|
|
100
186
|
const body = await request.json();
|
|
101
187
|
const { bot_token, webhook_url } = body;
|
|
@@ -168,14 +254,14 @@ async function handleGithubWebhook(request) {
|
|
|
168
254
|
}
|
|
169
255
|
|
|
170
256
|
const payload = await request.json();
|
|
171
|
-
const
|
|
172
|
-
if (!
|
|
257
|
+
const agentJobId = payload.agent_job_id || payload.job_id || extractAgentJobId(payload.branch);
|
|
258
|
+
if (!agentJobId) return Response.json({ ok: true, skipped: true, reason: 'not an agent job' });
|
|
173
259
|
|
|
174
260
|
try {
|
|
175
261
|
// Fetch log from repo via API (no longer sent in payload)
|
|
176
262
|
let log = payload.log || '';
|
|
177
263
|
if (!log) {
|
|
178
|
-
log = await
|
|
264
|
+
log = await fetchAgentJobLog(agentJobId, payload.commit_sha);
|
|
179
265
|
}
|
|
180
266
|
|
|
181
267
|
const results = {
|
|
@@ -189,10 +275,10 @@ async function handleGithubWebhook(request) {
|
|
|
189
275
|
commit_message: payload.commit_message || '',
|
|
190
276
|
};
|
|
191
277
|
|
|
192
|
-
const message = await
|
|
278
|
+
const message = await summarizeAgentJob(results);
|
|
193
279
|
await createNotification(message, payload);
|
|
194
280
|
|
|
195
|
-
console.log(`Notification saved for job ${
|
|
281
|
+
console.log(`Notification saved for agent-job ${agentJobId.slice(0, 8)}`);
|
|
196
282
|
|
|
197
283
|
return Response.json({ ok: true, notified: true });
|
|
198
284
|
} catch (err) {
|
|
@@ -201,18 +287,89 @@ async function handleGithubWebhook(request) {
|
|
|
201
287
|
}
|
|
202
288
|
}
|
|
203
289
|
|
|
204
|
-
async function
|
|
290
|
+
async function handleAgentJobStatus(request) {
|
|
205
291
|
try {
|
|
206
292
|
const url = new URL(request.url);
|
|
207
|
-
const
|
|
208
|
-
const result = await
|
|
293
|
+
const agentJobId = url.searchParams.get('agent_job_id') || url.searchParams.get('job_id');
|
|
294
|
+
const result = await getAgentJobStatus(agentJobId);
|
|
209
295
|
return Response.json(result);
|
|
210
296
|
} catch (err) {
|
|
211
|
-
console.error('Failed to get job status:', err);
|
|
212
|
-
return Response.json({ error: 'Failed to get job status' }, { status: 500 });
|
|
297
|
+
console.error('Failed to get agent job status:', err);
|
|
298
|
+
return Response.json({ error: 'Failed to get agent job status' }, { status: 500 });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function handleOAuthCallback(request) {
|
|
303
|
+
const url = new URL(request.url);
|
|
304
|
+
const code = url.searchParams.get('code');
|
|
305
|
+
const stateParam = url.searchParams.get('state');
|
|
306
|
+
const error = url.searchParams.get('error');
|
|
307
|
+
|
|
308
|
+
if (error) {
|
|
309
|
+
const desc = url.searchParams.get('error_description') || error;
|
|
310
|
+
return oauthResultPage(false, desc);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!code || !stateParam) {
|
|
314
|
+
return oauthResultPage(false, 'Missing code or state parameter.');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const state = parseOAuthState(stateParam);
|
|
319
|
+
const redirectUri = `${process.env.AUTH_URL}/api/oauth/callback`;
|
|
320
|
+
|
|
321
|
+
const tokenData = await exchangeCodeForToken({
|
|
322
|
+
code,
|
|
323
|
+
clientId: state.clientId,
|
|
324
|
+
clientSecret: state.clientSecret,
|
|
325
|
+
tokenUrl: state.tokenUrl,
|
|
326
|
+
redirectUri,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Save token with typed wrapper so the API can auto-refresh on fetch
|
|
330
|
+
const secretType = state.secretType || 'oauth2';
|
|
331
|
+
let stored;
|
|
332
|
+
if (secretType === 'oauth_token') {
|
|
333
|
+
stored = JSON.stringify({ type: 'oauth_token', token: tokenData });
|
|
334
|
+
} else {
|
|
335
|
+
stored = JSON.stringify({
|
|
336
|
+
type: 'oauth2',
|
|
337
|
+
token: tokenData,
|
|
338
|
+
clientId: state.clientId,
|
|
339
|
+
clientSecret: state.clientSecret,
|
|
340
|
+
tokenUrl: state.tokenUrl,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
setAgentJobSecret(state.secretName, stored, 'oauth');
|
|
344
|
+
|
|
345
|
+
return oauthResultPage(true, state.secretName);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
console.error('OAuth callback error:', err);
|
|
348
|
+
return oauthResultPage(false, err.message || 'Token exchange failed.');
|
|
213
349
|
}
|
|
214
350
|
}
|
|
215
351
|
|
|
352
|
+
function oauthResultPage(success, detail) {
|
|
353
|
+
const safe = String(detail).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]);
|
|
354
|
+
const messagePayload = JSON.stringify({ type: success ? 'oauth-success' : 'oauth-error', detail: safe });
|
|
355
|
+
const fallback = success
|
|
356
|
+
? `Token saved as <strong>${safe}</strong>. You can close this tab and return to settings.`
|
|
357
|
+
: `Error: ${safe}`;
|
|
358
|
+
|
|
359
|
+
const html = `<!DOCTYPE html><html><head><title>OAuth ${success ? 'Success' : 'Error'}</title></head><body>
|
|
360
|
+
<script>
|
|
361
|
+
if (window.opener) {
|
|
362
|
+
window.opener.postMessage(${messagePayload}, window.location.origin);
|
|
363
|
+
window.close();
|
|
364
|
+
} else {
|
|
365
|
+
document.body.innerHTML = '<p style="font-family:sans-serif;padding:2rem;">${fallback.replace(/'/g, "\\'")}</p>';
|
|
366
|
+
}
|
|
367
|
+
</script>
|
|
368
|
+
<noscript><p style="font-family:sans-serif;padding:2rem;">${fallback}</p></noscript>
|
|
369
|
+
</body></html>`;
|
|
370
|
+
return new Response(html, { status: success ? 200 : 400, headers: { 'Content-Type': 'text/html' } });
|
|
371
|
+
}
|
|
372
|
+
|
|
216
373
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
217
374
|
// Next.js Route Handlers (catch-all)
|
|
218
375
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -247,7 +404,8 @@ async function POST(request) {
|
|
|
247
404
|
|
|
248
405
|
// Route to handler
|
|
249
406
|
switch (routePath) {
|
|
250
|
-
case '/create-job':
|
|
407
|
+
case '/create-agent-job': return handleCreateAgentJob(request);
|
|
408
|
+
case '/set-agent-job-secret': return handleSetAgentSecret(request);
|
|
251
409
|
case '/telegram/webhook': return handleTelegramWebhook(request);
|
|
252
410
|
case '/telegram/register': return handleTelegramRegister(request);
|
|
253
411
|
case '/github/webhook': return handleGithubWebhook(request);
|
|
@@ -264,9 +422,11 @@ async function GET(request) {
|
|
|
264
422
|
if (authError) return authError;
|
|
265
423
|
|
|
266
424
|
switch (routePath) {
|
|
267
|
-
case '/ping':
|
|
268
|
-
case '/jobs/status':
|
|
269
|
-
|
|
425
|
+
case '/ping': return Response.json({ message: 'Pong!' });
|
|
426
|
+
case '/agent-jobs/status': return handleAgentJobStatus(request);
|
|
427
|
+
case '/get-agent-job-secret': return handleGetAgentSecret(request);
|
|
428
|
+
case '/oauth/callback': return handleOAuthCallback(request);
|
|
429
|
+
default: return Response.json({ error: 'Not found' }, { status: 404 });
|
|
270
430
|
}
|
|
271
431
|
}
|
|
272
432
|
|
package/bin/CLAUDE.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# bin/ — CLI Tools
|
|
2
|
+
|
|
3
|
+
Entry point: `cli.js` (invoked via `npx thepopebot <command>`).
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Purpose |
|
|
8
|
+
|---------|---------|
|
|
9
|
+
| `init [--no-managed] [--no-install]` | Scaffold project from templates, sync managed files, create `.env`, install deps |
|
|
10
|
+
| `setup` | Run interactive setup wizard (see `setup/CLAUDE.md`) |
|
|
11
|
+
| `setup-telegram` | Reconfigure Telegram webhook |
|
|
12
|
+
| `upgrade [@beta\|version]` | Upgrade package, run init, rebuild, commit, push, restart Docker |
|
|
13
|
+
| `reset [file]` | Restore a template file to defaults |
|
|
14
|
+
| `diff [file]` | Show diff between user file and package template |
|
|
15
|
+
| `reset-auth` | Regenerate `AUTH_SECRET` (invalidates all sessions) |
|
|
16
|
+
| `set-var <KEY> [VALUE]` | Set GitHub repository variable |
|
|
17
|
+
| `user:password <email>` | Change user password |
|
|
18
|
+
| `sync <path>` | Dev helper — sync local package to test install |
|
|
19
|
+
|
|
20
|
+
## Managed Paths System
|
|
21
|
+
|
|
22
|
+
`managed-paths.js` defines files auto-synced by `init`. These are overwritten on every init/upgrade — users should not edit them.
|
|
23
|
+
|
|
24
|
+
**Managed paths**: `.github/workflows/`, `docker-compose.yml`, `.dockerignore`, `.gitignore`, `CLAUDE.md`, `config/CLAUDE.md`, `skills/CLAUDE.md`, `cron/CLAUDE.md`, `triggers/CLAUDE.md`, `docs/CLAUDE.md`.
|
|
25
|
+
|
|
26
|
+
`isManaged(relPath)` — returns true if a path is managed (exact match or directory prefix).
|
|
27
|
+
|
|
28
|
+
## Template Processing
|
|
29
|
+
|
|
30
|
+
- Templates live in `templates/` with optional `.template` suffix
|
|
31
|
+
- `.template` suffix is stripped when copying to the user project (e.g., `CLAUDE.md.template` → `CLAUDE.md`)
|
|
32
|
+
- Managed files are deleted from user projects if removed from templates
|
|
33
|
+
- Non-managed template files are only created, never overwritten
|
|
34
|
+
|
|
35
|
+
## docker-build.js
|
|
36
|
+
|
|
37
|
+
Builds the event-handler Docker image locally. Used by `docker-compose.yml` build step. Bakes the npm package, `web/` source, and `.next` build output into the image.
|
package/bin/cli.js
CHANGED
|
@@ -57,8 +57,6 @@ Commands:
|
|
|
57
57
|
reset [file] Restore a template file (or list available templates)
|
|
58
58
|
diff [file] Show differences between project files and package templates
|
|
59
59
|
sync <path> Sync local package to a test install (build, pack, Docker)
|
|
60
|
-
set-agent-secret <KEY> [VALUE] Set a GitHub secret with AGENT_ prefix (also updates .env)
|
|
61
|
-
set-agent-llm-secret <KEY> [VALUE] Set a GitHub secret with AGENT_LLM_ prefix
|
|
62
60
|
set-var <KEY> [VALUE] Set a GitHub repository variable
|
|
63
61
|
user:password <email> Change a user's password
|
|
64
62
|
`);
|
|
@@ -89,6 +87,7 @@ async function init() {
|
|
|
89
87
|
const packageDir = path.join(__dirname, '..');
|
|
90
88
|
const templatesDir = path.join(packageDir, 'templates');
|
|
91
89
|
const noManaged = args.includes('--no-managed');
|
|
90
|
+
const noInstall = args.includes('--no-install');
|
|
92
91
|
|
|
93
92
|
// Guard: warn if the directory is not empty (unless it's an existing thepopebot project)
|
|
94
93
|
const entries = fs.readdirSync(cwd);
|
|
@@ -262,18 +261,8 @@ async function init() {
|
|
|
262
261
|
console.log(' Skipped package.json (already exists)');
|
|
263
262
|
}
|
|
264
263
|
|
|
265
|
-
// Create .gitkeep files for empty dirs
|
|
266
|
-
const gitkeepDirs = ['cron', 'triggers', 'logs', 'tmp', 'data', 'data/clusters'];
|
|
267
|
-
for (const dir of gitkeepDirs) {
|
|
268
|
-
const gitkeep = path.join(cwd, dir, '.gitkeep');
|
|
269
|
-
if (!fs.existsSync(gitkeep)) {
|
|
270
|
-
fs.mkdirSync(path.join(cwd, dir), { recursive: true });
|
|
271
|
-
fs.writeFileSync(gitkeep, '');
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
264
|
// Create default skill activation symlinks
|
|
276
|
-
const defaultSkills = ['
|
|
265
|
+
const defaultSkills = ['agent-job-secrets'];
|
|
277
266
|
const activeDir = path.join(cwd, 'skills', 'active');
|
|
278
267
|
fs.mkdirSync(activeDir, { recursive: true });
|
|
279
268
|
for (const skill of defaultSkills) {
|
|
@@ -325,9 +314,11 @@ async function init() {
|
|
|
325
314
|
console.log(' To reset to default: npx thepopebot reset <file>');
|
|
326
315
|
}
|
|
327
316
|
|
|
328
|
-
// Run npm install
|
|
329
|
-
|
|
330
|
-
|
|
317
|
+
// Run npm install to ensure lock file reflects installed dependencies
|
|
318
|
+
if (!noInstall) {
|
|
319
|
+
console.log('\nInstalling dependencies...\n');
|
|
320
|
+
execSync('npm install', { stdio: 'inherit', cwd });
|
|
321
|
+
}
|
|
331
322
|
|
|
332
323
|
// Create or update .env with auto-generated infrastructure values
|
|
333
324
|
const envPath = path.join(cwd, '.env');
|
|
@@ -343,6 +334,7 @@ async function init() {
|
|
|
343
334
|
|
|
344
335
|
AUTH_SECRET=${authSecret}
|
|
345
336
|
AUTH_TRUST_HOST=true
|
|
337
|
+
DATABASE_PATH=data/db/thepopebot.sqlite
|
|
346
338
|
THEPOPEBOT_VERSION=${version}
|
|
347
339
|
|
|
348
340
|
# Uncomment to use a custom docker-compose file that won't be overwritten by upgrades.
|
|
@@ -641,7 +633,7 @@ async function upgrade() {
|
|
|
641
633
|
const running = execSync('docker compose ps --status running -q', { encoding: 'utf8', cwd }).trim();
|
|
642
634
|
if (running) {
|
|
643
635
|
console.log(' Pulling new image and restarting Docker containers...\n');
|
|
644
|
-
execSync('docker compose pull event-handler && docker compose up -d', { stdio: 'inherit', cwd });
|
|
636
|
+
execSync('docker compose pull event-handler && docker compose up -d --force-recreate event-handler', { stdio: 'inherit', cwd });
|
|
645
637
|
}
|
|
646
638
|
} catch {
|
|
647
639
|
// Docker not available or not running — skip
|
|
@@ -717,56 +709,6 @@ async function promptForValue(key) {
|
|
|
717
709
|
return value;
|
|
718
710
|
}
|
|
719
711
|
|
|
720
|
-
async function setAgentSecret(key, value) {
|
|
721
|
-
if (!key) {
|
|
722
|
-
console.error('\n Usage: thepopebot set-agent-secret <KEY> [VALUE]\n');
|
|
723
|
-
console.error(' Example: thepopebot set-agent-secret ANTHROPIC_API_KEY\n');
|
|
724
|
-
process.exit(1);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
if (!value) value = await promptForValue(key);
|
|
728
|
-
|
|
729
|
-
const { owner, repo } = loadRepoInfo();
|
|
730
|
-
const prefixedName = `AGENT_${key}`;
|
|
731
|
-
|
|
732
|
-
const { setSecret } = await import(path.join(__dirname, '..', 'setup', 'lib', 'github.mjs'));
|
|
733
|
-
const { updateEnvVariable } = await import(path.join(__dirname, '..', 'setup', 'lib', 'auth.mjs'));
|
|
734
|
-
|
|
735
|
-
const result = await setSecret(owner, repo, prefixedName, value);
|
|
736
|
-
if (result.success) {
|
|
737
|
-
console.log(`\n Set GitHub secret: ${prefixedName}`);
|
|
738
|
-
updateEnvVariable(key, value);
|
|
739
|
-
console.log(` Updated .env: ${key}`);
|
|
740
|
-
console.log('');
|
|
741
|
-
} else {
|
|
742
|
-
console.error(`\n Failed to set ${prefixedName}: ${result.error}\n`);
|
|
743
|
-
process.exit(1);
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
async function setAgentLlmSecret(key, value) {
|
|
748
|
-
if (!key) {
|
|
749
|
-
console.error('\n Usage: thepopebot set-agent-llm-secret <KEY> [VALUE]\n');
|
|
750
|
-
console.error(' Example: thepopebot set-agent-llm-secret BRAVE_API_KEY\n');
|
|
751
|
-
process.exit(1);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
if (!value) value = await promptForValue(key);
|
|
755
|
-
|
|
756
|
-
const { owner, repo } = loadRepoInfo();
|
|
757
|
-
const prefixedName = `AGENT_LLM_${key}`;
|
|
758
|
-
|
|
759
|
-
const { setSecret } = await import(path.join(__dirname, '..', 'setup', 'lib', 'github.mjs'));
|
|
760
|
-
|
|
761
|
-
const result = await setSecret(owner, repo, prefixedName, value);
|
|
762
|
-
if (result.success) {
|
|
763
|
-
console.log(`\n Set GitHub secret: ${prefixedName}\n`);
|
|
764
|
-
} else {
|
|
765
|
-
console.error(`\n Failed to set ${prefixedName}: ${result.error}\n`);
|
|
766
|
-
process.exit(1);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
712
|
async function setVar(key, value) {
|
|
771
713
|
if (!key) {
|
|
772
714
|
console.error('\n Usage: thepopebot set-var <KEY> [VALUE]\n');
|
|
@@ -849,12 +791,6 @@ switch (command) {
|
|
|
849
791
|
await sync(args[0]);
|
|
850
792
|
break;
|
|
851
793
|
}
|
|
852
|
-
case 'set-agent-secret':
|
|
853
|
-
await setAgentSecret(args[0], args[1]);
|
|
854
|
-
break;
|
|
855
|
-
case 'set-agent-llm-secret':
|
|
856
|
-
await setAgentLlmSecret(args[0], args[1]);
|
|
857
|
-
break;
|
|
858
794
|
case 'set-var':
|
|
859
795
|
await setVar(args[0], args[1]);
|
|
860
796
|
break;
|