reeboot 1.0.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/README.md +361 -0
- package/container/Dockerfile +48 -0
- package/container/entrypoint.sh +8 -0
- package/dist/agent-runner/index.d.ts +9 -0
- package/dist/agent-runner/index.d.ts.map +1 -0
- package/dist/agent-runner/index.js +21 -0
- package/dist/agent-runner/index.js.map +1 -0
- package/dist/agent-runner/interface.d.ts +56 -0
- package/dist/agent-runner/interface.d.ts.map +1 -0
- package/dist/agent-runner/interface.js +5 -0
- package/dist/agent-runner/interface.js.map +1 -0
- package/dist/agent-runner/pi-runner.d.ts +41 -0
- package/dist/agent-runner/pi-runner.d.ts.map +1 -0
- package/dist/agent-runner/pi-runner.js +162 -0
- package/dist/agent-runner/pi-runner.js.map +1 -0
- package/dist/channels/interface.d.ts +63 -0
- package/dist/channels/interface.d.ts.map +1 -0
- package/dist/channels/interface.js +33 -0
- package/dist/channels/interface.js.map +1 -0
- package/dist/channels/registry.d.ts +30 -0
- package/dist/channels/registry.d.ts.map +1 -0
- package/dist/channels/registry.js +71 -0
- package/dist/channels/registry.js.map +1 -0
- package/dist/channels/signal.d.ts +51 -0
- package/dist/channels/signal.d.ts.map +1 -0
- package/dist/channels/signal.js +263 -0
- package/dist/channels/signal.js.map +1 -0
- package/dist/channels/web.d.ts +35 -0
- package/dist/channels/web.d.ts.map +1 -0
- package/dist/channels/web.js +65 -0
- package/dist/channels/web.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +25 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +150 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/config.d.ts +366 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +140 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +69 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +166 -0
- package/dist/context.js.map +1 -0
- package/dist/credential-proxy.d.ts +25 -0
- package/dist/credential-proxy.d.ts.map +1 -0
- package/dist/credential-proxy.js +96 -0
- package/dist/credential-proxy.js.map +1 -0
- package/dist/daemon.d.ts +25 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +138 -0
- package/dist/daemon.js.map +1 -0
- package/dist/db/index.d.ts +23 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +113 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +408 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +55 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/doctor.d.ts +23 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +217 -0
- package/dist/doctor.js.map +1 -0
- package/dist/extensions/loader.d.ts +19 -0
- package/dist/extensions/loader.d.ts.map +1 -0
- package/dist/extensions/loader.js +124 -0
- package/dist/extensions/loader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +561 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +60 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +313 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/packages.d.ts +21 -0
- package/dist/packages.d.ts.map +1 -0
- package/dist/packages.js +116 -0
- package/dist/packages.js.map +1 -0
- package/dist/scheduler-registry.d.ts +8 -0
- package/dist/scheduler-registry.d.ts.map +1 -0
- package/dist/scheduler-registry.js +14 -0
- package/dist/scheduler-registry.js.map +1 -0
- package/dist/scheduler.d.ts +60 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +143 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +489 -0
- package/dist/server.js.map +1 -0
- package/dist/setup-wizard.d.ts +12 -0
- package/dist/setup-wizard.d.ts.map +1 -0
- package/dist/setup-wizard.js +163 -0
- package/dist/setup-wizard.js.map +1 -0
- package/extensions/confirm-destructive.ts +59 -0
- package/extensions/custom-compaction.ts +114 -0
- package/extensions/protected-paths.ts +30 -0
- package/extensions/sandbox/index.ts +317 -0
- package/extensions/sandbox/package-lock.json +92 -0
- package/extensions/sandbox/package.json +19 -0
- package/extensions/scheduler-tool.ts +65 -0
- package/extensions/session-name.ts +27 -0
- package/extensions/token-meter.ts +55 -0
- package/package.json +68 -0
- package/skills/send-message/SKILL.md +27 -0
- package/skills/web-search/SKILL.md +32 -0
- package/templates/global-agents.md +23 -0
- package/templates/main-agents.md +28 -0
- package/webchat/index.html +421 -0
package/README.md
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# reeboot
|
|
2
|
+
|
|
3
|
+
> Your personal AI agent. One command to install. Runs locally. Talk to it from anywhere.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install and launch the setup wizard
|
|
11
|
+
npx reeboot
|
|
12
|
+
|
|
13
|
+
# Or install globally
|
|
14
|
+
npm install -g reeboot
|
|
15
|
+
reeboot setup
|
|
16
|
+
reeboot start
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The wizard will ask for your LLM provider, API key, model, and which channels to enable. After that, `reeboot start` runs the agent — open the WebChat URL it prints, or scan the WhatsApp QR code.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## What It Can Do
|
|
24
|
+
|
|
25
|
+
| Capability | Description |
|
|
26
|
+
|---|---|
|
|
27
|
+
| **WebChat** | Browser-based chat UI, available instantly at `http://localhost:3000` |
|
|
28
|
+
| **WhatsApp** | Scan a QR code — your agent lives in your WhatsApp DMs |
|
|
29
|
+
| **Signal** | Connect via a Signal Docker container (json-rpc or polling mode) |
|
|
30
|
+
| **Multi-context** | Separate conversation threads (work, personal, projects) |
|
|
31
|
+
| **Scheduled tasks** | Ask your agent to remind you or run jobs on a cron schedule |
|
|
32
|
+
| **Extensions** | Pi-compatible extension system — tools, compaction, custom prompts |
|
|
33
|
+
| **Skills** | Drop Markdown skill files into `~/.reeboot/skills/` for instant capabilities |
|
|
34
|
+
| **Packages** | Install community tool packages: `reeboot install npm:reeboot-github-tools` |
|
|
35
|
+
| **Daemon mode** | Run as a background service (launchd on macOS, systemd on Linux) |
|
|
36
|
+
| **Doctor** | `reeboot doctor` diagnoses your setup before you even start |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Architecture Overview
|
|
41
|
+
|
|
42
|
+
Reeboot is a single Node.js process. All channels (WhatsApp, Signal, WebChat) connect to the same orchestrator, which routes messages to the AI agent and returns responses.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
┌──────────────────────────────────┐
|
|
46
|
+
│ reeboot process │
|
|
47
|
+
│ │
|
|
48
|
+
WhatsApp ────────►│ ChannelRegistry │
|
|
49
|
+
Signal ────────►│ │ │
|
|
50
|
+
WebChat ────────►│ MessageBus ──► Orchestrator │
|
|
51
|
+
HTTP API ────────►│ │ │
|
|
52
|
+
│ AgentRunner (pi) │
|
|
53
|
+
│ │ │
|
|
54
|
+
│ LLM Provider │
|
|
55
|
+
│ (Anthropic / OpenAI …) │
|
|
56
|
+
└──────────────────────────────────┘
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Configuration lives in `~/.reeboot/config.json`. Sessions and conversation history are stored in `~/.reeboot/db/reeboot.db` (SQLite). Extensions are loaded from `~/.reeboot/extensions/` and `~/.reeboot/packages/`.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Configuration Reference
|
|
64
|
+
|
|
65
|
+
Config file: `~/.reeboot/config.json`
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"agent": {
|
|
70
|
+
"provider": "anthropic",
|
|
71
|
+
"apiKey": "sk-ant-...",
|
|
72
|
+
"model": "claude-opus-4-5",
|
|
73
|
+
"name": "Reeboot",
|
|
74
|
+
"turnTimeout": 300000,
|
|
75
|
+
"rateLimitRetries": 3
|
|
76
|
+
},
|
|
77
|
+
"channels": {
|
|
78
|
+
"web": {
|
|
79
|
+
"enabled": true,
|
|
80
|
+
"port": 3000
|
|
81
|
+
},
|
|
82
|
+
"whatsapp": {
|
|
83
|
+
"enabled": false
|
|
84
|
+
},
|
|
85
|
+
"signal": {
|
|
86
|
+
"enabled": false,
|
|
87
|
+
"phoneNumber": "+15551234567",
|
|
88
|
+
"apiUrl": "http://localhost:8080",
|
|
89
|
+
"pollInterval": 1000
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"extensions": {
|
|
93
|
+
"packages": []
|
|
94
|
+
},
|
|
95
|
+
"credentialProxy": {
|
|
96
|
+
"enabled": false
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Environment variables** (override config values):
|
|
102
|
+
- `REEBOOT_API_KEY` — LLM provider API key
|
|
103
|
+
- `REEBOOT_PROVIDER` — provider name
|
|
104
|
+
- `REEBOOT_MODEL` — model ID
|
|
105
|
+
- `REEBOOT_PORT` — HTTP port (default: 3000)
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Extension System
|
|
110
|
+
|
|
111
|
+
Reeboot uses a three-level extension ladder. Pick the right level for what you want to do:
|
|
112
|
+
|
|
113
|
+
### Level 1 — Skills (Markdown, easiest)
|
|
114
|
+
|
|
115
|
+
Drop a `SKILL.md` file into `~/.reeboot/skills/<skill-name>/SKILL.md`. The agent reads it as a system-level instruction when the skill is invoked. Great for domain-specific personas, checklists, or prompt templates.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
~/.reeboot/skills/
|
|
119
|
+
morning-standup/
|
|
120
|
+
SKILL.md ← "When asked for standup, ask 3 questions then summarise..."
|
|
121
|
+
code-review/
|
|
122
|
+
SKILL.md
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Level 2 — Pi Extensions (TypeScript, full tool access)
|
|
126
|
+
|
|
127
|
+
Drop a `.ts` file into `~/.reeboot/extensions/`. Extensions are pi-compatible — they can register tools, hook into system prompt generation, and intercept messages.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// ~/.reeboot/extensions/my-tool.ts
|
|
131
|
+
export default {
|
|
132
|
+
tools: [
|
|
133
|
+
{
|
|
134
|
+
name: 'get_weather',
|
|
135
|
+
description: 'Get current weather for a city',
|
|
136
|
+
inputSchema: { ... },
|
|
137
|
+
handler: async ({ city }) => { ... }
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Reload without restart: `reeboot reload`
|
|
144
|
+
|
|
145
|
+
### Level 3 — Channel Adapters (TypeScript, custom channels)
|
|
146
|
+
|
|
147
|
+
Implement the `ChannelAdapter` interface from `reeboot/channels` to add new messaging channels (Telegram, SMS, Slack, etc.):
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import type { ChannelAdapter } from 'reeboot/channels';
|
|
151
|
+
|
|
152
|
+
export class TelegramAdapter implements ChannelAdapter {
|
|
153
|
+
// ...
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Community Packages
|
|
158
|
+
|
|
159
|
+
Install published packages that bundle tools, extensions, or channel adapters:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
reeboot install npm:reeboot-github-tools
|
|
163
|
+
reeboot install npm:reeboot-obsidian-tools
|
|
164
|
+
reeboot install git:github.com/you/my-reeboot-pack
|
|
165
|
+
reeboot install ./path/to/local-package
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
List installed packages:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
reeboot packages list
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Uninstall:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
reeboot uninstall reeboot-github-tools
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Publishing a community package** — add a `pi` manifest to your `package.json`:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"name": "reeboot-github-tools",
|
|
185
|
+
"pi": {
|
|
186
|
+
"extensions": ["./dist/github-extension.js"],
|
|
187
|
+
"skills": ["./skills/"]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## WhatsApp Setup
|
|
195
|
+
|
|
196
|
+
1. Enable WhatsApp in your config (`"whatsapp": { "enabled": true }`)
|
|
197
|
+
2. Start the agent: `reeboot start`
|
|
198
|
+
3. Run the channel login: `reeboot channel login whatsapp`
|
|
199
|
+
4. A QR code appears in your terminal — scan it with WhatsApp (Settings → Linked Devices → Link a Device)
|
|
200
|
+
5. The agent is now available in your WhatsApp DMs
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
┌─────────────────────────────────────┐
|
|
204
|
+
│ ██████░░██░░░░████░░███░░░██████ │
|
|
205
|
+
│ ██░░░░░░██░░░░██░░░░██░██░░██ │ ← Scan with WhatsApp
|
|
206
|
+
│ ██░░░░░░████░░████░░█████░░██ │
|
|
207
|
+
│ ██░░░░░░██░░░░██░░░░██░██░░██ │
|
|
208
|
+
│ ██████░░██░░░░████░░███░░░██████ │
|
|
209
|
+
└─────────────────────────────────────┘
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The session persists across restarts (credentials saved in `~/.reeboot/credentials/`).
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Signal Setup
|
|
217
|
+
|
|
218
|
+
Signal requires the [`bbernhard/signal-cli-rest-api`](https://github.com/bbernhard/signal-cli-rest-api) Docker container.
|
|
219
|
+
|
|
220
|
+
**Step 1 — Link your Signal account**
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
docker run -p 8080:8080 \
|
|
224
|
+
-v ~/.reeboot/signal-data:/home/user/.local/share/signal-cli \
|
|
225
|
+
-e MODE=native \
|
|
226
|
+
bbernhard/signal-cli-rest-api:latest
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Then open `http://localhost:8080/v1/qrcodelink?device_name=reeboot` in your browser and scan the QR with Signal (Settings → Linked Devices → Link new device).
|
|
230
|
+
|
|
231
|
+
**Step 2 — Run in json-rpc mode (recommended)**
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
docker run -p 8080:8080 \
|
|
235
|
+
-v ~/.reeboot/signal-data:/home/user/.local/share/signal-cli \
|
|
236
|
+
-e MODE=json-rpc \
|
|
237
|
+
bbernhard/signal-cli-rest-api:latest
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Step 3 — Enable in reeboot config**
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
"signal": {
|
|
244
|
+
"enabled": true,
|
|
245
|
+
"phoneNumber": "+15551234567",
|
|
246
|
+
"apiUrl": "http://localhost:8080"
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Then: `reeboot start`
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## CLI Reference
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
reeboot [command] [options]
|
|
258
|
+
|
|
259
|
+
Commands:
|
|
260
|
+
start Start the agent server
|
|
261
|
+
stop Stop the running daemon
|
|
262
|
+
setup Interactive setup wizard
|
|
263
|
+
status Show agent and channel status
|
|
264
|
+
doctor Run pre-flight diagnostics
|
|
265
|
+
reload Hot-reload extensions and skills
|
|
266
|
+
restart Gracefully restart the agent
|
|
267
|
+
|
|
268
|
+
install <pkg> Install a pi-compatible package
|
|
269
|
+
uninstall <name> Uninstall a package
|
|
270
|
+
|
|
271
|
+
packages list List installed packages
|
|
272
|
+
|
|
273
|
+
channel list List channels and their status
|
|
274
|
+
channel login <ch> Authenticate a channel (whatsapp, signal)
|
|
275
|
+
channel logout <ch> Disconnect a channel
|
|
276
|
+
|
|
277
|
+
Options:
|
|
278
|
+
start:
|
|
279
|
+
--daemon Run as background service (launchd/systemd)
|
|
280
|
+
--no-interactive Skip prompts (use with --provider etc.)
|
|
281
|
+
--provider <name> LLM provider
|
|
282
|
+
--api-key <key> API key
|
|
283
|
+
--model <id> Model ID
|
|
284
|
+
--channels <list> Comma-separated channel list
|
|
285
|
+
--name <name> Agent name
|
|
286
|
+
|
|
287
|
+
setup:
|
|
288
|
+
--no-interactive Non-interactive (use with flags below)
|
|
289
|
+
--provider, --api-key, --model, --channels, --name
|
|
290
|
+
|
|
291
|
+
doctor:
|
|
292
|
+
--skip-network Skip network checks (API key validation, Signal version)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Docker
|
|
298
|
+
|
|
299
|
+
Run reeboot as a container, mounting your config from the host:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
docker run -d \
|
|
303
|
+
-v ~/.reeboot:/home/reeboot/.reeboot \
|
|
304
|
+
-p 3000:3000 \
|
|
305
|
+
--name reeboot \
|
|
306
|
+
reeboot/reeboot:latest
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Health check:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
curl http://localhost:3000/api/health
|
|
313
|
+
# {"status":"ok","uptime":42,"version":"1.0.0"}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
WebChat is available at `http://localhost:3000`.
|
|
317
|
+
|
|
318
|
+
**Docker Compose example:**
|
|
319
|
+
|
|
320
|
+
```yaml
|
|
321
|
+
services:
|
|
322
|
+
reeboot:
|
|
323
|
+
image: reeboot/reeboot:latest
|
|
324
|
+
ports:
|
|
325
|
+
- "3000:3000"
|
|
326
|
+
volumes:
|
|
327
|
+
- ~/.reeboot:/home/reeboot/.reeboot
|
|
328
|
+
restart: unless-stopped
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## CI/CD Secrets
|
|
334
|
+
|
|
335
|
+
To use the GitHub Actions publish pipeline, add these repository secrets:
|
|
336
|
+
|
|
337
|
+
| Secret | Description |
|
|
338
|
+
|---|---|
|
|
339
|
+
| `NPM_TOKEN` | npm automation token (`npm token create --type=automation`) |
|
|
340
|
+
| `DOCKERHUB_TOKEN` | Docker Hub access token (Hub → Account Settings → Security) |
|
|
341
|
+
|
|
342
|
+
The workflow automatically publishes to npm and pushes Docker images when you push a `v*` tag:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
git tag v1.0.0
|
|
346
|
+
git push origin v1.0.0
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
MIT
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Links
|
|
358
|
+
|
|
359
|
+
- [npm package](https://www.npmjs.com/package/reeboot)
|
|
360
|
+
- [Docker Hub](https://hub.docker.com/r/reeboot/reeboot)
|
|
361
|
+
- [Architecture decisions](../architecture-decisions.md)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# ── Stage 1: builder ─────────────────────────────────────────────────────────
|
|
2
|
+
FROM node:22-slim AS builder
|
|
3
|
+
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
# Install dependencies first (better layer caching)
|
|
7
|
+
COPY package*.json ./
|
|
8
|
+
RUN npm ci
|
|
9
|
+
|
|
10
|
+
# Copy source and build
|
|
11
|
+
COPY . .
|
|
12
|
+
RUN npm run build
|
|
13
|
+
|
|
14
|
+
# ── Stage 2: runtime ─────────────────────────────────────────────────────────
|
|
15
|
+
FROM node:22-slim
|
|
16
|
+
|
|
17
|
+
# Create non-root user (uid 1000) — rename existing node user if uid 1000 is taken
|
|
18
|
+
RUN if id -u 1000 >/dev/null 2>&1; then \
|
|
19
|
+
usermod -l reeboot -d /home/reeboot -m $(getent passwd 1000 | cut -d: -f1); \
|
|
20
|
+
else \
|
|
21
|
+
useradd -m -u 1000 -s /bin/bash reeboot; \
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
USER reeboot
|
|
25
|
+
WORKDIR /home/reeboot
|
|
26
|
+
|
|
27
|
+
# Copy built output and runtime assets from builder
|
|
28
|
+
COPY --from=builder --chown=reeboot:reeboot /app/dist ./dist
|
|
29
|
+
COPY --from=builder --chown=reeboot:reeboot /app/extensions ./extensions
|
|
30
|
+
COPY --from=builder --chown=reeboot:reeboot /app/skills ./skills
|
|
31
|
+
COPY --from=builder --chown=reeboot:reeboot /app/templates ./templates
|
|
32
|
+
COPY --from=builder --chown=reeboot:reeboot /app/container ./container
|
|
33
|
+
COPY --from=builder --chown=reeboot:reeboot /app/webchat ./webchat
|
|
34
|
+
COPY --from=builder --chown=reeboot:reeboot /app/package.json ./package.json
|
|
35
|
+
COPY --from=builder --chown=reeboot:reeboot /app/package-lock.json ./package-lock.json
|
|
36
|
+
|
|
37
|
+
# Install production dependencies only
|
|
38
|
+
RUN npm ci --omit=dev
|
|
39
|
+
|
|
40
|
+
# Make entrypoint executable
|
|
41
|
+
RUN chmod +x ./container/entrypoint.sh
|
|
42
|
+
|
|
43
|
+
# Config and data directory (mount from host: -v ~/.reeboot:/home/reeboot/.reeboot)
|
|
44
|
+
VOLUME ["/home/reeboot/.reeboot"]
|
|
45
|
+
|
|
46
|
+
EXPOSE 3000
|
|
47
|
+
|
|
48
|
+
ENTRYPOINT ["./container/entrypoint.sh"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# reeboot container entrypoint
|
|
3
|
+
# Starts the agent in non-interactive mode (no TTY in container).
|
|
4
|
+
# Binds to 0.0.0.0 so the port is reachable from outside the container.
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
export REEBOOT_HOST="${REEBOOT_HOST:-0.0.0.0}"
|
|
8
|
+
exec node dist/index.js start --no-interactive "$@"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Config } from '../config.js';
|
|
2
|
+
import type { AgentRunner, ContextConfig } from './interface.js';
|
|
3
|
+
export type { AgentRunner, AgentRunnerFactory, ContextConfig, RunnerEvent } from './interface.js';
|
|
4
|
+
/**
|
|
5
|
+
* Factory function: reads config.agent.runner and returns the appropriate AgentRunner.
|
|
6
|
+
* Phase 1 only supports "pi". Unknown values throw a descriptive error.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createRunner(context: ContextConfig, config: Config): AgentRunner;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent-runner/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAMjE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElG;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAahF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PiAgentRunner } from './pi-runner.js';
|
|
2
|
+
import { DefaultResourceLoader } from '@mariozechner/pi-coding-agent';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
/**
|
|
6
|
+
* Factory function: reads config.agent.runner and returns the appropriate AgentRunner.
|
|
7
|
+
* Phase 1 only supports "pi". Unknown values throw a descriptive error.
|
|
8
|
+
*/
|
|
9
|
+
export function createRunner(context, config) {
|
|
10
|
+
const runnerType = config.agent.runner ?? 'pi';
|
|
11
|
+
if (runnerType === 'pi') {
|
|
12
|
+
const agentDir = join(homedir(), '.reeboot');
|
|
13
|
+
const loader = new DefaultResourceLoader({
|
|
14
|
+
cwd: context.workspacePath,
|
|
15
|
+
agentDir,
|
|
16
|
+
});
|
|
17
|
+
return new PiAgentRunner(context, loader);
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`Unknown agent runner: ${runnerType}`);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent-runner/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAsB,EAAE,MAAc;IACjE,MAAM,UAAU,GAAI,MAAM,CAAC,KAAa,CAAC,MAAM,IAAI,IAAI,CAAC;IAExD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,qBAAqB,CAAC;YACvC,GAAG,EAAE,OAAO,CAAC,aAAa;YAC1B,QAAQ;SACT,CAAC,CAAC;QACH,OAAO,IAAI,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,yBAAyB,UAAU,EAAE,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type RunnerEvent = {
|
|
2
|
+
type: 'text_delta';
|
|
3
|
+
delta: string;
|
|
4
|
+
} | {
|
|
5
|
+
type: 'tool_call_start';
|
|
6
|
+
toolCallId: string;
|
|
7
|
+
toolName: string;
|
|
8
|
+
args: unknown;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'tool_call_end';
|
|
11
|
+
toolCallId: string;
|
|
12
|
+
toolName: string;
|
|
13
|
+
result: unknown;
|
|
14
|
+
isError: boolean;
|
|
15
|
+
} | {
|
|
16
|
+
type: 'message_end';
|
|
17
|
+
runId: string;
|
|
18
|
+
usage: {
|
|
19
|
+
input: number;
|
|
20
|
+
output: number;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
23
|
+
type: 'error';
|
|
24
|
+
message: string;
|
|
25
|
+
};
|
|
26
|
+
export interface AgentRunner {
|
|
27
|
+
/**
|
|
28
|
+
* Send a user message to the agent. Calls onEvent for each RunnerEvent as
|
|
29
|
+
* they arrive. Resolves when the turn completes (message_end received).
|
|
30
|
+
*/
|
|
31
|
+
prompt(content: string, onEvent: (event: RunnerEvent) => void): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Abort any in-flight prompt. No-op if no prompt is active.
|
|
34
|
+
*/
|
|
35
|
+
abort(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Dispose the runner and release underlying resources.
|
|
38
|
+
* Idempotent — safe to call multiple times.
|
|
39
|
+
*/
|
|
40
|
+
dispose(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Hot-reload extensions/skills without restarting the process.
|
|
43
|
+
* Calls loader.reload() on the underlying DefaultResourceLoader.
|
|
44
|
+
*/
|
|
45
|
+
reload(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export interface ContextConfig {
|
|
48
|
+
/** Unique context identifier (e.g., "main") */
|
|
49
|
+
id: string;
|
|
50
|
+
/** Workspace directory for this context (cwd for pi session) */
|
|
51
|
+
workspacePath: string;
|
|
52
|
+
}
|
|
53
|
+
export interface AgentRunnerFactory {
|
|
54
|
+
create(context: ContextConfig, config: import('../config.js').Config): AgentRunner;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/agent-runner/interface.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAClG;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAIvC,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9E;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;OAGG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAID,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,GAAG,WAAW,CAAC;CACpF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ─── RunnerEvent ─────────────────────────────────────────────────────────────
|
|
2
|
+
// Discriminated union of events forwarded from the pi AgentSession to callers.
|
|
3
|
+
// These intentionally use simple field names independent of pi SDK internals.
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=interface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/agent-runner/interface.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PiAgentRunner — wraps the pi SDK AgentSession.
|
|
3
|
+
*
|
|
4
|
+
* Pi SDK event mapping (verified against @mariozechner/pi-agent-core types.d.ts):
|
|
5
|
+
*
|
|
6
|
+
* pi event → RunnerEvent
|
|
7
|
+
* ─────────────────────────────────────────────────────────────────────
|
|
8
|
+
* message_update → text_delta
|
|
9
|
+
* .assistantMessageEvent.type === "text_delta"
|
|
10
|
+
* .assistantMessageEvent.delta (the text string)
|
|
11
|
+
*
|
|
12
|
+
* tool_execution_start → tool_call_start
|
|
13
|
+
* .toolCallId, .toolName, .args
|
|
14
|
+
*
|
|
15
|
+
* tool_execution_end → tool_call_end
|
|
16
|
+
* .toolCallId, .toolName, .result, .isError
|
|
17
|
+
*
|
|
18
|
+
* agent_end → message_end
|
|
19
|
+
* (usage is retrieved from session stats — pi does not put it on agent_end directly)
|
|
20
|
+
*
|
|
21
|
+
* All other pi events are silently ignored.
|
|
22
|
+
*
|
|
23
|
+
* agentDir: ~/.reeboot/ (global extensions/skills)
|
|
24
|
+
* cwd: context.workspacePath (project-local discovery)
|
|
25
|
+
*/
|
|
26
|
+
import type { AgentRunner, ContextConfig, RunnerEvent } from './interface.js';
|
|
27
|
+
import type { ResourceLoader } from '@mariozechner/pi-coding-agent';
|
|
28
|
+
export declare class PiAgentRunner implements AgentRunner {
|
|
29
|
+
private readonly context;
|
|
30
|
+
private readonly loader;
|
|
31
|
+
private abortController;
|
|
32
|
+
private disposed;
|
|
33
|
+
private _session;
|
|
34
|
+
constructor(context: ContextConfig, loader: ResourceLoader);
|
|
35
|
+
prompt(content: string, onEvent: (event: RunnerEvent) => void): Promise<void>;
|
|
36
|
+
abort(): void;
|
|
37
|
+
dispose(): Promise<void>;
|
|
38
|
+
reload(): Promise<void>;
|
|
39
|
+
private _getOrCreateSession;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=pi-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-runner.d.ts","sourceRoot":"","sources":["../../src/agent-runner/pi-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEpE,qBAAa,aAAc,YAAW,WAAW;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,QAAQ,CAAqE;gBAEzE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc;IAOpD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAmFnF,KAAK,IAAI,IAAI;IAiBP,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAUxB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;YAMf,mBAAmB;CAclC"}
|