bgrun 3.12.10 → 3.12.12

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.
package/dist/index.js CHANGED
@@ -510,85 +510,6 @@ var init_platform = __esm(() => {
510
510
  plat = createMeasure("platform");
511
511
  });
512
512
 
513
- // src/utils.ts
514
- import * as fs2 from "fs";
515
- function parseEnvString(envString) {
516
- const env = {};
517
- envString.split(",").forEach((pair) => {
518
- const [key, value] = pair.split("=");
519
- if (key && value)
520
- env[key] = value;
521
- });
522
- return env;
523
- }
524
- function calculateRuntime(startTime) {
525
- const start = new Date(startTime).getTime();
526
- const now = new Date().getTime();
527
- const diffInMinutes = Math.floor((now - start) / (1000 * 60));
528
- return `${diffInMinutes} minutes`;
529
- }
530
- async function getVersion() {
531
- try {
532
- const { join: join2 } = await import("path");
533
- const pkgPath = join2(import.meta.dir, "../package.json");
534
- const pkg = await Bun.file(pkgPath).json();
535
- return pkg.version || "0.0.0";
536
- } catch {
537
- return "0.0.0";
538
- }
539
- }
540
- function validateDirectory(directory) {
541
- if (!directory || !fs2.existsSync(directory)) {
542
- throw new Error(`Directory not found or invalid: '${directory}'`);
543
- }
544
- }
545
- function tailFile(path, prefix, colorFn, lines) {
546
- let position = 0;
547
- let lastPartial = "";
548
- if (!fs2.existsSync(path)) {
549
- return () => {};
550
- }
551
- const fd = fs2.openSync(path, "r");
552
- const printNewContent = () => {
553
- try {
554
- const stats = fs2.statSync(path);
555
- if (stats.size <= position)
556
- return;
557
- const buffer = Buffer.alloc(stats.size - position);
558
- fs2.readSync(fd, buffer, 0, buffer.length, position);
559
- let content = buffer.toString();
560
- content = lastPartial + content;
561
- lastPartial = "";
562
- const lineArray = content.split(/\r?\n/);
563
- if (!content.endsWith(`
564
- `)) {
565
- lastPartial = lineArray.pop() || "";
566
- }
567
- lineArray.forEach((line) => {
568
- if (line) {
569
- console.log(colorFn(prefix + line));
570
- }
571
- });
572
- position = stats.size;
573
- } catch (e) {}
574
- };
575
- const watcher = fs2.watch(path, { persistent: true }, (event) => {
576
- if (event === "change") {
577
- printNewContent();
578
- }
579
- });
580
- printNewContent();
581
- return () => {
582
- watcher.close();
583
- try {
584
- fs2.closeSync(fd);
585
- } catch {}
586
- };
587
- }
588
- var init_utils = __esm(() => {
589
- init_platform();
590
- });
591
-
592
513
  // src/db.ts
593
514
  var exports_db = {};
594
515
  __export(exports_db, {
@@ -628,7 +549,7 @@ __export(exports_db, {
628
549
  import { Database, z } from "sqlite-zod-orm";
629
550
  import { join as join2 } from "path";
630
551
  var {sleep } = globalThis.Bun;
631
- import { existsSync as existsSync3, copyFileSync as copyFileSync2 } from "fs";
552
+ import { existsSync as existsSync2, copyFileSync as copyFileSync2 } from "fs";
632
553
  function shouldAutoMigrateLegacyDb() {
633
554
  const raw = (process.env.BGRUN_DISABLE_LEGACY_MIGRATION || "").trim().toLowerCase();
634
555
  return !(raw === "1" || raw === "true" || raw === "yes");
@@ -828,7 +749,7 @@ function getDbInfo() {
828
749
  dbPath,
829
750
  bgrHome,
830
751
  dbFilename,
831
- exists: existsSync3(dbPath)
752
+ exists: existsSync2(dbPath)
832
753
  };
833
754
  }
834
755
  async function retryDatabaseOperation(operation, maxRetries = 5, delay = 100) {
@@ -887,7 +808,7 @@ var init_db = __esm(() => {
887
808
  dbPath = join2(bgrDir, dbFilename);
888
809
  bgrHome = bgrDir;
889
810
  legacyDbPath = join2(bgrDir, "bgr_v2.sqlite");
890
- if (shouldAutoMigrateLegacyDb() && !existsSync3(dbPath) && existsSync3(legacyDbPath)) {
811
+ if (shouldAutoMigrateLegacyDb() && !existsSync2(dbPath) && existsSync2(legacyDbPath)) {
891
812
  try {
892
813
  copyFileSync2(legacyDbPath, dbPath);
893
814
  console.log(`[bgrun] Migrated database: ${legacyDbPath} \u2192 ${dbPath}`);
@@ -908,71 +829,84 @@ var init_db = __esm(() => {
908
829
  });
909
830
  });
910
831
 
911
- // src/logger.ts
912
- import boxen from "boxen";
913
- import chalk from "chalk";
914
- function announce(message, title) {
915
- console.log(boxen(message, {
916
- padding: 1,
917
- margin: 1,
918
- borderColor: "green",
919
- title: title || "bgrun",
920
- titleAlignment: "center",
921
- borderStyle: "round"
922
- }));
832
+ // src/utils.ts
833
+ import * as fs2 from "fs";
834
+ function parseEnvString(envString) {
835
+ const env = {};
836
+ envString.split(",").forEach((pair) => {
837
+ const [key, value] = pair.split("=");
838
+ if (key && value)
839
+ env[key] = value;
840
+ });
841
+ return env;
923
842
  }
924
- function error(message) {
925
- const text = message instanceof Error ? message.stack || message.message : String(message);
926
- console.error(boxen(chalk.red(text), {
927
- padding: 1,
928
- margin: 1,
929
- borderColor: "red",
930
- title: "Error",
931
- titleAlignment: "center",
932
- borderStyle: "double"
933
- }));
934
- throw new BgrunError(text);
843
+ function calculateRuntime(startTime) {
844
+ const start = new Date(startTime).getTime();
845
+ const now = new Date().getTime();
846
+ const diffInMinutes = Math.floor((now - start) / (1000 * 60));
847
+ return `${diffInMinutes} minutes`;
935
848
  }
936
- var BgrunError;
937
- var init_logger = __esm(() => {
938
- BgrunError = class BgrunError extends Error {
939
- constructor(message) {
940
- super(message);
941
- this.name = "BgrunError";
942
- }
943
- };
944
- });
945
-
946
- // src/config.ts
947
- function formatEnvKey(key) {
948
- return key.toUpperCase().replace(/\./g, "_");
849
+ async function getVersion() {
850
+ try {
851
+ const { join: join3 } = await import("path");
852
+ const pkgPath = join3(import.meta.dir, "../package.json");
853
+ const pkg = await Bun.file(pkgPath).json();
854
+ return pkg.version || "0.0.0";
855
+ } catch {
856
+ return "0.0.0";
857
+ }
949
858
  }
950
- function flattenConfig(obj, prefix = "") {
951
- return Object.keys(obj).reduce((acc, key) => {
952
- const value = obj[key];
953
- const newPrefix = prefix ? `${prefix}.${key}` : key;
954
- if (Array.isArray(value)) {
955
- value.forEach((item, index) => {
956
- const indexedPrefix = `${newPrefix}.${index}`;
957
- if (typeof item === "object" && item !== null) {
958
- Object.assign(acc, flattenConfig(item, indexedPrefix));
959
- } else {
960
- acc[formatEnvKey(indexedPrefix)] = String(item);
859
+ function validateDirectory(directory) {
860
+ if (!directory || !fs2.existsSync(directory)) {
861
+ throw new Error(`Directory not found or invalid: '${directory}'`);
862
+ }
863
+ }
864
+ function tailFile(path, prefix, colorFn, lines) {
865
+ let position = 0;
866
+ let lastPartial = "";
867
+ if (!fs2.existsSync(path)) {
868
+ return () => {};
869
+ }
870
+ const fd = fs2.openSync(path, "r");
871
+ const printNewContent = () => {
872
+ try {
873
+ const stats = fs2.statSync(path);
874
+ if (stats.size <= position)
875
+ return;
876
+ const buffer = Buffer.alloc(stats.size - position);
877
+ fs2.readSync(fd, buffer, 0, buffer.length, position);
878
+ let content = buffer.toString();
879
+ content = lastPartial + content;
880
+ lastPartial = "";
881
+ const lineArray = content.split(/\r?\n/);
882
+ if (!content.endsWith(`
883
+ `)) {
884
+ lastPartial = lineArray.pop() || "";
885
+ }
886
+ lineArray.forEach((line) => {
887
+ if (line) {
888
+ console.log(colorFn(prefix + line));
961
889
  }
962
890
  });
963
- } else if (typeof value === "object" && value !== null) {
964
- Object.assign(acc, flattenConfig(value, newPrefix));
965
- } else {
966
- acc[formatEnvKey(newPrefix)] = String(value);
891
+ position = stats.size;
892
+ } catch (e) {}
893
+ };
894
+ const watcher = fs2.watch(path, { persistent: true }, (event) => {
895
+ if (event === "change") {
896
+ printNewContent();
967
897
  }
968
- return acc;
969
- }, {});
970
- }
971
- async function parseConfigFile(configPath) {
972
- const importPath = `${configPath}?t=${Date.now()}`;
973
- const parsedConfig = await import(importPath).then((m) => m.default);
974
- return flattenConfig(parsedConfig);
898
+ });
899
+ printNewContent();
900
+ return () => {
901
+ watcher.close();
902
+ try {
903
+ fs2.closeSync(fd);
904
+ } catch {}
905
+ };
975
906
  }
907
+ var init_utils = __esm(() => {
908
+ init_platform();
909
+ });
976
910
 
977
911
  // src/deps.ts
978
912
  var exports_deps = {};
@@ -1063,6 +997,143 @@ var init_deps = __esm(() => {
1063
997
  init_utils();
1064
998
  });
1065
999
 
1000
+ // src/log-rotation.ts
1001
+ var exports_log_rotation = {};
1002
+ __export(exports_log_rotation, {
1003
+ startLogRotation: () => startLogRotation,
1004
+ rotateLogFile: () => rotateLogFile,
1005
+ rotateAllLogs: () => rotateAllLogs
1006
+ });
1007
+ import { existsSync as existsSync4, statSync as statSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
1008
+ function rotateLogFile(filePath, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
1009
+ try {
1010
+ if (!existsSync4(filePath))
1011
+ return false;
1012
+ const stat = statSync2(filePath);
1013
+ if (stat.size <= maxBytes)
1014
+ return false;
1015
+ const content = readFileSync(filePath, "utf-8");
1016
+ const lines = content.split(`
1017
+ `);
1018
+ if (lines.length <= keepLines)
1019
+ return false;
1020
+ const truncated = lines.slice(-keepLines);
1021
+ const header = `--- [bgrun] Log rotated at ${new Date().toISOString()} (was ${lines.length} lines, ${formatBytes(stat.size)}) ---
1022
+ `;
1023
+ writeFileSync2(filePath, header + truncated.join(`
1024
+ `));
1025
+ return true;
1026
+ } catch {
1027
+ return false;
1028
+ }
1029
+ }
1030
+ function rotateAllLogs(getProcesses, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
1031
+ const processes = getProcesses();
1032
+ const rotated = [];
1033
+ let checked = 0;
1034
+ for (const proc of processes) {
1035
+ if (proc.stdout_path) {
1036
+ checked++;
1037
+ if (rotateLogFile(proc.stdout_path, maxBytes, keepLines)) {
1038
+ rotated.push(`${proc.name}/stdout`);
1039
+ }
1040
+ }
1041
+ if (proc.stderr_path) {
1042
+ checked++;
1043
+ if (rotateLogFile(proc.stderr_path, maxBytes, keepLines)) {
1044
+ rotated.push(`${proc.name}/stderr`);
1045
+ }
1046
+ }
1047
+ }
1048
+ return { rotated, checked };
1049
+ }
1050
+ function startLogRotation(getProcesses, intervalMs = DEFAULT_CHECK_INTERVAL_MS, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
1051
+ console.log(`[logs] Log rotation active: max ${formatBytes(maxBytes)}/file, keep ${keepLines} lines, check every ${intervalMs / 1000}s`);
1052
+ return setInterval(() => {
1053
+ const { rotated } = rotateAllLogs(getProcesses, maxBytes, keepLines);
1054
+ if (rotated.length > 0) {
1055
+ console.log(`[logs] Rotated ${rotated.length} log(s): ${rotated.join(", ")}`);
1056
+ }
1057
+ }, intervalMs);
1058
+ }
1059
+ function formatBytes(bytes) {
1060
+ if (bytes >= 1e6)
1061
+ return `${(bytes / 1e6).toFixed(1)}MB`;
1062
+ if (bytes >= 1000)
1063
+ return `${(bytes / 1000).toFixed(0)}KB`;
1064
+ return `${bytes}B`;
1065
+ }
1066
+ var DEFAULT_MAX_BYTES, DEFAULT_KEEP_LINES = 5000, DEFAULT_CHECK_INTERVAL_MS = 60000;
1067
+ var init_log_rotation = __esm(() => {
1068
+ DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
1069
+ });
1070
+
1071
+ // src/logger.ts
1072
+ import boxen from "boxen";
1073
+ import chalk from "chalk";
1074
+ function announce(message, title) {
1075
+ console.log(boxen(message, {
1076
+ padding: 1,
1077
+ margin: 1,
1078
+ borderColor: "green",
1079
+ title: title || "bgrun",
1080
+ titleAlignment: "center",
1081
+ borderStyle: "round"
1082
+ }));
1083
+ }
1084
+ function error(message) {
1085
+ const text = message instanceof Error ? message.stack || message.message : String(message);
1086
+ console.error(boxen(chalk.red(text), {
1087
+ padding: 1,
1088
+ margin: 1,
1089
+ borderColor: "red",
1090
+ title: "Error",
1091
+ titleAlignment: "center",
1092
+ borderStyle: "double"
1093
+ }));
1094
+ throw new BgrunError(text);
1095
+ }
1096
+ var BgrunError;
1097
+ var init_logger = __esm(() => {
1098
+ BgrunError = class BgrunError extends Error {
1099
+ constructor(message) {
1100
+ super(message);
1101
+ this.name = "BgrunError";
1102
+ }
1103
+ };
1104
+ });
1105
+
1106
+ // src/config.ts
1107
+ function formatEnvKey(key) {
1108
+ return key.toUpperCase().replace(/\./g, "_");
1109
+ }
1110
+ function flattenConfig(obj, prefix = "") {
1111
+ return Object.keys(obj).reduce((acc, key) => {
1112
+ const value = obj[key];
1113
+ const newPrefix = prefix ? `${prefix}.${key}` : key;
1114
+ if (Array.isArray(value)) {
1115
+ value.forEach((item, index) => {
1116
+ const indexedPrefix = `${newPrefix}.${index}`;
1117
+ if (typeof item === "object" && item !== null) {
1118
+ Object.assign(acc, flattenConfig(item, indexedPrefix));
1119
+ } else {
1120
+ acc[formatEnvKey(indexedPrefix)] = String(item);
1121
+ }
1122
+ });
1123
+ } else if (typeof value === "object" && value !== null) {
1124
+ Object.assign(acc, flattenConfig(value, newPrefix));
1125
+ } else {
1126
+ acc[formatEnvKey(newPrefix)] = String(value);
1127
+ }
1128
+ return acc;
1129
+ }, {});
1130
+ }
1131
+ async function parseConfigFile(configPath) {
1132
+ const importPath = `${configPath}?t=${Date.now()}`;
1133
+ const parsedConfig = await import(importPath).then((m) => m.default);
1134
+ return flattenConfig(parsedConfig);
1135
+ }
1136
+
1066
1137
  // src/commands/run.ts
1067
1138
  var {$: $2 } = globalThis.Bun;
1068
1139
  var {sleep: sleep2 } = globalThis.Bun;
@@ -1238,77 +1309,6 @@ var init_run = __esm(() => {
1238
1309
  run = createMeasure2("run");
1239
1310
  });
1240
1311
 
1241
- // src/log-rotation.ts
1242
- var exports_log_rotation = {};
1243
- __export(exports_log_rotation, {
1244
- startLogRotation: () => startLogRotation,
1245
- rotateLogFile: () => rotateLogFile,
1246
- rotateAllLogs: () => rotateAllLogs
1247
- });
1248
- import { existsSync as existsSync7, statSync as statSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1249
- function rotateLogFile(filePath, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
1250
- try {
1251
- if (!existsSync7(filePath))
1252
- return false;
1253
- const stat = statSync3(filePath);
1254
- if (stat.size <= maxBytes)
1255
- return false;
1256
- const content = readFileSync2(filePath, "utf-8");
1257
- const lines = content.split(`
1258
- `);
1259
- if (lines.length <= keepLines)
1260
- return false;
1261
- const truncated = lines.slice(-keepLines);
1262
- const header = `--- [bgrun] Log rotated at ${new Date().toISOString()} (was ${lines.length} lines, ${formatBytes(stat.size)}) ---
1263
- `;
1264
- writeFileSync2(filePath, header + truncated.join(`
1265
- `));
1266
- return true;
1267
- } catch {
1268
- return false;
1269
- }
1270
- }
1271
- function rotateAllLogs(getProcesses, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
1272
- const processes = getProcesses();
1273
- const rotated = [];
1274
- let checked = 0;
1275
- for (const proc of processes) {
1276
- if (proc.stdout_path) {
1277
- checked++;
1278
- if (rotateLogFile(proc.stdout_path, maxBytes, keepLines)) {
1279
- rotated.push(`${proc.name}/stdout`);
1280
- }
1281
- }
1282
- if (proc.stderr_path) {
1283
- checked++;
1284
- if (rotateLogFile(proc.stderr_path, maxBytes, keepLines)) {
1285
- rotated.push(`${proc.name}/stderr`);
1286
- }
1287
- }
1288
- }
1289
- return { rotated, checked };
1290
- }
1291
- function startLogRotation(getProcesses, intervalMs = DEFAULT_CHECK_INTERVAL_MS, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
1292
- console.log(`[logs] Log rotation active: max ${formatBytes(maxBytes)}/file, keep ${keepLines} lines, check every ${intervalMs / 1000}s`);
1293
- return setInterval(() => {
1294
- const { rotated } = rotateAllLogs(getProcesses, maxBytes, keepLines);
1295
- if (rotated.length > 0) {
1296
- console.log(`[logs] Rotated ${rotated.length} log(s): ${rotated.join(", ")}`);
1297
- }
1298
- }, intervalMs);
1299
- }
1300
- function formatBytes(bytes) {
1301
- if (bytes >= 1e6)
1302
- return `${(bytes / 1e6).toFixed(1)}MB`;
1303
- if (bytes >= 1000)
1304
- return `${(bytes / 1000).toFixed(0)}KB`;
1305
- return `${bytes}B`;
1306
- }
1307
- var DEFAULT_MAX_BYTES, DEFAULT_KEEP_LINES = 5000, DEFAULT_CHECK_INTERVAL_MS = 60000;
1308
- var init_log_rotation = __esm(() => {
1309
- DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
1310
- });
1311
-
1312
1312
  // src/server.ts
1313
1313
  var exports_server = {};
1314
1314
  __export(exports_server, {
@@ -1316,7 +1316,7 @@ __export(exports_server, {
1316
1316
  guardRestartCounts: () => guardRestartCounts,
1317
1317
  guardEvents: () => guardEvents
1318
1318
  });
1319
- import path2 from "path";
1319
+ import path from "path";
1320
1320
  async function cleanupPort(port) {
1321
1321
  if (process.platform !== "win32")
1322
1322
  return port;
@@ -1354,7 +1354,7 @@ async function cleanupPort(port) {
1354
1354
  }
1355
1355
  async function startServer() {
1356
1356
  const { start } = await import("melina");
1357
- const appDir = path2.join(import.meta.dir, "../dashboard/app");
1357
+ const appDir = path.join(import.meta.dir, "../dashboard/app");
1358
1358
  const requestedPort = process.env.BUN_PORT ? parseInt(process.env.BUN_PORT, 10) : 3000;
1359
1359
  _originalPort = requestedPort;
1360
1360
  const resolvedPort = await cleanupPort(requestedPort);
@@ -1363,7 +1363,7 @@ async function startServer() {
1363
1363
  await start({
1364
1364
  appDir,
1365
1365
  defaultTitle: "bgrun Dashboard - Process Manager",
1366
- globalCss: path2.join(appDir, "globals.css"),
1366
+ globalCss: path.join(appDir, "globals.css"),
1367
1367
  ...needsExplicitPort && { port: resolvedPort }
1368
1368
  });
1369
1369
  startGuard();
@@ -2033,7 +2033,7 @@ init_logger();
2033
2033
  init_utils();
2034
2034
  init_run();
2035
2035
  import * as fs4 from "fs";
2036
- import path from "path";
2036
+ import path2 from "path";
2037
2037
  import chalk4 from "chalk";
2038
2038
  async function handleWatch(options, logOptions) {
2039
2039
  let currentProcess = null;
@@ -2046,10 +2046,10 @@ async function handleWatch(options, logOptions) {
2046
2046
  if (!isDead)
2047
2047
  return false;
2048
2048
  console.log(chalk4.yellow(`\uD83D\uDC80 Process '${options.name}' died immediately after ${reason}\u2014dumping logs:`));
2049
- const readAndDump = (path2, color, label) => {
2049
+ const readAndDump = (path3, color, label) => {
2050
2050
  try {
2051
- if (fs4.existsSync(path2)) {
2052
- const content = fs4.readFileSync(path2, "utf8").trim();
2051
+ if (fs4.existsSync(path3)) {
2052
+ const content = fs4.readFileSync(path3, "utf8").trim();
2053
2053
  if (content) {
2054
2054
  console.log(`${color.bold(label)}:
2055
2055
  ${color(content)}
@@ -2087,8 +2087,8 @@ ${color(content)}
2087
2087
  resolve();
2088
2088
  return;
2089
2089
  }
2090
- const dir = path.dirname(logPath);
2091
- const filename = path.basename(logPath);
2090
+ const dir = path2.dirname(logPath);
2091
+ const filename = path2.basename(logPath);
2092
2092
  const watcher2 = fs4.watch(dir, (eventType, changedFilename) => {
2093
2093
  if (changedFilename === filename && eventType === "change") {
2094
2094
  if (checkReady()) {
@@ -2134,12 +2134,12 @@ ${color(content)}
2134
2134
  }
2135
2135
  return stops;
2136
2136
  };
2137
- const restartProcess = async (path2) => {
2137
+ const restartProcess = async (path3) => {
2138
2138
  if (isRestarting)
2139
2139
  return;
2140
2140
  isRestarting = true;
2141
- const restartReason = path2 ? `restart (change in ${path2})` : "initial start";
2142
- lastRestartPath = path2 || null;
2141
+ const restartReason = path3 ? `restart (change in ${path3})` : "initial start";
2142
+ lastRestartPath = path3 || null;
2143
2143
  tailStops.forEach((stop) => stop());
2144
2144
  tailStops = [];
2145
2145
  console.clear();
@@ -2192,7 +2192,7 @@ ${color(content)}
2192
2192
  const watcher = fs4.watch(workdir, { recursive: true }, (eventType, filename) => {
2193
2193
  if (filename == null)
2194
2194
  return;
2195
- const fullPath = path.join(workdir, filename);
2195
+ const fullPath = path2.join(workdir, filename);
2196
2196
  if (fullPath.includes(".git") || fullPath.includes("node_modules"))
2197
2197
  return;
2198
2198
  if (debounceTimeout)
@@ -0,0 +1,95 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+ var __require = import.meta.require;
18
+
19
+ // src/log-rotation.ts
20
+ var exports_log_rotation = {};
21
+ __export(exports_log_rotation, {
22
+ startLogRotation: () => startLogRotation,
23
+ rotateLogFile: () => rotateLogFile,
24
+ rotateAllLogs: () => rotateAllLogs
25
+ });
26
+ import { existsSync, statSync, readFileSync, writeFileSync } from "fs";
27
+ function rotateLogFile(filePath, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
28
+ try {
29
+ if (!existsSync(filePath))
30
+ return false;
31
+ const stat = statSync(filePath);
32
+ if (stat.size <= maxBytes)
33
+ return false;
34
+ const content = readFileSync(filePath, "utf-8");
35
+ const lines = content.split(`
36
+ `);
37
+ if (lines.length <= keepLines)
38
+ return false;
39
+ const truncated = lines.slice(-keepLines);
40
+ const header = `--- [bgrun] Log rotated at ${new Date().toISOString()} (was ${lines.length} lines, ${formatBytes(stat.size)}) ---
41
+ `;
42
+ writeFileSync(filePath, header + truncated.join(`
43
+ `));
44
+ return true;
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+ function rotateAllLogs(getProcesses, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
50
+ const processes = getProcesses();
51
+ const rotated = [];
52
+ let checked = 0;
53
+ for (const proc of processes) {
54
+ if (proc.stdout_path) {
55
+ checked++;
56
+ if (rotateLogFile(proc.stdout_path, maxBytes, keepLines)) {
57
+ rotated.push(`${proc.name}/stdout`);
58
+ }
59
+ }
60
+ if (proc.stderr_path) {
61
+ checked++;
62
+ if (rotateLogFile(proc.stderr_path, maxBytes, keepLines)) {
63
+ rotated.push(`${proc.name}/stderr`);
64
+ }
65
+ }
66
+ }
67
+ return { rotated, checked };
68
+ }
69
+ function startLogRotation(getProcesses, intervalMs = DEFAULT_CHECK_INTERVAL_MS, maxBytes = DEFAULT_MAX_BYTES, keepLines = DEFAULT_KEEP_LINES) {
70
+ console.log(`[logs] Log rotation active: max ${formatBytes(maxBytes)}/file, keep ${keepLines} lines, check every ${intervalMs / 1000}s`);
71
+ return setInterval(() => {
72
+ const { rotated } = rotateAllLogs(getProcesses, maxBytes, keepLines);
73
+ if (rotated.length > 0) {
74
+ console.log(`[logs] Rotated ${rotated.length} log(s): ${rotated.join(", ")}`);
75
+ }
76
+ }, intervalMs);
77
+ }
78
+ function formatBytes(bytes) {
79
+ if (bytes >= 1e6)
80
+ return `${(bytes / 1e6).toFixed(1)}MB`;
81
+ if (bytes >= 1000)
82
+ return `${(bytes / 1000).toFixed(0)}KB`;
83
+ return `${bytes}B`;
84
+ }
85
+ var DEFAULT_MAX_BYTES, DEFAULT_KEEP_LINES = 5000, DEFAULT_CHECK_INTERVAL_MS = 60000;
86
+ var init_log_rotation = __esm(() => {
87
+ DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
88
+ });
89
+ init_log_rotation();
90
+
91
+ export {
92
+ startLogRotation,
93
+ rotateLogFile,
94
+ rotateAllLogs
95
+ };