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.
Files changed (110) hide show
  1. package/README.md +361 -0
  2. package/container/Dockerfile +48 -0
  3. package/container/entrypoint.sh +8 -0
  4. package/dist/agent-runner/index.d.ts +9 -0
  5. package/dist/agent-runner/index.d.ts.map +1 -0
  6. package/dist/agent-runner/index.js +21 -0
  7. package/dist/agent-runner/index.js.map +1 -0
  8. package/dist/agent-runner/interface.d.ts +56 -0
  9. package/dist/agent-runner/interface.d.ts.map +1 -0
  10. package/dist/agent-runner/interface.js +5 -0
  11. package/dist/agent-runner/interface.js.map +1 -0
  12. package/dist/agent-runner/pi-runner.d.ts +41 -0
  13. package/dist/agent-runner/pi-runner.d.ts.map +1 -0
  14. package/dist/agent-runner/pi-runner.js +162 -0
  15. package/dist/agent-runner/pi-runner.js.map +1 -0
  16. package/dist/channels/interface.d.ts +63 -0
  17. package/dist/channels/interface.d.ts.map +1 -0
  18. package/dist/channels/interface.js +33 -0
  19. package/dist/channels/interface.js.map +1 -0
  20. package/dist/channels/registry.d.ts +30 -0
  21. package/dist/channels/registry.d.ts.map +1 -0
  22. package/dist/channels/registry.js +71 -0
  23. package/dist/channels/registry.js.map +1 -0
  24. package/dist/channels/signal.d.ts +51 -0
  25. package/dist/channels/signal.d.ts.map +1 -0
  26. package/dist/channels/signal.js +263 -0
  27. package/dist/channels/signal.js.map +1 -0
  28. package/dist/channels/web.d.ts +35 -0
  29. package/dist/channels/web.d.ts.map +1 -0
  30. package/dist/channels/web.js +65 -0
  31. package/dist/channels/web.js.map +1 -0
  32. package/dist/channels/whatsapp.d.ts +25 -0
  33. package/dist/channels/whatsapp.d.ts.map +1 -0
  34. package/dist/channels/whatsapp.js +150 -0
  35. package/dist/channels/whatsapp.js.map +1 -0
  36. package/dist/config.d.ts +366 -0
  37. package/dist/config.d.ts.map +1 -0
  38. package/dist/config.js +140 -0
  39. package/dist/config.js.map +1 -0
  40. package/dist/context.d.ts +69 -0
  41. package/dist/context.d.ts.map +1 -0
  42. package/dist/context.js +166 -0
  43. package/dist/context.js.map +1 -0
  44. package/dist/credential-proxy.d.ts +25 -0
  45. package/dist/credential-proxy.d.ts.map +1 -0
  46. package/dist/credential-proxy.js +96 -0
  47. package/dist/credential-proxy.js.map +1 -0
  48. package/dist/daemon.d.ts +25 -0
  49. package/dist/daemon.d.ts.map +1 -0
  50. package/dist/daemon.js +138 -0
  51. package/dist/daemon.js.map +1 -0
  52. package/dist/db/index.d.ts +23 -0
  53. package/dist/db/index.d.ts.map +1 -0
  54. package/dist/db/index.js +113 -0
  55. package/dist/db/index.js.map +1 -0
  56. package/dist/db/schema.d.ts +408 -0
  57. package/dist/db/schema.d.ts.map +1 -0
  58. package/dist/db/schema.js +55 -0
  59. package/dist/db/schema.js.map +1 -0
  60. package/dist/doctor.d.ts +23 -0
  61. package/dist/doctor.d.ts.map +1 -0
  62. package/dist/doctor.js +217 -0
  63. package/dist/doctor.js.map +1 -0
  64. package/dist/extensions/loader.d.ts +19 -0
  65. package/dist/extensions/loader.d.ts.map +1 -0
  66. package/dist/extensions/loader.js +124 -0
  67. package/dist/extensions/loader.js.map +1 -0
  68. package/dist/index.d.ts +3 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +561 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/orchestrator.d.ts +60 -0
  73. package/dist/orchestrator.d.ts.map +1 -0
  74. package/dist/orchestrator.js +313 -0
  75. package/dist/orchestrator.js.map +1 -0
  76. package/dist/packages.d.ts +21 -0
  77. package/dist/packages.d.ts.map +1 -0
  78. package/dist/packages.js +116 -0
  79. package/dist/packages.js.map +1 -0
  80. package/dist/scheduler-registry.d.ts +8 -0
  81. package/dist/scheduler-registry.d.ts.map +1 -0
  82. package/dist/scheduler-registry.js +14 -0
  83. package/dist/scheduler-registry.js.map +1 -0
  84. package/dist/scheduler.d.ts +60 -0
  85. package/dist/scheduler.d.ts.map +1 -0
  86. package/dist/scheduler.js +143 -0
  87. package/dist/scheduler.js.map +1 -0
  88. package/dist/server.d.ts +18 -0
  89. package/dist/server.d.ts.map +1 -0
  90. package/dist/server.js +489 -0
  91. package/dist/server.js.map +1 -0
  92. package/dist/setup-wizard.d.ts +12 -0
  93. package/dist/setup-wizard.d.ts.map +1 -0
  94. package/dist/setup-wizard.js +163 -0
  95. package/dist/setup-wizard.js.map +1 -0
  96. package/extensions/confirm-destructive.ts +59 -0
  97. package/extensions/custom-compaction.ts +114 -0
  98. package/extensions/protected-paths.ts +30 -0
  99. package/extensions/sandbox/index.ts +317 -0
  100. package/extensions/sandbox/package-lock.json +92 -0
  101. package/extensions/sandbox/package.json +19 -0
  102. package/extensions/scheduler-tool.ts +65 -0
  103. package/extensions/session-name.ts +27 -0
  104. package/extensions/token-meter.ts +55 -0
  105. package/package.json +68 -0
  106. package/skills/send-message/SKILL.md +27 -0
  107. package/skills/web-search/SKILL.md +32 -0
  108. package/templates/global-agents.md +23 -0
  109. package/templates/main-agents.md +28 -0
  110. package/webchat/index.html +421 -0
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: web-search
3
+ description: Search the web using SearXNG. Use when you need to find current information, research a topic, look up facts, or gather information from the internet.
4
+ ---
5
+
6
+ # Web Search Skill
7
+
8
+ Use this skill when you need to search the web for information.
9
+
10
+ ## Instructions
11
+
12
+ 1. Formulate a clear, concise search query for the topic
13
+ 2. Use the `web_search` tool with your query
14
+ 3. Review the results and extract relevant information
15
+ 4. Cite your sources when presenting findings
16
+
17
+ ## When to Use
18
+
19
+ - Looking up current events or news
20
+ - Researching a technical topic
21
+ - Finding documentation or tutorials
22
+ - Verifying facts or statistics
23
+ - Discovering resources on a subject
24
+
25
+ ## Example
26
+
27
+ ```
28
+ User: What is the current version of Node.js LTS?
29
+ → web_search("Node.js LTS version 2025")
30
+ → Review results
31
+ → Report: "The current Node.js LTS version is X.Y.Z (sources: ...)"
32
+ ```
@@ -0,0 +1,23 @@
1
+ # Global Agent Memory
2
+
3
+ This file is shared across all contexts. Use it for persistent facts, preferences, and knowledge that should be available everywhere.
4
+
5
+ ## About Me
6
+
7
+ <!-- Add facts about yourself here: name, location, occupation, preferences, etc. -->
8
+
9
+ ## Persistent Preferences
10
+
11
+ <!-- Communication style, language preferences, formatting preferences -->
12
+
13
+ ## Important People & Relationships
14
+
15
+ <!-- Key people, their roles, contact preferences -->
16
+
17
+ ## Projects & Responsibilities
18
+
19
+ <!-- Ongoing projects, responsibilities, goals -->
20
+
21
+ ## Knowledge Base
22
+
23
+ <!-- Important domain knowledge, frequently referenced facts -->
@@ -0,0 +1,28 @@
1
+ # Reeboot — Personal Assistant
2
+
3
+ You are Reeboot, a personal AI assistant running locally on this machine.
4
+
5
+ ## Persona
6
+
7
+ - You are helpful, concise, and direct
8
+ - You remember context across conversations
9
+ - You have access to scheduled tasks and can act proactively
10
+ - You communicate via the configured channels (WhatsApp, Signal, WebChat)
11
+
12
+ ## Capabilities
13
+
14
+ - Answer questions and help with tasks
15
+ - Access and manage contexts and sessions
16
+ - Execute scheduled prompts and tasks
17
+ - Coordinate across channels
18
+
19
+ ## Instructions
20
+
21
+ - Always be brief unless detail is requested
22
+ - Reference global memory (AGENTS.md in contexts/global/) for persistent facts
23
+ - Use workspace/ for files and artifacts
24
+ - Escalate to the user when in doubt
25
+
26
+ ## Workspace
27
+
28
+ All files created during sessions are stored in `workspace/`.
@@ -0,0 +1,421 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Reeboot WebChat</title>
7
+ <style>
8
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
9
+
10
+ :root {
11
+ --bg: #0f0f0f;
12
+ --surface: #1a1a1a;
13
+ --border: #2a2a2a;
14
+ --text: #e0e0e0;
15
+ --text-muted: #888;
16
+ --accent: #4f9cf9;
17
+ --user-bg: #1e3a5f;
18
+ --assistant-bg: #1a1a1a;
19
+ --tool-bg: #1e2a1e;
20
+ --error: #e05252;
21
+ --radius: 8px;
22
+ }
23
+
24
+ body {
25
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
26
+ background: var(--bg);
27
+ color: var(--text);
28
+ height: 100dvh;
29
+ display: flex;
30
+ flex-direction: column;
31
+ }
32
+
33
+ header {
34
+ padding: 12px 16px;
35
+ border-bottom: 1px solid var(--border);
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 10px;
39
+ background: var(--surface);
40
+ }
41
+
42
+ header h1 { font-size: 1rem; font-weight: 600; }
43
+
44
+ #status {
45
+ margin-left: auto;
46
+ font-size: 0.75rem;
47
+ color: var(--text-muted);
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 6px;
51
+ }
52
+
53
+ #status-dot {
54
+ width: 8px; height: 8px;
55
+ border-radius: 50%;
56
+ background: #555;
57
+ }
58
+ #status-dot.connected { background: #4caf50; }
59
+ #status-dot.connecting { background: #ff9800; }
60
+ #status-dot.error { background: var(--error); }
61
+
62
+ #messages {
63
+ flex: 1;
64
+ overflow-y: auto;
65
+ padding: 16px;
66
+ display: flex;
67
+ flex-direction: column;
68
+ gap: 12px;
69
+ }
70
+
71
+ .message {
72
+ max-width: 80%;
73
+ padding: 10px 14px;
74
+ border-radius: var(--radius);
75
+ line-height: 1.5;
76
+ font-size: 0.9rem;
77
+ white-space: pre-wrap;
78
+ word-break: break-word;
79
+ }
80
+
81
+ .message.user {
82
+ background: var(--user-bg);
83
+ align-self: flex-end;
84
+ border-bottom-right-radius: 2px;
85
+ }
86
+
87
+ .message.assistant {
88
+ background: var(--assistant-bg);
89
+ border: 1px solid var(--border);
90
+ align-self: flex-start;
91
+ border-bottom-left-radius: 2px;
92
+ }
93
+
94
+ .message.assistant.streaming::after {
95
+ content: '▋';
96
+ animation: blink 1s step-end infinite;
97
+ color: var(--accent);
98
+ }
99
+
100
+ @keyframes blink { 50% { opacity: 0; } }
101
+
102
+ .message.error-msg {
103
+ background: #2a1515;
104
+ border: 1px solid var(--error);
105
+ color: var(--error);
106
+ align-self: center;
107
+ font-size: 0.8rem;
108
+ }
109
+
110
+ .tool-indicator {
111
+ background: var(--tool-bg);
112
+ border: 1px solid #2d4a2d;
113
+ border-radius: 4px;
114
+ padding: 4px 10px;
115
+ font-size: 0.75rem;
116
+ color: #7db87d;
117
+ align-self: flex-start;
118
+ font-family: 'SF Mono', 'Fira Code', monospace;
119
+ cursor: pointer;
120
+ user-select: none;
121
+ }
122
+
123
+ .tool-indicator summary { list-style: none; }
124
+ .tool-indicator summary::-webkit-details-marker { display: none; }
125
+
126
+ .tool-details {
127
+ margin-top: 6px;
128
+ color: var(--text-muted);
129
+ font-size: 0.72rem;
130
+ white-space: pre-wrap;
131
+ }
132
+
133
+ footer {
134
+ padding: 12px 16px;
135
+ border-top: 1px solid var(--border);
136
+ background: var(--surface);
137
+ }
138
+
139
+ #input-row {
140
+ display: flex;
141
+ gap: 8px;
142
+ align-items: flex-end;
143
+ }
144
+
145
+ #input {
146
+ flex: 1;
147
+ background: #111;
148
+ border: 1px solid var(--border);
149
+ border-radius: var(--radius);
150
+ color: var(--text);
151
+ padding: 10px 12px;
152
+ font-size: 0.9rem;
153
+ font-family: inherit;
154
+ resize: none;
155
+ min-height: 42px;
156
+ max-height: 160px;
157
+ outline: none;
158
+ transition: border-color 0.15s;
159
+ }
160
+ #input:focus { border-color: var(--accent); }
161
+ #input:disabled { opacity: 0.4; cursor: not-allowed; }
162
+
163
+ button {
164
+ border: none;
165
+ border-radius: var(--radius);
166
+ padding: 10px 16px;
167
+ font-size: 0.85rem;
168
+ font-family: inherit;
169
+ cursor: pointer;
170
+ transition: opacity 0.15s;
171
+ white-space: nowrap;
172
+ }
173
+ button:disabled { opacity: 0.4; cursor: not-allowed; }
174
+
175
+ #send-btn {
176
+ background: var(--accent);
177
+ color: #fff;
178
+ font-weight: 600;
179
+ }
180
+ #send-btn:hover:not(:disabled) { opacity: 0.85; }
181
+
182
+ #cancel-btn {
183
+ background: #3a1515;
184
+ color: var(--error);
185
+ display: none;
186
+ }
187
+ #cancel-btn.visible { display: block; }
188
+ #cancel-btn:hover:not(:disabled) { opacity: 0.85; }
189
+
190
+ .hint {
191
+ font-size: 0.72rem;
192
+ color: var(--text-muted);
193
+ margin-top: 6px;
194
+ text-align: right;
195
+ }
196
+ </style>
197
+ </head>
198
+ <body>
199
+
200
+ <header>
201
+ <h1>🤖 Reeboot</h1>
202
+ <div id="status">
203
+ <div id="status-dot" class="connecting"></div>
204
+ <span id="status-text">Connecting…</span>
205
+ </div>
206
+ </header>
207
+
208
+ <div id="messages"></div>
209
+
210
+ <footer>
211
+ <div id="input-row">
212
+ <textarea
213
+ id="input"
214
+ placeholder="Send a message…"
215
+ rows="1"
216
+ autocomplete="off"
217
+ spellcheck="true"
218
+ ></textarea>
219
+ <button id="send-btn" disabled>Send</button>
220
+ <button id="cancel-btn">Cancel</button>
221
+ </div>
222
+ <div class="hint">Enter to send · Shift+Enter for newline</div>
223
+ </footer>
224
+
225
+ <script>
226
+ (function () {
227
+ 'use strict';
228
+
229
+ // ── Config ─────────────────────────────────────────────────────────────────
230
+ const contextId = 'main';
231
+ const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
232
+ const wsUrl = `${wsProtocol}//${location.host}/ws/chat/${contextId}`;
233
+
234
+ // ── State ──────────────────────────────────────────────────────────────────
235
+ let ws = null;
236
+ let isBusy = false;
237
+ let currentAssistantEl = null;
238
+ let reconnectDelay = 1000;
239
+
240
+ // ── Elements ───────────────────────────────────────────────────────────────
241
+ const messagesEl = document.getElementById('messages');
242
+ const inputEl = document.getElementById('input');
243
+ const sendBtn = document.getElementById('send-btn');
244
+ const cancelBtn = document.getElementById('cancel-btn');
245
+ const statusDot = document.getElementById('status-dot');
246
+ const statusText = document.getElementById('status-text');
247
+
248
+ // ── Status helpers ─────────────────────────────────────────────────────────
249
+ function setStatus(state, text) {
250
+ statusDot.className = state;
251
+ statusText.textContent = text;
252
+ }
253
+
254
+ // ── UI helpers ─────────────────────────────────────────────────────────────
255
+ function appendMessage(role, text) {
256
+ const el = document.createElement('div');
257
+ el.className = `message ${role}`;
258
+ el.textContent = text;
259
+ messagesEl.appendChild(el);
260
+ messagesEl.scrollTop = messagesEl.scrollHeight;
261
+ return el;
262
+ }
263
+
264
+ function appendError(text) {
265
+ const el = document.createElement('div');
266
+ el.className = 'message error-msg';
267
+ el.textContent = `⚠ ${text}`;
268
+ messagesEl.appendChild(el);
269
+ messagesEl.scrollTop = messagesEl.scrollHeight;
270
+ }
271
+
272
+ function appendToolIndicator(toolName) {
273
+ const el = document.createElement('details');
274
+ el.className = 'tool-indicator';
275
+ const summary = document.createElement('summary');
276
+ summary.textContent = `⚙ ${toolName}`;
277
+ el.appendChild(summary);
278
+ messagesEl.appendChild(el);
279
+ messagesEl.scrollTop = messagesEl.scrollHeight;
280
+ return el;
281
+ }
282
+
283
+ function setBusy(busy) {
284
+ isBusy = busy;
285
+ inputEl.disabled = busy;
286
+ sendBtn.disabled = busy || ws?.readyState !== WebSocket.OPEN;
287
+ if (busy) {
288
+ cancelBtn.classList.add('visible');
289
+ } else {
290
+ cancelBtn.classList.remove('visible');
291
+ currentAssistantEl?.classList.remove('streaming');
292
+ currentAssistantEl = null;
293
+ }
294
+ }
295
+
296
+ // ── Auto-resize textarea ───────────────────────────────────────────────────
297
+ inputEl.addEventListener('input', () => {
298
+ inputEl.style.height = 'auto';
299
+ inputEl.style.height = Math.min(inputEl.scrollHeight, 160) + 'px';
300
+ });
301
+
302
+ // ── Send ───────────────────────────────────────────────────────────────────
303
+ function sendMessage() {
304
+ const content = inputEl.value.trim();
305
+ if (!content || isBusy || ws?.readyState !== WebSocket.OPEN) return;
306
+
307
+ appendMessage('user', content);
308
+ inputEl.value = '';
309
+ inputEl.style.height = 'auto';
310
+
311
+ ws.send(JSON.stringify({ type: 'message', content }));
312
+ setBusy(true);
313
+
314
+ // Prepare streaming assistant bubble
315
+ currentAssistantEl = appendMessage('assistant', '');
316
+ currentAssistantEl.classList.add('streaming');
317
+ }
318
+
319
+ inputEl.addEventListener('keydown', (e) => {
320
+ if (e.key === 'Enter' && !e.shiftKey) {
321
+ e.preventDefault();
322
+ sendMessage();
323
+ }
324
+ });
325
+
326
+ sendBtn.addEventListener('click', sendMessage);
327
+
328
+ cancelBtn.addEventListener('click', () => {
329
+ if (ws?.readyState === WebSocket.OPEN) {
330
+ ws.send(JSON.stringify({ type: 'cancel' }));
331
+ }
332
+ setBusy(false);
333
+ });
334
+
335
+ // ── WebSocket ──────────────────────────────────────────────────────────────
336
+ function connect() {
337
+ setStatus('connecting', 'Connecting…');
338
+ ws = new WebSocket(wsUrl);
339
+
340
+ ws.onopen = () => {
341
+ reconnectDelay = 1000;
342
+ // Wait for connected message before enabling input
343
+ };
344
+
345
+ ws.onmessage = (e) => {
346
+ let msg;
347
+ try { msg = JSON.parse(e.data); } catch { return; }
348
+
349
+ switch (msg.type) {
350
+ case 'connected':
351
+ setStatus('connected', `Connected · ${contextId}`);
352
+ sendBtn.disabled = false;
353
+ break;
354
+
355
+ case 'text_delta':
356
+ if (currentAssistantEl) {
357
+ currentAssistantEl.textContent += msg.delta;
358
+ messagesEl.scrollTop = messagesEl.scrollHeight;
359
+ }
360
+ break;
361
+
362
+ case 'tool_call_start': {
363
+ const toolEl = appendToolIndicator(msg.toolName);
364
+ toolEl.dataset.toolCallId = msg.toolCallId;
365
+ break;
366
+ }
367
+
368
+ case 'tool_call_end': {
369
+ // Find the open tool indicator and add result
370
+ const open = messagesEl.querySelector(
371
+ `.tool-indicator[data-tool-call-id="${msg.toolCallId}"]`
372
+ );
373
+ if (open) {
374
+ const details = document.createElement('div');
375
+ details.className = 'tool-details';
376
+ const result = typeof msg.result === 'string' ? msg.result : JSON.stringify(msg.result, null, 2);
377
+ details.textContent = result.slice(0, 500) + (result.length > 500 ? '…' : '');
378
+ open.appendChild(details);
379
+ if (msg.isError) open.style.borderColor = '#5a2a2a';
380
+ }
381
+ break;
382
+ }
383
+
384
+ case 'message_end':
385
+ setBusy(false);
386
+ break;
387
+
388
+ case 'cancelled':
389
+ setBusy(false);
390
+ appendError('Turn cancelled.');
391
+ break;
392
+
393
+ case 'error':
394
+ setBusy(false);
395
+ appendError(msg.message || 'Unknown error');
396
+ break;
397
+ }
398
+ };
399
+
400
+ ws.onclose = (e) => {
401
+ setStatus('error', `Disconnected (${e.code})`);
402
+ sendBtn.disabled = true;
403
+ setBusy(false);
404
+
405
+ // Reconnect unless intentionally closed
406
+ if (e.code !== 1000) {
407
+ setTimeout(connect, reconnectDelay);
408
+ reconnectDelay = Math.min(reconnectDelay * 2, 30000);
409
+ }
410
+ };
411
+
412
+ ws.onerror = () => {
413
+ setStatus('error', 'Connection error');
414
+ };
415
+ }
416
+
417
+ connect();
418
+ })();
419
+ </script>
420
+ </body>
421
+ </html>