@owloops/browserbird 1.3.2 → 1.3.4
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/dist/index.mjs +26 -19
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -122,8 +122,8 @@ function unknownSubcommand(subcommand, command, validCommands) {
|
|
|
122
122
|
/** @fileoverview ASCII banner displayed on daemon startup and in help text. */
|
|
123
123
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
124
124
|
const buildInfo = [];
|
|
125
|
-
buildInfo.push(`commit: ${"
|
|
126
|
-
buildInfo.push(`built: 2026-03-
|
|
125
|
+
buildInfo.push(`commit: ${"f239d892bb040418ad100b83135df7e5442acfef".substring(0, 7)}`);
|
|
126
|
+
buildInfo.push(`built: 2026-03-11T02:04:59+04:00`);
|
|
127
127
|
const buildString = buildInfo.length > 0 ? ` (${buildInfo.join(", ")})` : "";
|
|
128
128
|
const VERSION = `browserbird ${pkg.version}${buildString}`;
|
|
129
129
|
const BIRD = [
|
|
@@ -2944,10 +2944,12 @@ function registerSystemCronJobs(config, retentionDays) {
|
|
|
2944
2944
|
logger.info("system birds registered");
|
|
2945
2945
|
}
|
|
2946
2946
|
/** Registers the cron_run job handler and starts the scheduler tick loop. */
|
|
2947
|
-
function startScheduler(
|
|
2948
|
-
|
|
2947
|
+
function startScheduler(getConfig, signal, deps) {
|
|
2948
|
+
const initialConfig = getConfig();
|
|
2949
|
+
registerSystemCronJobs(initialConfig, initialConfig.database.retentionDays);
|
|
2949
2950
|
registerHandler("cron_run", async (raw) => {
|
|
2950
2951
|
const payload = raw;
|
|
2952
|
+
const config = getConfig();
|
|
2951
2953
|
const agent = config.agents.find((a) => a.id === payload.agentId);
|
|
2952
2954
|
if (!agent) throw new Error(`agent "${payload.agentId}" not found`);
|
|
2953
2955
|
const needsBrowserLock = config.browser.enabled && getBrowserMode() === "persistent";
|
|
@@ -3014,6 +3016,7 @@ function startScheduler(config, signal, deps) {
|
|
|
3014
3016
|
const scheduleErrors = /* @__PURE__ */ new Map();
|
|
3015
3017
|
const tick = () => {
|
|
3016
3018
|
if (signal.aborted) return;
|
|
3019
|
+
const config = getConfig();
|
|
3017
3020
|
const now = /* @__PURE__ */ new Date();
|
|
3018
3021
|
const jobs = getEnabledCronJobs();
|
|
3019
3022
|
for (const job of jobs) {
|
|
@@ -3135,7 +3138,7 @@ function createCoalescer(config, onDispatch) {
|
|
|
3135
3138
|
//#region src/channel/handler.ts
|
|
3136
3139
|
const BROWSER_TOOL_PREFIX = "mcp__playwright__";
|
|
3137
3140
|
const LOCK_HEARTBEAT_MS = 3e4;
|
|
3138
|
-
function createHandler(client,
|
|
3141
|
+
function createHandler(client, getConfig, signal, getTeamId) {
|
|
3139
3142
|
const locks = /* @__PURE__ */ new Map();
|
|
3140
3143
|
let activeSpawns = 0;
|
|
3141
3144
|
function getLock(key) {
|
|
@@ -3243,6 +3246,7 @@ function createHandler(client, config, signal, getTeamId) {
|
|
|
3243
3246
|
} catch {}
|
|
3244
3247
|
return;
|
|
3245
3248
|
}
|
|
3249
|
+
const config = getConfig();
|
|
3246
3250
|
if (activeSpawns >= config.sessions.maxConcurrent) {
|
|
3247
3251
|
const blocks = busyBlocks(activeSpawns, config.sessions.maxConcurrent);
|
|
3248
3252
|
await client.postMessage(channelId, threadTs, "Too many active sessions. Try again shortly.", { blocks });
|
|
@@ -3599,20 +3603,21 @@ const DEDUP_CLEANUP_MS = 6e4;
|
|
|
3599
3603
|
function logDispatchError(err) {
|
|
3600
3604
|
logger.error(`dispatch error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3601
3605
|
}
|
|
3602
|
-
function createSlackChannel(
|
|
3606
|
+
function createSlackChannel(getConfig, signal) {
|
|
3603
3607
|
const recentEvents = /* @__PURE__ */ new Map();
|
|
3604
3608
|
let botUserId = "";
|
|
3605
3609
|
let teamId = "";
|
|
3610
|
+
const initConfig = getConfig();
|
|
3606
3611
|
const socketClient = new SocketModeClient({
|
|
3607
|
-
appToken:
|
|
3612
|
+
appToken: initConfig.slack.appToken,
|
|
3608
3613
|
logLevel: LogLevel.WARN,
|
|
3609
3614
|
clientPingTimeout: 15e3,
|
|
3610
3615
|
serverPingTimeout: 6e4
|
|
3611
3616
|
});
|
|
3612
|
-
const webClient = new WebClient(
|
|
3617
|
+
const webClient = new WebClient(initConfig.slack.botToken);
|
|
3613
3618
|
const channelClient = new SlackChannelClient(webClient);
|
|
3614
|
-
const handler = createHandler(channelClient,
|
|
3615
|
-
const coalescer = createCoalescer(
|
|
3619
|
+
const handler = createHandler(channelClient, getConfig, signal, () => teamId);
|
|
3620
|
+
const coalescer = createCoalescer(initConfig.slack.coalesce, (dispatch) => {
|
|
3616
3621
|
handler.handle(dispatch).catch(logDispatchError);
|
|
3617
3622
|
});
|
|
3618
3623
|
const dedupTimer = setInterval(() => {
|
|
@@ -3639,6 +3644,7 @@ function createSlackChannel(config, signal) {
|
|
|
3639
3644
|
if (subtype && IGNORED_SUBTYPES.has(subtype)) return;
|
|
3640
3645
|
if (event["bot_id"]) return;
|
|
3641
3646
|
if (isDuplicate(body)) return;
|
|
3647
|
+
const config = getConfig();
|
|
3642
3648
|
const isDm = event["channel_type"] === "im";
|
|
3643
3649
|
if (!isDm && config.slack.requireMention) return;
|
|
3644
3650
|
const channelId = event["channel"];
|
|
@@ -3660,10 +3666,11 @@ function createSlackChannel(config, signal) {
|
|
|
3660
3666
|
}).catch(logDispatchError);
|
|
3661
3667
|
else coalescer.push(channelId, threadTs, userId, cleanText, messageTs);
|
|
3662
3668
|
});
|
|
3663
|
-
if (
|
|
3669
|
+
if (initConfig.slack.requireMention) socketClient.on("app_mention", async ({ ack, body, event }) => {
|
|
3664
3670
|
await ack();
|
|
3665
3671
|
if (!event) return;
|
|
3666
3672
|
if (isDuplicate(body)) return;
|
|
3673
|
+
const config = getConfig();
|
|
3667
3674
|
const channelId = event["channel"];
|
|
3668
3675
|
if (!isChannelAllowed(channelId, config.slack.channels)) return;
|
|
3669
3676
|
if (isQuietHours(config.slack.quietHours)) return;
|
|
@@ -3711,7 +3718,7 @@ function createSlackChannel(config, signal) {
|
|
|
3711
3718
|
const commandBody = body;
|
|
3712
3719
|
if (commandBody.command !== "/bird") return;
|
|
3713
3720
|
try {
|
|
3714
|
-
await handleSlashCommand(commandBody, webClient, channelClient,
|
|
3721
|
+
await handleSlashCommand(commandBody, webClient, channelClient, getConfig(), statusProvider);
|
|
3715
3722
|
} catch (err) {
|
|
3716
3723
|
logger.error(`/bird command error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3717
3724
|
}
|
|
@@ -3735,7 +3742,7 @@ function createSlackChannel(config, signal) {
|
|
|
3735
3742
|
if (selected.startsWith("retry:")) {
|
|
3736
3743
|
const sessionUid = selected.slice(6);
|
|
3737
3744
|
if (!sessionUid) continue;
|
|
3738
|
-
await handleSessionRetry(sessionUid, channel, user ?? "unknown",
|
|
3745
|
+
await handleSessionRetry(sessionUid, channel, user ?? "unknown", getConfig(), handler);
|
|
3739
3746
|
}
|
|
3740
3747
|
}
|
|
3741
3748
|
}
|
|
@@ -3765,8 +3772,8 @@ function createSlackChannel(config, signal) {
|
|
|
3765
3772
|
function collectNames(channels) {
|
|
3766
3773
|
for (const ch of channels) if (ch !== "*" && !ch.startsWith("C") && !ch.startsWith("D") && !ch.startsWith("G")) namesToResolve.add(ch);
|
|
3767
3774
|
}
|
|
3768
|
-
collectNames(
|
|
3769
|
-
for (const agent of
|
|
3775
|
+
collectNames(initConfig.slack.channels);
|
|
3776
|
+
for (const agent of initConfig.agents) collectNames(agent.channels);
|
|
3770
3777
|
if (namesToResolve.size === 0) return;
|
|
3771
3778
|
const nameToId = /* @__PURE__ */ new Map();
|
|
3772
3779
|
try {
|
|
@@ -3796,8 +3803,8 @@ function createSlackChannel(config, signal) {
|
|
|
3796
3803
|
return ch;
|
|
3797
3804
|
});
|
|
3798
3805
|
}
|
|
3799
|
-
|
|
3800
|
-
for (const agent of
|
|
3806
|
+
initConfig.slack.channels = resolveList(initConfig.slack.channels, "slack");
|
|
3807
|
+
for (const agent of initConfig.agents) agent.channels = resolveList(agent.channels, `agent "${agent.id}"`);
|
|
3801
3808
|
}
|
|
3802
3809
|
async function start() {
|
|
3803
3810
|
const authResult = await webClient.auth.test();
|
|
@@ -3955,7 +3962,7 @@ async function startDaemon(options) {
|
|
|
3955
3962
|
currentConfig = config;
|
|
3956
3963
|
if (!schedulerStarted && config.agents.length > 0) {
|
|
3957
3964
|
logger.info("starting scheduler...");
|
|
3958
|
-
startScheduler(
|
|
3965
|
+
startScheduler(getConfig, controller.signal, { postToSlack: (channel, text, opts) => slackHandle ? slackHandle.postMessage(channel, text, opts) : Promise.resolve() });
|
|
3959
3966
|
schedulerStarted = true;
|
|
3960
3967
|
}
|
|
3961
3968
|
if (!healthStarted) {
|
|
@@ -3964,7 +3971,7 @@ async function startDaemon(options) {
|
|
|
3964
3971
|
}
|
|
3965
3972
|
if (!slackStarted && config.slack.botToken && config.slack.appToken) {
|
|
3966
3973
|
logger.info("connecting to slack...");
|
|
3967
|
-
slackHandle = createSlackChannel(
|
|
3974
|
+
slackHandle = createSlackChannel(getConfig, controller.signal);
|
|
3968
3975
|
slackHandle.start().catch((err) => {
|
|
3969
3976
|
logger.error(`slack failed to start: ${err instanceof Error ? err.message : String(err)}`);
|
|
3970
3977
|
});
|