@owloops/browserbird 1.6.1 → 1.7.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.
Files changed (2) hide show
  1. package/dist/index.mjs +48 -9
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -192,8 +192,8 @@ function unknownSubcommand(subcommand, command, validCommands) {
192
192
  /** @fileoverview ASCII banner displayed on daemon startup and in help text. */
193
193
  const pkg = createRequire(import.meta.url)("../package.json");
194
194
  const buildInfo = [];
195
- buildInfo.push(`commit: ${"ef1bf69c128bbeb16790f862e5173f259610511e".substring(0, 7)}`);
196
- buildInfo.push(`built: 2026-03-19T14:43:58+04:00`);
195
+ buildInfo.push(`commit: ${"15ead4a5a3d42d49a5b1c8a7bb3b4bc34d32c539".substring(0, 7)}`);
196
+ buildInfo.push(`built: 2026-03-20T00:08:17+04:00`);
197
197
  const buildString = buildInfo.length > 0 ? ` (${buildInfo.join(", ")})` : "";
198
198
  const VERSION = `browserbird ${pkg.version}${buildString}`;
199
199
  const BIRD = [
@@ -3107,13 +3107,34 @@ function buildCommand(options) {
3107
3107
  const oauthToken = process.env["CLAUDE_CODE_OAUTH_TOKEN"];
3108
3108
  const apiKey = process.env["ANTHROPIC_API_KEY"];
3109
3109
  const env = oauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: oauthToken } : apiKey ? { ANTHROPIC_API_KEY: apiKey } : {};
3110
- env["CLAUDE_CONFIG_DIR"] = resolve(".browserbird", "claude");
3110
+ const configDir = resolve(".browserbird", "claude");
3111
+ ensureClaudeSettings(configDir);
3112
+ env["CLAUDE_CONFIG_DIR"] = configDir;
3111
3113
  return {
3112
3114
  binary: "claude",
3113
3115
  args,
3114
3116
  env
3115
3117
  };
3116
3118
  }
3119
+ const CLAUDE_SETTINGS = {
3120
+ enabledPlugins: {
3121
+ "lua-lsp@claude-plugins-official": true,
3122
+ "gopls-lsp@claude-plugins-official": true,
3123
+ "frontend-design@claude-plugins-official": true
3124
+ },
3125
+ alwaysThinkingEnabled: false,
3126
+ effortLevel: "high",
3127
+ fastMode: false
3128
+ };
3129
+ let settingsEnsured = false;
3130
+ function ensureClaudeSettings(configDir) {
3131
+ if (settingsEnsured) return;
3132
+ settingsEnsured = true;
3133
+ const settingsPath = resolve(configDir, "settings.json");
3134
+ if (existsSync(settingsPath)) return;
3135
+ mkdirSync(configDir, { recursive: true });
3136
+ writeFileSync(settingsPath, JSON.stringify(CLAUDE_SETTINGS, null, 2) + "\n");
3137
+ }
3117
3138
  /** Parses a single line of stream-json output into zero or more StreamEvents. */
3118
3139
  function parseStreamLine(line) {
3119
3140
  const trimmed = line.trim();
@@ -4071,12 +4092,17 @@ function createHandler(client, getConfig, signal, getTeamId, getChannelNameToId)
4071
4092
  let timedOutMs = 0;
4072
4093
  const activeTasks = /* @__PURE__ */ new Map();
4073
4094
  let toolCount = 0;
4095
+ let toolErrors = 0;
4096
+ let toolSuccesses = 0;
4074
4097
  function isStreamExpired(err) {
4075
4098
  const msg = err instanceof Error ? err.message : String(err);
4076
4099
  return msg.includes("not_in_streaming_state") || msg.includes("streaming");
4077
4100
  }
4078
4101
  async function safeAppend(content) {
4079
- if (streamDead) return;
4102
+ if (streamDead) {
4103
+ if (content.markdown_text) await client.postMessage(channelId, threadTs, content.markdown_text).catch(() => {});
4104
+ return;
4105
+ }
4080
4106
  try {
4081
4107
  await streamer.append(content);
4082
4108
  } catch (err) {
@@ -4087,7 +4113,10 @@ function createHandler(client, getConfig, signal, getTeamId, getChannelNameToId)
4087
4113
  }
4088
4114
  }
4089
4115
  async function safeStop(opts) {
4090
- if (streamDead) return;
4116
+ if (streamDead) {
4117
+ if (opts?.blocks) await client.postMessage(channelId, threadTs, "", { blocks: opts.blocks }).catch(() => {});
4118
+ return;
4119
+ }
4091
4120
  try {
4092
4121
  await streamer.stop(opts);
4093
4122
  } catch (err) {
@@ -4144,13 +4173,23 @@ function createHandler(client, getConfig, signal, getTeamId, getChannelNameToId)
4144
4173
  if (toolName) {
4145
4174
  activeTasks.delete(event.toolCallId);
4146
4175
  const title = toolTaskTitle(toolName);
4147
- await safeAppend({ chunks: [{
4176
+ if (event.isError) toolErrors++;
4177
+ else toolSuccesses++;
4178
+ const chunks = [{
4148
4179
  type: "task_update",
4149
4180
  id: event.toolCallId,
4150
4181
  title,
4151
4182
  status: event.isError ? "error" : "complete",
4152
4183
  ...event.output ? { output: event.output } : {}
4153
- }] });
4184
+ }];
4185
+ if (activeTasks.size === 0) {
4186
+ const label = toolErrors === 0 ? `Completed (${toolCount} ${toolCount === 1 ? "step" : "steps"})` : `${toolSuccesses} passed, ${toolErrors} failed`;
4187
+ chunks.push({
4188
+ type: "plan_update",
4189
+ title: label
4190
+ });
4191
+ }
4192
+ await safeAppend({ chunks });
4154
4193
  }
4155
4194
  break;
4156
4195
  }
@@ -4190,9 +4229,9 @@ function createHandler(client, getConfig, signal, getTeamId, getChannelNameToId)
4190
4229
  await safeAppend({ chunks: staleChunks });
4191
4230
  activeTasks.clear();
4192
4231
  }
4193
- if (toolCount > 0) await safeAppend({ chunks: [{
4232
+ if (toolCount > 0 && (hasError || activeTasks.size > 0)) await safeAppend({ chunks: [{
4194
4233
  type: "plan_update",
4195
- title: hasError ? "Finished with errors" : `Completed (${toolCount} ${toolCount === 1 ? "step" : "steps"})`
4234
+ title: hasError ? "Finished with errors" : `Interrupted (${toolCount} ${toolCount === 1 ? "step" : "steps"})`
4196
4235
  }] });
4197
4236
  if (timedOut) {
4198
4237
  await safeStop({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owloops/browserbird",
3
- "version": "1.6.1",
3
+ "version": "1.7.1",
4
4
  "description": "AI agent orchestrator with a real browser, a cron scheduler, and a web dashboard",
5
5
  "type": "module",
6
6
  "bin": {