samoagent 0.4.0 → 0.4.1
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 +6 -3
- package/dist/cli.js +126 -6
- package/docs/release-checklist.md +56 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -14,13 +14,15 @@ Requirements:
|
|
|
14
14
|
- `RECALL_API_KEY`.
|
|
15
15
|
- `ngrok` installed and authenticated (free plan). `join` starts and manages ngrok automatically — you don't run it yourself.
|
|
16
16
|
|
|
17
|
+
Install the CLI from npm:
|
|
18
|
+
|
|
17
19
|
```bash
|
|
18
|
-
|
|
20
|
+
npm install -g samoagent
|
|
19
21
|
export RECALL_API_KEY=...
|
|
20
|
-
|
|
22
|
+
samoagent join "https://meet.google.com/..." --name Leo
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
During development use `bun
|
|
25
|
+
During development use `bun install`, `bun run build`, then `bun run samoagent ...`.
|
|
24
26
|
|
|
25
27
|
## What It Provides
|
|
26
28
|
|
|
@@ -35,6 +37,7 @@ samoagent gives an AI agent a small set of meeting tools:
|
|
|
35
37
|
- `transcript` - print the transcript (local file, or post-call from Recall).
|
|
36
38
|
- `screenshot` - capture the local Mac screen (fallback when no call frame is available).
|
|
37
39
|
- `dicts` - list available Deepgram keyword dictionaries.
|
|
40
|
+
- `doctor` - check local prerequisites before joining a call.
|
|
38
41
|
|
|
39
42
|
The agent still decides what to say, when to inspect a frame, and how to use the meeting context. samoagent is the local adapter that exposes those call capabilities.
|
|
40
43
|
|
package/dist/cli.js
CHANGED
|
@@ -36,7 +36,7 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
|
|
|
36
36
|
var require_package = __commonJS((exports, module) => {
|
|
37
37
|
module.exports = {
|
|
38
38
|
name: "samoagent",
|
|
39
|
-
version: "0.4.
|
|
39
|
+
version: "0.4.1",
|
|
40
40
|
description: "Let AI agents join Zoom and Google Meet calls as active participants.",
|
|
41
41
|
type: "module",
|
|
42
42
|
license: "Apache-2.0",
|
|
@@ -48,6 +48,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
48
48
|
"dictionaries/",
|
|
49
49
|
"LICENSE",
|
|
50
50
|
"README.md",
|
|
51
|
+
"docs/",
|
|
51
52
|
"avatar.html",
|
|
52
53
|
"avatar.png",
|
|
53
54
|
"logo.svg"
|
|
@@ -93,7 +94,7 @@ import { homedir } from "os";
|
|
|
93
94
|
import { join, dirname } from "path";
|
|
94
95
|
import { fileURLToPath } from "url";
|
|
95
96
|
var RECALL_BASE = "https://us-east-1.recall.ai/api/v1";
|
|
96
|
-
var AVATAR_URL = "https://
|
|
97
|
+
var AVATAR_URL = "https://samoagent.dev/avatar.html";
|
|
97
98
|
|
|
98
99
|
class ExitError extends Error {
|
|
99
100
|
code;
|
|
@@ -1437,13 +1438,81 @@ async function cmdServe(args) {
|
|
|
1437
1438
|
await new Promise(() => {});
|
|
1438
1439
|
}
|
|
1439
1440
|
|
|
1441
|
+
// src/commands/doctor.ts
|
|
1442
|
+
import { existsSync as existsSync10 } from "fs";
|
|
1443
|
+
function commandVersion(command, args = ["--version"]) {
|
|
1444
|
+
try {
|
|
1445
|
+
const proc = Bun.spawnSync([command, ...args]);
|
|
1446
|
+
if (proc.exitCode !== 0) {
|
|
1447
|
+
const stderr = new TextDecoder().decode(proc.stderr).trim();
|
|
1448
|
+
return {
|
|
1449
|
+
ok: false,
|
|
1450
|
+
detail: stderr || `${command} --version exited ${proc.exitCode}`
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
const stdout = new TextDecoder().decode(proc.stdout).trim();
|
|
1454
|
+
return {
|
|
1455
|
+
ok: true,
|
|
1456
|
+
detail: stdout.split(/\r?\n/)[0] ?? ""
|
|
1457
|
+
};
|
|
1458
|
+
} catch (e) {
|
|
1459
|
+
return {
|
|
1460
|
+
ok: false,
|
|
1461
|
+
detail: e instanceof Error ? e.message : String(e)
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
async function cmdDoctor() {
|
|
1466
|
+
const bunVersion = commandVersion("bun");
|
|
1467
|
+
const ngrokVersion = commandVersion("ngrok");
|
|
1468
|
+
const ffmpegVersion = commandVersion("ffmpeg", ["-version"]);
|
|
1469
|
+
const checks = [
|
|
1470
|
+
{
|
|
1471
|
+
name: "Bun",
|
|
1472
|
+
ok: bunVersion.ok,
|
|
1473
|
+
detail: bunVersion.detail || "not found in PATH"
|
|
1474
|
+
},
|
|
1475
|
+
{
|
|
1476
|
+
name: "RECALL_API_KEY",
|
|
1477
|
+
ok: Boolean(process.env.RECALL_API_KEY),
|
|
1478
|
+
detail: process.env.RECALL_API_KEY ? "set" : "missing"
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
name: "ngrok",
|
|
1482
|
+
ok: ngrokVersion.ok,
|
|
1483
|
+
detail: ngrokVersion.detail || "not found in PATH"
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
name: "ffmpeg",
|
|
1487
|
+
ok: ffmpegVersion.ok,
|
|
1488
|
+
detail: ffmpegVersion.detail || "not found in PATH"
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
name: "state",
|
|
1492
|
+
ok: true,
|
|
1493
|
+
detail: existsSync10(stateFile()) ? `active state at ${stateFile()}` : "no active bot state"
|
|
1494
|
+
}
|
|
1495
|
+
];
|
|
1496
|
+
process.stdout.write(`samoagent doctor
|
|
1497
|
+
|
|
1498
|
+
`);
|
|
1499
|
+
for (const check of checks) {
|
|
1500
|
+
process.stdout.write(`${check.ok ? "OK" : "FAIL"} ${check.name}: ${check.detail}
|
|
1501
|
+
`);
|
|
1502
|
+
}
|
|
1503
|
+
if (checks.some((check) => !check.ok)) {
|
|
1504
|
+
process.exit(1);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1440
1508
|
// src/cli.ts
|
|
1441
1509
|
var USAGE = `usage: samoagent <command> [options]
|
|
1442
1510
|
|
|
1443
|
-
|
|
1444
|
-
|
|
1511
|
+
Put your AI agent in Zoom and Google Meet calls.
|
|
1512
|
+
samoagent joins through Recall.ai, streams live transcript lines,
|
|
1513
|
+
captures call frames on demand, and sends explicit chat messages.
|
|
1445
1514
|
|
|
1446
|
-
Requires: RECALL_API_KEY env var (get one at recall.ai) and ngrok.
|
|
1515
|
+
Requires: Bun, RECALL_API_KEY env var (get one at recall.ai), and ngrok.
|
|
1447
1516
|
|
|
1448
1517
|
commands:
|
|
1449
1518
|
join <url> [--name N] [--dict D] [--port P] [--transcript-dir DIR] [--rtmp-url URL] [--rtmp] [--no-ws-video] [--frame-dir DIR]
|
|
@@ -1455,11 +1524,52 @@ commands:
|
|
|
1455
1524
|
dicts
|
|
1456
1525
|
watch
|
|
1457
1526
|
frame [--out FILE] [--archive] [bot_id]
|
|
1527
|
+
doctor
|
|
1458
1528
|
|
|
1459
1529
|
flags:
|
|
1460
1530
|
-h, --help Show this help message
|
|
1461
1531
|
-v, --version Show version number
|
|
1462
1532
|
`;
|
|
1533
|
+
var COMMAND_HELP = {
|
|
1534
|
+
join: `usage: samoagent join <url> [options]
|
|
1535
|
+
|
|
1536
|
+
Join a Zoom or Google Meet call as a Recall.ai bot.
|
|
1537
|
+
By default, samoagent streams transcript events and receives call frames over WebSocket.
|
|
1538
|
+
|
|
1539
|
+
options:
|
|
1540
|
+
--name N Bot display name
|
|
1541
|
+
--dict D Deepgram keyword dictionary name
|
|
1542
|
+
--port P Local callback server port (default: 8080)
|
|
1543
|
+
--transcript-dir DIR Directory for transcript.txt
|
|
1544
|
+
--frame-dir DIR Directory for on-demand frame output
|
|
1545
|
+
--no-ws-video Disable WebSocket call-frame capture
|
|
1546
|
+
--rtmp Use local RTMP path through ngrok TCP
|
|
1547
|
+
--rtmp-url URL Use an existing RTMP endpoint
|
|
1548
|
+
|
|
1549
|
+
examples:
|
|
1550
|
+
samoagent join "https://meet.google.com/abc-defg-hij" --name Leo
|
|
1551
|
+
samoagent join "https://zoom.us/j/123" --dict postgresfm
|
|
1552
|
+
`,
|
|
1553
|
+
frame: `usage: samoagent frame [--out FILE] [--archive] [bot_id]
|
|
1554
|
+
|
|
1555
|
+
Write the latest call frame to disk.
|
|
1556
|
+
With the default WebSocket path, frames stay in memory until this command is run.
|
|
1557
|
+
|
|
1558
|
+
options:
|
|
1559
|
+
--out FILE Output path. Defaults to latest frame path from active state.
|
|
1560
|
+
--archive Also write a timestamped PNG+JSON archive copy.
|
|
1561
|
+
|
|
1562
|
+
examples:
|
|
1563
|
+
samoagent frame
|
|
1564
|
+
samoagent frame --out /tmp/current-call.png
|
|
1565
|
+
samoagent frame --archive
|
|
1566
|
+
`,
|
|
1567
|
+
doctor: `usage: samoagent doctor
|
|
1568
|
+
|
|
1569
|
+
Check local prerequisites for joining meetings:
|
|
1570
|
+
Bun, RECALL_API_KEY, ngrok, ffmpeg, and active samoagent state.
|
|
1571
|
+
`
|
|
1572
|
+
};
|
|
1463
1573
|
|
|
1464
1574
|
class ArgError extends Error {
|
|
1465
1575
|
}
|
|
@@ -1481,6 +1591,7 @@ function parseArgs(argv) {
|
|
|
1481
1591
|
dicts: new Set,
|
|
1482
1592
|
watch: new Set,
|
|
1483
1593
|
frame: new Set(["--out"]),
|
|
1594
|
+
doctor: new Set,
|
|
1484
1595
|
_serve: new Set(["--port", "--transcript-file", "--webhook-token", "--call-id-file", "--frame-token"])
|
|
1485
1596
|
};
|
|
1486
1597
|
const boolFlags = {
|
|
@@ -1493,6 +1604,7 @@ function parseArgs(argv) {
|
|
|
1493
1604
|
dicts: new Set,
|
|
1494
1605
|
watch: new Set,
|
|
1495
1606
|
frame: new Set(["--archive"]),
|
|
1607
|
+
doctor: new Set,
|
|
1496
1608
|
_serve: new Set
|
|
1497
1609
|
};
|
|
1498
1610
|
const knownCommands = Object.keys(valueFlags);
|
|
@@ -1586,6 +1698,7 @@ function parseArgs(argv) {
|
|
|
1586
1698
|
}
|
|
1587
1699
|
case "dicts":
|
|
1588
1700
|
case "watch":
|
|
1701
|
+
case "doctor":
|
|
1589
1702
|
break;
|
|
1590
1703
|
case "_serve": {
|
|
1591
1704
|
const rawPort2 = opts["--port"];
|
|
@@ -1630,6 +1743,8 @@ async function dispatch(args) {
|
|
|
1630
1743
|
return cmdDicts();
|
|
1631
1744
|
case "watch":
|
|
1632
1745
|
return cmdWatch();
|
|
1746
|
+
case "doctor":
|
|
1747
|
+
return cmdDoctor();
|
|
1633
1748
|
case "_serve":
|
|
1634
1749
|
return cmdServe(args);
|
|
1635
1750
|
default:
|
|
@@ -1638,10 +1753,15 @@ async function dispatch(args) {
|
|
|
1638
1753
|
}
|
|
1639
1754
|
async function main() {
|
|
1640
1755
|
const argv = process.argv.slice(2);
|
|
1641
|
-
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h"
|
|
1756
|
+
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
1642
1757
|
process.stdout.write(USAGE);
|
|
1643
1758
|
process.exit(argv.length === 0 ? 2 : 0);
|
|
1644
1759
|
}
|
|
1760
|
+
if (argv.length >= 2 && (argv[1] === "--help" || argv[1] === "-h")) {
|
|
1761
|
+
const help = COMMAND_HELP[argv[0]];
|
|
1762
|
+
process.stdout.write(help ?? USAGE);
|
|
1763
|
+
process.exit(help ? 0 : 2);
|
|
1764
|
+
}
|
|
1645
1765
|
if (argv[0] === "--version" || argv[0] === "-v" || argv[0] === "-V") {
|
|
1646
1766
|
const pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
|
|
1647
1767
|
process.stdout.write(`samoagent ${pkg.version}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Release Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist for each npm release.
|
|
4
|
+
|
|
5
|
+
## Before Release
|
|
6
|
+
|
|
7
|
+
- Confirm `main` is clean and up to date.
|
|
8
|
+
- Run `bun test`.
|
|
9
|
+
- Run `bun run build`.
|
|
10
|
+
- Smoke-test the built CLI:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
./dist/cli.js --version
|
|
14
|
+
./dist/cli.js --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Check package metadata:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm pack --dry-run
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- Confirm `package.json` has the intended version, description, homepage, license, files, and keywords.
|
|
24
|
+
- Confirm `README.md` installation and usage examples match the current CLI.
|
|
25
|
+
|
|
26
|
+
## Publish
|
|
27
|
+
|
|
28
|
+
- Bump `package.json` version.
|
|
29
|
+
- Commit and push the version bump.
|
|
30
|
+
- Create and publish a GitHub release tag matching the package version, for example `v0.4.1`.
|
|
31
|
+
- Wait for the `Publish to npm` GitHub Actions workflow to pass.
|
|
32
|
+
|
|
33
|
+
## After Publish
|
|
34
|
+
|
|
35
|
+
- Verify npm has the new version:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm view samoagent version
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- Smoke-test the registry package from a clean prefix:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
tmp="$(mktemp -d)"
|
|
45
|
+
npm_config_prefix="$tmp" npm install -g samoagent
|
|
46
|
+
PATH="$tmp/bin:$PATH" samoagent --version
|
|
47
|
+
rm -rf "$tmp"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Confirm the package page shows Apache-2.0 license, homepage, README, and provenance.
|
|
51
|
+
- Confirm GitHub Pages is healthy at `https://samoagent.dev/`.
|
|
52
|
+
|
|
53
|
+
## Secret Hygiene
|
|
54
|
+
|
|
55
|
+
- Keep `NPM_TOKEN` only in GitHub Actions secrets.
|
|
56
|
+
- Rotate `NPM_TOKEN` immediately if it is pasted into chat, logs, issues, PRs, or local shell history.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "samoagent",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Let AI agents join Zoom and Google Meet calls as active participants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"dictionaries/",
|
|
13
13
|
"LICENSE",
|
|
14
14
|
"README.md",
|
|
15
|
+
"docs/",
|
|
15
16
|
"avatar.html",
|
|
16
17
|
"avatar.png",
|
|
17
18
|
"logo.svg"
|