openbuilder 0.1.0 → 0.1.2
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 +66 -2
- package/package.json +1 -1
- package/scripts/builder-auth.ts +17 -8
- package/scripts/builder-join.ts +41 -6
package/README.md
CHANGED
|
@@ -293,14 +293,78 @@ To set up OpenBuilder as an automated meeting bot (e.g. for OpenClaw agents):
|
|
|
293
293
|
- Caption mode (`--captions`) is the most reliable on headless servers
|
|
294
294
|
- Audio mode (`--audio`) requires PulseAudio + ffmpeg + OpenAI key + Xvfb (experimental on servers)
|
|
295
295
|
|
|
296
|
+
## Platform Compatibility
|
|
297
|
+
|
|
298
|
+
OpenBuilder works anywhere OpenClaw runs, as long as Playwright Chromium is available.
|
|
299
|
+
|
|
300
|
+
| Platform | Status | Notes |
|
|
301
|
+
|----------|--------|-------|
|
|
302
|
+
| **macOS** (Mac Mini, MacBook — Intel & Apple Silicon) | ✅ Tested | Chromium installs automatically. Captions mode works great. No PulseAudio needed. |
|
|
303
|
+
| **Linux x64** (Ubuntu, Debian, VPS, EC2) | ✅ Tested | May need system deps: `npx playwright-core install-deps chromium`. Headless servers need Xvfb. |
|
|
304
|
+
| **Windows** (via WSL2) | ✅ Should work | Same as Linux x64. Not yet tested — feedback welcome. |
|
|
305
|
+
| **Docker / Podman** | ✅ Should work | Run `npx playwright-core install-deps chromium` in container. Not yet tested. |
|
|
306
|
+
| **Raspberry Pi** (ARM64, Pi 4/5) | ⚠️ Not tested | Playwright Chromium ARM builds can be unreliable. May need manual Chromium install. |
|
|
307
|
+
| **Raspberry Pi 3** (ARMv7) | ❌ Not supported | Playwright does not ship ARMv7 Chromium. |
|
|
308
|
+
|
|
309
|
+
### macOS (Mac Mini, MacBook)
|
|
310
|
+
|
|
311
|
+
- `npx openbuilder` installs Chromium automatically
|
|
312
|
+
- Audio capture mode is not available (no PulseAudio) — captions mode is the default and works great
|
|
313
|
+
- Auth: `npx openbuilder auth` opens a browser window — sign in and press Enter
|
|
314
|
+
- For headless/unattended operation: use `--auto` auth with `.env` credentials
|
|
315
|
+
|
|
316
|
+
### Linux (Ubuntu, Debian, VPS, EC2)
|
|
317
|
+
|
|
318
|
+
- Install system dependencies: `npx playwright-core install-deps chromium`
|
|
319
|
+
- For headless servers (no display): start Xvfb first — `Xvfb :99 -screen 0 1280x720x24 &` and `export DISPLAY=:99`
|
|
320
|
+
- Audio capture mode available if PulseAudio + ffmpeg are installed (optional — captions mode works without them)
|
|
321
|
+
|
|
322
|
+
### VPS Providers
|
|
323
|
+
|
|
324
|
+
Works on any VPS that runs OpenClaw:
|
|
325
|
+
|
|
326
|
+
- **AWS** (EC2, Lightsail) — tested ✅
|
|
327
|
+
- **Oracle Cloud** (Always Free tier) — should work
|
|
328
|
+
- **Hetzner**, **Fly.io**, **GCP**, **Railway**, **Render** — should work (Linux x64)
|
|
329
|
+
- **DigitalOcean** — should work
|
|
330
|
+
|
|
331
|
+
Minimum: 1 vCPU, 1GB RAM (Chromium is the main resource consumer).
|
|
332
|
+
|
|
333
|
+
### Requirements
|
|
334
|
+
|
|
335
|
+
1. **Node.js 18+**
|
|
336
|
+
2. **OpenClaw** running on the machine
|
|
337
|
+
3. **A Google account** for the bot (or join as guest with `--anon`)
|
|
338
|
+
4. **An AI API key** — Claude (Anthropic) or OpenAI — for meeting reports (optional but recommended)
|
|
339
|
+
|
|
340
|
+
### Quick Setup (any platform)
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
npx openbuilder # Install skill + Chromium
|
|
344
|
+
npx openbuilder auth # Sign into Google (one-time)
|
|
345
|
+
npx openbuilder config set anthropicApiKey sk-ant-... # For AI reports
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Then tell your OpenClaw agent: "Join this meeting: https://meet.google.com/..."
|
|
349
|
+
|
|
350
|
+
### Known Limitations
|
|
351
|
+
|
|
352
|
+
- **Google Meet only** — Zoom and Teams support planned for a future release
|
|
353
|
+
- **Captions depend on Google Meet's CC feature** — if Meet changes their DOM structure, caption scraping may break
|
|
354
|
+
- **Audio capture mode is experimental** on headless servers — PulseAudio routing can be unreliable. Use `--captions` for reliability
|
|
355
|
+
- **Bot appears as a participant** — other meeting participants will see "Super Liang" (or your bot's Google account name) in the People panel
|
|
356
|
+
- **Google may block automated logins** — if Google flags the bot account, re-run `npx openbuilder auth` interactively or from a different IP
|
|
357
|
+
- **One meeting at a time** per bot instance
|
|
358
|
+
|
|
296
359
|
## OpenClaw Integration
|
|
297
360
|
|
|
298
361
|
OpenBuilder ships as an OpenClaw skill. After running `npx openbuilder`, it's available to your OpenClaw agent. The agent can:
|
|
299
362
|
|
|
300
363
|
- Join meetings on your behalf
|
|
301
364
|
- Capture and summarize transcripts
|
|
302
|
-
- Generate full meeting reports
|
|
303
|
-
- Send screenshots to your chat
|
|
365
|
+
- Generate full meeting reports with action items and decisions
|
|
366
|
+
- Send screenshots to your chat on demand
|
|
367
|
+
- Tell you what's being discussed in real time
|
|
304
368
|
|
|
305
369
|
See [SKILL.md](./SKILL.md) for the full agent integration guide.
|
|
306
370
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbuilder",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Open-source AI meeting assistant — join Google Meet, capture transcripts, generate AI-powered meeting reports with summaries, action items, and speaker analytics",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/scripts/builder-auth.ts
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
* Saves session to ~/.openbuilder/auth.json via Playwright's storageState.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { execSync } from "node:child_process";
|
|
12
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { homedir } from "node:os";
|
|
13
15
|
import { createInterface } from "node:readline";
|
|
14
16
|
import { config as dotenvConfig } from "dotenv";
|
|
15
17
|
import { join, dirname } from "node:path";
|
|
@@ -163,15 +165,22 @@ async function main() {
|
|
|
163
165
|
"--window-size=1280,720",
|
|
164
166
|
];
|
|
165
167
|
|
|
166
|
-
// Find full Chrome for headed mode
|
|
168
|
+
// Find full Chrome for headed mode (cross-platform)
|
|
167
169
|
let executablePath: string | undefined;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
try {
|
|
171
|
+
const playwrightCache = join(homedir(), ".cache", "ms-playwright");
|
|
172
|
+
if (existsSync(playwrightCache)) {
|
|
173
|
+
const result = execSync(
|
|
174
|
+
process.platform === "darwin"
|
|
175
|
+
? `find "${playwrightCache}" -path "*/Chromium.app/Contents/MacOS/Chromium" -type f 2>/dev/null | head -1`
|
|
176
|
+
: `find "${playwrightCache}" -path "*/chrome-linux*/chrome" -type f 2>/dev/null | head -1`,
|
|
177
|
+
{ encoding: "utf-8" },
|
|
178
|
+
).trim();
|
|
179
|
+
if (result && existsSync(result)) {
|
|
180
|
+
executablePath = result;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} catch { /* fallback to default */ }
|
|
175
184
|
|
|
176
185
|
const browser = await pw.chromium.launch({
|
|
177
186
|
headless,
|
package/scripts/builder-join.ts
CHANGED
|
@@ -529,6 +529,32 @@ async function waitForMeetingEnd(
|
|
|
529
529
|
return "Navigated away from meeting";
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
// Detect if redirected to Meet homepage (meeting ended and Google kicked us out)
|
|
533
|
+
const currentUrl = page.url();
|
|
534
|
+
if (
|
|
535
|
+
currentUrl === "https://meet.google.com/" ||
|
|
536
|
+
currentUrl === "https://meet.google.com" ||
|
|
537
|
+
currentUrl.match(/^https:\/\/meet\.google\.com\/?\?/) ||
|
|
538
|
+
currentUrl === "https://meet.google.com/landing"
|
|
539
|
+
) {
|
|
540
|
+
return "Meeting ended (redirected to homepage)";
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Check if the Leave call button is gone (meeting UI disappeared)
|
|
544
|
+
try {
|
|
545
|
+
const leaveBtn = page.locator('[aria-label*="Leave call" i]').first();
|
|
546
|
+
const hasMeetingUI = await leaveBtn.isVisible({ timeout: 500 });
|
|
547
|
+
if (!hasMeetingUI) {
|
|
548
|
+
// Double-check: no meeting controls means we're not in a meeting
|
|
549
|
+
const hasAnyControls = await page.locator('[aria-label*="microphone" i], [aria-label*="camera" i]').first().isVisible({ timeout: 500 }).catch(() => false);
|
|
550
|
+
if (!hasAnyControls) {
|
|
551
|
+
return "Meeting ended (meeting UI gone)";
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
} catch {
|
|
555
|
+
// Couldn't check — continue
|
|
556
|
+
}
|
|
557
|
+
|
|
532
558
|
// Check if all other participants have left
|
|
533
559
|
const participantCount = await getParticipantCount(page);
|
|
534
560
|
|
|
@@ -1333,11 +1359,16 @@ export async function joinMeeting(opts: {
|
|
|
1333
1359
|
let fullChromePath: string | undefined;
|
|
1334
1360
|
if (useFullChrome) {
|
|
1335
1361
|
try {
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1362
|
+
const playwrightCache = join(homedir(), ".cache", "ms-playwright");
|
|
1363
|
+
if (existsSync(playwrightCache)) {
|
|
1364
|
+
const result = execSync(
|
|
1365
|
+
process.platform === "darwin"
|
|
1366
|
+
? `find "${playwrightCache}" -path "*/Chromium.app/Contents/MacOS/Chromium" -type f 2>/dev/null | head -1`
|
|
1367
|
+
: `find "${playwrightCache}" -path "*/chrome-linux*/chrome" -type f 2>/dev/null | head -1`,
|
|
1368
|
+
{ encoding: "utf-8" },
|
|
1369
|
+
).trim();
|
|
1370
|
+
fullChromePath = result || undefined;
|
|
1371
|
+
}
|
|
1341
1372
|
} catch { /* fallback to default */ }
|
|
1342
1373
|
}
|
|
1343
1374
|
if (useFullChrome && fullChromePath) {
|
|
@@ -1368,8 +1399,12 @@ export async function joinMeeting(opts: {
|
|
|
1368
1399
|
const fullChromePath = useFullChrome
|
|
1369
1400
|
? (() => {
|
|
1370
1401
|
try {
|
|
1402
|
+
const playwrightCache = join(homedir(), ".cache", "ms-playwright");
|
|
1403
|
+
if (!existsSync(playwrightCache)) return undefined;
|
|
1371
1404
|
const result = execSync(
|
|
1372
|
-
|
|
1405
|
+
process.platform === "darwin"
|
|
1406
|
+
? `find "${playwrightCache}" -path "*/Chromium.app/Contents/MacOS/Chromium" -type f 2>/dev/null | head -1`
|
|
1407
|
+
: `find "${playwrightCache}" -path "*/chrome-linux*/chrome" -type f 2>/dev/null | head -1`,
|
|
1373
1408
|
{ encoding: "utf-8" },
|
|
1374
1409
|
).trim();
|
|
1375
1410
|
return result || undefined;
|