@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.
Files changed (2) hide show
  1. package/dist/index.mjs +26 -19
  2. 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: ${"a46d410834815674642b4bb23c54a0f002c1f286".substring(0, 7)}`);
126
- buildInfo.push(`built: 2026-03-10T20:39:12+04:00`);
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(config, signal, deps) {
2948
- registerSystemCronJobs(config, config.database.retentionDays);
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, config, signal, getTeamId) {
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(config, signal) {
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: config.slack.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(config.slack.botToken);
3617
+ const webClient = new WebClient(initConfig.slack.botToken);
3613
3618
  const channelClient = new SlackChannelClient(webClient);
3614
- const handler = createHandler(channelClient, config, signal, () => teamId);
3615
- const coalescer = createCoalescer(config.slack.coalesce, (dispatch) => {
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 (config.slack.requireMention) socketClient.on("app_mention", async ({ ack, body, event }) => {
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, config, statusProvider);
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", config, handler);
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(config.slack.channels);
3769
- for (const agent of config.agents) collectNames(agent.channels);
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
- config.slack.channels = resolveList(config.slack.channels, "slack");
3800
- for (const agent of config.agents) agent.channels = resolveList(agent.channels, `agent "${agent.id}"`);
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(config, controller.signal, { postToSlack: (channel, text, opts) => slackHandle ? slackHandle.postMessage(channel, text, opts) : Promise.resolve() });
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(config, controller.signal);
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owloops/browserbird",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "AI agent orchestrator with a real browser, a cron scheduler, and a web dashboard",
5
5
  "type": "module",
6
6
  "bin": {