@owloops/browserbird 1.8.1 → 1.8.3

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 +29 -58
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -193,8 +193,8 @@ function unknownSubcommand(subcommand, command, validCommands) {
193
193
  /** @fileoverview ASCII banner displayed on daemon startup and in help text. */
194
194
  const pkg = createRequire(import.meta.url)("../package.json");
195
195
  const buildInfo = [];
196
- buildInfo.push(`commit: ${"b1eae905defc5deba32405ad32f6c702a1a2c1a1".substring(0, 7)}`);
197
- buildInfo.push(`built: 2026-03-22T16:55:56+04:00`);
196
+ buildInfo.push(`commit: ${"2f0bea968791cd11c9e83c7461f7e8d466376792".substring(0, 7)}`);
197
+ buildInfo.push(`built: 2026-03-22T17:18:51+04:00`);
198
198
  const buildString = buildInfo.length > 0 ? ` (${buildInfo.join(", ")})` : "";
199
199
  const VERSION = `browserbird ${pkg.version}${buildString}`;
200
200
  const BIRD = [
@@ -1010,6 +1010,7 @@ function deleteCronJob(jobUid) {
1010
1010
  try {
1011
1011
  d.prepare("DELETE FROM cron_runs WHERE job_uid = ?").run(jobUid);
1012
1012
  d.prepare("UPDATE jobs SET cron_job_uid = NULL WHERE cron_job_uid = ?").run(jobUid);
1013
+ d.prepare("DELETE FROM key_bindings WHERE target_type = 'bird' AND target_id = ?").run(jobUid);
1013
1014
  const result = d.prepare("DELETE FROM cron_jobs WHERE uid = ?").run(jobUid);
1014
1015
  d.exec("COMMIT");
1015
1016
  return Number(result.changes) > 0;
@@ -1413,6 +1414,25 @@ function ensureVaultKey(envPath) {
1413
1414
 
1414
1415
  //#endregion
1415
1416
  //#region src/db/keys.ts
1417
+ const KEY_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
1418
+ const RESERVED_KEY_NAMES = new Set([
1419
+ "ANTHROPIC_API_KEY",
1420
+ "CLAUDE_CODE_OAUTH_TOKEN",
1421
+ "CLAUDE_CONFIG_DIR",
1422
+ "CLAUDECODE",
1423
+ "CLAUDE_CODE_ENTRYPOINT",
1424
+ "SLACK_BOT_TOKEN",
1425
+ "SLACK_APP_TOKEN",
1426
+ "BROWSERBIRD_VAULT_KEY",
1427
+ "BROWSERBIRD_CONFIG",
1428
+ "BROWSERBIRD_DB"
1429
+ ]);
1430
+ function validateKeyName(raw) {
1431
+ const name = raw.trim().toUpperCase();
1432
+ if (!KEY_NAME_RE.test(name)) return { error: "Name must match [A-Z][A-Z0-9_]* (e.g. GITHUB_TOKEN)" };
1433
+ if (RESERVED_KEY_NAMES.has(name)) return { error: `"${name}" is reserved (managed via config)` };
1434
+ return { name };
1435
+ }
1416
1436
  function decryptValue(raw) {
1417
1437
  return isEncrypted(raw) ? decrypt(raw, getVaultKey()) : raw;
1418
1438
  }
@@ -2119,61 +2139,6 @@ function maskSecret(value) {
2119
2139
  hint: prefix ? `${prefix}...${tail}` : `...${tail}`
2120
2140
  };
2121
2141
  }
2122
- const KEY_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
2123
- const BLOCKED_KEY_PREFIXES = [
2124
- "LD_",
2125
- "DYLD_",
2126
- "NODE_",
2127
- "NPM_",
2128
- "GIT_",
2129
- "PYTHON",
2130
- "RUBY",
2131
- "PERL",
2132
- "JAVA_",
2133
- "CLAUDE_",
2134
- "BROWSERBIRD_"
2135
- ];
2136
- const BLOCKED_KEY_NAMES = new Set([
2137
- "ANTHROPIC_API_KEY",
2138
- "CLAUDECODE",
2139
- "SLACK_BOT_TOKEN",
2140
- "SLACK_APP_TOKEN",
2141
- "PATH",
2142
- "HOME",
2143
- "SHELL",
2144
- "USER",
2145
- "LOGNAME",
2146
- "TERM",
2147
- "IFS",
2148
- "CDPATH",
2149
- "CPATH",
2150
- "CPPATH",
2151
- "LIBRARY_PATH",
2152
- "TMPDIR",
2153
- "TZDIR",
2154
- "GCONV_PATH",
2155
- "HOSTALIASES",
2156
- "MALLOC_TRACE",
2157
- "RESOLV_HOST_CONF",
2158
- "HTTP_PROXY",
2159
- "HTTPS_PROXY",
2160
- "ALL_PROXY",
2161
- "NO_PROXY",
2162
- "CURL_CA_BUNDLE",
2163
- "SSL_CERT_FILE",
2164
- "SSL_CERT_DIR",
2165
- "REQUESTS_CA_BUNDLE"
2166
- ]);
2167
- function isDangerousKeyName(name) {
2168
- if (BLOCKED_KEY_NAMES.has(name)) return true;
2169
- return BLOCKED_KEY_PREFIXES.some((p) => name.startsWith(p));
2170
- }
2171
- function validateKeyName(raw) {
2172
- const name = raw.trim().toUpperCase();
2173
- if (!KEY_NAME_RE.test(name)) return { error: "Name must match [A-Z][A-Z0-9_]* (e.g. GITHUB_TOKEN)" };
2174
- if (isDangerousKeyName(name)) return { error: `"${name}" is a reserved or dangerous name` };
2175
- return { name };
2176
- }
2177
2142
  const HH_MM_RE = /^\d{2}:\d{2}$/;
2178
2143
  const ALLOWED_TOP_LEVEL_KEYS = new Set([
2179
2144
  "timezone",
@@ -6202,6 +6167,12 @@ async function handleKeys(argv) {
6202
6167
  process.exitCode = 1;
6203
6168
  return;
6204
6169
  }
6170
+ const validated = validateKeyName(name);
6171
+ if ("error" in validated) {
6172
+ logger.error(validated.error);
6173
+ process.exitCode = 1;
6174
+ return;
6175
+ }
6205
6176
  let secret = values.value;
6206
6177
  if (!secret) {
6207
6178
  secret = await promptSecret(`value for ${name.toUpperCase()}: `);
@@ -6212,7 +6183,7 @@ async function handleKeys(argv) {
6212
6183
  }
6213
6184
  }
6214
6185
  try {
6215
- const key = createKey(name.toUpperCase(), secret, values.description?.trim());
6186
+ const key = createKey(validated.name, secret, values.description?.trim());
6216
6187
  logger.success(`key ${key.name} created`);
6217
6188
  process.stderr.write(c("dim", ` hint: run 'browserbird keys bind ${key.name} channel *' to bind it`) + "\n");
6218
6189
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owloops/browserbird",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "AI agent orchestrator with a real browser, a cron scheduler, and a web dashboard",
5
5
  "type": "module",
6
6
  "bin": {