@owloops/browserbird 1.0.4 → 1.0.5

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.
@@ -23,12 +23,22 @@ var __exportAll = (all, no_symbols) => {
23
23
 
24
24
  //#endregion
25
25
  //#region src/core/logger.ts
26
- /** @fileoverview Structured logger. Writes to stderr, respects NO_COLOR. */
26
+ /**
27
+ * @fileoverview Structured logger. Respects NO_COLOR.
28
+ *
29
+ * Stream routing by mode:
30
+ * - CLI mode (default): all logs to stderr, keeping stdout clean for data output.
31
+ * - Daemon mode: errors/warnings to stderr, everything else to stdout.
32
+ * Cloud platforms (Railway, Fly, etc.) treat stderr lines as errors, so this
33
+ * prevents info lines from showing up red.
34
+ *
35
+ * Call `logger.setMode('daemon')` once at startup to switch.
36
+ */
27
37
  function shouldUseColor() {
28
38
  if (process.env["NO_COLOR"] !== void 0) return false;
29
39
  if (process.env["TERM"] === "dumb") return false;
30
40
  if (process.argv.includes("--no-color")) return false;
31
- return process.stderr.isTTY === true;
41
+ return process.stdout.isTTY === true || process.stderr.isTTY === true;
32
42
  }
33
43
  const useColor = shouldUseColor();
34
44
  function style(format, text) {
@@ -42,27 +52,31 @@ const LOG_LEVELS = {
42
52
  DEBUG: 3
43
53
  };
44
54
  let currentLevel = LOG_LEVELS.INFO;
55
+ let daemonMode = false;
45
56
  function timestamp() {
46
57
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
47
58
  }
48
- function write(prefix, message) {
59
+ function out(prefix, message) {
60
+ (daemonMode ? process.stdout : process.stderr).write(`${style("dim", timestamp())} ${prefix} ${message}\n`);
61
+ }
62
+ function err(prefix, message) {
49
63
  process.stderr.write(`${style("dim", timestamp())} ${prefix} ${message}\n`);
50
64
  }
51
65
  const logger = {
52
66
  error(message) {
53
- if (currentLevel >= LOG_LEVELS.ERROR) write(style("red", "[error]"), message);
67
+ if (currentLevel >= LOG_LEVELS.ERROR) err(style("red", "[error]"), message);
54
68
  },
55
69
  warn(message) {
56
- if (currentLevel >= LOG_LEVELS.WARN) write(style("yellow", "[warn]"), message);
70
+ if (currentLevel >= LOG_LEVELS.WARN) err(style("yellow", "[warn]"), message);
57
71
  },
58
72
  info(message) {
59
- if (currentLevel >= LOG_LEVELS.INFO) write(style("blue", "[info]"), message);
73
+ if (currentLevel >= LOG_LEVELS.INFO) out(style("blue", "[info]"), message);
60
74
  },
61
75
  debug(message) {
62
- if (currentLevel >= LOG_LEVELS.DEBUG) write(style("dim", "[debug]"), message);
76
+ if (currentLevel >= LOG_LEVELS.DEBUG) out(style("dim", "[debug]"), message);
63
77
  },
64
78
  success(message) {
65
- if (currentLevel >= LOG_LEVELS.INFO) write(style("green", "[ok]"), message);
79
+ if (currentLevel >= LOG_LEVELS.INFO) out(style("green", "[ok]"), message);
66
80
  },
67
81
  setLevel(level) {
68
82
  currentLevel = {
@@ -71,6 +85,9 @@ const logger = {
71
85
  info: LOG_LEVELS.INFO,
72
86
  debug: LOG_LEVELS.DEBUG
73
87
  }[level] ?? LOG_LEVELS.INFO;
88
+ },
89
+ setMode(mode) {
90
+ daemonMode = mode === "daemon";
74
91
  }
75
92
  };
76
93
 
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as updateSessionProviderId, A as completeCronRun, B as listFlights, C as failStaleJobs, D as retryAllFailedJobs, E as listJobs, F as ensureSystemCronJob, G as deleteStaleSessions, H as updateCronJob, I as getCronJob, J as getSessionCount, K as findSession, L as getEnabledCronJobs, M as createCronRun, N as deleteCronJob, O as retryJob, P as deleteOldCronRuns, Q as touchSession, R as getFlightStats, S as failJob, T as hasPendingCronJob, U as updateCronJobStatus, V as setCronJobEnabled, W as createSession, X as getSessionTokenStats, Y as getSessionMessages, Z as listSessions, _ as clearJobs, a as getSetting, at as logger, b as deleteJob, c as getUserCount, d as getRecentLogs, et as shortUid, f as insertLog, g as claimNextJob, h as logMessage, i as createUser, it as resolveByUid, j as createCronJob, k as SYSTEM_CRON_PREFIX, l as setSetting, m as getMessageStats, n as resolveDbPath, nt as openDatabase, o as getUserByEmail, p as deleteOldMessages, q as getSession, r as resolveDbPathFromArgv, rt as optimizeDatabase, s as getUserById, tt as closeDatabase, u as deleteOldLogs, v as completeJob, w as getJobStats, x as deleteOldJobs, y as createJob, z as listCronJobs } from "./db-BsYEYsul.mjs";
1
+ import { $ as updateSessionProviderId, A as completeCronRun, B as listFlights, C as failStaleJobs, D as retryAllFailedJobs, E as listJobs, F as ensureSystemCronJob, G as deleteStaleSessions, H as updateCronJob, I as getCronJob, J as getSessionCount, K as findSession, L as getEnabledCronJobs, M as createCronRun, N as deleteCronJob, O as retryJob, P as deleteOldCronRuns, Q as touchSession, R as getFlightStats, S as failJob, T as hasPendingCronJob, U as updateCronJobStatus, V as setCronJobEnabled, W as createSession, X as getSessionTokenStats, Y as getSessionMessages, Z as listSessions, _ as clearJobs, a as getSetting, at as logger, b as deleteJob, c as getUserCount, d as getRecentLogs, et as shortUid, f as insertLog, g as claimNextJob, h as logMessage, i as createUser, it as resolveByUid, j as createCronJob, k as SYSTEM_CRON_PREFIX, l as setSetting, m as getMessageStats, n as resolveDbPath, nt as openDatabase, o as getUserByEmail, p as deleteOldMessages, q as getSession, r as resolveDbPathFromArgv, rt as optimizeDatabase, s as getUserById, tt as closeDatabase, u as deleteOldLogs, v as completeJob, w as getJobStats, x as deleteOldJobs, y as createJob, z as listCronJobs } from "./db-DAXqDqAz.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { parseArgs, styleText } from "node:util";
4
4
  import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
@@ -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: ${"31deacfff288caf3ef7112dbf1077a0430fb74a6".substring(0, 7)}`);
126
- buildInfo.push(`built: 2026-03-01T15:25:23+04:00`);
125
+ buildInfo.push(`commit: ${"586c182ef205aa8aeb3b28c768ad78da04c3899b".substring(0, 7)}`);
126
+ buildInfo.push(`built: 2026-03-01T15:50:40+04:00`);
127
127
  const buildString = buildInfo.length > 0 ? ` (${buildInfo.join(", ")})` : "";
128
128
  const VERSION = `browserbird ${pkg.version}${buildString}`;
129
129
  const BIRD = [
@@ -3703,7 +3703,7 @@ async function handleBirdCreateSubmission(view, webClient, defaultTimezone) {
3703
3703
  logger.warn("bird_create submission missing required fields");
3704
3704
  return;
3705
3705
  }
3706
- const { createCronJob, setCronJobEnabled } = await import("./db-BsYEYsul.mjs").then((n) => n.t);
3706
+ const { createCronJob, setCronJobEnabled } = await import("./db-DAXqDqAz.mjs").then((n) => n.t);
3707
3707
  const bird = createCronJob(name, schedule, prompt, channelId || void 0, "default", defaultTimezone);
3708
3708
  if (enabledValue !== "enabled") setCronJobEnabled(bird.uid, false);
3709
3709
  await webClient.chat.postMessage({
@@ -3717,7 +3717,7 @@ async function handleBirdCreateSubmission(view, webClient, defaultTimezone) {
3717
3717
  }
3718
3718
  async function handleSessionRetry(sessionUid, channelId, userId, config, handler) {
3719
3719
  try {
3720
- const { getSession, getLastInboundMessage } = await import("./db-BsYEYsul.mjs").then((n) => n.t);
3720
+ const { getSession, getLastInboundMessage } = await import("./db-DAXqDqAz.mjs").then((n) => n.t);
3721
3721
  const session = getSession(sessionUid);
3722
3722
  if (!session) {
3723
3723
  logger.warn(`retry: session ${sessionUid} not found`);
@@ -3787,7 +3787,8 @@ const stubDeps = {
3787
3787
  };
3788
3788
  async function startDaemon(options) {
3789
3789
  setupShutdown();
3790
- process.stderr.write(BANNER + "\n\n");
3790
+ logger.setMode("daemon");
3791
+ process.stdout.write(BANNER + "\n\n");
3791
3792
  if (options.flags.verbose) logger.setLevel("debug");
3792
3793
  const configPath = resolve(options.flags.config ?? process.env["BROWSERBIRD_CONFIG"] ?? "browserbird.json");
3793
3794
  const envPath = resolve(".env");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owloops/browserbird",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Self-hosted AI agent for Slack with a real browser, a scheduler, and a web dashboard",
5
5
  "type": "module",
6
6
  "bin": {