zubo 0.1.3 → 0.1.5
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/.dockerignore +12 -0
- package/Dockerfile +24 -0
- package/docker-compose.yml +20 -0
- package/package.json +1 -1
- package/site/docs/index.html +59 -11
- package/site/index.html +154 -61
- package/site/script.js +14 -5
- package/site/style.css +38 -0
- package/src/tools/builtin-integrations/google/gmail/handler.ts +8 -2
- package/src/tools/builtin-skills/http-request/handler.ts +7 -1
package/.dockerignore
ADDED
package/Dockerfile
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Zubo — Dockerfile
|
|
2
|
+
# Runs the Zubo AI agent using the official Bun runtime image.
|
|
3
|
+
# Persistent data (config, database, memory, skills) lives in /root/.zubo
|
|
4
|
+
# and should be mounted as a volume.
|
|
5
|
+
|
|
6
|
+
FROM oven/bun:1
|
|
7
|
+
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
|
|
10
|
+
# Install dependencies first (layer cache optimisation)
|
|
11
|
+
COPY package.json bun.lock ./
|
|
12
|
+
RUN bun install --frozen-lockfile
|
|
13
|
+
|
|
14
|
+
# Copy the rest of the project
|
|
15
|
+
COPY . .
|
|
16
|
+
|
|
17
|
+
# Webchat dashboard port
|
|
18
|
+
EXPOSE 8787
|
|
19
|
+
|
|
20
|
+
# Persistent storage mount point — config.json, zubo.db, workspace, logs, etc.
|
|
21
|
+
VOLUME /root/.zubo
|
|
22
|
+
|
|
23
|
+
# Start the agent
|
|
24
|
+
CMD ["bun", "run", "src/index.ts", "start"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Zubo — Docker Compose
|
|
2
|
+
# Usage:
|
|
3
|
+
# 1. Copy .env.example to .env and fill in your API keys
|
|
4
|
+
# 2. docker compose up -d
|
|
5
|
+
# 3. Open http://localhost:8787 for the webchat dashboard
|
|
6
|
+
|
|
7
|
+
services:
|
|
8
|
+
zubo:
|
|
9
|
+
build: .
|
|
10
|
+
container_name: zubo
|
|
11
|
+
restart: unless-stopped
|
|
12
|
+
|
|
13
|
+
ports:
|
|
14
|
+
- "8787:8787" # Webchat dashboard
|
|
15
|
+
|
|
16
|
+
volumes:
|
|
17
|
+
- ~/.zubo:/root/.zubo # Persistent data (config, DB, memory, skills, logs)
|
|
18
|
+
|
|
19
|
+
env_file:
|
|
20
|
+
- .env # API keys: ANTHROPIC_API_KEY, OPENAI_API_KEY, TELEGRAM_BOT_TOKEN, etc.
|
package/package.json
CHANGED
package/site/docs/index.html
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Getting Started — Zubo Docs</title>
|
|
7
|
-
<meta name="description" content="Get started with Zubo, a self-hosted AI agent with persistent semantic memory, multi-channel presence,
|
|
7
|
+
<meta name="description" content="Get started with Zubo, a self-hosted AI agent with persistent semantic memory, multi-channel presence, 20+ tools, sub-agent delegation, and workflow automation.">
|
|
8
8
|
<meta name="theme-color" content="#060608">
|
|
9
9
|
<link rel="canonical" href="https://zubo.bot/docs/">
|
|
10
10
|
<meta property="og:title" content="Getting Started — Zubo Docs">
|
|
11
|
-
<meta property="og:description" content="Get started with Zubo, a self-hosted AI agent with persistent semantic memory, multi-channel presence,
|
|
11
|
+
<meta property="og:description" content="Get started with Zubo, a self-hosted AI agent with persistent semantic memory, multi-channel presence, 20+ tools, sub-agent delegation, and workflow automation.">
|
|
12
12
|
<meta property="og:type" content="article">
|
|
13
13
|
<meta property="og:url" content="https://zubo.bot/docs/">
|
|
14
14
|
<meta property="og:image" content="https://zubo.bot/og-image.png">
|
|
15
15
|
<meta property="og:site_name" content="Zubo">
|
|
16
16
|
<meta name="twitter:card" content="summary_large_image">
|
|
17
17
|
<meta name="twitter:title" content="Getting Started — Zubo Docs">
|
|
18
|
-
<meta name="twitter:description" content="Get started with Zubo, a self-hosted AI agent with persistent semantic memory,
|
|
18
|
+
<meta name="twitter:description" content="Get started with Zubo, a self-hosted AI agent with persistent semantic memory, 20+ tools, and workflow automation.">
|
|
19
19
|
<meta name="twitter:image" content="https://zubo.bot/og-image.png">
|
|
20
20
|
<meta name="twitter:creator" content="@thomaskanze">
|
|
21
21
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
<h1>Getting Started with Zubo</h1>
|
|
88
88
|
|
|
89
89
|
<p>
|
|
90
|
-
Zubo is a self-hosted AI agent with persistent semantic memory, multi-channel presence across Telegram, Discord, Slack, WhatsApp, Signal, and Web Chat,
|
|
90
|
+
Zubo is a self-hosted AI agent with persistent semantic memory, multi-channel presence across Telegram, Discord, Slack, WhatsApp, Signal, and Web Chat, 20+ smart built-in tools, sub-agent delegation, and workflow automation. It runs entirely on your machine — your data never leaves your infrastructure. Whether you need a personal assistant that remembers everything, an automation hub that connects your services, or an AI copilot embedded in every chat platform you use, Zubo handles it from a single process with a single configuration file.
|
|
91
91
|
</p>
|
|
92
92
|
|
|
93
93
|
<!-- ================================================================ -->
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
|
|
126
126
|
<h3>Tools</h3>
|
|
127
127
|
<ul>
|
|
128
|
-
<li><strong>
|
|
128
|
+
<li><strong>20+ built-in tools</strong> including shell command execution, file I/O (read, write, list, search), web search (DuckDuckGo, Brave, Google), HTTP requests, memory read/write/search, secrets management, and cron job scheduling.</li>
|
|
129
129
|
<li>Tools are permission-gated with three levels: <code>safe</code>, <code>sensitive</code>, and <code>dangerous</code>. Dangerous operations require explicit confirmation tokens.</li>
|
|
130
130
|
</ul>
|
|
131
131
|
|
|
@@ -200,21 +200,69 @@
|
|
|
200
200
|
<!-- ================================================================ -->
|
|
201
201
|
<h2 id="installation">Installation</h2>
|
|
202
202
|
|
|
203
|
+
<p>Choose the installation method that fits your platform.</p>
|
|
204
|
+
|
|
205
|
+
<h3 id="install-mac-linux">macOS & Linux</h3>
|
|
206
|
+
|
|
203
207
|
<p>Zubo requires <strong>Bun v1.0+</strong> as its runtime. If you do not have Bun installed, visit <a href="https://bun.sh" target="_blank" rel="noopener">bun.sh</a> and run the one-line installer.</p>
|
|
204
208
|
|
|
205
|
-
<
|
|
209
|
+
<p><strong>One-liner (recommended):</strong></p>
|
|
210
|
+
|
|
211
|
+
<pre><code>curl -fsSL https://zubo.bot/install.sh | bash</code></pre>
|
|
206
212
|
|
|
207
|
-
<p>
|
|
213
|
+
<p>This installs Bun (if needed), installs Zubo globally, and runs the setup wizard automatically.</p>
|
|
214
|
+
|
|
215
|
+
<p><strong>Manual install:</strong></p>
|
|
208
216
|
|
|
209
217
|
<pre><code># Using Bun (recommended)
|
|
210
218
|
bun add -g zubo
|
|
211
219
|
|
|
212
220
|
# Or using npm
|
|
213
|
-
npm i -g zubo
|
|
221
|
+
npm i -g zubo
|
|
222
|
+
|
|
223
|
+
# Then run the setup wizard
|
|
224
|
+
zubo setup</code></pre>
|
|
225
|
+
|
|
226
|
+
<h3 id="install-windows">Windows (via WSL)</h3>
|
|
227
|
+
|
|
228
|
+
<p>Zubo runs on Windows through the Windows Subsystem for Linux (WSL). This gives you full compatibility with zero workarounds.</p>
|
|
229
|
+
|
|
230
|
+
<p><strong>Step 1:</strong> Install WSL (requires Windows 10 version 2004+ or Windows 11):</p>
|
|
231
|
+
|
|
232
|
+
<pre><code>wsl --install</code></pre>
|
|
233
|
+
|
|
234
|
+
<p>Restart your computer when prompted. This installs Ubuntu by default.</p>
|
|
235
|
+
|
|
236
|
+
<p><strong>Step 2:</strong> Open the Ubuntu terminal from the Start Menu and install Zubo:</p>
|
|
237
|
+
|
|
238
|
+
<pre><code>curl -fsSL https://zubo.bot/install.sh | bash</code></pre>
|
|
239
|
+
|
|
240
|
+
<p>That's it. Zubo runs inside WSL with full access to all features. The web dashboard is accessible from your Windows browser at <code>http://localhost:3000</code>.</p>
|
|
241
|
+
|
|
242
|
+
<h3 id="install-docker">Docker</h3>
|
|
243
|
+
|
|
244
|
+
<p>Run Zubo as a container with no local dependencies.</p>
|
|
245
|
+
|
|
246
|
+
<pre><code># Clone the repo
|
|
247
|
+
git clone https://github.com/apwn/zubo.git && cd zubo
|
|
248
|
+
|
|
249
|
+
# Copy the example env and add your API key
|
|
250
|
+
cp .env.example .env
|
|
251
|
+
|
|
252
|
+
# Start Zubo
|
|
253
|
+
docker compose up -d</code></pre>
|
|
254
|
+
|
|
255
|
+
<p>The container exposes port <code>8787</code> for the web dashboard and mounts <code>~/.zubo</code> for persistent data. Stop with <code>docker compose down</code>.</p>
|
|
256
|
+
|
|
257
|
+
<p>To configure, edit <code>.env</code> or mount your own <code>config.json</code>:</p>
|
|
258
|
+
|
|
259
|
+
<pre><code>volumes:
|
|
260
|
+
- ~/.zubo:/root/.zubo
|
|
261
|
+
- ./my-config.json:/root/.zubo/config.json</code></pre>
|
|
214
262
|
|
|
215
|
-
<
|
|
263
|
+
<h3 id="setup-wizard">The Setup Wizard</h3>
|
|
216
264
|
|
|
217
|
-
<
|
|
265
|
+
<p>After installing (on any platform), run the setup wizard:</p>
|
|
218
266
|
|
|
219
267
|
<pre><code>zubo setup</code></pre>
|
|
220
268
|
|
|
@@ -228,7 +276,7 @@ npm i -g zubo</code></pre>
|
|
|
228
276
|
<li>Create a default <code>SYSTEM.md</code> system prompt that you can customize later.</li>
|
|
229
277
|
</ul>
|
|
230
278
|
|
|
231
|
-
<h3>
|
|
279
|
+
<h3 id="starting">Starting Zubo</h3>
|
|
232
280
|
|
|
233
281
|
<pre><code># Start in foreground (logs to stdout)
|
|
234
282
|
zubo start
|
package/site/index.html
CHANGED
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Zubo —
|
|
7
|
-
<meta name="description" content="
|
|
6
|
+
<title>Zubo — Your AI Agent. Your Machine. Your Rules.</title>
|
|
7
|
+
<meta name="description" content="Open-source AI agent that runs on your machine. Persistent memory, 20+ tools, 6 messaging channels, 11+ LLM providers. One install, works everywhere.">
|
|
8
8
|
<meta name="theme-color" content="#060608">
|
|
9
9
|
<link rel="canonical" href="https://zubo.bot/">
|
|
10
|
-
<meta property="og:title" content="Zubo —
|
|
11
|
-
<meta property="og:description" content="
|
|
10
|
+
<meta property="og:title" content="Zubo — Your AI Agent. Your Machine. Your Rules.">
|
|
11
|
+
<meta property="og:description" content="Open-source AI agent that runs on your machine. Persistent memory, 20+ tools, works across Telegram, Discord, Slack, WhatsApp, and more. One install, zero cloud.">
|
|
12
12
|
<meta property="og:type" content="website">
|
|
13
13
|
<meta property="og:url" content="https://zubo.bot/">
|
|
14
14
|
<meta property="og:image" content="https://zubo.bot/og-image.png">
|
|
15
15
|
<meta property="og:site_name" content="Zubo">
|
|
16
16
|
<meta name="twitter:card" content="summary_large_image">
|
|
17
|
-
<meta name="twitter:title" content="Zubo —
|
|
18
|
-
<meta name="twitter:description" content="
|
|
17
|
+
<meta name="twitter:title" content="Zubo — Your AI Agent. Your Machine. Your Rules.">
|
|
18
|
+
<meta name="twitter:description" content="Open-source AI agent that runs on your machine. Persistent memory, 20+ tools, works across Telegram, Discord, Slack, WhatsApp, and more. One install, zero cloud.">
|
|
19
19
|
<meta name="twitter:image" content="https://zubo.bot/og-image.png">
|
|
20
20
|
<meta name="twitter:creator" content="@thomaskanze">
|
|
21
21
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
@@ -74,12 +74,12 @@
|
|
|
74
74
|
|
|
75
75
|
<h1 class="hero-title">
|
|
76
76
|
<span class="hero-line">Your AI Agent.</span>
|
|
77
|
-
<span class="hero-line"><span class="gradient-text">
|
|
77
|
+
<span class="hero-line"><span class="gradient-text">Your Machine.</span></span>
|
|
78
78
|
</h1>
|
|
79
79
|
|
|
80
80
|
<p class="hero-subtitle">
|
|
81
|
-
Zubo runs on your machine
|
|
82
|
-
|
|
81
|
+
Zubo runs on your machine, remembers everything you tell it, works across all your
|
|
82
|
+
messaging apps, and connects to your favorite tools. No cloud. No subscriptions. No forgetting.
|
|
83
83
|
</p>
|
|
84
84
|
|
|
85
85
|
<div class="hero-actions">
|
|
@@ -231,8 +231,8 @@
|
|
|
231
231
|
<div class="container">
|
|
232
232
|
<div class="section-header reveal">
|
|
233
233
|
<span class="section-badge">Capabilities</span>
|
|
234
|
-
<h2 class="section-title">
|
|
235
|
-
<p class="section-subtitle">
|
|
234
|
+
<h2 class="section-title">One agent.<br><span class="gradient-text">Endless capabilities.</span></h2>
|
|
235
|
+
<p class="section-subtitle">Memory, tools, scheduling, multi-channel support — everything works out of the box. No plugins required.</p>
|
|
236
236
|
</div>
|
|
237
237
|
|
|
238
238
|
<div class="bento reveal-stagger">
|
|
@@ -272,7 +272,7 @@
|
|
|
272
272
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/><circle cx="12" cy="16" r="1"/></svg>
|
|
273
273
|
</div>
|
|
274
274
|
<h3>100% Private</h3>
|
|
275
|
-
<p>Runs entirely on your machine. SQLite database, local vector store. Your conversations never leave your hardware.
|
|
275
|
+
<p>Runs entirely on your machine. SQLite database, local vector store. Your conversations never leave your hardware. Your data stays yours.</p>
|
|
276
276
|
</div>
|
|
277
277
|
|
|
278
278
|
<!-- Row 2 -->
|
|
@@ -280,8 +280,8 @@
|
|
|
280
280
|
<div class="bento-icon">
|
|
281
281
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
|
282
282
|
</div>
|
|
283
|
-
<h3>
|
|
284
|
-
<p>Schedule tasks in plain English —
|
|
283
|
+
<h3>Runs on Autopilot</h3>
|
|
284
|
+
<p>Schedule tasks in plain English — “every weekday at 9am” just works. Zubo monitors, alerts, and acts on your behalf — even when you're away.</p>
|
|
285
285
|
</div>
|
|
286
286
|
|
|
287
287
|
<div class="bento-card tilt-card" data-feature="extensible">
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="7.5 4.21 12 6.81 16.5 4.21"/><polyline points="7.5 19.79 7.5 14.6 3 12"/><polyline points="21 12 16.5 14.6 16.5 19.79"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
|
|
298
298
|
</div>
|
|
299
299
|
<h3>Any LLM, Your Choice</h3>
|
|
300
|
-
<p>
|
|
300
|
+
<p>11+ providers including Anthropic, OpenAI, Gemini, Ollama, Groq, DeepSeek, and more. Smart routing sends simple queries to fast, cheap models automatically — so you save money without thinking about it.</p>
|
|
301
301
|
<div class="bento-models">
|
|
302
302
|
<span class="model-tag">Claude</span>
|
|
303
303
|
<span class="model-tag">GPT-4o</span>
|
|
@@ -440,86 +440,179 @@
|
|
|
440
440
|
<h2 class="section-title">Running in <span class="gradient-text">60 seconds</span>.</h2>
|
|
441
441
|
</div>
|
|
442
442
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
<
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
443
|
+
<!-- OS toggle -->
|
|
444
|
+
<div class="os-toggle reveal">
|
|
445
|
+
<button class="os-btn active" data-os="mac" onclick="switchOS('mac')">
|
|
446
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>
|
|
447
|
+
macOS / Linux
|
|
448
|
+
</button>
|
|
449
|
+
<button class="os-btn" data-os="windows" onclick="switchOS('windows')">
|
|
450
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M0 3.449L9.75 2.1v9.451H0m10.949-9.602L24 0v11.4H10.949M0 12.6h9.75v9.451L0 20.699M10.949 12.6H24V24l-12.9-1.801"/></svg>
|
|
451
|
+
Windows
|
|
452
|
+
</button>
|
|
453
|
+
<button class="os-btn" data-os="docker" onclick="switchOS('docker')">
|
|
454
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.186.186 0 00-.185.186v1.887c0 .102.083.185.185.185zm-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.186.186 0 00-.185.185v1.888c0 .102.082.185.185.186zm0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.186.186 0 00-.185.185v1.887c0 .102.082.186.185.186zm-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.186.186 0 00-.185.185v1.887c0 .102.083.186.185.186zm-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.186.186 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.186.186.186zm5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.186v1.887c0 .102.082.185.185.185zm-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.186v1.887c0 .102.083.185.185.185zm-2.964 0h2.119a.186.186 0 00.185-.185V9.006a.186.186 0 00-.185-.186H5.136a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185zm-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185zM23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.687 11.687 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.33 12.33 0 003.544-1.372 10.078 10.078 0 002.506-2.053c1.076-1.223 1.718-2.58 2.198-3.794h.19c1.18 0 1.907-.482 2.31-.882.265-.26.478-.57.625-.916l.087-.252z"/></svg>
|
|
455
|
+
Docker
|
|
456
|
+
</button>
|
|
457
|
+
</div>
|
|
458
|
+
|
|
459
|
+
<!-- macOS / Linux terminal -->
|
|
460
|
+
<div class="os-content active" data-os-content="mac">
|
|
461
|
+
<div class="qs-terminal glow-border reveal">
|
|
462
|
+
<div class="qs-chrome">
|
|
463
|
+
<div class="terminal-dots">
|
|
464
|
+
<span class="td td-r"></span>
|
|
465
|
+
<span class="td td-y"></span>
|
|
466
|
+
<span class="td td-g"></span>
|
|
467
|
+
</div>
|
|
468
|
+
<div class="qs-tabs">
|
|
469
|
+
<button class="qs-tab active" data-tab="one-liner">One-liner</button>
|
|
470
|
+
<button class="qs-tab" data-tab="bun">bun</button>
|
|
471
|
+
<button class="qs-tab" data-tab="npm">npm</button>
|
|
472
|
+
</div>
|
|
473
|
+
<div class="qs-chrome-spacer"></div>
|
|
474
|
+
</div>
|
|
475
|
+
<div class="qs-body">
|
|
476
|
+
<div class="qs-pane active" id="qs-one-liner">
|
|
477
|
+
<div class="qs-line">
|
|
478
|
+
<span class="qs-comment"># Install and launch in one shot</span>
|
|
479
|
+
</div>
|
|
480
|
+
<div class="qs-line qs-cmd">
|
|
481
|
+
<span class="qs-prompt">$</span>
|
|
482
|
+
<span class="qs-text">curl -fsSL https://zubo.bot/install.sh | bash</span>
|
|
483
|
+
<button class="copy-btn" data-copy="curl -fsSL https://zubo.bot/install.sh | bash" aria-label="Copy command">
|
|
484
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
485
|
+
</button>
|
|
486
|
+
</div>
|
|
487
|
+
</div>
|
|
488
|
+
<div class="qs-pane" id="qs-bun">
|
|
489
|
+
<div class="qs-line">
|
|
490
|
+
<span class="qs-comment"># Install Zubo</span>
|
|
491
|
+
</div>
|
|
492
|
+
<div class="qs-line qs-cmd">
|
|
493
|
+
<span class="qs-prompt">$</span>
|
|
494
|
+
<span class="qs-text">bun add -g zubo</span>
|
|
495
|
+
<button class="copy-btn" data-copy="bun add -g zubo" aria-label="Copy command">
|
|
496
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
497
|
+
</button>
|
|
498
|
+
</div>
|
|
499
|
+
<div class="qs-line qs-spacer"></div>
|
|
500
|
+
<div class="qs-line">
|
|
501
|
+
<span class="qs-comment"># Meet your new agent</span>
|
|
502
|
+
</div>
|
|
503
|
+
<div class="qs-line qs-cmd">
|
|
504
|
+
<span class="qs-prompt">$</span>
|
|
505
|
+
<span class="qs-text">zubo setup</span>
|
|
506
|
+
<button class="copy-btn" data-copy="zubo setup" aria-label="Copy command">
|
|
507
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
508
|
+
</button>
|
|
509
|
+
</div>
|
|
510
|
+
</div>
|
|
511
|
+
<div class="qs-pane" id="qs-npm">
|
|
512
|
+
<div class="qs-line">
|
|
513
|
+
<span class="qs-comment"># Install Zubo</span>
|
|
514
|
+
</div>
|
|
515
|
+
<div class="qs-line qs-cmd">
|
|
516
|
+
<span class="qs-prompt">$</span>
|
|
517
|
+
<span class="qs-text">npm i -g zubo</span>
|
|
518
|
+
<button class="copy-btn" data-copy="npm i -g zubo" aria-label="Copy command">
|
|
519
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
520
|
+
</button>
|
|
521
|
+
</div>
|
|
522
|
+
<div class="qs-line qs-spacer"></div>
|
|
523
|
+
<div class="qs-line">
|
|
524
|
+
<span class="qs-comment"># Meet your new agent</span>
|
|
525
|
+
</div>
|
|
526
|
+
<div class="qs-line qs-cmd">
|
|
527
|
+
<span class="qs-prompt">$</span>
|
|
528
|
+
<span class="qs-text">zubo setup</span>
|
|
529
|
+
<button class="copy-btn" data-copy="zubo setup" aria-label="Copy command">
|
|
530
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
531
|
+
</button>
|
|
532
|
+
</div>
|
|
533
|
+
</div>
|
|
454
534
|
</div>
|
|
455
|
-
<div class="qs-chrome-spacer"></div>
|
|
456
535
|
</div>
|
|
457
|
-
<
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
<span class="
|
|
466
|
-
<
|
|
467
|
-
|
|
468
|
-
</button>
|
|
536
|
+
<p class="qs-note reveal">Works on macOS & Linux. The installer sets up Bun and everything else for you.</p>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<!-- Windows terminal -->
|
|
540
|
+
<div class="os-content" data-os-content="windows">
|
|
541
|
+
<div class="qs-terminal glow-border reveal">
|
|
542
|
+
<div class="qs-chrome">
|
|
543
|
+
<div class="terminal-dots">
|
|
544
|
+
<span class="td td-r"></span>
|
|
545
|
+
<span class="td td-y"></span>
|
|
546
|
+
<span class="td td-g"></span>
|
|
469
547
|
</div>
|
|
548
|
+
<div class="terminal-title">PowerShell</div>
|
|
549
|
+
<div class="qs-chrome-spacer"></div>
|
|
470
550
|
</div>
|
|
471
|
-
|
|
472
|
-
<div class="qs-pane" id="qs-bun">
|
|
551
|
+
<div class="qs-body">
|
|
473
552
|
<div class="qs-line">
|
|
474
|
-
<span class="qs-comment"># Install
|
|
553
|
+
<span class="qs-comment"># Install WSL (one-time, requires restart)</span>
|
|
475
554
|
</div>
|
|
476
555
|
<div class="qs-line qs-cmd">
|
|
477
|
-
<span class="qs-prompt"
|
|
478
|
-
<span class="qs-text">
|
|
479
|
-
<button class="copy-btn" data-copy="
|
|
556
|
+
<span class="qs-prompt">></span>
|
|
557
|
+
<span class="qs-text">wsl --install</span>
|
|
558
|
+
<button class="copy-btn" data-copy="wsl --install" aria-label="Copy command">
|
|
480
559
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
481
560
|
</button>
|
|
482
561
|
</div>
|
|
483
562
|
<div class="qs-line qs-spacer"></div>
|
|
484
563
|
<div class="qs-line">
|
|
485
|
-
<span class="qs-comment">#
|
|
564
|
+
<span class="qs-comment"># Then open WSL and install Zubo</span>
|
|
486
565
|
</div>
|
|
487
566
|
<div class="qs-line qs-cmd">
|
|
488
567
|
<span class="qs-prompt">$</span>
|
|
489
|
-
<span class="qs-text">zubo
|
|
490
|
-
<button class="copy-btn" data-copy="zubo
|
|
568
|
+
<span class="qs-text">curl -fsSL https://zubo.bot/install.sh | bash</span>
|
|
569
|
+
<button class="copy-btn" data-copy="curl -fsSL https://zubo.bot/install.sh | bash" aria-label="Copy command">
|
|
491
570
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
492
571
|
</button>
|
|
493
572
|
</div>
|
|
494
573
|
</div>
|
|
495
|
-
|
|
496
|
-
|
|
574
|
+
</div>
|
|
575
|
+
<p class="qs-note reveal">Runs inside WSL (Windows Subsystem for Linux). Full performance, native experience.</p>
|
|
576
|
+
</div>
|
|
577
|
+
|
|
578
|
+
<!-- Docker terminal -->
|
|
579
|
+
<div class="os-content" data-os-content="docker">
|
|
580
|
+
<div class="qs-terminal glow-border reveal">
|
|
581
|
+
<div class="qs-chrome">
|
|
582
|
+
<div class="terminal-dots">
|
|
583
|
+
<span class="td td-r"></span>
|
|
584
|
+
<span class="td td-y"></span>
|
|
585
|
+
<span class="td td-g"></span>
|
|
586
|
+
</div>
|
|
587
|
+
<div class="terminal-title">Terminal</div>
|
|
588
|
+
<div class="qs-chrome-spacer"></div>
|
|
589
|
+
</div>
|
|
590
|
+
<div class="qs-body">
|
|
497
591
|
<div class="qs-line">
|
|
498
|
-
<span class="qs-comment">#
|
|
592
|
+
<span class="qs-comment"># Clone and start with Docker</span>
|
|
499
593
|
</div>
|
|
500
594
|
<div class="qs-line qs-cmd">
|
|
501
595
|
<span class="qs-prompt">$</span>
|
|
502
|
-
<span class="qs-text">
|
|
503
|
-
<button class="copy-btn" data-copy="
|
|
596
|
+
<span class="qs-text">git clone https://github.com/apwn/zubo.git && cd zubo</span>
|
|
597
|
+
<button class="copy-btn" data-copy="git clone https://github.com/apwn/zubo.git && cd zubo" aria-label="Copy command">
|
|
504
598
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
505
599
|
</button>
|
|
506
600
|
</div>
|
|
507
601
|
<div class="qs-line qs-spacer"></div>
|
|
508
602
|
<div class="qs-line">
|
|
509
|
-
<span class="qs-comment">#
|
|
603
|
+
<span class="qs-comment"># Launch Zubo in a container</span>
|
|
510
604
|
</div>
|
|
511
605
|
<div class="qs-line qs-cmd">
|
|
512
606
|
<span class="qs-prompt">$</span>
|
|
513
|
-
<span class="qs-text">
|
|
514
|
-
<button class="copy-btn" data-copy="
|
|
607
|
+
<span class="qs-text">docker compose up -d</span>
|
|
608
|
+
<button class="copy-btn" data-copy="docker compose up -d" aria-label="Copy command">
|
|
515
609
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
516
610
|
</button>
|
|
517
611
|
</div>
|
|
518
612
|
</div>
|
|
519
613
|
</div>
|
|
614
|
+
<p class="qs-note reveal">Works on any OS with Docker. Dashboard at <strong>localhost:8787</strong>.</p>
|
|
520
615
|
</div>
|
|
521
|
-
|
|
522
|
-
<p class="qs-note reveal">Works on macOS & Linux. The installer sets up Bun and everything else for you.</p>
|
|
523
616
|
</div>
|
|
524
617
|
</section>
|
|
525
618
|
|
|
@@ -552,8 +645,8 @@
|
|
|
552
645
|
</div>
|
|
553
646
|
<div class="container">
|
|
554
647
|
<div class="cta-content reveal">
|
|
555
|
-
<h2>Ready to
|
|
556
|
-
<p>
|
|
648
|
+
<h2>Ready to meet your <span class="gradient-text">new AI agent</span>?</h2>
|
|
649
|
+
<p>One install. Free and open source. You only pay for the LLM API you choose.</p>
|
|
557
650
|
<div class="cta-actions">
|
|
558
651
|
<a href="#get-started" class="btn btn-primary btn-xl">
|
|
559
652
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
|
@@ -616,7 +709,7 @@
|
|
|
616
709
|
"@context": "https://schema.org",
|
|
617
710
|
"@type": "SoftwareApplication",
|
|
618
711
|
"name": "Zubo",
|
|
619
|
-
"description": "
|
|
712
|
+
"description": "Open-source AI agent with persistent semantic memory, multi-channel presence, 20+ smart tools, sub-agent delegation, and workflow automation. Runs locally on your machine.",
|
|
620
713
|
"url": "https://zubo.bot",
|
|
621
714
|
"applicationCategory": "DeveloperApplication",
|
|
622
715
|
"operatingSystem": "macOS, Linux, Windows",
|
package/site/script.js
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
Vanilla JS, zero dependencies
|
|
4
4
|
============================================ */
|
|
5
5
|
|
|
6
|
+
/* OS toggle — must be global for inline onclick handlers */
|
|
7
|
+
function switchOS(os) {
|
|
8
|
+
document.querySelectorAll('.os-btn').forEach(function (b) { b.classList.remove('active'); });
|
|
9
|
+
document.querySelectorAll('.os-content').forEach(function (c) { c.classList.remove('active'); });
|
|
10
|
+
var btn = document.querySelector('.os-btn[data-os="' + os + '"]');
|
|
11
|
+
if (btn) btn.classList.add('active');
|
|
12
|
+
var content = document.querySelector('[data-os-content="' + os + '"]');
|
|
13
|
+
if (content) content.classList.add('active');
|
|
14
|
+
}
|
|
15
|
+
|
|
6
16
|
(function () {
|
|
7
17
|
'use strict';
|
|
8
18
|
|
|
@@ -231,14 +241,13 @@
|
|
|
231
241
|
});
|
|
232
242
|
|
|
233
243
|
/* ------------------------------------------
|
|
234
|
-
6. Quick Start tab switching
|
|
244
|
+
6. Quick Start tab switching (within macOS/Linux)
|
|
235
245
|
------------------------------------------ */
|
|
236
246
|
document.querySelectorAll('.qs-tab').forEach(function (tab) {
|
|
237
247
|
tab.addEventListener('click', function () {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// Activate clicked tab and matching pane
|
|
248
|
+
var parent = tab.closest('.os-content') || document;
|
|
249
|
+
parent.querySelectorAll('.qs-tab').forEach(function (t) { t.classList.remove('active'); });
|
|
250
|
+
parent.querySelectorAll('.qs-pane').forEach(function (p) { p.classList.remove('active'); });
|
|
242
251
|
tab.classList.add('active');
|
|
243
252
|
var paneId = 'qs-' + tab.getAttribute('data-tab');
|
|
244
253
|
var pane = document.getElementById(paneId);
|
package/site/style.css
CHANGED
|
@@ -986,6 +986,44 @@ h1, h2, h3, h4,
|
|
|
986
986
|
color: #c4b5fd;
|
|
987
987
|
}
|
|
988
988
|
.qs-chrome-spacer { flex: 1; }
|
|
989
|
+
|
|
990
|
+
/* OS toggle */
|
|
991
|
+
.os-toggle {
|
|
992
|
+
display: flex;
|
|
993
|
+
justify-content: center;
|
|
994
|
+
gap: 6px;
|
|
995
|
+
margin-bottom: 24px;
|
|
996
|
+
}
|
|
997
|
+
.os-btn {
|
|
998
|
+
display: inline-flex;
|
|
999
|
+
align-items: center;
|
|
1000
|
+
gap: 8px;
|
|
1001
|
+
background: rgba(255,255,255,0.04);
|
|
1002
|
+
border: 1px solid var(--border);
|
|
1003
|
+
border-radius: 10px;
|
|
1004
|
+
padding: 10px 20px;
|
|
1005
|
+
font-family: var(--font);
|
|
1006
|
+
font-size: 14px;
|
|
1007
|
+
font-weight: 500;
|
|
1008
|
+
color: var(--text-muted);
|
|
1009
|
+
cursor: pointer;
|
|
1010
|
+
transition: all 0.25s var(--ease);
|
|
1011
|
+
}
|
|
1012
|
+
.os-btn:hover {
|
|
1013
|
+
color: var(--text-secondary);
|
|
1014
|
+
border-color: rgba(124, 58, 237, 0.2);
|
|
1015
|
+
background: rgba(255,255,255,0.06);
|
|
1016
|
+
}
|
|
1017
|
+
.os-btn.active {
|
|
1018
|
+
background: rgba(124, 58, 237, 0.12);
|
|
1019
|
+
border-color: rgba(124, 58, 237, 0.35);
|
|
1020
|
+
color: #c4b5fd;
|
|
1021
|
+
}
|
|
1022
|
+
.os-btn svg { opacity: 0.7; }
|
|
1023
|
+
.os-btn.active svg { opacity: 1; }
|
|
1024
|
+
.os-content { display: none; }
|
|
1025
|
+
.os-content.active { display: block; }
|
|
1026
|
+
|
|
989
1027
|
.qs-body {
|
|
990
1028
|
padding: 28px 28px 32px;
|
|
991
1029
|
font-family: var(--mono);
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
const API = "https://gmail.googleapis.com/gmail/v1/users/me";
|
|
2
2
|
|
|
3
|
+
/** RFC 2047 encode a header value if it contains non-ASCII characters (e.g. emojis) */
|
|
4
|
+
function mimeEncode(value: string): string {
|
|
5
|
+
if (/^[\x20-\x7E]*$/.test(value)) return value;
|
|
6
|
+
return `=?UTF-8?B?${Buffer.from(value, "utf-8").toString("base64")}?=`;
|
|
7
|
+
}
|
|
8
|
+
|
|
3
9
|
async function getToken(): Promise<string> {
|
|
4
10
|
const Zubo = (globalThis as any).Zubo;
|
|
5
11
|
if (Zubo?.getGoogleToken) return Zubo.getGoogleToken();
|
|
@@ -80,7 +86,7 @@ export default async function (input: Record<string, unknown>): Promise<string>
|
|
|
80
86
|
case "send": {
|
|
81
87
|
if (!to) return JSON.stringify({ error: "to is required" });
|
|
82
88
|
if (!subject) return JSON.stringify({ error: "subject is required" });
|
|
83
|
-
const raw = Buffer.from(`To: ${to}\r\nSubject: ${subject}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${body || ""}`).toString("base64url");
|
|
89
|
+
const raw = Buffer.from(`To: ${to}\r\nSubject: ${mimeEncode(subject)}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${body || ""}`).toString("base64url");
|
|
84
90
|
const res = await fetch(`${API}/messages/send`, {
|
|
85
91
|
method: "POST", headers,
|
|
86
92
|
body: JSON.stringify({ raw }),
|
|
@@ -106,7 +112,7 @@ export default async function (input: Record<string, unknown>): Promise<string>
|
|
|
106
112
|
const replyTo = getHeader("From");
|
|
107
113
|
const subj = getHeader("Subject").startsWith("Re:") ? getHeader("Subject") : `Re: ${getHeader("Subject")}`;
|
|
108
114
|
const msgId = getHeader("Message-ID");
|
|
109
|
-
const raw = Buffer.from(`To: ${replyTo}\r\nSubject: ${subj}\r\nIn-Reply-To: ${msgId}\r\nReferences: ${msgId}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${body}`).toString("base64url");
|
|
115
|
+
const raw = Buffer.from(`To: ${replyTo}\r\nSubject: ${mimeEncode(subj)}\r\nIn-Reply-To: ${msgId}\r\nReferences: ${msgId}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${body}`).toString("base64url");
|
|
110
116
|
const res = await fetch(`${API}/messages/send`, {
|
|
111
117
|
method: "POST", headers,
|
|
112
118
|
body: JSON.stringify({ raw, threadId: origData.threadId }),
|
|
@@ -37,11 +37,17 @@ function validateUrl(raw: string): void {
|
|
|
37
37
|
export default async function (input: Record<string, unknown>): Promise<string> {
|
|
38
38
|
const url = input.url as string;
|
|
39
39
|
const method = ((input.method as string) || "GET").toUpperCase();
|
|
40
|
-
const
|
|
40
|
+
const rawHeaders = (input.headers as Record<string, string>) || {};
|
|
41
41
|
const body = input.body as string | undefined;
|
|
42
42
|
|
|
43
43
|
validateUrl(url);
|
|
44
44
|
|
|
45
|
+
// Strip non-ASCII characters from header values (HTTP/1.1 requires ASCII)
|
|
46
|
+
const headers: Record<string, string> = {};
|
|
47
|
+
for (const [key, value] of Object.entries(rawHeaders)) {
|
|
48
|
+
headers[key] = String(value).replace(/[^\x20-\x7E]/g, "");
|
|
49
|
+
}
|
|
50
|
+
|
|
45
51
|
const opts: RequestInit = {
|
|
46
52
|
method,
|
|
47
53
|
headers: {
|