thepopebot 1.2.70-beta.8 → 1.2.70
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 +29 -162
- package/lib/ai/agent.js +4 -4
- package/lib/ai/index.js +39 -18
- package/lib/ai/tools.js +36 -2
- package/lib/auth/middleware.js +21 -1
- package/lib/chat/api.js +34 -5
- package/lib/chat/components/app-sidebar.js +1 -1
- package/lib/chat/components/app-sidebar.jsx +1 -1
- package/lib/chat/components/icons.js +25 -3
- package/lib/chat/components/icons.jsx +25 -3
- package/lib/chat/components/message.js +174 -14
- package/lib/chat/components/message.jsx +228 -44
- package/lib/chat/components/notifications-page.js +2 -1
- package/lib/chat/components/notifications-page.jsx +2 -1
- package/lib/chat/components/tool-call.js +85 -0
- package/lib/chat/components/tool-call.jsx +103 -0
- package/lib/paths.js +6 -1
- package/lib/utils/render-md.js +44 -4
- package/package.json +1 -1
- package/setup/setup.mjs +5 -6
- package/templates/.github/workflows/rebuild-event-handler.yml +3 -2
- package/templates/.github/workflows/upgrade-event-handler.yml +3 -2
- package/templates/CLAUDE.md +1 -1
- package/templates/CLAUDE.md.template +514 -56
- package/templates/app/globals.css +1 -0
- package/templates/config/EVENT_HANDLER.md +210 -0
- package/templates/config/PI_SKILL_GUIDE.md +89 -0
- package/templates/config/CHATBOT.md +0 -87
package/README.md
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
# thepopebot
|
|
2
|
-
|
|
3
|
-
**Autonomous AI agents. All the power. None of the leaked API keys.**
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Why thepopebot?
|
|
8
|
-
|
|
9
|
-
**Secure by default** — Other frameworks hand credentials to the LLM and hope for the best. thepopebot is different: the AI literally cannot access your secrets, even if it tries. Secrets are filtered at the process level before the agent's shell even starts.
|
|
1
|
+
# Why thepopebot?
|
|
10
2
|
|
|
11
3
|
**The repository IS the agent** — Every action your agent takes is a git commit. You can see exactly what it did, when, and why. If it screws up, revert it. Want to clone your agent? Fork the repo — code, personality, scheduled jobs, full history, all of it goes with your fork.
|
|
12
4
|
|
|
@@ -56,15 +48,9 @@ You interact with your bot via the web chat interface or Telegram (optional). Th
|
|
|
56
48
|
|
|
57
49
|
---
|
|
58
50
|
|
|
59
|
-
##
|
|
60
|
-
|
|
61
|
-
| | thepopebot | Other platforms |
|
|
62
|
-
|---|---|---|
|
|
63
|
-
| **Public repos** | Free. $0. GitHub Actions doesn't charge. | $20-100+/month |
|
|
64
|
-
| **Private repos** | 2,000 free minutes/month (every GitHub plan, including free) | $20-100+/month |
|
|
65
|
-
| **Infrastructure** | GitHub Actions (already included) | Dedicated servers |
|
|
51
|
+
## Star History
|
|
66
52
|
|
|
67
|
-
|
|
53
|
+
[](https://www.star-history.com/#stephengpope/thepopebot&type=date&legend=top-left)
|
|
68
54
|
|
|
69
55
|
---
|
|
70
56
|
|
|
@@ -124,12 +110,6 @@ docker compose up -d
|
|
|
124
110
|
|
|
125
111
|
---
|
|
126
112
|
|
|
127
|
-
## Star History
|
|
128
|
-
|
|
129
|
-
[](https://www.star-history.com/#stephengpope/thepopebot&type=date&legend=top-left)
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
113
|
## Manual Updating
|
|
134
114
|
|
|
135
115
|
**1. Update the package**
|
|
@@ -144,7 +124,26 @@ npm install thepopebot@latest
|
|
|
144
124
|
npx thepopebot init
|
|
145
125
|
```
|
|
146
126
|
|
|
147
|
-
For most people, that's it — `init` handles everything. It updates your project files, runs `npm install`, and updates `THEPOPEBOT_VERSION` in your local `.env`.
|
|
127
|
+
For most people, that's it — `init` handles everything. It updates your project files, runs `npm install`, and updates `THEPOPEBOT_VERSION` in your local `.env`. See [Understanding `init`](#understanding-init) below for details on what this updates and how to handle custom changes.
|
|
128
|
+
|
|
129
|
+
**3. Rebuild for local dev**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm run build
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**4. Commit and push**
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
git add -A && git commit -m "upgrade thepopebot to vX.X.X"
|
|
139
|
+
git push
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Pushing to `main` triggers the `rebuild-event-handler.yml` workflow on your server. It detects the version change, runs `thepopebot init`, updates `THEPOPEBOT_VERSION` in the server's `.env`, pulls the new Docker image, restarts the container, rebuilds `.next`, and reloads PM2 — no manual `docker compose` needed.
|
|
143
|
+
|
|
144
|
+
> **Upgrade failed?** See [Recovering from a Failed Upgrade](docs/UPGRADE.md#recovering-from-a-failed-upgrade).
|
|
145
|
+
|
|
146
|
+
### Understanding `init`
|
|
148
147
|
|
|
149
148
|
#### How your project is structured
|
|
150
149
|
|
|
@@ -154,7 +153,7 @@ When you ran `thepopebot init` the first time, it scaffolded a project folder wi
|
|
|
154
153
|
|
|
155
154
|
| Files | What they do |
|
|
156
155
|
|-------|-------------|
|
|
157
|
-
| `config/SOUL.md`, `
|
|
156
|
+
| `config/SOUL.md`, `EVENT_HANDLER.md`, `AGENT.md`, etc. | Your agent's personality, behavior, and prompts |
|
|
158
157
|
| `config/CRONS.json`, `TRIGGERS.json` | Your scheduled jobs and webhook triggers |
|
|
159
158
|
| `app/` | Next.js pages and UI components |
|
|
160
159
|
| `docker/job/` | The Dockerfile for your agent's job container |
|
|
@@ -198,21 +197,6 @@ If you've made custom changes to managed files (e.g., added extra steps to a Git
|
|
|
198
197
|
npx thepopebot init --no-managed
|
|
199
198
|
```
|
|
200
199
|
|
|
201
|
-
**3. Rebuild for local dev**
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
npm run build
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**4. Commit and push**
|
|
208
|
-
|
|
209
|
-
```bash
|
|
210
|
-
git add -A && git commit -m "upgrade thepopebot to vX.X.X"
|
|
211
|
-
git push
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Pushing to `main` triggers the `rebuild-event-handler.yml` workflow on your server. It detects the version change, runs `thepopebot init`, updates `THEPOPEBOT_VERSION` in the server's `.env`, pulls the new Docker image, restarts the container, rebuilds `.next`, and reloads PM2 — no manual `docker compose` needed.
|
|
215
|
-
|
|
216
200
|
---
|
|
217
201
|
|
|
218
202
|
## CLI Commands
|
|
@@ -269,88 +253,11 @@ The `templates/` directory contains files scaffolded into user projects by `thep
|
|
|
269
253
|
|
|
270
254
|
---
|
|
271
255
|
|
|
272
|
-
##
|
|
273
|
-
|
|
274
|
-
Deploy your agent to a cloud VPS with HTTPS.
|
|
275
|
-
|
|
276
|
-
### 1. Server prerequisites
|
|
277
|
-
|
|
278
|
-
You need a VPS (any provider — Hetzner, DigitalOcean, AWS, etc.) with:
|
|
279
|
-
|
|
280
|
-
- Docker + Docker Compose
|
|
281
|
-
- Node.js 18+
|
|
282
|
-
- Git
|
|
283
|
-
- GitHub CLI (`gh`)
|
|
284
|
-
|
|
285
|
-
Point a domain (e.g., `mybot.example.com`) to your server's IP address with a DNS A record.
|
|
286
|
-
|
|
287
|
-
### 2. Scaffold and configure
|
|
288
|
-
|
|
289
|
-
SSH into your server and scaffold the project:
|
|
290
|
-
|
|
291
|
-
```bash
|
|
292
|
-
mkdir my-agent && cd my-agent
|
|
293
|
-
npx thepopebot@latest init
|
|
294
|
-
npm run setup
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
When the setup wizard asks for `APP_URL`, enter your production URL with `https://` (e.g., `https://mybot.example.com`).
|
|
298
|
-
|
|
299
|
-
Set the `RUNS_ON` GitHub variable so workflows use your server's self-hosted runner instead of GitHub-hosted runners:
|
|
300
|
-
|
|
301
|
-
```bash
|
|
302
|
-
gh variable set RUNS_ON --body "self-hosted" --repo OWNER/REPO
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### 3. Enable HTTPS (Let's Encrypt)
|
|
306
|
-
|
|
307
|
-
The `docker-compose.yml` has Let's Encrypt support built in but commented out. Three edits to enable it:
|
|
308
|
-
|
|
309
|
-
**a) Add your email to `.env`:**
|
|
310
|
-
|
|
311
|
-
```
|
|
312
|
-
LETSENCRYPT_EMAIL=you@example.com
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
**b) In `docker-compose.yml`, remove the `#` from the TLS lines in the traefik service command:**
|
|
316
|
-
|
|
317
|
-
```yaml
|
|
318
|
-
# Before (commented out):
|
|
319
|
-
# - --entrypoints.web.http.redirections.entrypoint.to=websecure
|
|
320
|
-
# ...
|
|
321
|
-
|
|
322
|
-
# After (uncommented):
|
|
323
|
-
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
|
324
|
-
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
|
325
|
-
- --certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}
|
|
326
|
-
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
|
327
|
-
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
**c) In the event-handler labels, switch from HTTP to HTTPS:**
|
|
331
|
-
|
|
332
|
-
Add a `#` to comment out the HTTP entrypoint, and remove the `#` from the two HTTPS lines:
|
|
333
|
-
|
|
334
|
-
```yaml
|
|
335
|
-
# Before:
|
|
336
|
-
- traefik.http.routers.event-handler.entrypoints=web
|
|
337
|
-
# - traefik.http.routers.event-handler.entrypoints=websecure
|
|
338
|
-
# - traefik.http.routers.event-handler.tls.certresolver=letsencrypt
|
|
339
|
-
|
|
340
|
-
# After:
|
|
341
|
-
# - traefik.http.routers.event-handler.entrypoints=web
|
|
342
|
-
- traefik.http.routers.event-handler.entrypoints=websecure
|
|
343
|
-
- traefik.http.routers.event-handler.tls.certresolver=letsencrypt
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
### 4. Build and launch
|
|
256
|
+
## Security
|
|
347
257
|
|
|
348
|
-
|
|
349
|
-
npm run build
|
|
350
|
-
docker compose up -d
|
|
351
|
-
```
|
|
258
|
+
thepopebot includes API key authentication, webhook secret validation (fail-closed), session encryption, secret filtering in the Docker agent, and auto-merge path restrictions. However, all software carries risk — thepopebot is provided as-is, and you are responsible for securing your own infrastructure. If you're running locally with a tunnel (ngrok, Cloudflare Tunnel, port forwarding), be aware that your dev server endpoints are publicly accessible with no rate limiting and no TLS on the local hop.
|
|
352
259
|
|
|
353
|
-
|
|
260
|
+
See [docs/SECURITY.md](docs/SECURITY.md) for full details on what's exposed, the risks, and recommendations.
|
|
354
261
|
|
|
355
262
|
---
|
|
356
263
|
|
|
@@ -363,7 +270,9 @@ Ports 80 and 443 must be open on your server. Port 80 is required even with HTTP
|
|
|
363
270
|
| [Customization](docs/CUSTOMIZATION.md) | Personality, skills, operating system files, using your bot, security details |
|
|
364
271
|
| [Chat Integrations](docs/CHAT_INTEGRATIONS.md) | Web chat, Telegram, adding new channels |
|
|
365
272
|
| [Auto-Merge](docs/AUTO_MERGE.md) | Auto-merge controls, ALLOWED_PATHS configuration |
|
|
273
|
+
| [Deployment](docs/DEPLOYMENT.md) | VPS setup, Docker Compose, HTTPS with Let's Encrypt |
|
|
366
274
|
| [How to Use Pi](docs/HOW_TO_USE_PI.md) | Guide to the Pi coding agent |
|
|
275
|
+
| [Pre-Release](docs/PRE_RELEASE.md) | Installing beta/alpha builds, going back to stable |
|
|
367
276
|
| [Security](docs/SECURITY.md) | Security disclaimer, local development risks |
|
|
368
277
|
| [Upgrading](docs/UPGRADE.md) | Automated upgrades, recovering from failed upgrades |
|
|
369
278
|
|
|
@@ -372,45 +281,3 @@ Ports 80 and 443 must be open on your server. Port 80 is required even with HTTP
|
|
|
372
281
|
| Document | Description |
|
|
373
282
|
|----------|-------------|
|
|
374
283
|
| [NPM](docs/NPM.md) | Updating pi-skills, versioning, and publishing releases |
|
|
375
|
-
|
|
376
|
-
---
|
|
377
|
-
|
|
378
|
-
## Security
|
|
379
|
-
|
|
380
|
-
thepopebot includes API key authentication, webhook secret validation (fail-closed), session encryption, secret filtering in the Docker agent, and auto-merge path restrictions. However, all software carries risk — thepopebot is provided as-is, and you are responsible for securing your own infrastructure. If you're running locally with a tunnel (ngrok, Cloudflare Tunnel, port forwarding), be aware that your dev server endpoints are publicly accessible with no rate limiting and no TLS on the local hop.
|
|
381
|
-
|
|
382
|
-
See [docs/SECURITY.md](docs/SECURITY.md) for full details on what's exposed, the risks, and recommendations.
|
|
383
|
-
|
|
384
|
-
---
|
|
385
|
-
|
|
386
|
-
## Pre-Release Versions
|
|
387
|
-
|
|
388
|
-
Pre-release builds (beta, alpha, rc) are published to separate npm dist-tags. They won't be installed by normal `npm update` or `thepopebot init` — you have to opt in explicitly.
|
|
389
|
-
|
|
390
|
-
**Install the latest pre-release:**
|
|
391
|
-
|
|
392
|
-
```bash
|
|
393
|
-
mkdir my-agent && cd my-agent
|
|
394
|
-
npx thepopebot@beta init
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
**Install a specific version:**
|
|
398
|
-
|
|
399
|
-
```bash
|
|
400
|
-
npx thepopebot@1.3.0-beta.1 init
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
**Check available versions:**
|
|
404
|
-
|
|
405
|
-
```bash
|
|
406
|
-
npm info thepopebot
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**Go back to stable:**
|
|
410
|
-
|
|
411
|
-
```bash
|
|
412
|
-
npm install thepopebot@latest
|
|
413
|
-
npx thepopebot init
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
Pre-releases may contain breaking changes or incomplete features. Use them for testing and feedback — not production agents.
|
package/lib/ai/agent.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
|
2
2
|
import { SystemMessage } from '@langchain/core/messages';
|
|
3
3
|
import { createModel } from './model.js';
|
|
4
|
-
import { createJobTool, getJobStatusTool } from './tools.js';
|
|
4
|
+
import { createJobTool, getJobStatusTool, getSystemTechnicalSpecsTool, getPiSkillCreationGuideTool } from './tools.js';
|
|
5
5
|
import { SqliteSaver } from '@langchain/langgraph-checkpoint-sqlite';
|
|
6
|
-
import {
|
|
6
|
+
import { eventHandlerMd, thepopebotDb } from '../paths.js';
|
|
7
7
|
import { render_md } from '../utils/render-md.js';
|
|
8
8
|
|
|
9
9
|
let _agent = null;
|
|
@@ -16,14 +16,14 @@ let _agent = null;
|
|
|
16
16
|
export async function getAgent() {
|
|
17
17
|
if (!_agent) {
|
|
18
18
|
const model = await createModel();
|
|
19
|
-
const tools = [createJobTool, getJobStatusTool];
|
|
19
|
+
const tools = [createJobTool, getJobStatusTool, getSystemTechnicalSpecsTool, getPiSkillCreationGuideTool];
|
|
20
20
|
const checkpointer = SqliteSaver.fromConnString(thepopebotDb);
|
|
21
21
|
|
|
22
22
|
_agent = createReactAgent({
|
|
23
23
|
llm: model,
|
|
24
24
|
tools,
|
|
25
25
|
checkpointSaver: checkpointer,
|
|
26
|
-
prompt: (state) => [new SystemMessage(render_md(
|
|
26
|
+
prompt: (state) => [new SystemMessage(render_md(eventHandlerMd)), ...state.messages],
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
return _agent;
|
package/lib/ai/index.js
CHANGED
|
@@ -149,24 +149,45 @@ async function* chatStream(threadId, message, attachments = [], options = {}) {
|
|
|
149
149
|
for await (const event of stream) {
|
|
150
150
|
// streamMode: 'messages' yields [message, metadata] tuples
|
|
151
151
|
const msg = Array.isArray(event) ? event[0] : event;
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
152
|
+
const msgType = msg._getType?.();
|
|
153
|
+
|
|
154
|
+
if (msgType === 'ai') {
|
|
155
|
+
// Tool calls — AIMessage.tool_calls is an array of { id, name, args }
|
|
156
|
+
if (msg.tool_calls?.length > 0) {
|
|
157
|
+
for (const tc of msg.tool_calls) {
|
|
158
|
+
yield {
|
|
159
|
+
type: 'tool-call',
|
|
160
|
+
toolCallId: tc.id,
|
|
161
|
+
toolName: tc.name,
|
|
162
|
+
args: tc.args,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Text content (wrapped in structured object)
|
|
168
|
+
let text = '';
|
|
169
|
+
if (typeof msg.content === 'string') {
|
|
170
|
+
text = msg.content;
|
|
171
|
+
} else if (Array.isArray(msg.content)) {
|
|
172
|
+
text = msg.content
|
|
173
|
+
.filter((b) => b.type === 'text' && b.text)
|
|
174
|
+
.map((b) => b.text)
|
|
175
|
+
.join('');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (text) {
|
|
179
|
+
fullText += text;
|
|
180
|
+
yield { type: 'text', text };
|
|
181
|
+
}
|
|
182
|
+
} else if (msgType === 'tool') {
|
|
183
|
+
// Tool result — ToolMessage has tool_call_id and content
|
|
184
|
+
yield {
|
|
185
|
+
type: 'tool-result',
|
|
186
|
+
toolCallId: msg.tool_call_id,
|
|
187
|
+
result: msg.content,
|
|
188
|
+
};
|
|
169
189
|
}
|
|
190
|
+
// Skip other message types (human, system)
|
|
170
191
|
}
|
|
171
192
|
|
|
172
193
|
// Save assistant response to DB
|
|
@@ -192,7 +213,7 @@ async function autoTitle(threadId, firstMessage) {
|
|
|
192
213
|
const chat = getChatById(threadId);
|
|
193
214
|
if (!chat || chat.title !== 'New Chat') return;
|
|
194
215
|
|
|
195
|
-
const model = await createModel();
|
|
216
|
+
const model = await createModel({ maxTokens: 250 });
|
|
196
217
|
const response = await model.invoke([
|
|
197
218
|
['system', 'Generate a short (3-6 word) title for this chat based on the user\'s first message. Return ONLY the title, nothing else.'],
|
|
198
219
|
['human', firstMessage],
|
package/lib/ai/tools.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import { tool } from '@langchain/core/tools';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { createJob } from '../tools/create-job.js';
|
|
4
5
|
import { getJobStatus } from '../tools/github.js';
|
|
6
|
+
import { claudeMd, skillGuidePath } from '../paths.js';
|
|
5
7
|
|
|
6
8
|
const createJobTool = tool(
|
|
7
9
|
async ({ job_description }) => {
|
|
@@ -15,7 +17,7 @@ const createJobTool = tool(
|
|
|
15
17
|
{
|
|
16
18
|
name: 'create_job',
|
|
17
19
|
description:
|
|
18
|
-
'Create an autonomous job
|
|
20
|
+
'Create an autonomous job that runs a Docker agent in a container. The Docker agent has full filesystem access, web search, browser automation, and other abilities. The job description you provide becomes the Docker agent\'s task prompt. Returns the job ID and branch name.',
|
|
19
21
|
schema: z.object({
|
|
20
22
|
job_description: z
|
|
21
23
|
.string()
|
|
@@ -46,4 +48,36 @@ const getJobStatusTool = tool(
|
|
|
46
48
|
}
|
|
47
49
|
);
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
const getSystemTechnicalSpecsTool = tool(
|
|
52
|
+
async () => {
|
|
53
|
+
try {
|
|
54
|
+
return fs.readFileSync(claudeMd, 'utf8');
|
|
55
|
+
} catch {
|
|
56
|
+
return 'No technical documentation found (CLAUDE.md not present in project root).';
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'get_system_technical_specs',
|
|
61
|
+
description:
|
|
62
|
+
'Read the system architecture and technical documentation (CLAUDE.md). Use this when you need to understand how the system itself works — the event handler, Docker agent, API routes, database, cron/trigger configuration, GitHub Actions, deployment, or file structure. Use this before planning jobs that modify system configuration or infrastructure. NOT for Pi skill creation (use get_pi_skill_creation_guide for that).',
|
|
63
|
+
schema: z.object({}),
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const getPiSkillCreationGuideTool = tool(
|
|
68
|
+
async () => {
|
|
69
|
+
try {
|
|
70
|
+
return fs.readFileSync(skillGuidePath, 'utf8');
|
|
71
|
+
} catch {
|
|
72
|
+
return 'Skill guide not found.';
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'get_pi_skill_creation_guide',
|
|
77
|
+
description:
|
|
78
|
+
'Load the guide for creating, modifying, and understanding Pi agent skills (pi-skills). Use this when the user wants to create a new skill, asks how skills work, wants to modify an existing skill, or when you need to understand the skill format (SKILL.md, {baseDir}, activation, testing). This is about Pi skills specifically — the lightweight bash/Node.js wrappers that extend what the Docker agent can do. NOT for understanding the system architecture (use get_system_technical_specs for that).',
|
|
79
|
+
schema: z.object({}),
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
export { createJobTool, getJobStatusTool, getSystemTechnicalSpecsTool, getPiSkillCreationGuideTool };
|
package/lib/auth/middleware.js
CHANGED
|
@@ -23,7 +23,27 @@ export const middleware = auth((req) => {
|
|
|
23
23
|
|
|
24
24
|
// Everything else requires auth
|
|
25
25
|
if (!req.auth) {
|
|
26
|
-
|
|
26
|
+
const response = NextResponse.redirect(new URL('/login', req.url));
|
|
27
|
+
|
|
28
|
+
// Clear stale session cookies that can't be decrypted (e.g. after AUTH_SECRET rotation
|
|
29
|
+
// or container restart). Auth.js clears these internally in route handlers via
|
|
30
|
+
// sessionStore.clean(), but NOT in middleware — so the bad cookie loops forever.
|
|
31
|
+
// Only session-token cookies are cleared; csrf-token and callback-url are left intact.
|
|
32
|
+
const cookieNames = Object.keys(req.cookies.getAll().reduce((acc, c) => { acc[c.name] = true; return acc; }, {}));
|
|
33
|
+
const staleSessionCookies = cookieNames.filter(name =>
|
|
34
|
+
name === 'authjs.session-token' ||
|
|
35
|
+
name === '__Secure-authjs.session-token' ||
|
|
36
|
+
/^authjs\.session-token\.\d+$/.test(name) ||
|
|
37
|
+
/^__Secure-authjs\.session-token\.\d+$/.test(name)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (staleSessionCookies.length > 0) {
|
|
41
|
+
for (const name of staleSessionCookies) {
|
|
42
|
+
response.cookies.set(name, '', { maxAge: 0, path: '/' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return response;
|
|
27
47
|
}
|
|
28
48
|
});
|
|
29
49
|
|
package/lib/chat/api.js
CHANGED
|
@@ -81,17 +81,46 @@ export async function POST(request) {
|
|
|
81
81
|
// Signal start of assistant message
|
|
82
82
|
writer.write({ type: 'start' });
|
|
83
83
|
|
|
84
|
-
const textId = crypto.randomUUID();
|
|
85
84
|
let textStarted = false;
|
|
85
|
+
let textId = crypto.randomUUID();
|
|
86
86
|
|
|
87
87
|
for await (const chunk of chunks) {
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
if (chunk.type === 'text') {
|
|
89
|
+
if (!textStarted) {
|
|
90
|
+
textId = crypto.randomUUID();
|
|
91
|
+
writer.write({ type: 'text-start', id: textId });
|
|
92
|
+
textStarted = true;
|
|
93
|
+
}
|
|
94
|
+
writer.write({ type: 'text-delta', id: textId, delta: chunk.text });
|
|
95
|
+
|
|
96
|
+
} else if (chunk.type === 'tool-call') {
|
|
97
|
+
// Close any open text block before tool events
|
|
98
|
+
if (textStarted) {
|
|
99
|
+
writer.write({ type: 'text-end', id: textId });
|
|
100
|
+
textStarted = false;
|
|
101
|
+
}
|
|
102
|
+
writer.write({
|
|
103
|
+
type: 'tool-input-start',
|
|
104
|
+
toolCallId: chunk.toolCallId,
|
|
105
|
+
toolName: chunk.toolName,
|
|
106
|
+
});
|
|
107
|
+
writer.write({
|
|
108
|
+
type: 'tool-input-available',
|
|
109
|
+
toolCallId: chunk.toolCallId,
|
|
110
|
+
toolName: chunk.toolName,
|
|
111
|
+
input: chunk.args,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
} else if (chunk.type === 'tool-result') {
|
|
115
|
+
writer.write({
|
|
116
|
+
type: 'tool-output-available',
|
|
117
|
+
toolCallId: chunk.toolCallId,
|
|
118
|
+
output: chunk.result,
|
|
119
|
+
});
|
|
91
120
|
}
|
|
92
|
-
writer.write({ type: 'text-delta', id: textId, delta: chunk });
|
|
93
121
|
}
|
|
94
122
|
|
|
123
|
+
// Close final text block if still open
|
|
95
124
|
if (textStarted) {
|
|
96
125
|
writer.write({ type: 'text-end', id: textId });
|
|
97
126
|
}
|
|
@@ -42,7 +42,7 @@ function AppSidebar({ user }) {
|
|
|
42
42
|
/* @__PURE__ */ jsxs(SidebarHeader, { children: [
|
|
43
43
|
/* @__PURE__ */ jsxs("div", { className: collapsed ? "flex justify-center" : "flex items-center justify-between", children: [
|
|
44
44
|
!collapsed && /* @__PURE__ */ jsxs("span", { className: "px-2 font-semibold text-lg", children: [
|
|
45
|
-
"
|
|
45
|
+
"ThePopeBot",
|
|
46
46
|
version && /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-normal text-muted-foreground", children: [
|
|
47
47
|
" v",
|
|
48
48
|
version
|
|
@@ -49,7 +49,7 @@ export function AppSidebar({ user }) {
|
|
|
49
49
|
{/* Top row: brand name + toggle icon (open) or just toggle icon (collapsed) */}
|
|
50
50
|
<div className={collapsed ? 'flex justify-center' : 'flex items-center justify-between'}>
|
|
51
51
|
{!collapsed && (
|
|
52
|
-
<span className="px-2 font-semibold text-lg">
|
|
52
|
+
<span className="px-2 font-semibold text-lg">ThePopeBot{version && <span className="text-[11px] font-normal text-muted-foreground"> v{version}</span>}</span>
|
|
53
53
|
)}
|
|
54
54
|
<Tooltip>
|
|
55
55
|
<TooltipTrigger asChild>
|
|
@@ -209,7 +209,7 @@ function PaperclipIcon({ size = 16 }) {
|
|
|
209
209
|
}
|
|
210
210
|
);
|
|
211
211
|
}
|
|
212
|
-
function XIcon({ size = 16 }) {
|
|
212
|
+
function XIcon({ size = 16, className = "" }) {
|
|
213
213
|
return /* @__PURE__ */ jsxs(
|
|
214
214
|
"svg",
|
|
215
215
|
{
|
|
@@ -222,6 +222,7 @@ function XIcon({ size = 16 }) {
|
|
|
222
222
|
strokeLinejoin: "round",
|
|
223
223
|
width: size,
|
|
224
224
|
height: size,
|
|
225
|
+
className,
|
|
225
226
|
children: [
|
|
226
227
|
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
227
228
|
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
@@ -311,7 +312,7 @@ function RefreshIcon({ size = 16 }) {
|
|
|
311
312
|
}
|
|
312
313
|
);
|
|
313
314
|
}
|
|
314
|
-
function ChevronDownIcon({ size = 16 }) {
|
|
315
|
+
function ChevronDownIcon({ size = 16, className = "" }) {
|
|
315
316
|
return /* @__PURE__ */ jsx(
|
|
316
317
|
"svg",
|
|
317
318
|
{
|
|
@@ -324,6 +325,7 @@ function ChevronDownIcon({ size = 16 }) {
|
|
|
324
325
|
strokeLinejoin: "round",
|
|
325
326
|
width: size,
|
|
326
327
|
height: size,
|
|
328
|
+
className,
|
|
327
329
|
children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
|
|
328
330
|
}
|
|
329
331
|
);
|
|
@@ -389,7 +391,7 @@ function CopyIcon({ size = 16 }) {
|
|
|
389
391
|
}
|
|
390
392
|
);
|
|
391
393
|
}
|
|
392
|
-
function CheckIcon({ size = 16 }) {
|
|
394
|
+
function CheckIcon({ size = 16, className = "" }) {
|
|
393
395
|
return /* @__PURE__ */ jsx(
|
|
394
396
|
"svg",
|
|
395
397
|
{
|
|
@@ -402,6 +404,7 @@ function CheckIcon({ size = 16 }) {
|
|
|
402
404
|
strokeLinejoin: "round",
|
|
403
405
|
width: size,
|
|
404
406
|
height: size,
|
|
407
|
+
className,
|
|
405
408
|
children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
|
|
406
409
|
}
|
|
407
410
|
);
|
|
@@ -635,6 +638,24 @@ function LifeBuoyIcon({ size = 16 }) {
|
|
|
635
638
|
}
|
|
636
639
|
);
|
|
637
640
|
}
|
|
641
|
+
function WrenchIcon({ size = 16, className = "" }) {
|
|
642
|
+
return /* @__PURE__ */ jsx(
|
|
643
|
+
"svg",
|
|
644
|
+
{
|
|
645
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
646
|
+
viewBox: "0 0 24 24",
|
|
647
|
+
fill: "none",
|
|
648
|
+
stroke: "currentColor",
|
|
649
|
+
strokeWidth: 2,
|
|
650
|
+
strokeLinecap: "round",
|
|
651
|
+
strokeLinejoin: "round",
|
|
652
|
+
width: size,
|
|
653
|
+
height: size,
|
|
654
|
+
className,
|
|
655
|
+
children: /* @__PURE__ */ jsx("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" })
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
}
|
|
638
659
|
function LogOutIcon({ size = 16 }) {
|
|
639
660
|
return /* @__PURE__ */ jsxs(
|
|
640
661
|
"svg",
|
|
@@ -688,6 +709,7 @@ export {
|
|
|
688
709
|
SunIcon,
|
|
689
710
|
SwarmIcon,
|
|
690
711
|
TrashIcon,
|
|
712
|
+
WrenchIcon,
|
|
691
713
|
XIcon,
|
|
692
714
|
ZapIcon
|
|
693
715
|
};
|
|
@@ -205,7 +205,7 @@ export function PaperclipIcon({ size = 16 }) {
|
|
|
205
205
|
);
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
export function XIcon({ size = 16 }) {
|
|
208
|
+
export function XIcon({ size = 16, className = '' }) {
|
|
209
209
|
return (
|
|
210
210
|
<svg
|
|
211
211
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -217,6 +217,7 @@ export function XIcon({ size = 16 }) {
|
|
|
217
217
|
strokeLinejoin="round"
|
|
218
218
|
width={size}
|
|
219
219
|
height={size}
|
|
220
|
+
className={className}
|
|
220
221
|
>
|
|
221
222
|
<path d="M18 6 6 18" />
|
|
222
223
|
<path d="m6 6 12 12" />
|
|
@@ -304,7 +305,7 @@ export function RefreshIcon({ size = 16 }) {
|
|
|
304
305
|
);
|
|
305
306
|
}
|
|
306
307
|
|
|
307
|
-
export function ChevronDownIcon({ size = 16 }) {
|
|
308
|
+
export function ChevronDownIcon({ size = 16, className = '' }) {
|
|
308
309
|
return (
|
|
309
310
|
<svg
|
|
310
311
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -316,6 +317,7 @@ export function ChevronDownIcon({ size = 16 }) {
|
|
|
316
317
|
strokeLinejoin="round"
|
|
317
318
|
width={size}
|
|
318
319
|
height={size}
|
|
320
|
+
className={className}
|
|
319
321
|
>
|
|
320
322
|
<path d="m6 9 6 6 6-6" />
|
|
321
323
|
</svg>
|
|
@@ -380,7 +382,7 @@ export function CopyIcon({ size = 16 }) {
|
|
|
380
382
|
);
|
|
381
383
|
}
|
|
382
384
|
|
|
383
|
-
export function CheckIcon({ size = 16 }) {
|
|
385
|
+
export function CheckIcon({ size = 16, className = '' }) {
|
|
384
386
|
return (
|
|
385
387
|
<svg
|
|
386
388
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -392,6 +394,7 @@ export function CheckIcon({ size = 16 }) {
|
|
|
392
394
|
strokeLinejoin="round"
|
|
393
395
|
width={size}
|
|
394
396
|
height={size}
|
|
397
|
+
className={className}
|
|
395
398
|
>
|
|
396
399
|
<path d="M20 6 9 17l-5-5" />
|
|
397
400
|
</svg>
|
|
@@ -626,6 +629,25 @@ export function LifeBuoyIcon({ size = 16 }) {
|
|
|
626
629
|
);
|
|
627
630
|
}
|
|
628
631
|
|
|
632
|
+
export function WrenchIcon({ size = 16, className = '' }) {
|
|
633
|
+
return (
|
|
634
|
+
<svg
|
|
635
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
636
|
+
viewBox="0 0 24 24"
|
|
637
|
+
fill="none"
|
|
638
|
+
stroke="currentColor"
|
|
639
|
+
strokeWidth={2}
|
|
640
|
+
strokeLinecap="round"
|
|
641
|
+
strokeLinejoin="round"
|
|
642
|
+
width={size}
|
|
643
|
+
height={size}
|
|
644
|
+
className={className}
|
|
645
|
+
>
|
|
646
|
+
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
|
|
647
|
+
</svg>
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
|
|
629
651
|
export function LogOutIcon({ size = 16 }) {
|
|
630
652
|
return (
|
|
631
653
|
<svg
|