@electric-ax/agents-server 0.4.13 → 0.4.14

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.
@@ -893,11 +893,11 @@ var StreamClient = class {
893
893
  if (res.status === 404 || res.status === 204) return;
894
894
  if (!res.ok) throw new Error(`Subscription delete failed: ${res.status} ${await res.text()}`);
895
895
  }
896
- async addSubscriptionStreams(subscriptionId, streams$1) {
896
+ async addSubscriptionStreams(subscriptionId, streams) {
897
897
  const res = await fetch(this.subscriptionChildUrl(subscriptionId, `streams`), {
898
898
  method: `POST`,
899
899
  headers: await this.requestHeaders({ "content-type": `application/json` }),
900
- body: JSON.stringify({ streams: streams$1.map((stream) => this.backendSubscriptionPath(normalizeSubscriptionStreamPath(stream))) })
900
+ body: JSON.stringify({ streams: streams.map((stream) => this.backendSubscriptionPath(normalizeSubscriptionStreamPath(stream))) })
901
901
  });
902
902
  return await this.subscriptionJson(res, `Subscription stream add failed`);
903
903
  }
@@ -1139,35 +1139,48 @@ const LOG_LEVEL = process.env.ELECTRIC_AGENTS_LOG_LEVEL ?? `info`;
1139
1139
  const IS_ELECTRON_MAIN = Boolean(process.versions.electron);
1140
1140
  const USE_FILE_LOGS = process.env.ELECTRIC_AGENTS_LOG_FILE !== `false`;
1141
1141
  const USE_PRETTY_LOGS = LOG_LEVEL !== `silent` && !process.env.VITEST && !IS_ELECTRON_MAIN;
1142
- const LOG_DIR = USE_FILE_LOGS ? process.env.ELECTRIC_AGENTS_LOG_DIR ?? path.resolve(process.cwd(), `logs`) : void 0;
1143
- const LOG_FILE = LOG_DIR ? path.join(LOG_DIR, `agent-server-${Date.now()}.jsonl`) : void 0;
1144
- if (LOG_DIR) fs.mkdirSync(LOG_DIR, { recursive: true });
1145
- const streams = [];
1146
- if (LOG_FILE) streams.push({ stream: pino.destination({
1147
- dest: LOG_FILE,
1148
- sync: IS_ELECTRON_MAIN
1149
- }) });
1150
- if (USE_PRETTY_LOGS) streams.push({ stream: pino.transport({
1151
- target: `pino-pretty`,
1152
- options: {
1153
- colorize: true,
1154
- ignore: `pid,hostname,name`,
1155
- translateTime: `SYS:HH:MM:ss`
1156
- }
1157
- }) });
1158
- const logger = streams.length > 0 ? pino({
1159
- base: void 0,
1160
- level: LOG_LEVEL
1161
- }, pino.multistream(streams)) : pino({
1162
- base: void 0,
1163
- enabled: false,
1164
- level: LOG_LEVEL
1165
- });
1142
+ let _logger;
1143
+ function getLogger() {
1144
+ if (_logger) return _logger;
1145
+ const streams = [];
1146
+ try {
1147
+ if (USE_FILE_LOGS) {
1148
+ const logDir = process.env.ELECTRIC_AGENTS_LOG_DIR ?? path.resolve(process.cwd(), `logs`);
1149
+ fs.mkdirSync(logDir, { recursive: true });
1150
+ const logFile = path.join(logDir, `agent-server-${Date.now()}.jsonl`);
1151
+ streams.push({ stream: pino.destination({
1152
+ dest: logFile,
1153
+ sync: IS_ELECTRON_MAIN
1154
+ }) });
1155
+ }
1156
+ } catch (err) {
1157
+ process.stderr.write(`[agents-server] Failed to initialize file logging: ${err instanceof Error ? err.message : err}\n`);
1158
+ }
1159
+ try {
1160
+ if (USE_PRETTY_LOGS) streams.push({ stream: pino.transport({
1161
+ target: `pino-pretty`,
1162
+ options: {
1163
+ colorize: true,
1164
+ ignore: `pid,hostname,name`,
1165
+ translateTime: `SYS:HH:MM:ss`
1166
+ }
1167
+ }) });
1168
+ } catch {}
1169
+ _logger = streams.length > 0 ? pino({
1170
+ base: void 0,
1171
+ level: LOG_LEVEL
1172
+ }, pino.multistream(streams)) : pino({
1173
+ base: void 0,
1174
+ enabled: false,
1175
+ level: LOG_LEVEL
1176
+ });
1177
+ return _logger;
1178
+ }
1166
1179
  function formatArgs(args) {
1167
1180
  const errors = [];
1168
1181
  const parts = [];
1169
- for (const a of args) if (a instanceof Error) errors.push(a);
1170
- else parts.push(typeof a === `string` ? a : JSON.stringify(a));
1182
+ for (const value of args) if (value instanceof Error) errors.push(value);
1183
+ else parts.push(typeof value === `string` ? value : JSON.stringify(value));
1171
1184
  return {
1172
1185
  err: errors[0],
1173
1186
  msg: parts.join(` `)
@@ -1176,20 +1189,20 @@ function formatArgs(args) {
1176
1189
  const serverLog = {
1177
1190
  info(...args) {
1178
1191
  const { msg } = formatArgs(args);
1179
- logger.info(msg);
1192
+ getLogger().info(msg);
1180
1193
  },
1181
1194
  warn(...args) {
1182
1195
  const { err, msg } = formatArgs(args);
1183
- if (err) logger.warn({ err }, msg);
1184
- else logger.warn(msg);
1196
+ if (err) getLogger().warn({ err }, msg);
1197
+ else getLogger().warn(msg);
1185
1198
  },
1186
1199
  error(...args) {
1187
1200
  const { err, msg } = formatArgs(args);
1188
- if (err) logger.error({ err }, msg);
1189
- else logger.error(msg);
1201
+ if (err) getLogger().error({ err }, msg);
1202
+ else getLogger().error(msg);
1190
1203
  },
1191
1204
  event(obj, msg) {
1192
- logger.info(obj, msg);
1205
+ getLogger().info(obj, msg);
1193
1206
  }
1194
1207
  };
1195
1208
 
@@ -5647,7 +5660,7 @@ async function notificationFromClaim(ctx, input) {
5647
5660
  leaseExpiresAt: input.claim.lease_ttl_ms ? new Date(Date.now() + input.claim.lease_ttl_ms) : void 0
5648
5661
  });
5649
5662
  await ctx.entityManager.registry.updateStatus(entity.url, `running`);
5650
- const streams$1 = input.claim.streams.map((stream) => ({
5663
+ const streams = input.claim.streams.map((stream) => ({
5651
5664
  path: withLeadingSlash(stream.path),
5652
5665
  offset: stream.tail_offset ?? ``
5653
5666
  }));
@@ -5656,7 +5669,7 @@ async function notificationFromClaim(ctx, input) {
5656
5669
  epoch: input.claim.generation,
5657
5670
  wakeId: input.claim.wake_id,
5658
5671
  streamPath: primaryStream,
5659
- streams: streams$1,
5672
+ streams,
5660
5673
  callback: appendPathToUrl(ctx.publicUrl, `/_electric/wake-callbacks/${encodeURIComponent(input.claim.wake_id)}`),
5661
5674
  claimToken: input.claim.token,
5662
5675
  triggerEvent: `message_received`,
package/dist/index.cjs CHANGED
@@ -1218,35 +1218,48 @@ const LOG_LEVEL = process.env.ELECTRIC_AGENTS_LOG_LEVEL ?? `info`;
1218
1218
  const IS_ELECTRON_MAIN = Boolean(process.versions.electron);
1219
1219
  const USE_FILE_LOGS = process.env.ELECTRIC_AGENTS_LOG_FILE !== `false`;
1220
1220
  const USE_PRETTY_LOGS = LOG_LEVEL !== `silent` && !process.env.VITEST && !IS_ELECTRON_MAIN;
1221
- const LOG_DIR = USE_FILE_LOGS ? process.env.ELECTRIC_AGENTS_LOG_DIR ?? node_path.default.resolve(process.cwd(), `logs`) : void 0;
1222
- const LOG_FILE = LOG_DIR ? node_path.default.join(LOG_DIR, `agent-server-${Date.now()}.jsonl`) : void 0;
1223
- if (LOG_DIR) node_fs.default.mkdirSync(LOG_DIR, { recursive: true });
1224
- const streams = [];
1225
- if (LOG_FILE) streams.push({ stream: pino.default.destination({
1226
- dest: LOG_FILE,
1227
- sync: IS_ELECTRON_MAIN
1228
- }) });
1229
- if (USE_PRETTY_LOGS) streams.push({ stream: pino.default.transport({
1230
- target: `pino-pretty`,
1231
- options: {
1232
- colorize: true,
1233
- ignore: `pid,hostname,name`,
1234
- translateTime: `SYS:HH:MM:ss`
1235
- }
1236
- }) });
1237
- const logger = streams.length > 0 ? (0, pino.default)({
1238
- base: void 0,
1239
- level: LOG_LEVEL
1240
- }, pino.default.multistream(streams)) : (0, pino.default)({
1241
- base: void 0,
1242
- enabled: false,
1243
- level: LOG_LEVEL
1244
- });
1221
+ let _logger;
1222
+ function getLogger() {
1223
+ if (_logger) return _logger;
1224
+ const streams = [];
1225
+ try {
1226
+ if (USE_FILE_LOGS) {
1227
+ const logDir = process.env.ELECTRIC_AGENTS_LOG_DIR ?? node_path.default.resolve(process.cwd(), `logs`);
1228
+ node_fs.default.mkdirSync(logDir, { recursive: true });
1229
+ const logFile = node_path.default.join(logDir, `agent-server-${Date.now()}.jsonl`);
1230
+ streams.push({ stream: pino.default.destination({
1231
+ dest: logFile,
1232
+ sync: IS_ELECTRON_MAIN
1233
+ }) });
1234
+ }
1235
+ } catch (err) {
1236
+ process.stderr.write(`[agents-server] Failed to initialize file logging: ${err instanceof Error ? err.message : err}\n`);
1237
+ }
1238
+ try {
1239
+ if (USE_PRETTY_LOGS) streams.push({ stream: pino.default.transport({
1240
+ target: `pino-pretty`,
1241
+ options: {
1242
+ colorize: true,
1243
+ ignore: `pid,hostname,name`,
1244
+ translateTime: `SYS:HH:MM:ss`
1245
+ }
1246
+ }) });
1247
+ } catch {}
1248
+ _logger = streams.length > 0 ? (0, pino.default)({
1249
+ base: void 0,
1250
+ level: LOG_LEVEL
1251
+ }, pino.default.multistream(streams)) : (0, pino.default)({
1252
+ base: void 0,
1253
+ enabled: false,
1254
+ level: LOG_LEVEL
1255
+ });
1256
+ return _logger;
1257
+ }
1245
1258
  function formatArgs(args) {
1246
1259
  const errors = [];
1247
1260
  const parts = [];
1248
- for (const a of args) if (a instanceof Error) errors.push(a);
1249
- else parts.push(typeof a === `string` ? a : JSON.stringify(a));
1261
+ for (const value of args) if (value instanceof Error) errors.push(value);
1262
+ else parts.push(typeof value === `string` ? value : JSON.stringify(value));
1250
1263
  return {
1251
1264
  err: errors[0],
1252
1265
  msg: parts.join(` `)
@@ -1255,20 +1268,20 @@ function formatArgs(args) {
1255
1268
  const serverLog = {
1256
1269
  info(...args) {
1257
1270
  const { msg } = formatArgs(args);
1258
- logger.info(msg);
1271
+ getLogger().info(msg);
1259
1272
  },
1260
1273
  warn(...args) {
1261
1274
  const { err, msg } = formatArgs(args);
1262
- if (err) logger.warn({ err }, msg);
1263
- else logger.warn(msg);
1275
+ if (err) getLogger().warn({ err }, msg);
1276
+ else getLogger().warn(msg);
1264
1277
  },
1265
1278
  error(...args) {
1266
1279
  const { err, msg } = formatArgs(args);
1267
- if (err) logger.error({ err }, msg);
1268
- else logger.error(msg);
1280
+ if (err) getLogger().error({ err }, msg);
1281
+ else getLogger().error(msg);
1269
1282
  },
1270
1283
  event(obj, msg) {
1271
- logger.info(obj, msg);
1284
+ getLogger().info(obj, msg);
1272
1285
  }
1273
1286
  };
1274
1287
 
@@ -2248,11 +2261,11 @@ var StreamClient = class {
2248
2261
  if (res.status === 404 || res.status === 204) return;
2249
2262
  if (!res.ok) throw new Error(`Subscription delete failed: ${res.status} ${await res.text()}`);
2250
2263
  }
2251
- async addSubscriptionStreams(subscriptionId, streams$1) {
2264
+ async addSubscriptionStreams(subscriptionId, streams) {
2252
2265
  const res = await fetch(this.subscriptionChildUrl(subscriptionId, `streams`), {
2253
2266
  method: `POST`,
2254
2267
  headers: await this.requestHeaders({ "content-type": `application/json` }),
2255
- body: JSON.stringify({ streams: streams$1.map((stream) => this.backendSubscriptionPath(normalizeSubscriptionStreamPath(stream))) })
2268
+ body: JSON.stringify({ streams: streams.map((stream) => this.backendSubscriptionPath(normalizeSubscriptionStreamPath(stream))) })
2256
2269
  });
2257
2270
  return await this.subscriptionJson(res, `Subscription stream add failed`);
2258
2271
  }
@@ -7884,7 +7897,7 @@ async function notificationFromClaim(ctx, input) {
7884
7897
  leaseExpiresAt: input.claim.lease_ttl_ms ? new Date(Date.now() + input.claim.lease_ttl_ms) : void 0
7885
7898
  });
7886
7899
  await ctx.entityManager.registry.updateStatus(entity.url, `running`);
7887
- const streams$1 = input.claim.streams.map((stream) => ({
7900
+ const streams = input.claim.streams.map((stream) => ({
7888
7901
  path: withLeadingSlash(stream.path),
7889
7902
  offset: stream.tail_offset ?? ``
7890
7903
  }));
@@ -7893,7 +7906,7 @@ async function notificationFromClaim(ctx, input) {
7893
7906
  epoch: input.claim.generation,
7894
7907
  wakeId: input.claim.wake_id,
7895
7908
  streamPath: primaryStream,
7896
- streams: streams$1,
7909
+ streams,
7897
7910
  callback: (0, __electric_ax_agents_runtime.appendPathToUrl)(ctx.publicUrl, `/_electric/wake-callbacks/${encodeURIComponent(input.claim.wake_id)}`),
7898
7911
  claimToken: input.claim.token,
7899
7912
  triggerEvent: `message_received`,
package/dist/index.js CHANGED
@@ -1189,35 +1189,48 @@ const LOG_LEVEL = process.env.ELECTRIC_AGENTS_LOG_LEVEL ?? `info`;
1189
1189
  const IS_ELECTRON_MAIN = Boolean(process.versions.electron);
1190
1190
  const USE_FILE_LOGS = process.env.ELECTRIC_AGENTS_LOG_FILE !== `false`;
1191
1191
  const USE_PRETTY_LOGS = LOG_LEVEL !== `silent` && !process.env.VITEST && !IS_ELECTRON_MAIN;
1192
- const LOG_DIR = USE_FILE_LOGS ? process.env.ELECTRIC_AGENTS_LOG_DIR ?? path.resolve(process.cwd(), `logs`) : void 0;
1193
- const LOG_FILE = LOG_DIR ? path.join(LOG_DIR, `agent-server-${Date.now()}.jsonl`) : void 0;
1194
- if (LOG_DIR) fs.mkdirSync(LOG_DIR, { recursive: true });
1195
- const streams = [];
1196
- if (LOG_FILE) streams.push({ stream: pino.destination({
1197
- dest: LOG_FILE,
1198
- sync: IS_ELECTRON_MAIN
1199
- }) });
1200
- if (USE_PRETTY_LOGS) streams.push({ stream: pino.transport({
1201
- target: `pino-pretty`,
1202
- options: {
1203
- colorize: true,
1204
- ignore: `pid,hostname,name`,
1205
- translateTime: `SYS:HH:MM:ss`
1206
- }
1207
- }) });
1208
- const logger = streams.length > 0 ? pino({
1209
- base: void 0,
1210
- level: LOG_LEVEL
1211
- }, pino.multistream(streams)) : pino({
1212
- base: void 0,
1213
- enabled: false,
1214
- level: LOG_LEVEL
1215
- });
1192
+ let _logger;
1193
+ function getLogger() {
1194
+ if (_logger) return _logger;
1195
+ const streams = [];
1196
+ try {
1197
+ if (USE_FILE_LOGS) {
1198
+ const logDir = process.env.ELECTRIC_AGENTS_LOG_DIR ?? path.resolve(process.cwd(), `logs`);
1199
+ fs.mkdirSync(logDir, { recursive: true });
1200
+ const logFile = path.join(logDir, `agent-server-${Date.now()}.jsonl`);
1201
+ streams.push({ stream: pino.destination({
1202
+ dest: logFile,
1203
+ sync: IS_ELECTRON_MAIN
1204
+ }) });
1205
+ }
1206
+ } catch (err) {
1207
+ process.stderr.write(`[agents-server] Failed to initialize file logging: ${err instanceof Error ? err.message : err}\n`);
1208
+ }
1209
+ try {
1210
+ if (USE_PRETTY_LOGS) streams.push({ stream: pino.transport({
1211
+ target: `pino-pretty`,
1212
+ options: {
1213
+ colorize: true,
1214
+ ignore: `pid,hostname,name`,
1215
+ translateTime: `SYS:HH:MM:ss`
1216
+ }
1217
+ }) });
1218
+ } catch {}
1219
+ _logger = streams.length > 0 ? pino({
1220
+ base: void 0,
1221
+ level: LOG_LEVEL
1222
+ }, pino.multistream(streams)) : pino({
1223
+ base: void 0,
1224
+ enabled: false,
1225
+ level: LOG_LEVEL
1226
+ });
1227
+ return _logger;
1228
+ }
1216
1229
  function formatArgs(args) {
1217
1230
  const errors = [];
1218
1231
  const parts = [];
1219
- for (const a of args) if (a instanceof Error) errors.push(a);
1220
- else parts.push(typeof a === `string` ? a : JSON.stringify(a));
1232
+ for (const value of args) if (value instanceof Error) errors.push(value);
1233
+ else parts.push(typeof value === `string` ? value : JSON.stringify(value));
1221
1234
  return {
1222
1235
  err: errors[0],
1223
1236
  msg: parts.join(` `)
@@ -1226,20 +1239,20 @@ function formatArgs(args) {
1226
1239
  const serverLog = {
1227
1240
  info(...args) {
1228
1241
  const { msg } = formatArgs(args);
1229
- logger.info(msg);
1242
+ getLogger().info(msg);
1230
1243
  },
1231
1244
  warn(...args) {
1232
1245
  const { err, msg } = formatArgs(args);
1233
- if (err) logger.warn({ err }, msg);
1234
- else logger.warn(msg);
1246
+ if (err) getLogger().warn({ err }, msg);
1247
+ else getLogger().warn(msg);
1235
1248
  },
1236
1249
  error(...args) {
1237
1250
  const { err, msg } = formatArgs(args);
1238
- if (err) logger.error({ err }, msg);
1239
- else logger.error(msg);
1251
+ if (err) getLogger().error({ err }, msg);
1252
+ else getLogger().error(msg);
1240
1253
  },
1241
1254
  event(obj, msg) {
1242
- logger.info(obj, msg);
1255
+ getLogger().info(obj, msg);
1243
1256
  }
1244
1257
  };
1245
1258
 
@@ -2219,11 +2232,11 @@ var StreamClient = class {
2219
2232
  if (res.status === 404 || res.status === 204) return;
2220
2233
  if (!res.ok) throw new Error(`Subscription delete failed: ${res.status} ${await res.text()}`);
2221
2234
  }
2222
- async addSubscriptionStreams(subscriptionId, streams$1) {
2235
+ async addSubscriptionStreams(subscriptionId, streams) {
2223
2236
  const res = await fetch(this.subscriptionChildUrl(subscriptionId, `streams`), {
2224
2237
  method: `POST`,
2225
2238
  headers: await this.requestHeaders({ "content-type": `application/json` }),
2226
- body: JSON.stringify({ streams: streams$1.map((stream) => this.backendSubscriptionPath(normalizeSubscriptionStreamPath(stream))) })
2239
+ body: JSON.stringify({ streams: streams.map((stream) => this.backendSubscriptionPath(normalizeSubscriptionStreamPath(stream))) })
2227
2240
  });
2228
2241
  return await this.subscriptionJson(res, `Subscription stream add failed`);
2229
2242
  }
@@ -7855,7 +7868,7 @@ async function notificationFromClaim(ctx, input) {
7855
7868
  leaseExpiresAt: input.claim.lease_ttl_ms ? new Date(Date.now() + input.claim.lease_ttl_ms) : void 0
7856
7869
  });
7857
7870
  await ctx.entityManager.registry.updateStatus(entity.url, `running`);
7858
- const streams$1 = input.claim.streams.map((stream) => ({
7871
+ const streams = input.claim.streams.map((stream) => ({
7859
7872
  path: withLeadingSlash(stream.path),
7860
7873
  offset: stream.tail_offset ?? ``
7861
7874
  }));
@@ -7864,7 +7877,7 @@ async function notificationFromClaim(ctx, input) {
7864
7877
  epoch: input.claim.generation,
7865
7878
  wakeId: input.claim.wake_id,
7866
7879
  streamPath: primaryStream,
7867
- streams: streams$1,
7880
+ streams,
7868
7881
  callback: appendPathToUrl(ctx.publicUrl, `/_electric/wake-callbacks/${encodeURIComponent(input.claim.wake_id)}`),
7869
7882
  claimToken: input.claim.token,
7870
7883
  triggerEvent: `message_received`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-ax/agents-server",
3
- "version": "0.4.13",
3
+ "version": "0.4.14",
4
4
  "description": "Electric Agents entity runtime server",
5
5
  "author": "Durable Stream contributors",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  "@durable-streams/client": "^0.2.6",
40
40
  "@durable-streams/server": "^0.3.5",
41
41
  "@durable-streams/state": "^0.2.9",
42
- "@electric-sql/client": "^1.5.19",
42
+ "@electric-sql/client": "^1.5.20",
43
43
  "@mariozechner/pi-agent-core": "^0.70.2",
44
44
  "@opentelemetry/api": "^1.9.1",
45
45
  "@sinclair/typebox": "^0.34.48",
@@ -54,7 +54,7 @@
54
54
  "pino-pretty": "^13.0.0",
55
55
  "postgres": "^3.4.0",
56
56
  "undici": "^7.24.7",
57
- "@electric-ax/agents-runtime": "0.3.6"
57
+ "@electric-ax/agents-runtime": "0.3.7"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/node": "^22.19.15",
@@ -65,9 +65,9 @@
65
65
  "tsx": "^4.19.0",
66
66
  "typescript": "^5.0.0",
67
67
  "vitest": "^4.1.0",
68
- "@electric-ax/agents": "0.4.10",
68
+ "@electric-ax/agents": "0.4.11",
69
69
  "@electric-ax/agents-server-conformance-tests": "0.1.9",
70
- "@electric-ax/agents-server-ui": "0.4.13"
70
+ "@electric-ax/agents-server-ui": "0.4.14"
71
71
  },
72
72
  "files": [
73
73
  "dist",
package/src/utils/log.ts CHANGED
@@ -8,62 +8,73 @@ const USE_FILE_LOGS = process.env.ELECTRIC_AGENTS_LOG_FILE !== `false`
8
8
  const USE_PRETTY_LOGS =
9
9
  LOG_LEVEL !== `silent` && !process.env.VITEST && !IS_ELECTRON_MAIN
10
10
 
11
- const LOG_DIR = USE_FILE_LOGS
12
- ? (process.env.ELECTRIC_AGENTS_LOG_DIR ?? path.resolve(process.cwd(), `logs`))
13
- : undefined
14
- const LOG_FILE = LOG_DIR
15
- ? path.join(LOG_DIR, `agent-server-${Date.now()}.jsonl`)
16
- : undefined
11
+ let _logger: pino.Logger | undefined
17
12
 
18
- if (LOG_DIR) {
19
- fs.mkdirSync(LOG_DIR, { recursive: true })
20
- }
13
+ function getLogger(): pino.Logger {
14
+ if (_logger) return _logger
21
15
 
22
- export const LOG_FILE_PATH = LOG_FILE
16
+ const streams: Array<pino.StreamEntry> = []
23
17
 
24
- const streams: Array<pino.StreamEntry> = []
25
- if (LOG_FILE) {
26
- streams.push({
27
- stream: pino.destination({
28
- dest: LOG_FILE,
29
- sync: IS_ELECTRON_MAIN,
30
- }),
31
- })
32
- }
33
- if (USE_PRETTY_LOGS) {
34
- streams.push({
35
- stream: pino.transport({
36
- target: `pino-pretty`,
37
- options: {
38
- colorize: true,
39
- ignore: `pid,hostname,name`,
40
- translateTime: `SYS:HH:MM:ss`,
41
- },
42
- }),
43
- })
44
- }
18
+ try {
19
+ if (USE_FILE_LOGS) {
20
+ const logDir =
21
+ process.env.ELECTRIC_AGENTS_LOG_DIR ??
22
+ path.resolve(process.cwd(), `logs`)
23
+ fs.mkdirSync(logDir, { recursive: true })
24
+ const logFile = path.join(logDir, `agent-server-${Date.now()}.jsonl`)
25
+ streams.push({
26
+ stream: pino.destination({
27
+ dest: logFile,
28
+ sync: IS_ELECTRON_MAIN,
29
+ }),
30
+ })
31
+ }
32
+ } catch (err) {
33
+ process.stderr.write(
34
+ `[agents-server] Failed to initialize file logging: ${err instanceof Error ? err.message : err}\n`
35
+ )
36
+ }
45
37
 
46
- const logger =
47
- streams.length > 0
48
- ? pino(
49
- {
38
+ try {
39
+ if (USE_PRETTY_LOGS) {
40
+ streams.push({
41
+ stream: pino.transport({
42
+ target: `pino-pretty`,
43
+ options: {
44
+ colorize: true,
45
+ ignore: `pid,hostname,name`,
46
+ translateTime: `SYS:HH:MM:ss`,
47
+ },
48
+ }),
49
+ })
50
+ }
51
+ } catch {
52
+ // pino-pretty unavailable — continue without pretty logging
53
+ }
54
+
55
+ _logger =
56
+ streams.length > 0
57
+ ? pino(
58
+ {
59
+ base: undefined,
60
+ level: LOG_LEVEL,
61
+ },
62
+ pino.multistream(streams)
63
+ )
64
+ : pino({
50
65
  base: undefined,
66
+ enabled: false,
51
67
  level: LOG_LEVEL,
52
- },
53
- pino.multistream(streams)
54
- )
55
- : pino({
56
- base: undefined,
57
- enabled: false,
58
- level: LOG_LEVEL,
59
- })
68
+ })
69
+ return _logger
70
+ }
60
71
 
61
72
  function formatArgs(args: Array<unknown>): { err?: Error; msg: string } {
62
73
  const errors: Array<Error> = []
63
74
  const parts: Array<string> = []
64
- for (const a of args) {
65
- if (a instanceof Error) errors.push(a)
66
- else parts.push(typeof a === `string` ? a : JSON.stringify(a))
75
+ for (const value of args) {
76
+ if (value instanceof Error) errors.push(value)
77
+ else parts.push(typeof value === `string` ? value : JSON.stringify(value))
67
78
  }
68
79
  return {
69
80
  err: errors[0],
@@ -74,22 +85,22 @@ function formatArgs(args: Array<unknown>): { err?: Error; msg: string } {
74
85
  export const serverLog = {
75
86
  info(...args: Array<unknown>): void {
76
87
  const { msg } = formatArgs(args)
77
- logger.info(msg)
88
+ getLogger().info(msg)
78
89
  },
79
90
 
80
91
  warn(...args: Array<unknown>): void {
81
92
  const { err, msg } = formatArgs(args)
82
- if (err) logger.warn({ err }, msg)
83
- else logger.warn(msg)
93
+ if (err) getLogger().warn({ err }, msg)
94
+ else getLogger().warn(msg)
84
95
  },
85
96
 
86
97
  error(...args: Array<unknown>): void {
87
98
  const { err, msg } = formatArgs(args)
88
- if (err) logger.error({ err }, msg)
89
- else logger.error(msg)
99
+ if (err) getLogger().error({ err }, msg)
100
+ else getLogger().error(msg)
90
101
  },
91
102
 
92
103
  event(obj: Record<string, unknown>, msg: string): void {
93
- logger.info(obj, msg)
104
+ getLogger().info(obj, msg)
94
105
  },
95
106
  }