@owloops/browserbird 1.0.3 → 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,7 +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: ${"8508da3ffdb3230ea117b27463cc293726074f06".substring(0, 7)}`);
125
+ buildInfo.push(`commit: ${"586c182ef205aa8aeb3b28c768ad78da04c3899b".substring(0, 7)}`);
126
+ buildInfo.push(`built: 2026-03-01T15:50:40+04:00`);
126
127
  const buildString = buildInfo.length > 0 ? ` (${buildInfo.join(", ")})` : "";
127
128
  const VERSION = `browserbird ${pkg.version}${buildString}`;
128
129
  const BIRD = [
@@ -3702,7 +3703,7 @@ async function handleBirdCreateSubmission(view, webClient, defaultTimezone) {
3702
3703
  logger.warn("bird_create submission missing required fields");
3703
3704
  return;
3704
3705
  }
3705
- 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);
3706
3707
  const bird = createCronJob(name, schedule, prompt, channelId || void 0, "default", defaultTimezone);
3707
3708
  if (enabledValue !== "enabled") setCronJobEnabled(bird.uid, false);
3708
3709
  await webClient.chat.postMessage({
@@ -3716,7 +3717,7 @@ async function handleBirdCreateSubmission(view, webClient, defaultTimezone) {
3716
3717
  }
3717
3718
  async function handleSessionRetry(sessionUid, channelId, userId, config, handler) {
3718
3719
  try {
3719
- 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);
3720
3721
  const session = getSession(sessionUid);
3721
3722
  if (!session) {
3722
3723
  logger.warn(`retry: session ${sessionUid} not found`);
@@ -3786,7 +3787,8 @@ const stubDeps = {
3786
3787
  };
3787
3788
  async function startDaemon(options) {
3788
3789
  setupShutdown();
3789
- process.stderr.write(BANNER + "\n\n");
3790
+ logger.setMode("daemon");
3791
+ process.stdout.write(BANNER + "\n\n");
3790
3792
  if (options.flags.verbose) logger.setLevel("debug");
3791
3793
  const configPath = resolve(options.flags.config ?? process.env["BROWSERBIRD_CONFIG"] ?? "browserbird.json");
3792
3794
  const envPath = resolve(".env");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owloops/browserbird",
3
- "version": "1.0.3",
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": {