lark-agent-bot 0.3.11 → 0.3.13

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 (3) hide show
  1. package/README.md +6 -0
  2. package/install.js +112 -10
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,6 +12,12 @@ npm install -g lark-agent-bot
12
12
  The postinstall step downloads the prebuilt binary for your platform from
13
13
  [GitHub Releases](https://github.com/ClaymanTwinkle/lark-agent-bot/releases).
14
14
 
15
+ If `ffmpeg` is not on your `PATH`, it also downloads a static ffmpeg build
16
+ ([ffmpeg-static](https://github.com/eugeneware/ffmpeg-static), checksum-verified)
17
+ to `~/.lark-agent-bot/bin`, outside the package so upgrades keep it; voice
18
+ messages and video covers need it. Set `LARK_AGENT_BOT_SKIP_FFMPEG=1` to skip
19
+ this step.
20
+
15
21
  ## Usage
16
22
 
17
23
  ```bash
package/install.js CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { execSync } = require("child_process");
5
+ const { execFileSync, execSync } = require("child_process");
6
+ const crypto = require("crypto");
6
7
  const fs = require("fs");
8
+ const os = require("os");
7
9
  const path = require("path");
8
10
  const https = require("https");
9
11
  const http = require("http");
@@ -15,6 +17,22 @@ const NAME = "lark-agent-bot";
15
17
 
16
18
  const GITHUB_REPO = "ClaymanTwinkle/lark-agent-bot";
17
19
 
20
+ // Voice messages and video covers need ffmpeg. When it isn't on PATH, a
21
+ // static build from ffmpeg-static goes to ~/.lark-agent-bot/bin, where
22
+ // lark-agent-bot also looks. That directory is outside the npm package, so
23
+ // upgrades (which replace the package directory) keep it. Set
24
+ // LARK_AGENT_BOT_SKIP_FFMPEG=1 to skip.
25
+ const FFMPEG_REPO = "eugeneware/ffmpeg-static";
26
+ const FFMPEG_RELEASE = "b6.1.1";
27
+ // SHA-256 of each ffmpeg-<platform>-<arch>.gz asset in FFMPEG_RELEASE.
28
+ const FFMPEG_SHA256 = {
29
+ "darwin-arm64": "8923876afa8db5585022d7860ec7e589af192f441c56793971276d450ed3bbfa",
30
+ "darwin-x64": "929b375c1182d956c51f7ac25e0b2b0411fb01f6f407aa15c9758efeb4242106",
31
+ "linux-arm64": "754a678672298bc68156adff58aa7385a592c2b30b1d0ae8750c45c915c4bac0",
32
+ "linux-x64": "bfe8a8fc511530457b528c48d77b5737527b504a3797a9bc4866aeca69c2dffa",
33
+ "win32-x64": "8883a3dffbd0a16cf4ef95206ea05283f78908dbfb118f73c83f4951dcc06d77",
34
+ };
35
+
18
36
  const PLATFORM_MAP = {
19
37
  darwin: "darwin",
20
38
  linux: "linux",
@@ -149,11 +167,91 @@ function isNewerOrEqual(installed, expected) {
149
167
  return a.preNum >= b.preNum;
150
168
  }
151
169
 
170
+ function hasFFmpegOnPath() {
171
+ try {
172
+ execFileSync("ffmpeg", ["-version"], { stdio: "ignore", timeout: 10000 });
173
+ return true;
174
+ } catch {
175
+ return false;
176
+ }
177
+ }
178
+
179
+ function ffmpegToolDir() {
180
+ return path.join(os.homedir(), ".lark-agent-bot", "bin");
181
+ }
182
+
183
+ function ffmpegHint(toolDir) {
184
+ return (
185
+ "[lark-agent-bot] Voice messages and video covers need ffmpeg. Install it yourself:\n" +
186
+ " Windows: winget install Gyan.FFmpeg\n" +
187
+ " macOS: brew install ffmpeg\n" +
188
+ " Linux: sudo apt install ffmpeg (or your distro's package manager)\n" +
189
+ ` or put an ffmpeg executable in ${toolDir}`
190
+ );
191
+ }
192
+
193
+ // installFFmpeg never fails the install: without ffmpeg lark-agent-bot still
194
+ // works, it only loses voice conversion and video covers.
195
+ async function installFFmpeg(toolDir) {
196
+ if (process.env.LARK_AGENT_BOT_SKIP_FFMPEG) {
197
+ console.log("[lark-agent-bot] LARK_AGENT_BOT_SKIP_FFMPEG is set, skipping ffmpeg.");
198
+ return;
199
+ }
200
+ const ffmpegPath = path.join(toolDir, process.platform === "win32" ? "ffmpeg.exe" : "ffmpeg");
201
+ if (fs.existsSync(ffmpegPath)) {
202
+ console.log(`[lark-agent-bot] ffmpeg already at ${ffmpegPath}, skipping.`);
203
+ return;
204
+ }
205
+ if (hasFFmpegOnPath()) {
206
+ console.log("[lark-agent-bot] ffmpeg found on PATH, skipping.");
207
+ return;
208
+ }
209
+
210
+ const key = `${process.platform}-${process.arch}`;
211
+ const sha256 = FFMPEG_SHA256[key];
212
+ if (!sha256) {
213
+ console.warn(`[lark-agent-bot] No prebuilt ffmpeg for ${key}.`);
214
+ console.warn(ffmpegHint(toolDir));
215
+ return;
216
+ }
217
+
218
+ const url = `https://github.com/${FFMPEG_REPO}/releases/download/${FFMPEG_RELEASE}/ffmpeg-${key}.gz`;
219
+ const tmpPath = `${ffmpegPath}.download`;
220
+ try {
221
+ console.log(`[lark-agent-bot] ffmpeg not found, downloading from ${url}`);
222
+ const gz = await fetch(url);
223
+ fs.mkdirSync(toolDir, { recursive: true });
224
+ const actual = crypto.createHash("sha256").update(gz).digest("hex");
225
+ if (actual !== sha256) {
226
+ throw new Error(`checksum mismatch: got ${actual}, want ${sha256}`);
227
+ }
228
+ fs.writeFileSync(tmpPath, zlib.gunzipSync(gz), { mode: 0o755 });
229
+ fs.renameSync(tmpPath, ffmpegPath);
230
+ if (process.platform === "darwin") {
231
+ try {
232
+ execSync(`xattr -d com.apple.quarantine "${ffmpegPath}"`, { stdio: "pipe" });
233
+ } catch {
234
+ // xattr fails if the attribute doesn't exist, which is fine
235
+ }
236
+ }
237
+ console.log(`[lark-agent-bot] Installed ffmpeg to ${ffmpegPath}`);
238
+ } catch (err) {
239
+ try { fs.unlinkSync(tmpPath); } catch {}
240
+ console.warn(`[lark-agent-bot] Could not install ffmpeg: ${err.message}`);
241
+ console.warn(ffmpegHint(toolDir));
242
+ }
243
+ }
244
+
152
245
  async function main() {
246
+ const binDir = path.join(__dirname, "bin");
247
+ await installBinary(binDir);
248
+ await installFFmpeg(ffmpegToolDir());
249
+ }
250
+
251
+ async function installBinary(binDir) {
153
252
  const { platform, arch, ext, filename } = getPlatformInfo();
154
253
  console.log(`[lark-agent-bot] Platform: ${platform}/${arch}`);
155
254
 
156
- const binDir = path.join(__dirname, "bin");
157
255
  fs.mkdirSync(binDir, { recursive: true });
158
256
 
159
257
  const binaryName = platform === "windows" ? `${NAME}.exe` : NAME;
@@ -206,11 +304,15 @@ async function main() {
206
304
  console.log(`[lark-agent-bot] Installed to ${binaryPath}`);
207
305
  }
208
306
 
209
- main().catch((err) => {
210
- console.error(err.message);
211
- console.error(
212
- "[lark-agent-bot] Installation failed. You can install manually:\n" +
213
- ` https://github.com/${GITHUB_REPO}/releases/tag/${VERSION}`
214
- );
215
- process.exit(1);
216
- });
307
+ if (require.main === module) {
308
+ main().catch((err) => {
309
+ console.error(err.message);
310
+ console.error(
311
+ "[lark-agent-bot] Installation failed. You can install manually:\n" +
312
+ ` https://github.com/${GITHUB_REPO}/releases/tag/${VERSION}`
313
+ );
314
+ process.exit(1);
315
+ });
316
+ }
317
+
318
+ module.exports = { installFFmpeg };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lark-agent-bot",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "description": "Bridge local AI coding agents (Claude Code, Codex, Cursor, Gemini CLI, ...) to Feishu / Lark",
5
5
  "keywords": [
6
6
  "feishu",