@agent-team-foundation/first-tree-hub 0.9.3 → 0.9.6

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.
@@ -1,19 +1,20 @@
1
- import { f as __require, l as __commonJSMin, m as __toESM } from "./esm-CYu4tXXn.mjs";
2
- import { C as serverConfigSchema, S as resolveConfigReadonly, _ as loadAgents, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, v as migrateLegacyHome, w as setConfigValue } from "./bootstrap-CWcBzk6C.mjs";
3
- import { _ as withSpan, a as endWsConnectionSpan, b as require_pino, c as messageAttrs, d as rootLogger$1, g as startWsConnectionSpan, i as currentTraceId, n as applyLoggerConfig, o as getFastifyOtelPlugin, p as setWsConnectionAttrs, r as createLogger, t as adapterAttrs, u as observabilityPlugin, v as withWsMessageSpan, y as FIRST_TREE_HUB_ATTR } from "./observability-CJzDFY_G-CmvgUuzc.mjs";
1
+ import { m as __toESM } from "./esm-CYu4tXXn.mjs";
2
+ import { _ as withSpan, a as endWsConnectionSpan, b as require_pino, c as messageAttrs, d as rootLogger$1, g as startWsConnectionSpan, i as currentTraceId, n as applyLoggerConfig, o as getFastifyOtelPlugin, p as setWsConnectionAttrs, r as createLogger$1, t as adapterAttrs, u as observabilityPlugin, v as withWsMessageSpan, y as FIRST_TREE_HUB_ATTR } from "./observability-DV_fQKqV-CuLWzBxQ.mjs";
3
+ import { s as formatPrettyEntry$1, t as LOG_LEVELS$1, u as parseLogLevel$1 } from "./logger-core-BTmvdflj-DhdipBkV.mjs";
4
+ import { C as serverConfigSchema, S as resolveConfigReadonly, _ as loadAgents, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, v as migrateLegacyHome, w as setConfigValue } from "./bootstrap-DWifXj9b.mjs";
4
5
  import { $ as updateAdapterConfigSchema, A as createMemberSchema, B as notificationQuerySchema, C as agentTypeSchema$1, D as createAdapterMappingSchema, E as createAdapterConfigSchema, F as inboxPollQuerySchema, G as sendMessageSchema, H as refreshTokenSchema, I as isRedactedEnvValue, J as sessionEventMessageSchema, K as sendToAgentSchema, L as linkTaskChatSchema, M as createTaskSchema, N as delegateFeishuUserSchema, O as createAgentSchema, P as dryRunAgentRuntimeConfigSchema, Q as taskListQuerySchema, R as loginSchema, S as agentRuntimeConfigPayloadSchema$1, T as connectTokenExchangeSchema, U as runtimeStateMessageSchema, V as paginationQuerySchema, W as selfServiceFeishuBotSchema, X as sessionReconcileRequestSchema, Y as sessionEventSchema$1, Z as sessionStateMessageSchema, _ as addParticipantSchema, a as AGENT_SELECTOR_HEADER$1, at as updateSystemConfigSchema, b as agentBindRequestSchema, c as AGENT_TYPES, d as SYSTEM_CONFIG_DEFAULTS, et as updateAgentRuntimeConfigSchema, f as TASK_CREATOR_TYPES, g as WS_AUTH_FRAME_TIMEOUT_MS, h as TASK_TERMINAL_STATUSES, i as AGENT_BIND_REJECT_REASONS, it as updateOrganizationSchema, j as createOrganizationSchema, k as createChatSchema, l as AGENT_VISIBILITY, m as TASK_STATUSES, nt as updateChatSchema, o as AGENT_SOURCES, ot as updateTaskStatusSchema, p as TASK_HEALTH_SIGNALS, q as sessionCompletionMessageSchema, rt as updateMemberSchema, s as AGENT_STATUSES, st as wsAuthFrameSchema, tt as updateAgentSchema, u as DEFAULT_AGENT_RUNTIME_CONFIG_PAYLOAD, v as adminCreateTaskSchema, w as clientRegisterSchema, x as agentPinnedMessageSchema$1, y as adminUpdateTaskSchema, z as messageSourceSchema$1 } from "./feishu-GlaczcVf.mjs";
5
6
  import { createRequire } from "node:module";
6
- import { copyFileSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, watch, writeFileSync } from "node:fs";
7
- import { dirname, extname, isAbsolute, join, resolve } from "node:path";
8
7
  import { ZodError, z } from "zod";
8
+ import { dirname, isAbsolute, join, resolve } from "node:path";
9
9
  import { Writable } from "node:stream";
10
- import { stringify } from "yaml";
11
- import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
12
10
  import { homedir, hostname, platform, userInfo } from "node:os";
13
11
  import { EventEmitter } from "node:events";
12
+ import { closeSync, copyFileSync, createReadStream, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, unwatchFile, watch, watchFile, writeFileSync, writeSync } from "node:fs";
13
+ import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
14
14
  import WebSocket from "ws";
15
15
  import { query } from "@anthropic-ai/claude-agent-sdk";
16
16
  import { execFileSync, execSync, spawn, spawnSync } from "node:child_process";
17
+ import { stringify } from "yaml";
17
18
  import * as semver from "semver";
18
19
  import bcrypt from "bcrypt";
19
20
  import { and, asc, count, desc, eq, gt, inArray, isNotNull, isNull, lt, ne, or, sql } from "drizzle-orm";
@@ -30,7 +31,8 @@ import Fastify from "fastify";
30
31
  import { bigserial, boolean, index, integer, jsonb, pgTable, primaryKey, serial, text, timestamp, unique, uniqueIndex } from "drizzle-orm/pg-core";
31
32
  import { SignJWT, jwtVerify } from "jose";
32
33
  import { Client, EventDispatcher, LoggerLevel, WSClient } from "@larksuiteoapi/node-sdk";
33
- //#region ../client/dist/observability-BUvHY6T-.mjs
34
+ import { createInterface } from "node:readline";
35
+ //#region ../client/dist/observability-B4kO005X.mjs
34
36
  var import_pino = /* @__PURE__ */ __toESM(require_pino(), 1);
35
37
  /**
36
38
  * Logger core — format / level primitives shared between server and client.
@@ -97,6 +99,39 @@ const SKIP_KEYS = new Set([
97
99
  "hostname",
98
100
  "v"
99
101
  ]);
102
+ /**
103
+ * Pino `redact.paths` entries applied to every root logger in Hub. Keeps the
104
+ * list short on purpose — pino's redact walks each path on every log call, so
105
+ * we target obvious sensitive field names plus a narrow set of nested forms
106
+ * (`*.foo` matches a single nesting level in pino v9).
107
+ *
108
+ * Values matching these paths are replaced with the censor string `[REDACTED]`.
109
+ */
110
+ const LOG_REDACT_PATHS = [
111
+ "password",
112
+ "*.password",
113
+ "token",
114
+ "*.token",
115
+ "accessToken",
116
+ "*.accessToken",
117
+ "refreshToken",
118
+ "*.refreshToken",
119
+ "jwt",
120
+ "*.jwt",
121
+ "secret",
122
+ "*.secret",
123
+ "apiKey",
124
+ "*.apiKey",
125
+ "api_key",
126
+ "*.api_key",
127
+ "credentials",
128
+ "*.credentials",
129
+ "authorization",
130
+ "*.authorization",
131
+ "*.headers.cookie",
132
+ "*.headers.authorization"
133
+ ];
134
+ const LOG_REDACT_CENSOR = "[REDACTED]";
100
135
  function formatPrettyEntry(json) {
101
136
  const obj = JSON.parse(json);
102
137
  const level = obj.level;
@@ -123,42 +158,146 @@ function formatLocalTime() {
123
158
  return `${d.toLocaleDateString("sv-SE")} ${d.toLocaleTimeString("en-GB", { hour12: false })}`;
124
159
  }
125
160
  function createLoggerOutputStream(options) {
161
+ const getDest = options.getDestination ?? (() => process.stderr);
126
162
  return new Writable({ write(chunk, _, callback) {
127
163
  const text = chunk.toString();
164
+ const dest = getDest();
128
165
  try {
129
- if (options.getFormat() === "pretty") process.stdout.write(formatPrettyEntry(text));
130
- else process.stdout.write(text);
166
+ if (options.getFormat() === "pretty") dest.write(formatPrettyEntry(text));
167
+ else dest.write(text);
131
168
  if (options.onJsonEntry) try {
132
169
  const obj = JSON.parse(text);
133
170
  options.onJsonEntry(obj);
134
171
  } catch {}
135
172
  } catch {
136
- process.stdout.write(text);
173
+ dest.write(text);
137
174
  }
138
175
  callback();
139
176
  } });
140
177
  }
178
+ var RotatingFileStream = class extends Writable {
179
+ size;
180
+ fd;
181
+ path;
182
+ maxBytes;
183
+ maxFiles;
184
+ constructor(options) {
185
+ super();
186
+ this.path = options.path;
187
+ this.maxBytes = options.maxBytes;
188
+ this.maxFiles = Math.max(1, options.maxFiles);
189
+ mkdirSync(dirname(this.path), {
190
+ recursive: true,
191
+ mode: 448
192
+ });
193
+ try {
194
+ this.size = statSync(this.path).size;
195
+ } catch {
196
+ this.size = 0;
197
+ }
198
+ this.fd = openSync(this.path, "a", 384);
199
+ }
200
+ _write(chunk, _enc, callback) {
201
+ try {
202
+ const buf = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
203
+ writeSync(this.fd, buf);
204
+ this.size += buf.length;
205
+ if (this.size >= this.maxBytes) this.rotate();
206
+ callback();
207
+ } catch (err) {
208
+ callback(err instanceof Error ? err : new Error(String(err)));
209
+ }
210
+ }
211
+ _final(callback) {
212
+ try {
213
+ closeSync(this.fd);
214
+ callback();
215
+ } catch (err) {
216
+ callback(err instanceof Error ? err : new Error(String(err)));
217
+ }
218
+ }
219
+ rotate() {
220
+ closeSync(this.fd);
221
+ for (let i = this.maxFiles - 1; i >= 1; i--) renameIfExists(`${this.path}.${i}`, `${this.path}.${i + 1}`);
222
+ unlinkIfExists(`${this.path}.1`);
223
+ renameSync(this.path, `${this.path}.1`);
224
+ this.fd = openSync(this.path, "a", 384);
225
+ this.size = 0;
226
+ }
227
+ };
228
+ function isNotFound(err) {
229
+ return err instanceof Error && "code" in err && err.code === "ENOENT";
230
+ }
231
+ function renameIfExists(from, to) {
232
+ try {
233
+ unlinkIfExists(to);
234
+ renameSync(from, to);
235
+ } catch (err) {
236
+ if (!isNotFound(err)) throw err;
237
+ }
238
+ }
239
+ function unlinkIfExists(path) {
240
+ try {
241
+ unlinkSync(path);
242
+ } catch (err) {
243
+ if (!isNotFound(err)) throw err;
244
+ }
245
+ }
246
+ /** Rotation defaults for the background service log file. */
247
+ const SERVICE_LOG_MAX_BYTES = 10 * 1024 * 1024;
248
+ const SERVICE_LOG_MAX_FILES = 7;
141
249
  /**
142
250
  * Client-side logger. Same pretty / NDJSON formats as the server logger, but
143
251
  * intentionally lightweight — the client is deployed to agent user machines,
144
252
  * so we skip tracing, context propagation, and error sinks.
145
253
  */
146
254
  const initialLevel = parseLogLevel(process.env.FIRST_TREE_HUB_LOG_LEVEL);
255
+ const initialPinoLevel = process.env.NODE_ENV === "test" && !process.env.FIRST_TREE_HUB_LOG_LEVEL ? "silent" : initialLevel.level;
147
256
  let _format = process.env.NODE_ENV === "production" ? "json" : "pretty";
148
- let _level = initialLevel.level;
257
+ let _destination = process.stderr;
258
+ let _levelExplicit = false;
149
259
  function applyClientLoggerConfig(options = {}) {
150
- if (options.level) {
151
- _level = options.level;
152
- rootLogger.level = options.level;
153
- }
260
+ if (options.explicit === false) _levelExplicit = false;
261
+ if (options.level !== void 0 && (options.explicit === true || !_levelExplicit)) rootLogger.level = options.level;
262
+ if (options.explicit === true) _levelExplicit = true;
154
263
  if (options.format) _format = options.format;
264
+ if (options.destination) _destination = options.destination;
155
265
  }
156
- const outputStream = createLoggerOutputStream({ getFormat: () => _format });
266
+ const outputStream = createLoggerOutputStream({
267
+ getFormat: () => _format,
268
+ getDestination: () => _destination
269
+ });
157
270
  const rootLogger = (0, import_pino.default)({
158
- level: _level,
159
- timestamp: () => `,"time":"${formatLocalTime()}"`
271
+ level: initialPinoLevel,
272
+ timestamp: () => `,"time":"${formatLocalTime()}"`,
273
+ redact: {
274
+ paths: [...LOG_REDACT_PATHS],
275
+ censor: LOG_REDACT_CENSOR
276
+ }
160
277
  }, outputStream);
161
278
  if (initialLevel.fellBack) rootLogger.warn({ envValue: process.env.FIRST_TREE_HUB_LOG_LEVEL }, "invalid FIRST_TREE_HUB_LOG_LEVEL; falling back to info");
279
+ function createLogger(module) {
280
+ return rootLogger.child({ module });
281
+ }
282
+ /**
283
+ * Switch the client logger over to the background-service file sink.
284
+ *
285
+ * The launchd / systemd unit files already set `StandardOutPath` /
286
+ * `StandardError` as a fallback for crash-time stderr; this routes normal
287
+ * operational logs into a size-rotated NDJSON file at
288
+ * `<logDir>/client.log` so it doesn't grow unbounded. Must be called once
289
+ * at `client start` when running under `FIRST_TREE_HUB_SERVICE_MODE=1`.
290
+ */
291
+ function configureClientLoggerForService(logDir) {
292
+ applyClientLoggerConfig({
293
+ format: "json",
294
+ destination: new RotatingFileStream({
295
+ path: join(logDir, "client.log"),
296
+ maxBytes: SERVICE_LOG_MAX_BYTES,
297
+ maxFiles: SERVICE_LOG_MAX_FILES
298
+ })
299
+ });
300
+ }
162
301
  //#endregion
163
302
  //#region ../client/dist/index.mjs
164
303
  const adapterPlatformSchema = z.enum([
@@ -1148,6 +1287,8 @@ var ClientConnection = class extends EventEmitter {
1148
1287
  registered = false;
1149
1288
  /** Count of `server:welcome` frames received; drives `isReconnect` flag. */
1150
1289
  welcomeFramesReceived = 0;
1290
+ wsLogger;
1291
+ authLogger;
1151
1292
  boundAgents = /* @__PURE__ */ new Map();
1152
1293
  /** Agents scheduled to rebind automatically on every reconnect. */
1153
1294
  desiredBindings = /* @__PURE__ */ new Map();
@@ -1158,6 +1299,8 @@ var ClientConnection = class extends EventEmitter {
1158
1299
  this.serverUrl = config.serverUrl.replace(/\/+$/, "");
1159
1300
  this.sdkVersion = config.sdkVersion;
1160
1301
  this.getAccessToken = config.getAccessToken;
1302
+ this.wsLogger = createLogger("ws").child({ clientId: this.clientId });
1303
+ this.authLogger = createLogger("auth").child({ clientId: this.clientId });
1161
1304
  this.on("error", () => {});
1162
1305
  }
1163
1306
  get isConnected() {
@@ -1270,7 +1413,9 @@ var ClientConnection = class extends EventEmitter {
1270
1413
  }
1271
1414
  openWebSocket() {
1272
1415
  return new Promise((resolve, reject) => {
1273
- const ws = new WebSocket(`${this.serverUrl.replace(/^http/, "ws")}/api/v1/agent/ws/client`);
1416
+ const wsUrl = `${this.serverUrl.replace(/^http/, "ws")}/api/v1/agent/ws/client`;
1417
+ this.wsLogger.info({ url: wsUrl }, "connecting");
1418
+ const ws = new WebSocket(wsUrl);
1274
1419
  let settled = false;
1275
1420
  const settle = (fn, value) => {
1276
1421
  if (settled) return;
@@ -1290,6 +1435,7 @@ var ClientConnection = class extends EventEmitter {
1290
1435
  ws.on("open", async () => {
1291
1436
  this.ws = ws;
1292
1437
  this.reconnectAttempt = 0;
1438
+ this.wsLogger.debug("socket opened, sending auth");
1293
1439
  try {
1294
1440
  const token = await this.getAccessToken();
1295
1441
  ws.send(JSON.stringify({
@@ -1298,6 +1444,7 @@ var ClientConnection = class extends EventEmitter {
1298
1444
  }));
1299
1445
  this.scheduleProactiveAuthRefresh(token);
1300
1446
  } catch (err) {
1447
+ this.authLogger.error({ err }, "failed to obtain access token");
1301
1448
  settle(reject, err instanceof Error ? err : new Error(String(err)));
1302
1449
  ws.close();
1303
1450
  }
@@ -1315,9 +1462,14 @@ var ClientConnection = class extends EventEmitter {
1315
1462
  this.registered = false;
1316
1463
  this.rejectAllPendingBinds("WebSocket closed");
1317
1464
  if (!settled) {
1465
+ this.wsLogger.warn({ code }, "closed before ready");
1318
1466
  settle(reject, /* @__PURE__ */ new Error(`WebSocket closed before ready (code ${code})`));
1319
1467
  return;
1320
1468
  }
1469
+ this.wsLogger.warn({
1470
+ code,
1471
+ wasRegistered
1472
+ }, "disconnected");
1321
1473
  if (!this.closing) {
1322
1474
  this.emit("disconnected");
1323
1475
  if (wasRegistered) this.scheduleReconnect();
@@ -1331,6 +1483,7 @@ var ClientConnection = class extends EventEmitter {
1331
1483
  handleMessage(msg, connectResolve) {
1332
1484
  const type = msg.type;
1333
1485
  if (type === "auth:ok") {
1486
+ this.authLogger.info("auth accepted, registering client");
1334
1487
  this.ws?.send(JSON.stringify({
1335
1488
  type: "client:register",
1336
1489
  clientId: this.clientId,
@@ -1343,7 +1496,7 @@ var ClientConnection = class extends EventEmitter {
1343
1496
  if (type === "server:welcome") {
1344
1497
  const parsed = serverWelcomeFrameSchema.safeParse(msg);
1345
1498
  if (!parsed.success) {
1346
- process.stderr.write(`[ClientConnection] Ignoring malformed server:welcome frame: ${parsed.error.issues.map((i) => i.message).join(", ")}\n`);
1499
+ this.wsLogger.warn({ issues: parsed.error.issues.map((i) => i.message) }, "ignoring malformed server:welcome frame");
1347
1500
  return;
1348
1501
  }
1349
1502
  const isReconnect = this.welcomeFramesReceived > 0;
@@ -1355,12 +1508,16 @@ var ClientConnection = class extends EventEmitter {
1355
1508
  return;
1356
1509
  }
1357
1510
  if (type === "auth:rejected" || type === "auth:expired") {
1358
- if (type === "auth:expired") this.emit("auth:expired");
1511
+ if (type === "auth:expired") {
1512
+ this.authLogger.info("token expired, reconnecting with fresh token");
1513
+ this.emit("auth:expired");
1514
+ } else this.authLogger.warn("auth rejected by server");
1359
1515
  this.ws?.close(4401, type);
1360
1516
  return;
1361
1517
  }
1362
1518
  if (type === "client:register:rejected") {
1363
1519
  const err = /* @__PURE__ */ new Error(`client:register rejected: ${msg.message ?? "unknown"}`);
1520
+ this.wsLogger.error({ message: msg.message }, "client register rejected");
1364
1521
  this.emit("error", err);
1365
1522
  this.ws?.close(4403, "register rejected");
1366
1523
  return;
@@ -1369,6 +1526,7 @@ var ClientConnection = class extends EventEmitter {
1369
1526
  const isReconnect = this.boundAgents.size > 0 || this.desiredBindings.size > 0;
1370
1527
  this.registered = true;
1371
1528
  this.startHeartbeat();
1529
+ this.wsLogger.info({ isReconnect }, "registered");
1372
1530
  this.emit("connected");
1373
1531
  connectResolve?.();
1374
1532
  if (isReconnect) this.rebindAgents();
@@ -1476,6 +1634,10 @@ var ClientConnection = class extends EventEmitter {
1476
1634
  this.reconnectAttempt++;
1477
1635
  this.emit("reconnecting", this.reconnectAttempt);
1478
1636
  const delay = Math.min(RECONNECT_BASE_MS * 2 ** (this.reconnectAttempt - 1), RECONNECT_MAX_MS);
1637
+ this.wsLogger.debug({
1638
+ attempt: this.reconnectAttempt,
1639
+ delayMs: delay
1640
+ }, "scheduling reconnect");
1479
1641
  this.reconnectTimer = setTimeout(() => {
1480
1642
  this.reconnectTimer = null;
1481
1643
  if (!this.closing) this.openWebSocket().catch((err) => {
@@ -1531,9 +1693,11 @@ var ClientConnection = class extends EventEmitter {
1531
1693
  if (!exp) return;
1532
1694
  const delay = exp * 1e3 - Date.now() - AUTH_REFRESH_LEAD_MS;
1533
1695
  if (delay <= 0) return;
1696
+ this.authLogger.debug({ delayMs: delay }, "scheduled proactive auth refresh");
1534
1697
  this.authRefreshTimer = setTimeout(() => {
1535
1698
  this.authRefreshTimer = null;
1536
1699
  if (this.closing) return;
1700
+ this.authLogger.info("triggering proactive auth refresh");
1537
1701
  this.ws?.close(1e3, "proactive auth refresh");
1538
1702
  }, delay);
1539
1703
  }
@@ -1890,7 +2054,7 @@ function looksLikeCommitSha(ref) {
1890
2054
  function createGitMirrorManager(opts) {
1891
2055
  const mirrorsRoot = join(opts.dataDir, "git-mirrors");
1892
2056
  const cloneTimeoutMs = opts.cloneTimeoutMs ?? Number(process.env.FIRST_TREE_HUB_GIT_CLONE_TIMEOUT_MS ?? DEFAULT_CLONE_TIMEOUT_MS);
1893
- const log = opts.log ?? (() => {});
2057
+ const log = opts.log;
1894
2058
  const urlLocks = /* @__PURE__ */ new Map();
1895
2059
  function withUrlLock(url, op) {
1896
2060
  const key = hashUrl(url);
@@ -2033,7 +2197,7 @@ function createGitMirrorManager(opts) {
2033
2197
  "origin",
2034
2198
  "--auto"
2035
2199
  ], mirrorPath, 3e4);
2036
- log("mirrorConfigMigrated", { gitUrl: url });
2200
+ log?.info({ gitUrl: url }, "mirror config migrated");
2037
2201
  }
2038
2202
  return { migrated };
2039
2203
  }
@@ -2137,22 +2301,22 @@ function createGitMirrorManager(opts) {
2137
2301
  try {
2138
2302
  await bootstrapMirror(path, url);
2139
2303
  const elapsedMs = Date.now() - start;
2140
- log("ensureMirror", {
2304
+ log?.debug({
2141
2305
  gitUrl: url,
2142
2306
  elapsedMs,
2143
2307
  cloned: true
2144
- });
2308
+ }, "mirror ensured");
2145
2309
  return {
2146
2310
  mirrorPath: path,
2147
2311
  elapsedMs,
2148
2312
  cloned: true
2149
2313
  };
2150
2314
  } catch (err) {
2151
- if (err instanceof GitMirrorTimeoutError) log("mirrorCloneTimeout", {
2315
+ if (err instanceof GitMirrorTimeoutError) log?.warn({
2152
2316
  gitUrl: url,
2153
2317
  timeoutMs: cloneTimeoutMs,
2154
2318
  elapsedMs: cloneTimeoutMs
2155
- });
2319
+ }, "mirror clone timeout");
2156
2320
  if (existsSync(path)) rmSync(path, {
2157
2321
  recursive: true,
2158
2322
  force: true
@@ -2173,11 +2337,11 @@ function createGitMirrorManager(opts) {
2173
2337
  ], path, cloneTimeoutMs);
2174
2338
  return { elapsedMs };
2175
2339
  } catch (err) {
2176
- log("mirrorFetchFailed", {
2340
+ log?.warn({
2177
2341
  gitUrl: url,
2178
2342
  errorCode: err instanceof GitMirrorError ? "git-failed" : "unknown",
2179
2343
  stderr: err instanceof Error ? err.message.slice(0, 1024) : String(err).slice(0, 1024)
2180
- });
2344
+ }, "mirror fetch failed");
2181
2345
  throw err;
2182
2346
  }
2183
2347
  });
@@ -2189,11 +2353,11 @@ function createGitMirrorManager(opts) {
2189
2353
  const absTarget = resolve(targetPath);
2190
2354
  const branchName = deriveSessionBranchName(sessionKey, url);
2191
2355
  if (existsSync(absTarget) && !isHubManagedWorktree(absTarget)) {
2192
- log("worktreeCreateConflict", {
2356
+ log?.warn({
2193
2357
  gitUrl: url,
2194
2358
  targetPath: absTarget,
2195
2359
  occupantKind: classifyOccupant(absTarget)
2196
- });
2360
+ }, "worktree create conflict");
2197
2361
  throw new GitMirrorWorktreeConflictError(`Worktree target "${absTarget}" is already occupied by ${classifyOccupant(absTarget)} — aborting (D13)`);
2198
2362
  }
2199
2363
  const pathExists = existsSync(absTarget);
@@ -2409,6 +2573,17 @@ function cleanWorkspaces(workspaceRoot, activeChatIds, ttlMs = DEFAULT_WORKSPACE
2409
2573
  const MAX_RETRIES = 2;
2410
2574
  const TOOL_RESULT_PREVIEW_LIMIT = 400;
2411
2575
  const ASSISTANT_TEXT_EVENT_LIMIT = 8e3;
2576
+ const SUPPORTED_IMAGE_MIMES = new Set([
2577
+ "image/png",
2578
+ "image/jpeg",
2579
+ "image/gif",
2580
+ "image/webp"
2581
+ ]);
2582
+ function isImageFileContent(content) {
2583
+ if (!content || typeof content !== "object") return false;
2584
+ const c = content;
2585
+ return typeof c.data === "string" && typeof c.mimeType === "string" && typeof c.filename === "string" && SUPPORTED_IMAGE_MIMES.has(c.mimeType);
2586
+ }
2412
2587
  function extractContentBlocks(message) {
2413
2588
  if (!message || typeof message !== "object") return [];
2414
2589
  const inner = message.message;
@@ -2581,6 +2756,28 @@ const createClaudeCodeHandler = (config) => {
2581
2756
  /** Worktrees materialised for this session — each entry removed on shutdown. */
2582
2757
  const ownedWorktrees = [];
2583
2758
  function toSDKUserMessage(message, sessionId) {
2759
+ if (message.format === "file" && isImageFileContent(message.content)) {
2760
+ const { data, mimeType, filename } = message.content;
2761
+ return {
2762
+ type: "user",
2763
+ message: {
2764
+ role: "user",
2765
+ content: [{
2766
+ type: "text",
2767
+ text: `${message.senderId ? `[From: ${message.senderId}]\n\n` : ""}[Attached image: ${filename}]`
2768
+ }, {
2769
+ type: "image",
2770
+ source: {
2771
+ type: "base64",
2772
+ media_type: mimeType,
2773
+ data
2774
+ }
2775
+ }]
2776
+ },
2777
+ parent_tool_use_id: null,
2778
+ session_id: sessionId
2779
+ };
2780
+ }
2584
2781
  const rawContent = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
2585
2782
  return {
2586
2783
  type: "user",
@@ -2997,7 +3194,7 @@ function registerBuiltinHandlers() {
2997
3194
  }
2998
3195
  function createAgentConfigCache(opts) {
2999
3196
  const { sdk } = opts;
3000
- const log = opts.log ?? (() => {});
3197
+ const log = opts.log;
3001
3198
  const entries = /* @__PURE__ */ new Map();
3002
3199
  function urlsFromConfig(cfg) {
3003
3200
  return new Set(cfg.payload.gitRepos.map((r) => r.url));
@@ -3042,7 +3239,10 @@ function createAgentConfigCache(opts) {
3042
3239
  };
3043
3240
  slot.inflight = doFetch(agentId).catch((err) => {
3044
3241
  slot.inflight = null;
3045
- log(`[agent-config-cache] fetch failed for ${agentId}: ${err instanceof Error ? err.message : String(err)}`);
3242
+ log?.warn({
3243
+ agentId,
3244
+ err
3245
+ }, "agent config fetch failed");
3046
3246
  throw err;
3047
3247
  });
3048
3248
  entries.set(agentId, slot);
@@ -3212,13 +3412,21 @@ var SessionManager = class {
3212
3412
  const chatId = entry.chatId ?? entry.message.chatId;
3213
3413
  const messageId = entry.message.id;
3214
3414
  if (this.deduplicator.isDuplicate(messageId)) {
3215
- this.config.log(`Session ${chatId}: duplicate message ${messageId}, skipping`);
3415
+ this.config.log.debug({
3416
+ chatId,
3417
+ messageId
3418
+ }, "duplicate message, skipping");
3216
3419
  return;
3217
3420
  }
3218
3421
  if (this.config.agentConfigCache) try {
3219
3422
  await this.config.agentConfigCache.refreshIfNewer(this.config.agentIdentity.agentId, entry.message.configVersion);
3220
3423
  } catch (err) {
3221
- this.config.log(`[configVersionMismatch] agentId=${this.config.agentIdentity.agentId} chatId=${chatId} incomingVersion=${entry.message.configVersion} action=skip — ${err instanceof Error ? err.message : String(err)}`);
3424
+ this.config.log.warn({
3425
+ chatId,
3426
+ agentId: this.config.agentIdentity.agentId,
3427
+ incomingVersion: entry.message.configVersion,
3428
+ err
3429
+ }, "config version mismatch — skipping refresh");
3222
3430
  }
3223
3431
  const message = this.extractMessage(entry);
3224
3432
  await this.routeMessage(chatId, message, entry.id);
@@ -3228,7 +3436,7 @@ var SessionManager = class {
3228
3436
  if (command === "session:suspend") {
3229
3437
  const session = this.sessions.get(chatId);
3230
3438
  if (session?.status === "active") {
3231
- this.config.log(`Session ${chatId}: suspend command received`);
3439
+ this.config.log.info({ chatId }, "suspend command received");
3232
3440
  this.suspendSession(session);
3233
3441
  }
3234
3442
  return;
@@ -3237,7 +3445,7 @@ var SessionManager = class {
3237
3445
  const session = this.sessions.get(chatId);
3238
3446
  const hadMapping = this.evictedMappings.has(chatId);
3239
3447
  if (!session && !hadMapping) return;
3240
- this.config.log(`Session ${chatId}: terminate command received`);
3448
+ this.config.log.info({ chatId }, "terminate command received");
3241
3449
  if (session?.status === "active") {
3242
3450
  this._activeCount--;
3243
3451
  await session.handler.shutdown().catch(() => {});
@@ -3322,7 +3530,7 @@ var SessionManager = class {
3322
3530
  await this.ackEntry(entryId, chatId);
3323
3531
  existing.handler.inject(message);
3324
3532
  existing.lastActivity = Date.now();
3325
- this.config.log(`Session ${chatId}: message injected`);
3533
+ this.config.log.debug({ chatId }, "message injected");
3326
3534
  return;
3327
3535
  case "suspended":
3328
3536
  case "evicted":
@@ -3357,16 +3565,26 @@ var SessionManager = class {
3357
3565
  if (evicted) {
3358
3566
  const sessionId = await handler.resume(message, evicted.claudeSessionId, ctx);
3359
3567
  entry.claudeSessionId = sessionId;
3360
- this.config.log(`Session ${chatId}: resumed from eviction (${sessionId})`);
3568
+ this.config.log.info({
3569
+ chatId,
3570
+ sessionId
3571
+ }, "session resumed from eviction");
3361
3572
  } else {
3362
3573
  const sessionId = await handler.start(message, ctx);
3363
3574
  entry.claudeSessionId = sessionId;
3364
- this.config.log(`Session ${chatId}: created (${sessionId})`);
3575
+ this.config.log.info({
3576
+ chatId,
3577
+ sessionId
3578
+ }, "session created");
3365
3579
  }
3366
3580
  this.persistRegistry();
3367
3581
  this.notifySessionState(chatId, "active");
3368
3582
  } catch (err) {
3369
- this.config.log(`Session ${chatId}: ${evicted ? "resume" : "start"} failed: ${err instanceof Error ? err.message : String(err)}`);
3583
+ this.config.log.error({
3584
+ chatId,
3585
+ err,
3586
+ phase: evicted ? "resume" : "start"
3587
+ }, "session start/resume failed");
3370
3588
  this.sessions.delete(chatId);
3371
3589
  this.sessionRuntimeStates.delete(chatId);
3372
3590
  this.recomputeRuntimeState();
@@ -3391,11 +3609,17 @@ var SessionManager = class {
3391
3609
  entry.lastActivity = Date.now();
3392
3610
  try {
3393
3611
  await entry.handler.resume(message ?? void 0, entry.claudeSessionId, ctx);
3394
- this.config.log(`Session ${entry.chatId}: resumed (${entry.claudeSessionId})`);
3612
+ this.config.log.info({
3613
+ chatId: entry.chatId,
3614
+ sessionId: entry.claudeSessionId
3615
+ }, "session resumed");
3395
3616
  this.persistRegistry();
3396
3617
  this.notifySessionState(entry.chatId, "active");
3397
3618
  } catch (err) {
3398
- this.config.log(`Session ${entry.chatId}: resume failed: ${err instanceof Error ? err.message : String(err)}`);
3619
+ this.config.log.warn({
3620
+ chatId: entry.chatId,
3621
+ err
3622
+ }, "resume failed");
3399
3623
  entry.status = "suspended";
3400
3624
  this._activeCount--;
3401
3625
  }
@@ -3416,11 +3640,11 @@ var SessionManager = class {
3416
3640
  if (!oldestActive || session.lastActivity < oldestActive.lastActivity) oldestActive = session;
3417
3641
  }
3418
3642
  if (oldestActive) {
3419
- this.config.log(`Session ${oldestActive.chatId}: preempted for concurrency`);
3643
+ this.config.log.info({ chatId: oldestActive.chatId }, "session preempted for concurrency");
3420
3644
  this.suspendSession(oldestActive);
3421
3645
  return true;
3422
3646
  }
3423
- this.config.log(`Session ${chatId}: concurrency limit reached, queuing`);
3647
+ this.config.log.info({ chatId }, "concurrency limit reached, queuing");
3424
3648
  this.pendingQueue.push({
3425
3649
  message,
3426
3650
  chatId,
@@ -3434,7 +3658,10 @@ var SessionManager = class {
3434
3658
  this.sessionRuntimeStates.delete(entry.chatId);
3435
3659
  this.recomputeRuntimeState();
3436
3660
  entry.suspending = entry.handler.suspend().catch((err) => {
3437
- this.config.log(`Session ${entry.chatId}: suspend error: ${err instanceof Error ? err.message : String(err)}`);
3661
+ this.config.log.warn({
3662
+ chatId: entry.chatId,
3663
+ err
3664
+ }, "suspend error");
3438
3665
  }).finally(() => {
3439
3666
  entry.suspending = null;
3440
3667
  });
@@ -3448,7 +3675,10 @@ var SessionManager = class {
3448
3675
  const next = this.pendingQueue.shift();
3449
3676
  if (!next) return;
3450
3677
  this.routeMessage(next.chatId, next.message, next.entryId > 0 ? next.entryId : void 0).catch((err) => {
3451
- this.config.log(`Session ${next.chatId}: pending drain error: ${err instanceof Error ? err.message : String(err)}`);
3678
+ this.config.log.warn({
3679
+ chatId: next.chatId,
3680
+ err
3681
+ }, "pending drain error");
3452
3682
  });
3453
3683
  }
3454
3684
  evictIfNeeded() {
@@ -3475,7 +3705,7 @@ var SessionManager = class {
3475
3705
  claudeSessionId: candidate.session.claudeSessionId,
3476
3706
  lastActivity: candidate.session.lastActivity
3477
3707
  });
3478
- this.config.log(`Session ${candidate.key}: evicted (max_sessions reached)`);
3708
+ this.config.log.info({ chatId: candidate.key }, "session evicted (max_sessions reached)");
3479
3709
  if (candidate.session.status === "active") {
3480
3710
  this._activeCount--;
3481
3711
  candidate.session.handler.shutdown().catch(() => {});
@@ -3494,11 +3724,17 @@ var SessionManager = class {
3494
3724
  if (session.status !== "active") continue;
3495
3725
  const inactiveMs = now - session.lastActivity;
3496
3726
  if (inactiveMs > timeoutMs) {
3497
- this.config.log(`Session ${session.chatId}: idle ${this.config.session.idle_timeout}s, suspending`);
3727
+ this.config.log.info({
3728
+ chatId: session.chatId,
3729
+ idleTimeoutSec: this.config.session.idle_timeout
3730
+ }, "session idle, suspending");
3498
3731
  this.suspendSession(session);
3499
3732
  } else if (inactiveMs > blockedThresholdMs) {
3500
3733
  if (this.sessionRuntimeStates.get(session.chatId) === "working") {
3501
- this.config.log(`Session ${session.chatId}: working but no output for ${Math.round(inactiveMs / 1e3)}s, marking blocked`);
3734
+ this.config.log.warn({
3735
+ chatId: session.chatId,
3736
+ inactiveSec: Math.round(inactiveMs / 1e3)
3737
+ }, "session working but no output, marking blocked");
3502
3738
  this.setSessionRuntimeState(session.chatId, "blocked");
3503
3739
  }
3504
3740
  }
@@ -3525,14 +3761,18 @@ var SessionManager = class {
3525
3761
  try {
3526
3762
  await this.config.sdk.ack(entryId);
3527
3763
  } catch {
3528
- this.config.log(`Session ${chatId}: ACK failed for entry ${entryId}, continuing`);
3764
+ this.config.log.warn({
3765
+ chatId,
3766
+ entryId
3767
+ }, "ACK failed, continuing");
3529
3768
  }
3530
3769
  }
3531
3770
  buildSessionContext(chatId) {
3771
+ const sessionLog = this.config.log.child({ chatId });
3532
3772
  return {
3533
3773
  agent: this.config.agentIdentity,
3534
3774
  sdk: this.config.sdk,
3535
- log: (msg) => this.config.log(`Session ${chatId}: ${msg}`),
3775
+ log: (msg) => sessionLog.info(msg),
3536
3776
  chatId,
3537
3777
  touch: () => {
3538
3778
  const entry = this.sessions.get(chatId);
@@ -3591,7 +3831,7 @@ var SessionManager = class {
3591
3831
  claudeSessionId: data.claudeSessionId,
3592
3832
  lastActivity: data.lastActivity
3593
3833
  });
3594
- if (persisted.size > 0) this.config.log(`Loaded ${persisted.size} persisted session mapping(s)`);
3834
+ if (persisted.size > 0) this.config.log.info({ count: persisted.size }, "loaded persisted session mappings");
3595
3835
  }
3596
3836
  persistRegistry() {
3597
3837
  if (!this.registry) return;
@@ -3612,7 +3852,7 @@ var SessionManager = class {
3612
3852
  var AgentSlot = class {
3613
3853
  sessionManager = null;
3614
3854
  config;
3615
- logFn;
3855
+ logger;
3616
3856
  sdk = null;
3617
3857
  agentConfigCache = null;
3618
3858
  pollingTimer = null;
@@ -3620,9 +3860,10 @@ var AgentSlot = class {
3620
3860
  listeners = [];
3621
3861
  constructor(config) {
3622
3862
  this.config = config;
3623
- this.logFn = (msg) => {
3624
- process.stderr.write(`[${config.name}] ${msg}\n`);
3625
- };
3863
+ this.logger = createLogger("slot").child({
3864
+ agentName: config.name,
3865
+ agentId: config.agentId
3866
+ });
3626
3867
  }
3627
3868
  get clientConnection() {
3628
3869
  return this.config.clientConnection;
@@ -3642,21 +3883,21 @@ var AgentSlot = class {
3642
3883
  const sdk = (await this.clientConnection.bindAgent(this.config.agentId, this.config.runtimeType ?? this.config.type, this.config.runtimeVersion)).sdk;
3643
3884
  this.sdk = sdk;
3644
3885
  const agent = await sdk.register();
3645
- this.logFn(`Bound as ${agent.displayName ?? agent.agentId} (${agent.agentId})`);
3886
+ this.logger.info({ displayName: agent.displayName ?? agent.agentId }, "agent bound");
3646
3887
  if (agent.type === "human") {
3647
- this.logFn("Server reports type=human — message processing disabled");
3888
+ this.logger.info("server reports type=human — message processing disabled");
3648
3889
  return agent;
3649
3890
  }
3650
3891
  this.agentConfigCache = createAgentConfigCache({
3651
3892
  sdk,
3652
- log: this.logFn
3893
+ log: this.logger
3653
3894
  });
3654
3895
  try {
3655
3896
  const cfg = await this.agentConfigCache.refresh(agent.agentId);
3656
- this.logFn(`Loaded runtime config v${cfg.version}`);
3897
+ this.logger.info({ version: cfg.version }, "runtime config loaded");
3657
3898
  } catch (err) {
3658
3899
  const msg = err instanceof Error ? err.message : String(err);
3659
- this.logFn(`Failed to fetch agent config — bind aborted: ${msg}`);
3900
+ this.logger.error({ err }, "failed to fetch agent config — bind aborted");
3660
3901
  throw new Error(`Hub unreachable while loading agent config: ${msg}`);
3661
3902
  }
3662
3903
  const onMessage = (agentId) => {
@@ -3687,7 +3928,10 @@ var AgentSlot = class {
3687
3928
  const registryPath = join(DEFAULT_DATA_DIR, "sessions", `${this.config.name}.json`);
3688
3929
  const gitMirrorManager = createGitMirrorManager({
3689
3930
  dataDir: DEFAULT_DATA_DIR,
3690
- log: (event, fields) => this.logFn(`git[${event}] ${JSON.stringify(fields)}`)
3931
+ log: createLogger("git-mirror").child({
3932
+ agentName: this.config.name,
3933
+ agentId: this.config.agentId
3934
+ })
3691
3935
  });
3692
3936
  this.sessionManager = new SessionManager({
3693
3937
  session: this.config.session,
@@ -3706,7 +3950,7 @@ var AgentSlot = class {
3706
3950
  metadata: agent.metadata
3707
3951
  },
3708
3952
  sdk,
3709
- log: this.logFn,
3953
+ log: this.logger,
3710
3954
  registryPath,
3711
3955
  agentConfigCache: this.agentConfigCache,
3712
3956
  onStateChange: (chatId, state) => this.reportSessionState(chatId, state),
@@ -3716,7 +3960,11 @@ var AgentSlot = class {
3716
3960
  });
3717
3961
  const onCommand = (cmd) => {
3718
3962
  if (cmd.agentId === this.config.agentId && this.sessionManager) this.sessionManager.handleCommand(cmd.chatId, cmd.type).catch((err) => {
3719
- this.logFn(`Session command error: ${err instanceof Error ? err.message : String(err)}`);
3963
+ this.logger.error({
3964
+ err,
3965
+ chatId: cmd.chatId,
3966
+ type: cmd.type
3967
+ }, "session command error");
3720
3968
  });
3721
3969
  };
3722
3970
  this.clientConnection.on("session:command", onCommand);
@@ -3744,7 +3992,7 @@ var AgentSlot = class {
3744
3992
  this.listeners = [];
3745
3993
  await this.clientConnection.unbindAgent(this.config.agentId);
3746
3994
  await this.sessionManager?.shutdown();
3747
- this.logFn("Stopped");
3995
+ this.logger.info("stopped");
3748
3996
  }
3749
3997
  reportSessionState(chatId, state) {
3750
3998
  this.clientConnection.reportSessionState(this.config.agentId, chatId, state);
@@ -3786,7 +4034,7 @@ var AgentSlot = class {
3786
4034
  const { entries } = await this.sdk.pull(10);
3787
4035
  for (const entry of entries) await this.sessionManager.dispatch(entry);
3788
4036
  } catch (err) {
3789
- this.logFn(`Poll error: ${err instanceof Error ? err.message : String(err)}`);
4037
+ this.logger.warn({ err }, "poll error");
3790
4038
  }
3791
4039
  }
3792
4040
  };
@@ -3963,6 +4211,71 @@ function sleep(ms) {
3963
4211
  return new Promise((resolve) => setTimeout(resolve, ms));
3964
4212
  }
3965
4213
  //#endregion
4214
+ //#region src/core/output.ts
4215
+ /**
4216
+ * Print layer — the only place CLI code should write to stdout/stderr.
4217
+ *
4218
+ * Contract:
4219
+ * - `print.result(data)` / `print.fail(...)` emit machine-readable JSON on
4220
+ * stdout / stderr respectively. Scripts pipe into `jq` and expect a clean
4221
+ * envelope, so nothing else may touch stdout.
4222
+ * - `print.status` / `print.check` / `print.blank` / `print.line` are
4223
+ * human-friendly and go to stderr so they never pollute a redirected stdout.
4224
+ * In `--json` mode they are silenced — scripted consumers only care about
4225
+ * the envelope.
4226
+ */
4227
+ let jsonMode = false;
4228
+ function setJsonMode(enabled) {
4229
+ jsonMode = enabled;
4230
+ }
4231
+ function result(data) {
4232
+ process.stdout.write(`${JSON.stringify({
4233
+ ok: true,
4234
+ data
4235
+ })}\n`);
4236
+ }
4237
+ function fail(code, message, exitCode = 1) {
4238
+ process.stderr.write(`${JSON.stringify({
4239
+ ok: false,
4240
+ error: {
4241
+ code,
4242
+ message
4243
+ }
4244
+ })}\n`);
4245
+ process.exit(exitCode);
4246
+ }
4247
+ function status(label, message) {
4248
+ if (jsonMode) return;
4249
+ process.stderr.write(` ${label.padEnd(20)} ${message}\n`);
4250
+ }
4251
+ function check(pass, label, detail = "") {
4252
+ if (jsonMode) return;
4253
+ const icon = pass ? "✓" : "✗";
4254
+ const tail = detail ? ` ${detail}` : "";
4255
+ process.stderr.write(` ${icon} ${label.padEnd(22)}${tail}\n`);
4256
+ }
4257
+ function blank() {
4258
+ if (jsonMode) return;
4259
+ process.stderr.write("\n");
4260
+ }
4261
+ /**
4262
+ * Generic stderr writer for pre-formatted human text (multi-line tables,
4263
+ * interactive prompts). Prefer `status` / `check` when the text fits; this
4264
+ * exists so the `--json` mode gate can silence arbitrary human chatter.
4265
+ */
4266
+ function line(text) {
4267
+ if (jsonMode) return;
4268
+ process.stderr.write(text);
4269
+ }
4270
+ const print = {
4271
+ result,
4272
+ fail,
4273
+ status,
4274
+ check,
4275
+ blank,
4276
+ line
4277
+ };
4278
+ //#endregion
3966
4279
  //#region src/core/admin.ts
3967
4280
  /**
3968
4281
  * Check if any user exists.
@@ -4083,10 +4396,10 @@ var ClientRuntime = class {
4083
4396
  });
4084
4397
  registerBuiltinHandlers();
4085
4398
  this.connection.on("auth:expired", () => {
4086
- process.stderr.write(" ⚠️ Access token expired — reconnecting after refresh...\n");
4399
+ print.status("⚠️", "access token expired — reconnecting after refresh...");
4087
4400
  });
4088
4401
  this.connection.on("error", (err) => {
4089
- process.stderr.write(` \u26A0\uFE0F Client connection error: ${err.message}\n`);
4402
+ print.status("⚠️", `client connection error: ${err.message}`);
4090
4403
  });
4091
4404
  this.connection.on("agent:pinned", (message) => {
4092
4405
  this.handleAgentPinned(message);
@@ -4121,27 +4434,30 @@ var ClientRuntime = class {
4121
4434
  currentVersion: this.options.currentVersion,
4122
4435
  ...this.options.update,
4123
4436
  isTTY: Boolean(process.stdout.isTTY),
4124
- log: (level, msg) => process.stderr.write(` [update/${level}] ${msg}\n`),
4437
+ log: (level, msg) => print.status(`[update/${level}]`, msg),
4125
4438
  getQuietGateSnapshot: () => this.aggregateQuietGate()
4126
4439
  });
4127
4440
  await this.connection.connect();
4128
- process.stderr.write(` \u2713 Client registered: ${this.connection.clientId}\n`);
4441
+ print.check(true, "client registered", this.connection.clientId);
4129
4442
  if (this.agents.length === 0) {
4130
- process.stderr.write("\n No agents configured yet.\n");
4131
- process.stderr.write(" Add one with: first-tree-hub agent create <name> --type claude-code --client-id <id>\n\n");
4443
+ print.blank();
4444
+ print.status("", "no agents configured yet.");
4445
+ print.status("", "add one with: first-tree-hub agent create <name> --type claude-code --client-id <id>");
4446
+ print.blank();
4132
4447
  return;
4133
4448
  }
4134
4449
  await Promise.allSettled(this.agents.map(async (agent) => {
4135
4450
  try {
4136
4451
  const identity = await agent.slot.start();
4137
- process.stderr.write(` \u2713 ${agent.name}: connected (agent: ${identity.displayName ?? identity.agentId})\n`);
4452
+ print.check(true, `${agent.name}: connected`, `agent: ${identity.displayName ?? identity.agentId}`);
4138
4453
  } catch (error) {
4139
4454
  const msg = error instanceof Error ? error.message : String(error);
4140
- process.stderr.write(` \u2717 ${agent.name}: connection failed \u2014 ${msg}\n`);
4455
+ print.check(false, `${agent.name}: connection failed`, msg);
4141
4456
  }
4142
4457
  }));
4143
4458
  const connected = this.agents.length;
4144
- process.stderr.write(`\n ${connected} agent(s) running. Press Ctrl+C to stop.\n`);
4459
+ print.blank();
4460
+ print.status("", `${connected} agent(s) running. Press Ctrl+C to stop.`);
4145
4461
  }
4146
4462
  watchAgentsDir(agentsDir) {
4147
4463
  this.agentsDir = agentsDir;
@@ -4194,7 +4510,8 @@ var ClientRuntime = class {
4194
4510
  for (const [name, config] of all) {
4195
4511
  if (this.agentNames.has(name)) continue;
4196
4512
  if (this.agentIds.has(config.agentId)) continue;
4197
- process.stderr.write(`\n New agent detected: ${name}\n`);
4513
+ print.blank();
4514
+ print.status("", `new agent detected: ${name}`);
4198
4515
  this.addAgent(name, config);
4199
4516
  this.startAgent(name);
4200
4517
  }
@@ -4209,7 +4526,7 @@ var ClientRuntime = class {
4209
4526
  handleAgentPinned(message) {
4210
4527
  if (this.agentIds.has(message.agentId)) return;
4211
4528
  if (!this.agentsDir) {
4212
- process.stderr.write(` \u26A0\uFE0F Agent pinned (${message.agentId}) but no agents dir set — cannot auto-register.\n`);
4529
+ print.status("⚠️", `agent pinned (${message.agentId}) but no agents dir set — cannot auto-register.`);
4213
4530
  return;
4214
4531
  }
4215
4532
  const localName = this.pickLocalName(message);
@@ -4224,10 +4541,10 @@ var ClientRuntime = class {
4224
4541
  runtime: "claude-code"
4225
4542
  });
4226
4543
  writeFileSync(join(agentDir, "agent.yaml"), yaml, { mode: 384 });
4227
- process.stderr.write(` \u2713 Auto-added agent "${localName}" (${message.agentId}) from server push.\n`);
4544
+ print.check(true, `auto-added agent "${localName}"`, `${message.agentId} (from server push)`);
4228
4545
  } catch (err) {
4229
4546
  const msg = err instanceof Error ? err.message : String(err);
4230
- process.stderr.write(` \u2717 Failed to auto-add agent "${localName}": ${msg}\n`);
4547
+ print.check(false, `failed to auto-add agent "${localName}"`, msg);
4231
4548
  return;
4232
4549
  }
4233
4550
  this.scanForNewAgents(this.agentsDir);
@@ -4259,10 +4576,10 @@ var ClientRuntime = class {
4259
4576
  const entry = this.agents.find((a) => a.name === name);
4260
4577
  if (!entry) return;
4261
4578
  entry.slot.start().then((identity) => {
4262
- process.stderr.write(` \u2713 ${name}: connected (agent: ${identity.displayName ?? identity.agentId})\n`);
4579
+ print.check(true, `${name}: connected`, `agent: ${identity.displayName ?? identity.agentId}`);
4263
4580
  }).catch((err) => {
4264
4581
  const msg = err instanceof Error ? err.message : String(err);
4265
- process.stderr.write(` \u2717 ${name}: connection failed \u2014 ${msg}\n`);
4582
+ print.check(false, `${name}: connection failed`, msg);
4266
4583
  });
4267
4584
  }
4268
4585
  };
@@ -4441,16 +4758,6 @@ function getContainerPassword() {
4441
4758
  throw new Error("Cannot determine PostgreSQL password from container");
4442
4759
  }
4443
4760
  //#endregion
4444
- //#region src/core/output.ts
4445
- /** Print a styled status line to stderr (human-friendly output). */
4446
- function status(label, message) {
4447
- process.stderr.write(` ${label.padEnd(20)} ${message}\n`);
4448
- }
4449
- /** Print a blank line to stderr. */
4450
- function blank() {
4451
- process.stderr.write("\n");
4452
- }
4453
- //#endregion
4454
4761
  //#region src/core/doctor.ts
4455
4762
  function getServerConfig() {
4456
4763
  return resolveConfigReadonly({
@@ -4691,12 +4998,12 @@ async function checkWebSocket() {
4691
4998
  function printResults(results) {
4692
4999
  for (const r of results) {
4693
5000
  const icon = r.ok ? "✓" : "✗";
4694
- process.stderr.write(` ${icon} ${r.label.padEnd(22)} ${r.detail}\n`);
5001
+ print.line(` ${icon} ${r.label.padEnd(22)} ${r.detail}\n`);
4695
5002
  }
4696
5003
  blank();
4697
5004
  const failures = results.filter((r) => !r.ok);
4698
- if (failures.length === 0) process.stderr.write(" All checks passed.\n");
4699
- else process.stderr.write(` ${failures.length} issue(s) found.\n`);
5005
+ if (failures.length === 0) print.line(" All checks passed.\n");
5006
+ else print.line(` ${failures.length} issue(s) found.\n`);
4700
5007
  blank();
4701
5008
  }
4702
5009
  //#endregion
@@ -4782,7 +5089,7 @@ function sleepSync(ms) {
4782
5089
  }
4783
5090
  const LAUNCHD_LABEL = "dev.first-tree-hub.client";
4784
5091
  const SYSTEMD_UNIT = "first-tree-hub-client.service";
4785
- const LOG_DIR = join(DEFAULT_HOME_DIR$1, "logs");
5092
+ const LOG_DIR$1 = join(DEFAULT_HOME_DIR$1, "logs");
4786
5093
  function whichBin(name) {
4787
5094
  try {
4788
5095
  return execFileSync(process.platform === "win32" ? "where" : "which", [name], {
@@ -4824,7 +5131,7 @@ function resolveCliInvocation() {
4824
5131
  };
4825
5132
  }
4826
5133
  function ensureLogDir() {
4827
- mkdirSync(LOG_DIR, {
5134
+ mkdirSync(LOG_DIR$1, {
4828
5135
  recursive: true,
4829
5136
  mode: 448
4830
5137
  });
@@ -4845,8 +5152,8 @@ function renderPlist(invocation) {
4845
5152
  "start",
4846
5153
  "--no-interactive"
4847
5154
  ]).map((a) => ` <string>${escapeXml(a)}</string>`).join("\n");
4848
- const outLog = join(LOG_DIR, "client.out.log");
4849
- const errLog = join(LOG_DIR, "client.err.log");
5155
+ const stdoutFallback = join(LOG_DIR$1, "client.stdout.log");
5156
+ const stderrFallback = join(LOG_DIR$1, "client.stderr.log");
4850
5157
  return `<?xml version="1.0" encoding="UTF-8"?>
4851
5158
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTD/PropertyList-1.0.dtd">
4852
5159
  <plist version="1.0">
@@ -4861,6 +5168,8 @@ ${argsXml}
4861
5168
  <dict>
4862
5169
  <key>PATH</key>
4863
5170
  <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
5171
+ <key>FIRST_TREE_HUB_SERVICE_MODE</key>
5172
+ <string>1</string>
4864
5173
  </dict>
4865
5174
  <key>RunAtLoad</key>
4866
5175
  <true/>
@@ -4872,9 +5181,9 @@ ${argsXml}
4872
5181
  <key>ThrottleInterval</key>
4873
5182
  <integer>10</integer>
4874
5183
  <key>StandardOutPath</key>
4875
- <string>${escapeXml(outLog)}</string>
5184
+ <string>${escapeXml(stdoutFallback)}</string>
4876
5185
  <key>StandardErrorPath</key>
4877
- <string>${escapeXml(errLog)}</string>
5186
+ <string>${escapeXml(stderrFallback)}</string>
4878
5187
  </dict>
4879
5188
  </plist>
4880
5189
  `;
@@ -4947,7 +5256,7 @@ function installLaunchd() {
4947
5256
  const target = launchctlDomainTarget();
4948
5257
  const bootoutRes = runCapture("launchctl", ["bootout", `${target}/${LAUNCHD_LABEL}`], 15e3);
4949
5258
  if (!bootoutRes.ok) {
4950
- if (!/not find|no such|not loaded/i.test(bootoutRes.stderr)) process.stderr.write(` warning: launchctl bootout: ${bootoutRes.stderr || `exit ${bootoutRes.code ?? "unknown"}`}\n`);
5259
+ if (!/not find|no such|not loaded/i.test(bootoutRes.stderr)) print.line(` warning: launchctl bootout: ${bootoutRes.stderr || `exit ${bootoutRes.code ?? "unknown"}`}\n`);
4951
5260
  }
4952
5261
  waitForLabelEvicted(target, LAUNCHD_LABEL, 1e4);
4953
5262
  let lastBootstrapErr = null;
@@ -4966,13 +5275,13 @@ function installLaunchd() {
4966
5275
  }
4967
5276
  if (lastBootstrapErr) throw new Error(`launchctl bootstrap failed: ${lastBootstrapErr.stderr || `exit ${lastBootstrapErr.code ?? "unknown"}`}\n Command: launchctl bootstrap ${target} ${plistPath}\n Recovery: \`launchctl bootout ${target}/${LAUNCHD_LABEL}\` then \`first-tree-hub service install\`.`);
4968
5277
  const enableRes = runCapture("launchctl", ["enable", `${target}/${LAUNCHD_LABEL}`], 5e3);
4969
- if (!enableRes.ok) process.stderr.write(` warning: launchctl enable: ${enableRes.stderr || `exit ${enableRes.code ?? "unknown"}`}\n`);
5278
+ if (!enableRes.ok) print.line(` warning: launchctl enable: ${enableRes.stderr || `exit ${enableRes.code ?? "unknown"}`}\n`);
4970
5279
  const { state, detail } = launchdState();
4971
5280
  return {
4972
5281
  platform: "launchd",
4973
5282
  label: LAUNCHD_LABEL,
4974
5283
  unitPath: plistPath,
4975
- logDir: LOG_DIR,
5284
+ logDir: LOG_DIR$1,
4976
5285
  state,
4977
5286
  detail
4978
5287
  };
@@ -4980,13 +5289,13 @@ function installLaunchd() {
4980
5289
  function uninstallLaunchd() {
4981
5290
  const plistPath = launchdPlistPath();
4982
5291
  const res = runCapture("launchctl", ["bootout", `${launchctlDomainTarget()}/${LAUNCHD_LABEL}`], 15e3);
4983
- if (!res.ok && !/not find|no such|not loaded/i.test(res.stderr)) process.stderr.write(` warning: bootout during uninstall: ${res.stderr || `exit ${res.code ?? "unknown"}`}\n`);
5292
+ if (!res.ok && !/not find|no such|not loaded/i.test(res.stderr)) print.line(` warning: bootout during uninstall: ${res.stderr || `exit ${res.code ?? "unknown"}`}\n`);
4984
5293
  if (existsSync(plistPath)) rmSync(plistPath);
4985
5294
  return {
4986
5295
  platform: "launchd",
4987
5296
  label: LAUNCHD_LABEL,
4988
5297
  unitPath: plistPath,
4989
- logDir: LOG_DIR,
5298
+ logDir: LOG_DIR$1,
4990
5299
  state: "not-installed"
4991
5300
  };
4992
5301
  }
@@ -5004,9 +5313,10 @@ Type=simple
5004
5313
  ExecStart=${invocation.kind === "bin" ? `${shellQuote(invocation.program)} client start --no-interactive` : `${shellQuote(invocation.program)} ${invocation.args.map(shellQuote).join(" ")} client start --no-interactive`}
5005
5314
  Restart=always
5006
5315
  RestartSec=10
5007
- StandardOutput=append:${join(LOG_DIR, "client.out.log")}
5008
- StandardError=append:${join(LOG_DIR, "client.err.log")}
5316
+ StandardOutput=append:${join(LOG_DIR$1, "client.stdout.log")}
5317
+ StandardError=append:${join(LOG_DIR$1, "client.stderr.log")}
5009
5318
  Environment=PATH=/usr/local/bin:/usr/bin:/bin
5319
+ Environment=FIRST_TREE_HUB_SERVICE_MODE=1
5010
5320
 
5011
5321
  [Install]
5012
5322
  WantedBy=default.target
@@ -5061,7 +5371,7 @@ function installSystemd() {
5061
5371
  platform: "systemd",
5062
5372
  label: SYSTEMD_UNIT,
5063
5373
  unitPath,
5064
- logDir: LOG_DIR,
5374
+ logDir: LOG_DIR$1,
5065
5375
  state,
5066
5376
  detail
5067
5377
  };
@@ -5074,15 +5384,15 @@ function uninstallSystemd() {
5074
5384
  "--now",
5075
5385
  SYSTEMD_UNIT
5076
5386
  ], 1e4);
5077
- if (!disableRes.ok && !/not found|no such|not loaded/i.test(disableRes.stderr)) process.stderr.write(` warning: systemctl disable during uninstall: ${disableRes.stderr || `exit ${disableRes.code ?? "unknown"}`}\n`);
5387
+ if (!disableRes.ok && !/not found|no such|not loaded/i.test(disableRes.stderr)) print.line(` warning: systemctl disable during uninstall: ${disableRes.stderr || `exit ${disableRes.code ?? "unknown"}`}\n`);
5078
5388
  if (existsSync(unitPath)) rmSync(unitPath);
5079
5389
  const reloadRes = runCapture("systemctl", ["--user", "daemon-reload"], 5e3);
5080
- if (!reloadRes.ok) process.stderr.write(` warning: systemctl daemon-reload during uninstall: ${reloadRes.stderr || `exit ${reloadRes.code ?? "unknown"}`}\n`);
5390
+ if (!reloadRes.ok) print.line(` warning: systemctl daemon-reload during uninstall: ${reloadRes.stderr || `exit ${reloadRes.code ?? "unknown"}`}\n`);
5081
5391
  return {
5082
5392
  platform: "systemd",
5083
5393
  label: SYSTEMD_UNIT,
5084
5394
  unitPath,
5085
- logDir: LOG_DIR,
5395
+ logDir: LOG_DIR$1,
5086
5396
  state: "not-installed"
5087
5397
  };
5088
5398
  }
@@ -5108,7 +5418,7 @@ function getClientServiceStatus() {
5108
5418
  platform: "launchd",
5109
5419
  label: LAUNCHD_LABEL,
5110
5420
  unitPath: launchdPlistPath(),
5111
- logDir: LOG_DIR,
5421
+ logDir: LOG_DIR$1,
5112
5422
  state,
5113
5423
  detail
5114
5424
  };
@@ -5119,7 +5429,7 @@ function getClientServiceStatus() {
5119
5429
  platform: "systemd",
5120
5430
  label: SYSTEMD_UNIT,
5121
5431
  unitPath: systemdUnitPath(),
5122
- logDir: LOG_DIR,
5432
+ logDir: LOG_DIR$1,
5123
5433
  state,
5124
5434
  detail
5125
5435
  };
@@ -5128,7 +5438,7 @@ function getClientServiceStatus() {
5128
5438
  platform: "unsupported",
5129
5439
  label: "",
5130
5440
  unitPath: "",
5131
- logDir: LOG_DIR,
5441
+ logDir: LOG_DIR$1,
5132
5442
  state: "not-installed",
5133
5443
  detail: `platform ${process.platform} not supported`
5134
5444
  };
@@ -5168,22 +5478,22 @@ function runHomeMigration() {
5168
5478
  envOverride: process.env.FIRST_TREE_HUB_HOME ?? null
5169
5479
  });
5170
5480
  if (!result.migrated) {
5171
- if (result.reason === "failed") process.stderr.write(`[first-tree-hub] WARNING: failed to auto-migrate legacy home ${result.from} → ${result.to}: ${result.error ?? "unknown error"}\n Resolve manually: cp -R "${result.from}" "${result.to}"\n`);
5481
+ if (result.reason === "failed") print.line(`[first-tree-hub] WARNING: failed to auto-migrate legacy home ${result.from} → ${result.to}: ${result.error ?? "unknown error"}\n Resolve manually: cp -R "${result.from}" "${result.to}"\n`);
5172
5482
  return;
5173
5483
  }
5174
- process.stderr.write(`[first-tree-hub] Copied client home to new layout: ${result.from} → ${result.to}\n (Legacy directory preserved as a backup — delete it manually once you've verified the new location works.)\n`);
5484
+ print.line(`[first-tree-hub] Copied client home to new layout: ${result.from} → ${result.to}\n (Legacy directory preserved as a backup — delete it manually once you've verified the new location works.)\n`);
5175
5485
  if (process.argv.includes("--no-interactive")) {
5176
- process.stderr.write("[first-tree-hub] Note: running as background service — skipped auto re-register to avoid self-termination.\n Run `first-tree-hub client service install` from a terminal to refresh log paths.\n");
5486
+ print.line("[first-tree-hub] Note: running as background service — skipped auto re-register to avoid self-termination.\n Run `first-tree-hub client service install` from a terminal to refresh log paths.\n");
5177
5487
  return;
5178
5488
  }
5179
5489
  const status = getClientServiceStatus();
5180
5490
  if (status.platform === "unsupported" || status.state === "not-installed") return;
5181
5491
  try {
5182
5492
  installClientService();
5183
- process.stderr.write(`[first-tree-hub] Re-registered background service with new home paths.\n`);
5493
+ print.line(`[first-tree-hub] Re-registered background service with new home paths.\n`);
5184
5494
  } catch (err) {
5185
5495
  const msg = err instanceof Error ? err.message : String(err);
5186
- process.stderr.write(`[first-tree-hub] WARNING: home migration succeeded but re-registering the background service failed: ${msg}\n Run \`first-tree-hub client service install\` to refresh log paths.\n`);
5496
+ print.line(`[first-tree-hub] WARNING: home migration succeeded but re-registering the background service failed: ${msg}\n Run \`first-tree-hub client service install\` to refresh log paths.\n`);
5187
5497
  }
5188
5498
  }
5189
5499
  //#endregion
@@ -5319,7 +5629,7 @@ async function onboardCreate(args) {
5319
5629
  const metadata = {};
5320
5630
  if (args.role) metadata.role = args.role;
5321
5631
  if (args.domains) metadata.domains = args.domains.split(",").map((d) => d.trim());
5322
- process.stderr.write(`Creating agent "${args.id}"...\n`);
5632
+ print.line(`Creating agent "${args.id}"...\n`);
5323
5633
  const primary = await createAgentViaAdmin(serverUrl, accessToken, {
5324
5634
  name: args.id,
5325
5635
  type: args.type,
@@ -5328,11 +5638,11 @@ async function onboardCreate(args) {
5328
5638
  metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
5329
5639
  clientId: args.type === "human" ? void 0 : args.clientId
5330
5640
  });
5331
- process.stderr.write(`Agent "${args.id}" created (uuid ${primary.uuid}).\n`);
5641
+ print.line(`Agent "${args.id}" created (uuid ${primary.uuid}).\n`);
5332
5642
  if (args.type !== "human") saveAgentConfig(args.id, primary.uuid, "claude-code");
5333
5643
  let assistantUuid = null;
5334
5644
  if (args.assistant) {
5335
- process.stderr.write(`Creating assistant "${args.assistant}"...\n`);
5645
+ print.line(`Creating assistant "${args.assistant}"...\n`);
5336
5646
  try {
5337
5647
  const assistant = await createAgentViaAdmin(serverUrl, accessToken, {
5338
5648
  name: args.assistant,
@@ -5346,21 +5656,21 @@ async function onboardCreate(args) {
5346
5656
  });
5347
5657
  assistantUuid = assistant.uuid;
5348
5658
  saveAgentConfig(args.assistant, assistant.uuid, "claude-code");
5349
- process.stderr.write(`Assistant "${args.assistant}" ready.\n`);
5659
+ print.line(`Assistant "${args.assistant}" ready.\n`);
5350
5660
  } catch (err) {
5351
5661
  const msg = err instanceof Error ? err.message : String(err);
5352
- process.stderr.write(`Warning: Failed to create assistant "${args.assistant}": ${msg}\n`);
5662
+ print.line(`Warning: Failed to create assistant "${args.assistant}": ${msg}\n`);
5353
5663
  }
5354
5664
  }
5355
5665
  const runtimeAgent = args.type === "human" ? args.assistant : args.id;
5356
5666
  if (args.feishuBotAppId && args.feishuBotAppSecret) {
5357
5667
  const { bindFeishuBot } = await import("./feishu-GlaczcVf.mjs").then((n) => n.r);
5358
5668
  const targetAgentUuid = args.type === "human" ? assistantUuid : primary.uuid;
5359
- if (!targetAgentUuid) process.stderr.write(`Warning: Cannot bind Feishu bot — no runtime agent available for "${args.id}".\n`);
5669
+ if (!targetAgentUuid) print.line(`Warning: Cannot bind Feishu bot — no runtime agent available for "${args.id}".\n`);
5360
5670
  else {
5361
- process.stderr.write("Binding Feishu bot...\n");
5671
+ print.line("Binding Feishu bot...\n");
5362
5672
  await bindFeishuBot(serverUrl, accessToken, targetAgentUuid, args.feishuBotAppId, args.feishuBotAppSecret);
5363
- process.stderr.write("Feishu bot bound.\n");
5673
+ print.line("Feishu bot bound.\n");
5364
5674
  }
5365
5675
  }
5366
5676
  setConfigValue(join(DEFAULT_CONFIG_DIR, "client.yaml"), "server.url", serverUrl);
@@ -5369,21 +5679,21 @@ async function onboardCreate(args) {
5369
5679
  unlinkSync(STATE_FILE);
5370
5680
  } catch {}
5371
5681
  const typeLabel = args.type === "human" ? "Human" : args.type === "autonomous_agent" ? "Agent" : "Assistant";
5372
- process.stderr.write("\n✅ Onboard complete!\n\n");
5373
- process.stderr.write(` ${typeLabel}:${" ".repeat(Math.max(1, 10 - typeLabel.length))}${args.id}\n`);
5374
- if (args.assistant) process.stderr.write(` Assistant: ${args.assistant}\n`);
5375
- if (runtimeAgent) process.stderr.write(` Config: ${DEFAULT_HOME_DIR$1}/config/agents/${runtimeAgent}/agent.yaml\n`);
5376
- if (args.feishuBotAppId) process.stderr.write(` Feishu: bot bound (${args.feishuBotAppId})\n`);
5682
+ print.line("\n✅ Onboard complete!\n\n");
5683
+ print.line(` ${typeLabel}:${" ".repeat(Math.max(1, 10 - typeLabel.length))}${args.id}\n`);
5684
+ if (args.assistant) print.line(` Assistant: ${args.assistant}\n`);
5685
+ if (runtimeAgent) print.line(` Config: ${DEFAULT_HOME_DIR$1}/config/agents/${runtimeAgent}/agent.yaml\n`);
5686
+ if (args.feishuBotAppId) print.line(` Feishu: bot bound (${args.feishuBotAppId})\n`);
5377
5687
  if (args.type === "human") {
5378
- process.stderr.write("\n Next step — bind your Feishu account:\n");
5379
- process.stderr.write(` Send this message to the bot in Feishu: /bind ${args.id}\n`);
5380
- if (!args.feishuBotAppId) process.stderr.write(" (requires a Feishu bot to be configured in the system)\n");
5688
+ print.line("\n Next step — bind your Feishu account:\n");
5689
+ print.line(` Send this message to the bot in Feishu: /bind ${args.id}\n`);
5690
+ if (!args.feishuBotAppId) print.line(" (requires a Feishu bot to be configured in the system)\n");
5381
5691
  }
5382
5692
  if (runtimeAgent) {
5383
- process.stderr.write("\n Start the agent:\n");
5384
- process.stderr.write(" first-tree-hub client start\n");
5693
+ print.line("\n Start the agent:\n");
5694
+ print.line(" first-tree-hub client start\n");
5385
5695
  }
5386
- process.stderr.write("\n");
5696
+ print.line("\n");
5387
5697
  }
5388
5698
  //#endregion
5389
5699
  //#region src/core/prompt.ts
@@ -5495,2713 +5805,7 @@ function setNestedByDot(obj, dotPath, value) {
5495
5805
  if (lastKey !== void 0) current[lastKey] = value;
5496
5806
  }
5497
5807
  //#endregion
5498
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/streamsearch/sbmh.js
5499
- var require_sbmh = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5500
- /**
5501
- * Copyright Brian White. All rights reserved.
5502
- *
5503
- * @see https://github.com/mscdex/streamsearch
5504
- *
5505
- * Permission is hereby granted, free of charge, to any person obtaining a copy
5506
- * of this software and associated documentation files (the "Software"), to
5507
- * deal in the Software without restriction, including without limitation the
5508
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
5509
- * sell copies of the Software, and to permit persons to whom the Software is
5510
- * furnished to do so, subject to the following conditions:
5511
- *
5512
- * The above copyright notice and this permission notice shall be included in
5513
- * all copies or substantial portions of the Software.
5514
- *
5515
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5516
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5517
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5518
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5519
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
5520
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
5521
- * IN THE SOFTWARE.
5522
- *
5523
- * Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation
5524
- * by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool
5525
- */
5526
- const { EventEmitter: EventEmitter$2 } = __require("node:events");
5527
- const { inherits: inherits$5 } = __require("node:util");
5528
- function SBMH(needle) {
5529
- if (typeof needle === "string") needle = Buffer.from(needle);
5530
- if (!Buffer.isBuffer(needle)) throw new TypeError("The needle has to be a String or a Buffer.");
5531
- const needleLength = needle.length;
5532
- const needleLastCharIndex = needleLength - 1;
5533
- if (needleLength === 0) throw new Error("The needle cannot be an empty String/Buffer.");
5534
- if (needleLength > 256) throw new Error("The needle cannot have a length bigger than 256.");
5535
- this.maxMatches = Infinity;
5536
- this.matches = 0;
5537
- this._occ = new Uint8Array(256).fill(needleLength);
5538
- this._lookbehind_size = 0;
5539
- this._needle = needle;
5540
- this._bufpos = 0;
5541
- this._lookbehind = Buffer.alloc(needleLastCharIndex);
5542
- for (var i = 0; i < needleLastCharIndex; ++i) this._occ[needle[i]] = needleLastCharIndex - i;
5543
- }
5544
- inherits$5(SBMH, EventEmitter$2);
5545
- SBMH.prototype.reset = function() {
5546
- this._lookbehind_size = 0;
5547
- this.matches = 0;
5548
- this._bufpos = 0;
5549
- };
5550
- SBMH.prototype.push = function(chunk, pos) {
5551
- if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, "binary");
5552
- const chlen = chunk.length;
5553
- this._bufpos = pos || 0;
5554
- let r;
5555
- while (r !== chlen && this.matches < this.maxMatches) r = this._sbmh_feed(chunk);
5556
- return r;
5557
- };
5558
- SBMH.prototype._sbmh_feed = function(data) {
5559
- const len = data.length;
5560
- const needle = this._needle;
5561
- const needleLength = needle.length;
5562
- const needleLastCharIndex = needleLength - 1;
5563
- const needleLastChar = needle[needleLastCharIndex];
5564
- let pos = -this._lookbehind_size;
5565
- let ch;
5566
- if (pos < 0) {
5567
- while (pos < 0 && pos <= len - needleLength) {
5568
- ch = data[pos + needleLastCharIndex];
5569
- if (ch === needleLastChar && this._sbmh_memcmp(data, pos, needleLastCharIndex)) {
5570
- this._lookbehind_size = 0;
5571
- ++this.matches;
5572
- this.emit("info", true);
5573
- return this._bufpos = pos + needleLength;
5574
- }
5575
- pos += this._occ[ch];
5576
- }
5577
- while (pos < 0 && !this._sbmh_memcmp(data, pos, len - pos)) ++pos;
5578
- if (pos >= 0) {
5579
- this.emit("info", false, this._lookbehind, 0, this._lookbehind_size);
5580
- this._lookbehind_size = 0;
5581
- } else {
5582
- const bytesToCutOff = this._lookbehind_size + pos;
5583
- if (bytesToCutOff > 0) this.emit("info", false, this._lookbehind, 0, bytesToCutOff);
5584
- this._lookbehind_size -= bytesToCutOff;
5585
- this._lookbehind.copy(this._lookbehind, 0, bytesToCutOff, this._lookbehind_size);
5586
- data.copy(this._lookbehind, this._lookbehind_size);
5587
- this._lookbehind_size += len;
5588
- this._bufpos = len;
5589
- return len;
5590
- }
5591
- }
5592
- pos = data.indexOf(needle, pos + this._bufpos);
5593
- if (pos !== -1) {
5594
- ++this.matches;
5595
- if (pos === 0) this.emit("info", true);
5596
- else this.emit("info", true, data, this._bufpos, pos);
5597
- return this._bufpos = pos + needleLength;
5598
- }
5599
- pos = len - needleLastCharIndex;
5600
- if (pos < 0) pos = 0;
5601
- while (pos !== len && (data[pos] !== needle[0] || Buffer.compare(data.subarray(pos + 1, len), needle.subarray(1, len - pos)) !== 0)) ++pos;
5602
- if (pos !== len) {
5603
- data.copy(this._lookbehind, 0, pos, len);
5604
- this._lookbehind_size = len - pos;
5605
- }
5606
- if (pos !== 0) this.emit("info", false, data, this._bufpos, pos);
5607
- this._bufpos = len;
5608
- return len;
5609
- };
5610
- SBMH.prototype._sbmh_lookup_char = function(data, pos) {
5611
- return pos < 0 ? this._lookbehind[this._lookbehind_size + pos] : data[pos];
5612
- };
5613
- SBMH.prototype._sbmh_memcmp = function(data, pos, len) {
5614
- for (var i = 0; i < len; ++i) if (this._sbmh_lookup_char(data, pos + i) !== this._needle[i]) return false;
5615
- return true;
5616
- };
5617
- module.exports = SBMH;
5618
- }));
5619
- //#endregion
5620
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/dicer/lib/PartStream.js
5621
- var require_PartStream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5622
- const inherits$4 = __require("node:util").inherits;
5623
- const ReadableStream = __require("node:stream").Readable;
5624
- function PartStream(opts) {
5625
- ReadableStream.call(this, opts);
5626
- }
5627
- inherits$4(PartStream, ReadableStream);
5628
- PartStream.prototype._read = function(n) {};
5629
- module.exports = PartStream;
5630
- }));
5631
- //#endregion
5632
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/getLimit.js
5633
- var require_getLimit = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5634
- module.exports = function getLimit(limits, name, defaultLimit) {
5635
- if (!limits || limits[name] === void 0 || limits[name] === null) return defaultLimit;
5636
- if (typeof limits[name] !== "number" || isNaN(limits[name])) throw new TypeError("Limit " + name + " is not a valid number");
5637
- return limits[name];
5638
- };
5639
- }));
5640
- //#endregion
5641
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/dicer/lib/HeaderParser.js
5642
- var require_HeaderParser = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5643
- const EventEmitter$1 = __require("node:events").EventEmitter;
5644
- const inherits$3 = __require("node:util").inherits;
5645
- const getLimit = require_getLimit();
5646
- const StreamSearch = require_sbmh();
5647
- const B_DCRLF = Buffer.from("\r\n\r\n");
5648
- const RE_CRLF = /\r\n/g;
5649
- const RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/;
5650
- function HeaderParser(cfg) {
5651
- EventEmitter$1.call(this);
5652
- cfg = cfg || {};
5653
- const self = this;
5654
- this.nread = 0;
5655
- this.maxed = false;
5656
- this.npairs = 0;
5657
- this.maxHeaderPairs = getLimit(cfg, "maxHeaderPairs", 2e3);
5658
- this.maxHeaderSize = getLimit(cfg, "maxHeaderSize", 80 * 1024);
5659
- this.buffer = "";
5660
- this.header = {};
5661
- this.finished = false;
5662
- this.ss = new StreamSearch(B_DCRLF);
5663
- this.ss.on("info", function(isMatch, data, start, end) {
5664
- if (data && !self.maxed) {
5665
- if (self.nread + end - start >= self.maxHeaderSize) {
5666
- end = self.maxHeaderSize - self.nread + start;
5667
- self.nread = self.maxHeaderSize;
5668
- self.maxed = true;
5669
- } else self.nread += end - start;
5670
- self.buffer += data.toString("binary", start, end);
5671
- }
5672
- if (isMatch) self._finish();
5673
- });
5674
- }
5675
- inherits$3(HeaderParser, EventEmitter$1);
5676
- HeaderParser.prototype.push = function(data) {
5677
- const r = this.ss.push(data);
5678
- if (this.finished) return r;
5679
- };
5680
- HeaderParser.prototype.reset = function() {
5681
- this.finished = false;
5682
- this.buffer = "";
5683
- this.header = {};
5684
- this.ss.reset();
5685
- };
5686
- HeaderParser.prototype._finish = function() {
5687
- if (this.buffer) this._parseHeader();
5688
- this.ss.matches = this.ss.maxMatches;
5689
- const header = this.header;
5690
- this.header = {};
5691
- this.buffer = "";
5692
- this.finished = true;
5693
- this.nread = this.npairs = 0;
5694
- this.maxed = false;
5695
- this.emit("header", header);
5696
- };
5697
- HeaderParser.prototype._parseHeader = function() {
5698
- if (this.npairs === this.maxHeaderPairs) return;
5699
- const lines = this.buffer.split(RE_CRLF);
5700
- const len = lines.length;
5701
- let m, h;
5702
- for (var i = 0; i < len; ++i) {
5703
- if (lines[i].length === 0) continue;
5704
- if (lines[i][0] === " " || lines[i][0] === " ") {
5705
- if (h) {
5706
- this.header[h][this.header[h].length - 1] += lines[i];
5707
- continue;
5708
- }
5709
- }
5710
- const posColon = lines[i].indexOf(":");
5711
- if (posColon === -1 || posColon === 0) return;
5712
- m = RE_HDR.exec(lines[i]);
5713
- h = m[1].toLowerCase();
5714
- this.header[h] = this.header[h] || [];
5715
- this.header[h].push(m[2] || "");
5716
- if (++this.npairs === this.maxHeaderPairs) break;
5717
- }
5718
- };
5719
- module.exports = HeaderParser;
5720
- }));
5721
- //#endregion
5722
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/dicer/lib/Dicer.js
5723
- var require_Dicer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5724
- const WritableStream$1 = __require("node:stream").Writable;
5725
- const inherits$2 = __require("node:util").inherits;
5726
- const StreamSearch = require_sbmh();
5727
- const PartStream = require_PartStream();
5728
- const HeaderParser = require_HeaderParser();
5729
- const DASH = 45;
5730
- const B_ONEDASH = Buffer.from("-");
5731
- const B_CRLF = Buffer.from("\r\n");
5732
- const EMPTY_FN = function() {};
5733
- function Dicer(cfg) {
5734
- if (!(this instanceof Dicer)) return new Dicer(cfg);
5735
- WritableStream$1.call(this, cfg);
5736
- if (!cfg || !cfg.headerFirst && typeof cfg.boundary !== "string") throw new TypeError("Boundary required");
5737
- if (typeof cfg.boundary === "string") this.setBoundary(cfg.boundary);
5738
- else this._bparser = void 0;
5739
- this._headerFirst = cfg.headerFirst;
5740
- this._dashes = 0;
5741
- this._parts = 0;
5742
- this._finished = false;
5743
- this._realFinish = false;
5744
- this._isPreamble = true;
5745
- this._justMatched = false;
5746
- this._firstWrite = true;
5747
- this._inHeader = true;
5748
- this._part = void 0;
5749
- this._cb = void 0;
5750
- this._ignoreData = false;
5751
- this._partOpts = { highWaterMark: cfg.partHwm };
5752
- this._pause = false;
5753
- const self = this;
5754
- this._hparser = new HeaderParser(cfg);
5755
- this._hparser.on("header", function(header) {
5756
- self._inHeader = false;
5757
- self._part.emit("header", header);
5758
- });
5759
- }
5760
- inherits$2(Dicer, WritableStream$1);
5761
- Dicer.prototype.emit = function(ev) {
5762
- if (ev === "finish" && !this._realFinish) {
5763
- if (!this._finished) {
5764
- const self = this;
5765
- process.nextTick(function() {
5766
- self.emit("error", /* @__PURE__ */ new Error("Unexpected end of multipart data"));
5767
- if (self._part && !self._ignoreData) {
5768
- const type = self._isPreamble ? "Preamble" : "Part";
5769
- self._part.emit("error", /* @__PURE__ */ new Error(type + " terminated early due to unexpected end of multipart data"));
5770
- self._part.push(null);
5771
- process.nextTick(function() {
5772
- self._realFinish = true;
5773
- self.emit("finish");
5774
- self._realFinish = false;
5775
- });
5776
- return;
5777
- }
5778
- self._realFinish = true;
5779
- self.emit("finish");
5780
- self._realFinish = false;
5781
- });
5782
- }
5783
- } else WritableStream$1.prototype.emit.apply(this, arguments);
5784
- };
5785
- Dicer.prototype._write = function(data, encoding, cb) {
5786
- if (!this._hparser && !this._bparser) return cb();
5787
- if (this._headerFirst && this._isPreamble) {
5788
- if (!this._part) {
5789
- this._part = new PartStream(this._partOpts);
5790
- if (this.listenerCount("preamble") !== 0) this.emit("preamble", this._part);
5791
- else this._ignore();
5792
- }
5793
- const r = this._hparser.push(data);
5794
- if (!this._inHeader && r !== void 0 && r < data.length) data = data.slice(r);
5795
- else return cb();
5796
- }
5797
- if (this._firstWrite) {
5798
- this._bparser.push(B_CRLF);
5799
- this._firstWrite = false;
5800
- }
5801
- this._bparser.push(data);
5802
- if (this._pause) this._cb = cb;
5803
- else cb();
5804
- };
5805
- Dicer.prototype.reset = function() {
5806
- this._part = void 0;
5807
- this._bparser = void 0;
5808
- this._hparser = void 0;
5809
- };
5810
- Dicer.prototype.setBoundary = function(boundary) {
5811
- const self = this;
5812
- this._bparser = new StreamSearch("\r\n--" + boundary);
5813
- this._bparser.on("info", function(isMatch, data, start, end) {
5814
- self._oninfo(isMatch, data, start, end);
5815
- });
5816
- };
5817
- Dicer.prototype._ignore = function() {
5818
- if (this._part && !this._ignoreData) {
5819
- this._ignoreData = true;
5820
- this._part.on("error", EMPTY_FN);
5821
- this._part.resume();
5822
- }
5823
- };
5824
- Dicer.prototype._oninfo = function(isMatch, data, start, end) {
5825
- let buf;
5826
- const self = this;
5827
- let i = 0;
5828
- let r;
5829
- let shouldWriteMore = true;
5830
- if (!this._part && this._justMatched && data) {
5831
- while (this._dashes < 2 && start + i < end) if (data[start + i] === DASH) {
5832
- ++i;
5833
- ++this._dashes;
5834
- } else {
5835
- if (this._dashes) buf = B_ONEDASH;
5836
- this._dashes = 0;
5837
- break;
5838
- }
5839
- if (this._dashes === 2) {
5840
- if (start + i < end && this.listenerCount("trailer") !== 0) this.emit("trailer", data.slice(start + i, end));
5841
- this.reset();
5842
- this._finished = true;
5843
- if (self._parts === 0) {
5844
- self._realFinish = true;
5845
- self.emit("finish");
5846
- self._realFinish = false;
5847
- }
5848
- }
5849
- if (this._dashes) return;
5850
- }
5851
- if (this._justMatched) this._justMatched = false;
5852
- if (!this._part) {
5853
- this._part = new PartStream(this._partOpts);
5854
- this._part._read = function(n) {
5855
- self._unpause();
5856
- };
5857
- if (this._isPreamble && this.listenerCount("preamble") !== 0) this.emit("preamble", this._part);
5858
- else if (this._isPreamble !== true && this.listenerCount("part") !== 0) this.emit("part", this._part);
5859
- else this._ignore();
5860
- if (!this._isPreamble) this._inHeader = true;
5861
- }
5862
- if (data && start < end && !this._ignoreData) {
5863
- if (this._isPreamble || !this._inHeader) {
5864
- if (buf) shouldWriteMore = this._part.push(buf);
5865
- shouldWriteMore = this._part.push(data.slice(start, end));
5866
- if (!shouldWriteMore) this._pause = true;
5867
- } else if (!this._isPreamble && this._inHeader) {
5868
- if (buf) this._hparser.push(buf);
5869
- r = this._hparser.push(data.slice(start, end));
5870
- if (!this._inHeader && r !== void 0 && r < end) this._oninfo(false, data, start + r, end);
5871
- }
5872
- }
5873
- if (isMatch) {
5874
- this._hparser.reset();
5875
- if (this._isPreamble) this._isPreamble = false;
5876
- else if (start !== end) {
5877
- ++this._parts;
5878
- this._part.on("end", function() {
5879
- if (--self._parts === 0) if (self._finished) {
5880
- self._realFinish = true;
5881
- self.emit("finish");
5882
- self._realFinish = false;
5883
- } else self._unpause();
5884
- });
5885
- }
5886
- this._part.push(null);
5887
- this._part = void 0;
5888
- this._ignoreData = false;
5889
- this._justMatched = true;
5890
- this._dashes = 0;
5891
- }
5892
- };
5893
- Dicer.prototype._unpause = function() {
5894
- if (!this._pause) return;
5895
- this._pause = false;
5896
- if (this._cb) {
5897
- const cb = this._cb;
5898
- this._cb = void 0;
5899
- cb();
5900
- }
5901
- };
5902
- module.exports = Dicer;
5903
- }));
5904
- //#endregion
5905
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/decodeText.js
5906
- var require_decodeText = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5907
- const utf8Decoder = new TextDecoder("utf-8");
5908
- const textDecoders = new Map([["utf-8", utf8Decoder], ["utf8", utf8Decoder]]);
5909
- function getDecoder(charset) {
5910
- let lc;
5911
- while (true) switch (charset) {
5912
- case "utf-8":
5913
- case "utf8": return decoders.utf8;
5914
- case "latin1":
5915
- case "ascii":
5916
- case "us-ascii":
5917
- case "iso-8859-1":
5918
- case "iso8859-1":
5919
- case "iso88591":
5920
- case "iso_8859-1":
5921
- case "windows-1252":
5922
- case "iso_8859-1:1987":
5923
- case "cp1252":
5924
- case "x-cp1252": return decoders.latin1;
5925
- case "utf16le":
5926
- case "utf-16le":
5927
- case "ucs2":
5928
- case "ucs-2": return decoders.utf16le;
5929
- case "base64": return decoders.base64;
5930
- default:
5931
- if (lc === void 0) {
5932
- lc = true;
5933
- charset = charset.toLowerCase();
5934
- continue;
5935
- }
5936
- return decoders.other.bind(charset);
5937
- }
5938
- }
5939
- const decoders = {
5940
- utf8: (data, sourceEncoding) => {
5941
- if (data.length === 0) return "";
5942
- if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
5943
- return data.utf8Slice(0, data.length);
5944
- },
5945
- latin1: (data, sourceEncoding) => {
5946
- if (data.length === 0) return "";
5947
- if (typeof data === "string") return data;
5948
- return data.latin1Slice(0, data.length);
5949
- },
5950
- utf16le: (data, sourceEncoding) => {
5951
- if (data.length === 0) return "";
5952
- if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
5953
- return data.ucs2Slice(0, data.length);
5954
- },
5955
- base64: (data, sourceEncoding) => {
5956
- if (data.length === 0) return "";
5957
- if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
5958
- return data.base64Slice(0, data.length);
5959
- },
5960
- other: (data, sourceEncoding) => {
5961
- if (data.length === 0) return "";
5962
- if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
5963
- if (textDecoders.has(exports.toString())) try {
5964
- return textDecoders.get(exports).decode(data);
5965
- } catch {}
5966
- return typeof data === "string" ? data : data.toString();
5967
- }
5968
- };
5969
- function decodeText(text, sourceEncoding, destEncoding) {
5970
- if (text) return getDecoder(destEncoding)(text, sourceEncoding);
5971
- return text;
5972
- }
5973
- module.exports = decodeText;
5974
- }));
5975
- //#endregion
5976
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/parseParams.js
5977
- var require_parseParams = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5978
- const decodeText = require_decodeText();
5979
- const RE_ENCODED = /%[a-fA-F0-9][a-fA-F0-9]/g;
5980
- const EncodedLookup = {
5981
- "%00": "\0",
5982
- "%01": "",
5983
- "%02": "",
5984
- "%03": "",
5985
- "%04": "",
5986
- "%05": "",
5987
- "%06": "",
5988
- "%07": "\x07",
5989
- "%08": "\b",
5990
- "%09": " ",
5991
- "%0a": "\n",
5992
- "%0A": "\n",
5993
- "%0b": "\v",
5994
- "%0B": "\v",
5995
- "%0c": "\f",
5996
- "%0C": "\f",
5997
- "%0d": "\r",
5998
- "%0D": "\r",
5999
- "%0e": "",
6000
- "%0E": "",
6001
- "%0f": "",
6002
- "%0F": "",
6003
- "%10": "",
6004
- "%11": "",
6005
- "%12": "",
6006
- "%13": "",
6007
- "%14": "",
6008
- "%15": "",
6009
- "%16": "",
6010
- "%17": "",
6011
- "%18": "",
6012
- "%19": "",
6013
- "%1a": "",
6014
- "%1A": "",
6015
- "%1b": "\x1B",
6016
- "%1B": "\x1B",
6017
- "%1c": "",
6018
- "%1C": "",
6019
- "%1d": "",
6020
- "%1D": "",
6021
- "%1e": "",
6022
- "%1E": "",
6023
- "%1f": "",
6024
- "%1F": "",
6025
- "%20": " ",
6026
- "%21": "!",
6027
- "%22": "\"",
6028
- "%23": "#",
6029
- "%24": "$",
6030
- "%25": "%",
6031
- "%26": "&",
6032
- "%27": "'",
6033
- "%28": "(",
6034
- "%29": ")",
6035
- "%2a": "*",
6036
- "%2A": "*",
6037
- "%2b": "+",
6038
- "%2B": "+",
6039
- "%2c": ",",
6040
- "%2C": ",",
6041
- "%2d": "-",
6042
- "%2D": "-",
6043
- "%2e": ".",
6044
- "%2E": ".",
6045
- "%2f": "/",
6046
- "%2F": "/",
6047
- "%30": "0",
6048
- "%31": "1",
6049
- "%32": "2",
6050
- "%33": "3",
6051
- "%34": "4",
6052
- "%35": "5",
6053
- "%36": "6",
6054
- "%37": "7",
6055
- "%38": "8",
6056
- "%39": "9",
6057
- "%3a": ":",
6058
- "%3A": ":",
6059
- "%3b": ";",
6060
- "%3B": ";",
6061
- "%3c": "<",
6062
- "%3C": "<",
6063
- "%3d": "=",
6064
- "%3D": "=",
6065
- "%3e": ">",
6066
- "%3E": ">",
6067
- "%3f": "?",
6068
- "%3F": "?",
6069
- "%40": "@",
6070
- "%41": "A",
6071
- "%42": "B",
6072
- "%43": "C",
6073
- "%44": "D",
6074
- "%45": "E",
6075
- "%46": "F",
6076
- "%47": "G",
6077
- "%48": "H",
6078
- "%49": "I",
6079
- "%4a": "J",
6080
- "%4A": "J",
6081
- "%4b": "K",
6082
- "%4B": "K",
6083
- "%4c": "L",
6084
- "%4C": "L",
6085
- "%4d": "M",
6086
- "%4D": "M",
6087
- "%4e": "N",
6088
- "%4E": "N",
6089
- "%4f": "O",
6090
- "%4F": "O",
6091
- "%50": "P",
6092
- "%51": "Q",
6093
- "%52": "R",
6094
- "%53": "S",
6095
- "%54": "T",
6096
- "%55": "U",
6097
- "%56": "V",
6098
- "%57": "W",
6099
- "%58": "X",
6100
- "%59": "Y",
6101
- "%5a": "Z",
6102
- "%5A": "Z",
6103
- "%5b": "[",
6104
- "%5B": "[",
6105
- "%5c": "\\",
6106
- "%5C": "\\",
6107
- "%5d": "]",
6108
- "%5D": "]",
6109
- "%5e": "^",
6110
- "%5E": "^",
6111
- "%5f": "_",
6112
- "%5F": "_",
6113
- "%60": "`",
6114
- "%61": "a",
6115
- "%62": "b",
6116
- "%63": "c",
6117
- "%64": "d",
6118
- "%65": "e",
6119
- "%66": "f",
6120
- "%67": "g",
6121
- "%68": "h",
6122
- "%69": "i",
6123
- "%6a": "j",
6124
- "%6A": "j",
6125
- "%6b": "k",
6126
- "%6B": "k",
6127
- "%6c": "l",
6128
- "%6C": "l",
6129
- "%6d": "m",
6130
- "%6D": "m",
6131
- "%6e": "n",
6132
- "%6E": "n",
6133
- "%6f": "o",
6134
- "%6F": "o",
6135
- "%70": "p",
6136
- "%71": "q",
6137
- "%72": "r",
6138
- "%73": "s",
6139
- "%74": "t",
6140
- "%75": "u",
6141
- "%76": "v",
6142
- "%77": "w",
6143
- "%78": "x",
6144
- "%79": "y",
6145
- "%7a": "z",
6146
- "%7A": "z",
6147
- "%7b": "{",
6148
- "%7B": "{",
6149
- "%7c": "|",
6150
- "%7C": "|",
6151
- "%7d": "}",
6152
- "%7D": "}",
6153
- "%7e": "~",
6154
- "%7E": "~",
6155
- "%7f": "",
6156
- "%7F": "",
6157
- "%80": "€",
6158
- "%81": "",
6159
- "%82": "‚",
6160
- "%83": "ƒ",
6161
- "%84": "„",
6162
- "%85": "…",
6163
- "%86": "†",
6164
- "%87": "‡",
6165
- "%88": "ˆ",
6166
- "%89": "‰",
6167
- "%8a": "Š",
6168
- "%8A": "Š",
6169
- "%8b": "‹",
6170
- "%8B": "‹",
6171
- "%8c": "Œ",
6172
- "%8C": "Œ",
6173
- "%8d": "",
6174
- "%8D": "",
6175
- "%8e": "Ž",
6176
- "%8E": "Ž",
6177
- "%8f": "",
6178
- "%8F": "",
6179
- "%90": "",
6180
- "%91": "‘",
6181
- "%92": "’",
6182
- "%93": "“",
6183
- "%94": "”",
6184
- "%95": "•",
6185
- "%96": "–",
6186
- "%97": "—",
6187
- "%98": "˜",
6188
- "%99": "™",
6189
- "%9a": "š",
6190
- "%9A": "š",
6191
- "%9b": "›",
6192
- "%9B": "›",
6193
- "%9c": "œ",
6194
- "%9C": "œ",
6195
- "%9d": "",
6196
- "%9D": "",
6197
- "%9e": "ž",
6198
- "%9E": "ž",
6199
- "%9f": "Ÿ",
6200
- "%9F": "Ÿ",
6201
- "%a0": "\xA0",
6202
- "%A0": "\xA0",
6203
- "%a1": "¡",
6204
- "%A1": "¡",
6205
- "%a2": "¢",
6206
- "%A2": "¢",
6207
- "%a3": "£",
6208
- "%A3": "£",
6209
- "%a4": "¤",
6210
- "%A4": "¤",
6211
- "%a5": "¥",
6212
- "%A5": "¥",
6213
- "%a6": "¦",
6214
- "%A6": "¦",
6215
- "%a7": "§",
6216
- "%A7": "§",
6217
- "%a8": "¨",
6218
- "%A8": "¨",
6219
- "%a9": "©",
6220
- "%A9": "©",
6221
- "%aa": "ª",
6222
- "%Aa": "ª",
6223
- "%aA": "ª",
6224
- "%AA": "ª",
6225
- "%ab": "«",
6226
- "%Ab": "«",
6227
- "%aB": "«",
6228
- "%AB": "«",
6229
- "%ac": "¬",
6230
- "%Ac": "¬",
6231
- "%aC": "¬",
6232
- "%AC": "¬",
6233
- "%ad": "­",
6234
- "%Ad": "­",
6235
- "%aD": "­",
6236
- "%AD": "­",
6237
- "%ae": "®",
6238
- "%Ae": "®",
6239
- "%aE": "®",
6240
- "%AE": "®",
6241
- "%af": "¯",
6242
- "%Af": "¯",
6243
- "%aF": "¯",
6244
- "%AF": "¯",
6245
- "%b0": "°",
6246
- "%B0": "°",
6247
- "%b1": "±",
6248
- "%B1": "±",
6249
- "%b2": "²",
6250
- "%B2": "²",
6251
- "%b3": "³",
6252
- "%B3": "³",
6253
- "%b4": "´",
6254
- "%B4": "´",
6255
- "%b5": "µ",
6256
- "%B5": "µ",
6257
- "%b6": "¶",
6258
- "%B6": "¶",
6259
- "%b7": "·",
6260
- "%B7": "·",
6261
- "%b8": "¸",
6262
- "%B8": "¸",
6263
- "%b9": "¹",
6264
- "%B9": "¹",
6265
- "%ba": "º",
6266
- "%Ba": "º",
6267
- "%bA": "º",
6268
- "%BA": "º",
6269
- "%bb": "»",
6270
- "%Bb": "»",
6271
- "%bB": "»",
6272
- "%BB": "»",
6273
- "%bc": "¼",
6274
- "%Bc": "¼",
6275
- "%bC": "¼",
6276
- "%BC": "¼",
6277
- "%bd": "½",
6278
- "%Bd": "½",
6279
- "%bD": "½",
6280
- "%BD": "½",
6281
- "%be": "¾",
6282
- "%Be": "¾",
6283
- "%bE": "¾",
6284
- "%BE": "¾",
6285
- "%bf": "¿",
6286
- "%Bf": "¿",
6287
- "%bF": "¿",
6288
- "%BF": "¿",
6289
- "%c0": "À",
6290
- "%C0": "À",
6291
- "%c1": "Á",
6292
- "%C1": "Á",
6293
- "%c2": "Â",
6294
- "%C2": "Â",
6295
- "%c3": "Ã",
6296
- "%C3": "Ã",
6297
- "%c4": "Ä",
6298
- "%C4": "Ä",
6299
- "%c5": "Å",
6300
- "%C5": "Å",
6301
- "%c6": "Æ",
6302
- "%C6": "Æ",
6303
- "%c7": "Ç",
6304
- "%C7": "Ç",
6305
- "%c8": "È",
6306
- "%C8": "È",
6307
- "%c9": "É",
6308
- "%C9": "É",
6309
- "%ca": "Ê",
6310
- "%Ca": "Ê",
6311
- "%cA": "Ê",
6312
- "%CA": "Ê",
6313
- "%cb": "Ë",
6314
- "%Cb": "Ë",
6315
- "%cB": "Ë",
6316
- "%CB": "Ë",
6317
- "%cc": "Ì",
6318
- "%Cc": "Ì",
6319
- "%cC": "Ì",
6320
- "%CC": "Ì",
6321
- "%cd": "Í",
6322
- "%Cd": "Í",
6323
- "%cD": "Í",
6324
- "%CD": "Í",
6325
- "%ce": "Î",
6326
- "%Ce": "Î",
6327
- "%cE": "Î",
6328
- "%CE": "Î",
6329
- "%cf": "Ï",
6330
- "%Cf": "Ï",
6331
- "%cF": "Ï",
6332
- "%CF": "Ï",
6333
- "%d0": "Ð",
6334
- "%D0": "Ð",
6335
- "%d1": "Ñ",
6336
- "%D1": "Ñ",
6337
- "%d2": "Ò",
6338
- "%D2": "Ò",
6339
- "%d3": "Ó",
6340
- "%D3": "Ó",
6341
- "%d4": "Ô",
6342
- "%D4": "Ô",
6343
- "%d5": "Õ",
6344
- "%D5": "Õ",
6345
- "%d6": "Ö",
6346
- "%D6": "Ö",
6347
- "%d7": "×",
6348
- "%D7": "×",
6349
- "%d8": "Ø",
6350
- "%D8": "Ø",
6351
- "%d9": "Ù",
6352
- "%D9": "Ù",
6353
- "%da": "Ú",
6354
- "%Da": "Ú",
6355
- "%dA": "Ú",
6356
- "%DA": "Ú",
6357
- "%db": "Û",
6358
- "%Db": "Û",
6359
- "%dB": "Û",
6360
- "%DB": "Û",
6361
- "%dc": "Ü",
6362
- "%Dc": "Ü",
6363
- "%dC": "Ü",
6364
- "%DC": "Ü",
6365
- "%dd": "Ý",
6366
- "%Dd": "Ý",
6367
- "%dD": "Ý",
6368
- "%DD": "Ý",
6369
- "%de": "Þ",
6370
- "%De": "Þ",
6371
- "%dE": "Þ",
6372
- "%DE": "Þ",
6373
- "%df": "ß",
6374
- "%Df": "ß",
6375
- "%dF": "ß",
6376
- "%DF": "ß",
6377
- "%e0": "à",
6378
- "%E0": "à",
6379
- "%e1": "á",
6380
- "%E1": "á",
6381
- "%e2": "â",
6382
- "%E2": "â",
6383
- "%e3": "ã",
6384
- "%E3": "ã",
6385
- "%e4": "ä",
6386
- "%E4": "ä",
6387
- "%e5": "å",
6388
- "%E5": "å",
6389
- "%e6": "æ",
6390
- "%E6": "æ",
6391
- "%e7": "ç",
6392
- "%E7": "ç",
6393
- "%e8": "è",
6394
- "%E8": "è",
6395
- "%e9": "é",
6396
- "%E9": "é",
6397
- "%ea": "ê",
6398
- "%Ea": "ê",
6399
- "%eA": "ê",
6400
- "%EA": "ê",
6401
- "%eb": "ë",
6402
- "%Eb": "ë",
6403
- "%eB": "ë",
6404
- "%EB": "ë",
6405
- "%ec": "ì",
6406
- "%Ec": "ì",
6407
- "%eC": "ì",
6408
- "%EC": "ì",
6409
- "%ed": "í",
6410
- "%Ed": "í",
6411
- "%eD": "í",
6412
- "%ED": "í",
6413
- "%ee": "î",
6414
- "%Ee": "î",
6415
- "%eE": "î",
6416
- "%EE": "î",
6417
- "%ef": "ï",
6418
- "%Ef": "ï",
6419
- "%eF": "ï",
6420
- "%EF": "ï",
6421
- "%f0": "ð",
6422
- "%F0": "ð",
6423
- "%f1": "ñ",
6424
- "%F1": "ñ",
6425
- "%f2": "ò",
6426
- "%F2": "ò",
6427
- "%f3": "ó",
6428
- "%F3": "ó",
6429
- "%f4": "ô",
6430
- "%F4": "ô",
6431
- "%f5": "õ",
6432
- "%F5": "õ",
6433
- "%f6": "ö",
6434
- "%F6": "ö",
6435
- "%f7": "÷",
6436
- "%F7": "÷",
6437
- "%f8": "ø",
6438
- "%F8": "ø",
6439
- "%f9": "ù",
6440
- "%F9": "ù",
6441
- "%fa": "ú",
6442
- "%Fa": "ú",
6443
- "%fA": "ú",
6444
- "%FA": "ú",
6445
- "%fb": "û",
6446
- "%Fb": "û",
6447
- "%fB": "û",
6448
- "%FB": "û",
6449
- "%fc": "ü",
6450
- "%Fc": "ü",
6451
- "%fC": "ü",
6452
- "%FC": "ü",
6453
- "%fd": "ý",
6454
- "%Fd": "ý",
6455
- "%fD": "ý",
6456
- "%FD": "ý",
6457
- "%fe": "þ",
6458
- "%Fe": "þ",
6459
- "%fE": "þ",
6460
- "%FE": "þ",
6461
- "%ff": "ÿ",
6462
- "%Ff": "ÿ",
6463
- "%fF": "ÿ",
6464
- "%FF": "ÿ"
6465
- };
6466
- function encodedReplacer(match) {
6467
- return EncodedLookup[match];
6468
- }
6469
- const STATE_KEY = 0;
6470
- const STATE_VALUE = 1;
6471
- const STATE_CHARSET = 2;
6472
- const STATE_LANG = 3;
6473
- function parseParams(str) {
6474
- const res = [];
6475
- let state = STATE_KEY;
6476
- let charset = "";
6477
- let inquote = false;
6478
- let escaping = false;
6479
- let p = 0;
6480
- let tmp = "";
6481
- const len = str.length;
6482
- for (var i = 0; i < len; ++i) {
6483
- const char = str[i];
6484
- if (char === "\\" && inquote) if (escaping) escaping = false;
6485
- else {
6486
- escaping = true;
6487
- continue;
6488
- }
6489
- else if (char === "\"") if (!escaping) {
6490
- if (inquote) {
6491
- inquote = false;
6492
- state = STATE_KEY;
6493
- while (i + 1 < len && str[i + 1] !== ";") ++i;
6494
- } else inquote = true;
6495
- continue;
6496
- } else escaping = false;
6497
- else {
6498
- if (escaping && inquote) tmp += "\\";
6499
- escaping = false;
6500
- if ((state === STATE_CHARSET || state === STATE_LANG) && char === "'") {
6501
- if (state === STATE_CHARSET) {
6502
- state = STATE_LANG;
6503
- charset = tmp.substring(1);
6504
- } else state = STATE_VALUE;
6505
- tmp = "";
6506
- continue;
6507
- } else if (state === STATE_KEY && (char === "*" || char === "=") && res.length) {
6508
- state = char === "*" ? STATE_CHARSET : STATE_VALUE;
6509
- res[p] = [tmp, void 0];
6510
- tmp = "";
6511
- continue;
6512
- } else if (!inquote && char === ";") {
6513
- state = STATE_KEY;
6514
- if (charset) {
6515
- if (tmp.length) tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), "binary", charset);
6516
- charset = "";
6517
- } else if (tmp.length) tmp = decodeText(tmp, "binary", "utf8");
6518
- if (res[p] === void 0) res[p] = tmp;
6519
- else res[p][1] = tmp;
6520
- tmp = "";
6521
- ++p;
6522
- continue;
6523
- } else if (!inquote && (char === " " || char === " ")) continue;
6524
- }
6525
- tmp += char;
6526
- }
6527
- if (charset && tmp.length) tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), "binary", charset);
6528
- else if (tmp) tmp = decodeText(tmp, "binary", "utf8");
6529
- if (res[p] === void 0) {
6530
- if (tmp) res[p] = tmp;
6531
- } else res[p][1] = tmp;
6532
- return res;
6533
- }
6534
- module.exports = parseParams;
6535
- }));
6536
- //#endregion
6537
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/basename.js
6538
- var require_basename = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6539
- module.exports = function basename(path) {
6540
- if (typeof path !== "string") return "";
6541
- for (var i = path.length - 1; i >= 0; --i) switch (path.charCodeAt(i)) {
6542
- case 47:
6543
- case 92:
6544
- path = path.slice(i + 1);
6545
- return path === ".." || path === "." ? "" : path;
6546
- }
6547
- return path === ".." || path === "." ? "" : path;
6548
- };
6549
- }));
6550
- //#endregion
6551
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/types/multipart.js
6552
- var require_multipart$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6553
- const { Readable: Readable$1 } = __require("node:stream");
6554
- const { inherits: inherits$1 } = __require("node:util");
6555
- const Dicer = require_Dicer();
6556
- const parseParams = require_parseParams();
6557
- const decodeText = require_decodeText();
6558
- const basename = require_basename();
6559
- const getLimit = require_getLimit();
6560
- const RE_BOUNDARY = /^boundary$/i;
6561
- const RE_FIELD = /^form-data$/i;
6562
- const RE_CHARSET = /^charset$/i;
6563
- const RE_FILENAME = /^filename$/i;
6564
- const RE_NAME = /^name$/i;
6565
- Multipart.detect = /^multipart\/form-data/i;
6566
- function Multipart(boy, cfg) {
6567
- let i;
6568
- let len;
6569
- const self = this;
6570
- let boundary;
6571
- const limits = cfg.limits;
6572
- const isPartAFile = cfg.isPartAFile || ((fieldName, contentType, fileName) => contentType === "application/octet-stream" || fileName !== void 0);
6573
- const parsedConType = cfg.parsedConType || [];
6574
- const defCharset = cfg.defCharset || "utf8";
6575
- const preservePath = cfg.preservePath;
6576
- const fileOpts = { highWaterMark: cfg.fileHwm };
6577
- for (i = 0, len = parsedConType.length; i < len; ++i) if (Array.isArray(parsedConType[i]) && RE_BOUNDARY.test(parsedConType[i][0])) {
6578
- boundary = parsedConType[i][1];
6579
- break;
6580
- }
6581
- function checkFinished() {
6582
- if (nends === 0 && finished && !boy._done) {
6583
- finished = false;
6584
- self.end();
6585
- }
6586
- }
6587
- if (typeof boundary !== "string") throw new Error("Multipart: Boundary not found");
6588
- const fieldSizeLimit = getLimit(limits, "fieldSize", 1 * 1024 * 1024);
6589
- const fileSizeLimit = getLimit(limits, "fileSize", Infinity);
6590
- const filesLimit = getLimit(limits, "files", Infinity);
6591
- const fieldsLimit = getLimit(limits, "fields", Infinity);
6592
- const partsLimit = getLimit(limits, "parts", Infinity);
6593
- const headerPairsLimit = getLimit(limits, "headerPairs", 2e3);
6594
- const headerSizeLimit = getLimit(limits, "headerSize", 80 * 1024);
6595
- let nfiles = 0;
6596
- let nfields = 0;
6597
- let nends = 0;
6598
- let curFile;
6599
- let curField;
6600
- let finished = false;
6601
- this._needDrain = false;
6602
- this._pause = false;
6603
- this._cb = void 0;
6604
- this._nparts = 0;
6605
- this._boy = boy;
6606
- this.parser = new Dicer({
6607
- boundary,
6608
- maxHeaderPairs: headerPairsLimit,
6609
- maxHeaderSize: headerSizeLimit,
6610
- partHwm: fileOpts.highWaterMark,
6611
- highWaterMark: cfg.highWaterMark
6612
- });
6613
- this.parser.on("drain", function() {
6614
- self._needDrain = false;
6615
- if (self._cb && !self._pause) {
6616
- const cb = self._cb;
6617
- self._cb = void 0;
6618
- cb();
6619
- }
6620
- }).on("part", function onPart(part) {
6621
- if (++self._nparts > partsLimit) {
6622
- self.parser.removeListener("part", onPart);
6623
- self.parser.on("part", skipPart);
6624
- boy.hitPartsLimit = true;
6625
- boy.emit("partsLimit");
6626
- return skipPart(part);
6627
- }
6628
- if (curField) {
6629
- const field = curField;
6630
- field.emit("end");
6631
- field.removeAllListeners("end");
6632
- }
6633
- part.on("header", function(header) {
6634
- let contype;
6635
- let fieldname;
6636
- let parsed;
6637
- let charset;
6638
- let encoding;
6639
- let filename;
6640
- let nsize = 0;
6641
- if (header["content-type"]) {
6642
- parsed = parseParams(header["content-type"][0]);
6643
- if (parsed[0]) {
6644
- contype = parsed[0].toLowerCase();
6645
- for (i = 0, len = parsed.length; i < len; ++i) if (RE_CHARSET.test(parsed[i][0])) {
6646
- charset = parsed[i][1].toLowerCase();
6647
- break;
6648
- }
6649
- }
6650
- }
6651
- if (contype === void 0) contype = "text/plain";
6652
- if (charset === void 0) charset = defCharset;
6653
- if (header["content-disposition"]) {
6654
- parsed = parseParams(header["content-disposition"][0]);
6655
- if (!RE_FIELD.test(parsed[0])) return skipPart(part);
6656
- for (i = 0, len = parsed.length; i < len; ++i) if (RE_NAME.test(parsed[i][0])) fieldname = parsed[i][1];
6657
- else if (RE_FILENAME.test(parsed[i][0])) {
6658
- filename = parsed[i][1];
6659
- if (!preservePath) filename = basename(filename);
6660
- }
6661
- } else return skipPart(part);
6662
- if (header["content-transfer-encoding"]) encoding = header["content-transfer-encoding"][0].toLowerCase();
6663
- else encoding = "7bit";
6664
- let onData, onEnd;
6665
- if (isPartAFile(fieldname, contype, filename)) {
6666
- if (nfiles === filesLimit) {
6667
- if (!boy.hitFilesLimit) {
6668
- boy.hitFilesLimit = true;
6669
- boy.emit("filesLimit");
6670
- }
6671
- return skipPart(part);
6672
- }
6673
- ++nfiles;
6674
- if (boy.listenerCount("file") === 0) {
6675
- self.parser._ignore();
6676
- return;
6677
- }
6678
- ++nends;
6679
- const file = new FileStream(fileOpts);
6680
- curFile = file;
6681
- file.on("end", function() {
6682
- --nends;
6683
- self._pause = false;
6684
- checkFinished();
6685
- if (self._cb && !self._needDrain) {
6686
- const cb = self._cb;
6687
- self._cb = void 0;
6688
- cb();
6689
- }
6690
- });
6691
- file._read = function(n) {
6692
- if (!self._pause) return;
6693
- self._pause = false;
6694
- if (self._cb && !self._needDrain) {
6695
- const cb = self._cb;
6696
- self._cb = void 0;
6697
- cb();
6698
- }
6699
- };
6700
- boy.emit("file", fieldname, file, filename, encoding, contype);
6701
- onData = function(data) {
6702
- if ((nsize += data.length) > fileSizeLimit) {
6703
- const extralen = fileSizeLimit - nsize + data.length;
6704
- if (extralen > 0) file.push(data.slice(0, extralen));
6705
- file.truncated = true;
6706
- file.bytesRead = fileSizeLimit;
6707
- part.removeAllListeners("data");
6708
- file.emit("limit");
6709
- return;
6710
- } else if (!file.push(data)) self._pause = true;
6711
- file.bytesRead = nsize;
6712
- };
6713
- onEnd = function() {
6714
- curFile = void 0;
6715
- file.push(null);
6716
- };
6717
- } else {
6718
- if (nfields === fieldsLimit) {
6719
- if (!boy.hitFieldsLimit) {
6720
- boy.hitFieldsLimit = true;
6721
- boy.emit("fieldsLimit");
6722
- }
6723
- return skipPart(part);
6724
- }
6725
- ++nfields;
6726
- ++nends;
6727
- let buffer = "";
6728
- let truncated = false;
6729
- curField = part;
6730
- onData = function(data) {
6731
- if ((nsize += data.length) > fieldSizeLimit) {
6732
- const extralen = fieldSizeLimit - (nsize - data.length);
6733
- buffer += data.toString("binary", 0, extralen);
6734
- truncated = true;
6735
- part.removeAllListeners("data");
6736
- } else buffer += data.toString("binary");
6737
- };
6738
- onEnd = function() {
6739
- curField = void 0;
6740
- if (buffer.length) buffer = decodeText(buffer, "binary", charset);
6741
- boy.emit("field", fieldname, buffer, false, truncated, encoding, contype);
6742
- --nends;
6743
- checkFinished();
6744
- };
6745
- }
6746
- part._readableState.sync = false;
6747
- part.on("data", onData);
6748
- part.on("end", onEnd);
6749
- }).on("error", function(err) {
6750
- if (curFile) curFile.emit("error", err);
6751
- });
6752
- }).on("error", function(err) {
6753
- boy.emit("error", err);
6754
- }).on("finish", function() {
6755
- finished = true;
6756
- checkFinished();
6757
- });
6758
- }
6759
- Multipart.prototype.write = function(chunk, cb) {
6760
- const r = this.parser.write(chunk);
6761
- if (r && !this._pause) cb();
6762
- else {
6763
- this._needDrain = !r;
6764
- this._cb = cb;
6765
- }
6766
- };
6767
- Multipart.prototype.end = function() {
6768
- const self = this;
6769
- if (self.parser.writable) self.parser.end();
6770
- else if (!self._boy._done) process.nextTick(function() {
6771
- self._boy._done = true;
6772
- self._boy.emit("finish");
6773
- });
6774
- };
6775
- function skipPart(part) {
6776
- part.resume();
6777
- }
6778
- function FileStream(opts) {
6779
- Readable$1.call(this, opts);
6780
- this.bytesRead = 0;
6781
- this.truncated = false;
6782
- }
6783
- inherits$1(FileStream, Readable$1);
6784
- FileStream.prototype._read = function(n) {};
6785
- module.exports = Multipart;
6786
- }));
6787
- //#endregion
6788
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/Decoder.js
6789
- var require_Decoder = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6790
- const RE_PLUS = /\+/g;
6791
- const HEX = [
6792
- 0,
6793
- 0,
6794
- 0,
6795
- 0,
6796
- 0,
6797
- 0,
6798
- 0,
6799
- 0,
6800
- 0,
6801
- 0,
6802
- 0,
6803
- 0,
6804
- 0,
6805
- 0,
6806
- 0,
6807
- 0,
6808
- 0,
6809
- 0,
6810
- 0,
6811
- 0,
6812
- 0,
6813
- 0,
6814
- 0,
6815
- 0,
6816
- 0,
6817
- 0,
6818
- 0,
6819
- 0,
6820
- 0,
6821
- 0,
6822
- 0,
6823
- 0,
6824
- 0,
6825
- 0,
6826
- 0,
6827
- 0,
6828
- 0,
6829
- 0,
6830
- 0,
6831
- 0,
6832
- 0,
6833
- 0,
6834
- 0,
6835
- 0,
6836
- 0,
6837
- 0,
6838
- 0,
6839
- 0,
6840
- 1,
6841
- 1,
6842
- 1,
6843
- 1,
6844
- 1,
6845
- 1,
6846
- 1,
6847
- 1,
6848
- 1,
6849
- 1,
6850
- 0,
6851
- 0,
6852
- 0,
6853
- 0,
6854
- 0,
6855
- 0,
6856
- 0,
6857
- 1,
6858
- 1,
6859
- 1,
6860
- 1,
6861
- 1,
6862
- 1,
6863
- 0,
6864
- 0,
6865
- 0,
6866
- 0,
6867
- 0,
6868
- 0,
6869
- 0,
6870
- 0,
6871
- 0,
6872
- 0,
6873
- 0,
6874
- 0,
6875
- 0,
6876
- 0,
6877
- 0,
6878
- 0,
6879
- 0,
6880
- 0,
6881
- 0,
6882
- 0,
6883
- 0,
6884
- 0,
6885
- 0,
6886
- 0,
6887
- 0,
6888
- 0,
6889
- 1,
6890
- 1,
6891
- 1,
6892
- 1,
6893
- 1,
6894
- 1,
6895
- 0,
6896
- 0,
6897
- 0,
6898
- 0,
6899
- 0,
6900
- 0,
6901
- 0,
6902
- 0,
6903
- 0,
6904
- 0,
6905
- 0,
6906
- 0,
6907
- 0,
6908
- 0,
6909
- 0,
6910
- 0,
6911
- 0,
6912
- 0,
6913
- 0,
6914
- 0,
6915
- 0,
6916
- 0,
6917
- 0,
6918
- 0,
6919
- 0
6920
- ];
6921
- function Decoder() {
6922
- this.buffer = void 0;
6923
- }
6924
- Decoder.prototype.write = function(str) {
6925
- str = str.replace(RE_PLUS, " ");
6926
- let res = "";
6927
- let i = 0;
6928
- let p = 0;
6929
- const len = str.length;
6930
- for (; i < len; ++i) if (this.buffer !== void 0) if (!HEX[str.charCodeAt(i)]) {
6931
- res += "%" + this.buffer;
6932
- this.buffer = void 0;
6933
- --i;
6934
- } else {
6935
- this.buffer += str[i];
6936
- ++p;
6937
- if (this.buffer.length === 2) {
6938
- res += String.fromCharCode(parseInt(this.buffer, 16));
6939
- this.buffer = void 0;
6940
- }
6941
- }
6942
- else if (str[i] === "%") {
6943
- if (i > p) {
6944
- res += str.substring(p, i);
6945
- p = i;
6946
- }
6947
- this.buffer = "";
6948
- ++p;
6949
- }
6950
- if (p < len && this.buffer === void 0) res += str.substring(p);
6951
- return res;
6952
- };
6953
- Decoder.prototype.reset = function() {
6954
- this.buffer = void 0;
6955
- };
6956
- module.exports = Decoder;
6957
- }));
6958
- //#endregion
6959
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/types/urlencoded.js
6960
- var require_urlencoded = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6961
- const Decoder = require_Decoder();
6962
- const decodeText = require_decodeText();
6963
- const getLimit = require_getLimit();
6964
- const RE_CHARSET = /^charset$/i;
6965
- UrlEncoded.detect = /^application\/x-www-form-urlencoded/i;
6966
- function UrlEncoded(boy, cfg) {
6967
- const limits = cfg.limits;
6968
- const parsedConType = cfg.parsedConType;
6969
- this.boy = boy;
6970
- this.fieldSizeLimit = getLimit(limits, "fieldSize", 1 * 1024 * 1024);
6971
- this.fieldNameSizeLimit = getLimit(limits, "fieldNameSize", 100);
6972
- this.fieldsLimit = getLimit(limits, "fields", Infinity);
6973
- let charset;
6974
- for (var i = 0, len = parsedConType.length; i < len; ++i) if (Array.isArray(parsedConType[i]) && RE_CHARSET.test(parsedConType[i][0])) {
6975
- charset = parsedConType[i][1].toLowerCase();
6976
- break;
6977
- }
6978
- if (charset === void 0) charset = cfg.defCharset || "utf8";
6979
- this.decoder = new Decoder();
6980
- this.charset = charset;
6981
- this._fields = 0;
6982
- this._state = "key";
6983
- this._checkingBytes = true;
6984
- this._bytesKey = 0;
6985
- this._bytesVal = 0;
6986
- this._key = "";
6987
- this._val = "";
6988
- this._keyTrunc = false;
6989
- this._valTrunc = false;
6990
- this._hitLimit = false;
6991
- }
6992
- UrlEncoded.prototype.write = function(data, cb) {
6993
- if (this._fields === this.fieldsLimit) {
6994
- if (!this.boy.hitFieldsLimit) {
6995
- this.boy.hitFieldsLimit = true;
6996
- this.boy.emit("fieldsLimit");
6997
- }
6998
- return cb();
6999
- }
7000
- let idxeq;
7001
- let idxamp;
7002
- let i;
7003
- let p = 0;
7004
- const len = data.length;
7005
- while (p < len) if (this._state === "key") {
7006
- idxeq = idxamp = void 0;
7007
- for (i = p; i < len; ++i) {
7008
- if (!this._checkingBytes) ++p;
7009
- if (data[i] === 61) {
7010
- idxeq = i;
7011
- break;
7012
- } else if (data[i] === 38) {
7013
- idxamp = i;
7014
- break;
7015
- }
7016
- if (this._checkingBytes && this._bytesKey === this.fieldNameSizeLimit) {
7017
- this._hitLimit = true;
7018
- break;
7019
- } else if (this._checkingBytes) ++this._bytesKey;
7020
- }
7021
- if (idxeq !== void 0) {
7022
- if (idxeq > p) this._key += this.decoder.write(data.toString("binary", p, idxeq));
7023
- this._state = "val";
7024
- this._hitLimit = false;
7025
- this._checkingBytes = true;
7026
- this._val = "";
7027
- this._bytesVal = 0;
7028
- this._valTrunc = false;
7029
- this.decoder.reset();
7030
- p = idxeq + 1;
7031
- } else if (idxamp !== void 0) {
7032
- ++this._fields;
7033
- let key;
7034
- const keyTrunc = this._keyTrunc;
7035
- if (idxamp > p) key = this._key += this.decoder.write(data.toString("binary", p, idxamp));
7036
- else key = this._key;
7037
- this._hitLimit = false;
7038
- this._checkingBytes = true;
7039
- this._key = "";
7040
- this._bytesKey = 0;
7041
- this._keyTrunc = false;
7042
- this.decoder.reset();
7043
- if (key.length) this.boy.emit("field", decodeText(key, "binary", this.charset), "", keyTrunc, false);
7044
- p = idxamp + 1;
7045
- if (this._fields === this.fieldsLimit) return cb();
7046
- } else if (this._hitLimit) {
7047
- if (i > p) this._key += this.decoder.write(data.toString("binary", p, i));
7048
- p = i;
7049
- if ((this._bytesKey = this._key.length) === this.fieldNameSizeLimit) {
7050
- this._checkingBytes = false;
7051
- this._keyTrunc = true;
7052
- }
7053
- } else {
7054
- if (p < len) this._key += this.decoder.write(data.toString("binary", p));
7055
- p = len;
7056
- }
7057
- } else {
7058
- idxamp = void 0;
7059
- for (i = p; i < len; ++i) {
7060
- if (!this._checkingBytes) ++p;
7061
- if (data[i] === 38) {
7062
- idxamp = i;
7063
- break;
7064
- }
7065
- if (this._checkingBytes && this._bytesVal === this.fieldSizeLimit) {
7066
- this._hitLimit = true;
7067
- break;
7068
- } else if (this._checkingBytes) ++this._bytesVal;
7069
- }
7070
- if (idxamp !== void 0) {
7071
- ++this._fields;
7072
- if (idxamp > p) this._val += this.decoder.write(data.toString("binary", p, idxamp));
7073
- this.boy.emit("field", decodeText(this._key, "binary", this.charset), decodeText(this._val, "binary", this.charset), this._keyTrunc, this._valTrunc);
7074
- this._state = "key";
7075
- this._hitLimit = false;
7076
- this._checkingBytes = true;
7077
- this._key = "";
7078
- this._bytesKey = 0;
7079
- this._keyTrunc = false;
7080
- this.decoder.reset();
7081
- p = idxamp + 1;
7082
- if (this._fields === this.fieldsLimit) return cb();
7083
- } else if (this._hitLimit) {
7084
- if (i > p) this._val += this.decoder.write(data.toString("binary", p, i));
7085
- p = i;
7086
- if (this._val === "" && this.fieldSizeLimit === 0 || (this._bytesVal = this._val.length) === this.fieldSizeLimit) {
7087
- this._checkingBytes = false;
7088
- this._valTrunc = true;
7089
- }
7090
- } else {
7091
- if (p < len) this._val += this.decoder.write(data.toString("binary", p));
7092
- p = len;
7093
- }
7094
- }
7095
- cb();
7096
- };
7097
- UrlEncoded.prototype.end = function() {
7098
- if (this.boy._done) return;
7099
- if (this._state === "key" && this._key.length > 0) this.boy.emit("field", decodeText(this._key, "binary", this.charset), "", this._keyTrunc, false);
7100
- else if (this._state === "val") this.boy.emit("field", decodeText(this._key, "binary", this.charset), decodeText(this._val, "binary", this.charset), this._keyTrunc, this._valTrunc);
7101
- this.boy._done = true;
7102
- this.boy.emit("finish");
7103
- };
7104
- module.exports = UrlEncoded;
7105
- }));
7106
- //#endregion
7107
- //#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/main.js
7108
- var require_main = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7109
- const WritableStream = __require("node:stream").Writable;
7110
- const { inherits } = __require("node:util");
7111
- const Dicer = require_Dicer();
7112
- const MultipartParser = require_multipart$1();
7113
- const UrlencodedParser = require_urlencoded();
7114
- const parseParams = require_parseParams();
7115
- function Busboy(opts) {
7116
- if (!(this instanceof Busboy)) return new Busboy(opts);
7117
- if (typeof opts !== "object") throw new TypeError("Busboy expected an options-Object.");
7118
- if (typeof opts.headers !== "object") throw new TypeError("Busboy expected an options-Object with headers-attribute.");
7119
- if (typeof opts.headers["content-type"] !== "string") throw new TypeError("Missing Content-Type-header.");
7120
- const { headers, ...streamOptions } = opts;
7121
- this.opts = {
7122
- autoDestroy: false,
7123
- ...streamOptions
7124
- };
7125
- WritableStream.call(this, this.opts);
7126
- this._done = false;
7127
- this._parser = this.getParserByHeaders(headers);
7128
- this._finished = false;
7129
- }
7130
- inherits(Busboy, WritableStream);
7131
- Busboy.prototype.emit = function(ev) {
7132
- if (ev === "finish") {
7133
- if (!this._done) {
7134
- this._parser?.end();
7135
- return;
7136
- } else if (this._finished) return;
7137
- this._finished = true;
7138
- }
7139
- WritableStream.prototype.emit.apply(this, arguments);
7140
- };
7141
- Busboy.prototype.getParserByHeaders = function(headers) {
7142
- const parsed = parseParams(headers["content-type"]);
7143
- const cfg = {
7144
- defCharset: this.opts.defCharset,
7145
- fileHwm: this.opts.fileHwm,
7146
- headers,
7147
- highWaterMark: this.opts.highWaterMark,
7148
- isPartAFile: this.opts.isPartAFile,
7149
- limits: this.opts.limits,
7150
- parsedConType: parsed,
7151
- preservePath: this.opts.preservePath
7152
- };
7153
- if (MultipartParser.detect.test(parsed[0])) return new MultipartParser(this, cfg);
7154
- if (UrlencodedParser.detect.test(parsed[0])) return new UrlencodedParser(this, cfg);
7155
- throw new Error("Unsupported Content-Type.");
7156
- };
7157
- Busboy.prototype._write = function(chunk, encoding, cb) {
7158
- this._parser.write(chunk, cb);
7159
- };
7160
- module.exports = Busboy;
7161
- module.exports.default = Busboy;
7162
- module.exports.Busboy = Busboy;
7163
- module.exports.Dicer = Dicer;
7164
- }));
7165
- //#endregion
7166
- //#region ../../node_modules/.pnpm/fastify-plugin@5.1.0/node_modules/fastify-plugin/lib/getPluginName.js
7167
- var require_getPluginName = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7168
- const fpStackTracePattern = /at\s(?:.*\.)?plugin\s.*\n\s*(.*)/;
7169
- const fileNamePattern = /(\w*(\.\w*)*)\..*/;
7170
- module.exports = function getPluginName(fn) {
7171
- if (fn.name.length > 0) return fn.name;
7172
- const stackTraceLimit = Error.stackTraceLimit;
7173
- Error.stackTraceLimit = 10;
7174
- try {
7175
- throw new Error("anonymous function");
7176
- } catch (e) {
7177
- Error.stackTraceLimit = stackTraceLimit;
7178
- return extractPluginName(e.stack);
7179
- }
7180
- };
7181
- function extractPluginName(stack) {
7182
- const m = stack.match(fpStackTracePattern);
7183
- return m ? m[1].split(/[/\\]/).slice(-1)[0].match(fileNamePattern)[1] : "anonymous";
7184
- }
7185
- module.exports.extractPluginName = extractPluginName;
7186
- }));
7187
- //#endregion
7188
- //#region ../../node_modules/.pnpm/fastify-plugin@5.1.0/node_modules/fastify-plugin/lib/toCamelCase.js
7189
- var require_toCamelCase = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7190
- module.exports = function toCamelCase(name) {
7191
- if (name[0] === "@") name = name.slice(1).replace("/", "-");
7192
- return name.replace(/-(.)/g, function(match, g1) {
7193
- return g1.toUpperCase();
7194
- });
7195
- };
7196
- }));
7197
- //#endregion
7198
- //#region ../../node_modules/.pnpm/fastify-plugin@5.1.0/node_modules/fastify-plugin/plugin.js
7199
- var require_plugin = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7200
- const getPluginName = require_getPluginName();
7201
- const toCamelCase = require_toCamelCase();
7202
- let count = 0;
7203
- function plugin(fn, options = {}) {
7204
- let autoName = false;
7205
- if (fn.default !== void 0) fn = fn.default;
7206
- if (typeof fn !== "function") throw new TypeError(`fastify-plugin expects a function, instead got a '${typeof fn}'`);
7207
- if (typeof options === "string") options = { fastify: options };
7208
- if (typeof options !== "object" || Array.isArray(options) || options === null) throw new TypeError("The options object should be an object");
7209
- if (options.fastify !== void 0 && typeof options.fastify !== "string") throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`);
7210
- if (!options.name) {
7211
- autoName = true;
7212
- options.name = getPluginName(fn) + "-auto-" + count++;
7213
- }
7214
- fn[Symbol.for("skip-override")] = options.encapsulate !== true;
7215
- fn[Symbol.for("fastify.display-name")] = options.name;
7216
- fn[Symbol.for("plugin-meta")] = options;
7217
- if (!fn.default) fn.default = fn;
7218
- const camelCase = toCamelCase(options.name);
7219
- if (!autoName && !fn[camelCase]) fn[camelCase] = fn;
7220
- return fn;
7221
- }
7222
- module.exports = plugin;
7223
- module.exports.default = plugin;
7224
- module.exports.fastifyPlugin = plugin;
7225
- }));
7226
- //#endregion
7227
- //#region ../../node_modules/.pnpm/@fastify+multipart@10.0.0/node_modules/@fastify/multipart/lib/generateId.js
7228
- var require_generateId = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7229
- const HEX = [
7230
- "00",
7231
- "01",
7232
- "02",
7233
- "03",
7234
- "04",
7235
- "05",
7236
- "06",
7237
- "07",
7238
- "08",
7239
- "09",
7240
- "0a",
7241
- "0b",
7242
- "0c",
7243
- "0d",
7244
- "0e",
7245
- "0f",
7246
- "10",
7247
- "11",
7248
- "12",
7249
- "13",
7250
- "14",
7251
- "15",
7252
- "16",
7253
- "17",
7254
- "18",
7255
- "19",
7256
- "1a",
7257
- "1b",
7258
- "1c",
7259
- "1d",
7260
- "1e",
7261
- "1f",
7262
- "20",
7263
- "21",
7264
- "22",
7265
- "23",
7266
- "24",
7267
- "25",
7268
- "26",
7269
- "27",
7270
- "28",
7271
- "29",
7272
- "2a",
7273
- "2b",
7274
- "2c",
7275
- "2d",
7276
- "2e",
7277
- "2f",
7278
- "30",
7279
- "31",
7280
- "32",
7281
- "33",
7282
- "34",
7283
- "35",
7284
- "36",
7285
- "37",
7286
- "38",
7287
- "39",
7288
- "3a",
7289
- "3b",
7290
- "3c",
7291
- "3d",
7292
- "3e",
7293
- "3f",
7294
- "40",
7295
- "41",
7296
- "42",
7297
- "43",
7298
- "44",
7299
- "45",
7300
- "46",
7301
- "47",
7302
- "48",
7303
- "49",
7304
- "4a",
7305
- "4b",
7306
- "4c",
7307
- "4d",
7308
- "4e",
7309
- "4f",
7310
- "50",
7311
- "51",
7312
- "52",
7313
- "53",
7314
- "54",
7315
- "55",
7316
- "56",
7317
- "57",
7318
- "58",
7319
- "59",
7320
- "5a",
7321
- "5b",
7322
- "5c",
7323
- "5d",
7324
- "5e",
7325
- "5f",
7326
- "60",
7327
- "61",
7328
- "62",
7329
- "63",
7330
- "64",
7331
- "65",
7332
- "66",
7333
- "67",
7334
- "68",
7335
- "69",
7336
- "6a",
7337
- "6b",
7338
- "6c",
7339
- "6d",
7340
- "6e",
7341
- "6f",
7342
- "70",
7343
- "71",
7344
- "72",
7345
- "73",
7346
- "74",
7347
- "75",
7348
- "76",
7349
- "77",
7350
- "78",
7351
- "79",
7352
- "7a",
7353
- "7b",
7354
- "7c",
7355
- "7d",
7356
- "7e",
7357
- "7f",
7358
- "80",
7359
- "81",
7360
- "82",
7361
- "83",
7362
- "84",
7363
- "85",
7364
- "86",
7365
- "87",
7366
- "88",
7367
- "89",
7368
- "8a",
7369
- "8b",
7370
- "8c",
7371
- "8d",
7372
- "8e",
7373
- "8f",
7374
- "90",
7375
- "91",
7376
- "92",
7377
- "93",
7378
- "94",
7379
- "95",
7380
- "96",
7381
- "97",
7382
- "98",
7383
- "99",
7384
- "9a",
7385
- "9b",
7386
- "9c",
7387
- "9d",
7388
- "9e",
7389
- "9f",
7390
- "a0",
7391
- "a1",
7392
- "a2",
7393
- "a3",
7394
- "a4",
7395
- "a5",
7396
- "a6",
7397
- "a7",
7398
- "a8",
7399
- "a9",
7400
- "aa",
7401
- "ab",
7402
- "ac",
7403
- "ad",
7404
- "ae",
7405
- "af",
7406
- "b0",
7407
- "b1",
7408
- "b2",
7409
- "b3",
7410
- "b4",
7411
- "b5",
7412
- "b6",
7413
- "b7",
7414
- "b8",
7415
- "b9",
7416
- "ba",
7417
- "bb",
7418
- "bc",
7419
- "bd",
7420
- "be",
7421
- "bf",
7422
- "c0",
7423
- "c1",
7424
- "c2",
7425
- "c3",
7426
- "c4",
7427
- "c5",
7428
- "c6",
7429
- "c7",
7430
- "c8",
7431
- "c9",
7432
- "ca",
7433
- "cb",
7434
- "cc",
7435
- "cd",
7436
- "ce",
7437
- "cf",
7438
- "d0",
7439
- "d1",
7440
- "d2",
7441
- "d3",
7442
- "d4",
7443
- "d5",
7444
- "d6",
7445
- "d7",
7446
- "d8",
7447
- "d9",
7448
- "da",
7449
- "db",
7450
- "dc",
7451
- "dd",
7452
- "de",
7453
- "df",
7454
- "e0",
7455
- "e1",
7456
- "e2",
7457
- "e3",
7458
- "e4",
7459
- "e5",
7460
- "e6",
7461
- "e7",
7462
- "e8",
7463
- "e9",
7464
- "ea",
7465
- "eb",
7466
- "ec",
7467
- "ed",
7468
- "ee",
7469
- "ef",
7470
- "f0",
7471
- "f1",
7472
- "f2",
7473
- "f3",
7474
- "f4",
7475
- "f5",
7476
- "f6",
7477
- "f7",
7478
- "f8",
7479
- "f9",
7480
- "fa",
7481
- "fb",
7482
- "fc",
7483
- "fd",
7484
- "fe",
7485
- "ff"
7486
- ];
7487
- const random = Math.random;
7488
- function seed() {
7489
- return HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0];
7490
- }
7491
- module.exports.generateId = (function generateIdFn() {
7492
- let num = 0;
7493
- let str = seed();
7494
- return function generateId() {
7495
- return num === 255 ? (str = seed()) + HEX[num = 0] : str + HEX[++num];
7496
- };
7497
- })();
7498
- }));
7499
- //#endregion
7500
- //#region ../../node_modules/.pnpm/@fastify+error@4.2.0/node_modules/@fastify/error/index.js
7501
- var require_error = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7502
- const { format } = __require("node:util");
7503
- function toString() {
7504
- return `${this.name} [${this.code}]: ${this.message}`;
7505
- }
7506
- const FastifyGenericErrorSymbol = Symbol.for("fastify-error-generic");
7507
- function createError(code, message, statusCode = 500, Base = Error, captureStackTrace = createError.captureStackTrace) {
7508
- const shouldCreateFastifyGenericError = code === FastifyGenericErrorSymbol;
7509
- if (shouldCreateFastifyGenericError) code = "FST_ERR";
7510
- if (!code) throw new Error("Fastify error code must not be empty");
7511
- if (!message) throw new Error("Fastify error message must not be empty");
7512
- code = code.toUpperCase();
7513
- !statusCode && (statusCode = void 0);
7514
- const FastifySpecificErrorSymbol = Symbol.for(`fastify-error ${code}`);
7515
- function FastifyError(...args) {
7516
- if (!new.target) return new FastifyError(...args);
7517
- this.code = code;
7518
- this.name = "FastifyError";
7519
- this.statusCode = statusCode;
7520
- const lastElement = args.length - 1;
7521
- if (lastElement !== -1 && args[lastElement] && typeof args[lastElement] === "object" && "cause" in args[lastElement]) this.cause = args.pop().cause;
7522
- this.message = format(message, ...args);
7523
- Error.stackTraceLimit && captureStackTrace && Error.captureStackTrace(this, FastifyError);
7524
- }
7525
- FastifyError.prototype = Object.create(Base.prototype, {
7526
- constructor: {
7527
- value: FastifyError,
7528
- enumerable: false,
7529
- writable: true,
7530
- configurable: true
7531
- },
7532
- [FastifyGenericErrorSymbol]: {
7533
- value: true,
7534
- enumerable: false,
7535
- writable: false,
7536
- configurable: false
7537
- },
7538
- [FastifySpecificErrorSymbol]: {
7539
- value: true,
7540
- enumerable: false,
7541
- writable: false,
7542
- configurable: false
7543
- }
7544
- });
7545
- if (shouldCreateFastifyGenericError) Object.defineProperty(FastifyError, Symbol.hasInstance, {
7546
- value(instance) {
7547
- return instance && instance[FastifyGenericErrorSymbol];
7548
- },
7549
- configurable: false,
7550
- writable: false,
7551
- enumerable: false
7552
- });
7553
- else Object.defineProperty(FastifyError, Symbol.hasInstance, {
7554
- value(instance) {
7555
- return instance && instance[FastifySpecificErrorSymbol];
7556
- },
7557
- configurable: false,
7558
- writable: false,
7559
- enumerable: false
7560
- });
7561
- FastifyError.prototype[Symbol.toStringTag] = "Error";
7562
- FastifyError.prototype.toString = toString;
7563
- return FastifyError;
7564
- }
7565
- createError.captureStackTrace = true;
7566
- const FastifyErrorConstructor = createError(FastifyGenericErrorSymbol, "Fastify Error", 500, Error);
7567
- module.exports = createError;
7568
- module.exports.FastifyError = FastifyErrorConstructor;
7569
- module.exports.default = createError;
7570
- module.exports.createError = createError;
7571
- }));
7572
- //#endregion
7573
- //#region ../../node_modules/.pnpm/@fastify+multipart@10.0.0/node_modules/@fastify/multipart/lib/stream-consumer.js
7574
- var require_stream_consumer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7575
- module.exports = function streamToNull(stream) {
7576
- return new Promise((resolve, reject) => {
7577
- stream.on("data", () => {});
7578
- stream.on("close", () => {
7579
- resolve();
7580
- });
7581
- stream.on("end", () => {
7582
- resolve();
7583
- });
7584
- stream.on("error", (error) => {
7585
- reject(error);
7586
- });
7587
- });
7588
- };
7589
- }));
7590
- //#endregion
7591
- //#region ../../node_modules/.pnpm/@fastify+deepmerge@3.2.1/node_modules/@fastify/deepmerge/index.js
7592
- var require_deepmerge = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7593
- const JSON_PROTO = Object.getPrototypeOf({});
7594
- function defaultIsMergeableObjectFactory() {
7595
- return function defaultIsMergeableObject(value) {
7596
- return typeof value === "object" && value !== null && !(value instanceof RegExp) && !(value instanceof Date);
7597
- };
7598
- }
7599
- function deepmergeConstructor(options) {
7600
- function isNotPrototypeKey(value) {
7601
- return value !== "constructor" && value !== "prototype" && value !== "__proto__";
7602
- }
7603
- function cloneArray(value) {
7604
- let i = 0;
7605
- const il = value.length;
7606
- const result = new Array(il);
7607
- for (; i < il; ++i) result[i] = clone(value[i]);
7608
- return result;
7609
- }
7610
- function cloneObject(target) {
7611
- const result = {};
7612
- if (cloneProtoObject && Object.getPrototypeOf(target) !== JSON_PROTO) return cloneProtoObject(target);
7613
- const targetKeys = getKeys(target);
7614
- let i, il, key;
7615
- for (i = 0, il = targetKeys.length; i < il; ++i) isNotPrototypeKey(key = targetKeys[i]) && (result[key] = clone(target[key]));
7616
- return result;
7617
- }
7618
- function concatArrays(target, source) {
7619
- const tl = target.length;
7620
- const sl = source.length;
7621
- let i = 0;
7622
- const result = new Array(tl + sl);
7623
- for (; i < tl; ++i) result[i] = clone(target[i]);
7624
- for (i = 0; i < sl; ++i) result[i + tl] = clone(source[i]);
7625
- return result;
7626
- }
7627
- const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
7628
- function getSymbolsAndKeys(value) {
7629
- const result = Object.keys(value);
7630
- const keys = Object.getOwnPropertySymbols(value);
7631
- for (let i = 0, il = keys.length; i < il; ++i) propertyIsEnumerable.call(value, keys[i]) && result.push(keys[i]);
7632
- return result;
7633
- }
7634
- const getKeys = options?.symbols ? getSymbolsAndKeys : Object.keys;
7635
- const cloneProtoObject = typeof options?.cloneProtoObject === "function" ? options.cloneProtoObject : void 0;
7636
- const isMergeableObject = typeof options?.isMergeableObject === "function" ? options.isMergeableObject : defaultIsMergeableObjectFactory();
7637
- const onlyDefinedProperties = options?.onlyDefinedProperties === true;
7638
- function isPrimitive(value) {
7639
- return typeof value !== "object" || value === null;
7640
- }
7641
- const mergeArray = options && typeof options.mergeArray === "function" ? options.mergeArray({
7642
- clone,
7643
- deepmerge: _deepmerge,
7644
- getKeys,
7645
- isMergeableObject
7646
- }) : concatArrays;
7647
- function clone(entry) {
7648
- return isMergeableObject(entry) ? Array.isArray(entry) ? cloneArray(entry) : cloneObject(entry) : entry;
7649
- }
7650
- function mergeObject(target, source) {
7651
- const result = {};
7652
- const targetKeys = getKeys(target);
7653
- const sourceKeys = getKeys(source);
7654
- let i, il, key;
7655
- for (i = 0, il = targetKeys.length; i < il; ++i) isNotPrototypeKey(key = targetKeys[i]) && sourceKeys.indexOf(key) === -1 && (result[key] = clone(target[key]));
7656
- for (i = 0, il = sourceKeys.length; i < il; ++i) {
7657
- if (!isNotPrototypeKey(key = sourceKeys[i])) continue;
7658
- if (key in target) {
7659
- if (targetKeys.indexOf(key) !== -1) if (cloneProtoObject && isMergeableObject(source[key]) && Object.getPrototypeOf(source[key]) !== JSON_PROTO) result[key] = cloneProtoObject(source[key]);
7660
- else result[key] = _deepmerge(target[key], source[key]);
7661
- } else {
7662
- if (onlyDefinedProperties && typeof source[key] === "undefined") continue;
7663
- result[key] = clone(source[key]);
7664
- }
7665
- }
7666
- return result;
7667
- }
7668
- function _deepmerge(target, source) {
7669
- if (onlyDefinedProperties && typeof source === "undefined") return clone(target);
7670
- const sourceIsArray = Array.isArray(source);
7671
- const targetIsArray = Array.isArray(target);
7672
- if (isPrimitive(source)) return source;
7673
- else if (!isMergeableObject(target)) return clone(source);
7674
- else if (sourceIsArray && targetIsArray) return mergeArray(target, source);
7675
- else if (sourceIsArray !== targetIsArray) return clone(source);
7676
- else return mergeObject(target, source);
7677
- }
7678
- function _deepmergeAll() {
7679
- switch (arguments.length) {
7680
- case 0: return {};
7681
- case 1: return clone(arguments[0]);
7682
- case 2: return _deepmerge(arguments[0], arguments[1]);
7683
- }
7684
- let result;
7685
- for (let i = 0, il = arguments.length; i < il; ++i) result = _deepmerge(result, arguments[i]);
7686
- return result;
7687
- }
7688
- return options?.all ? _deepmergeAll : _deepmerge;
7689
- }
7690
- module.exports = deepmergeConstructor;
7691
- module.exports.default = deepmergeConstructor;
7692
- module.exports.deepmerge = deepmergeConstructor;
7693
- Object.defineProperty(module.exports, "isMergeableObject", { get: defaultIsMergeableObjectFactory });
7694
- }));
7695
- //#endregion
7696
- //#region ../../node_modules/.pnpm/secure-json-parse@4.1.0/node_modules/secure-json-parse/index.js
7697
- var require_secure_json_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7698
- const hasBuffer = typeof Buffer !== "undefined";
7699
- const suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
7700
- const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
7701
- /**
7702
- * @description Internal parse function that parses JSON text with security checks.
7703
- * @private
7704
- * @param {string|Buffer} text - The JSON text string or Buffer to parse.
7705
- * @param {Function} [reviver] - The JSON.parse() optional reviver argument.
7706
- * @param {import('./types').ParseOptions} [options] - Optional configuration object.
7707
- * @returns {*} The parsed object.
7708
- * @throws {SyntaxError} If a forbidden prototype property is found and `options.protoAction` or
7709
- * `options.constructorAction` is `'error'`.
7710
- */
7711
- function _parse(text, reviver, options) {
7712
- if (options == null) {
7713
- if (reviver !== null && typeof reviver === "object") {
7714
- options = reviver;
7715
- reviver = void 0;
7716
- }
7717
- }
7718
- if (hasBuffer && Buffer.isBuffer(text)) text = text.toString();
7719
- if (text && text.charCodeAt(0) === 65279) text = text.slice(1);
7720
- const obj = JSON.parse(text, reviver);
7721
- if (obj === null || typeof obj !== "object") return obj;
7722
- const protoAction = options && options.protoAction || "error";
7723
- const constructorAction = options && options.constructorAction || "error";
7724
- if (protoAction === "ignore" && constructorAction === "ignore") return obj;
7725
- if (protoAction !== "ignore" && constructorAction !== "ignore") {
7726
- if (suspectProtoRx.test(text) === false && suspectConstructorRx.test(text) === false) return obj;
7727
- } else if (protoAction !== "ignore" && constructorAction === "ignore") {
7728
- if (suspectProtoRx.test(text) === false) return obj;
7729
- } else if (suspectConstructorRx.test(text) === false) return obj;
7730
- return filter(obj, {
7731
- protoAction,
7732
- constructorAction,
7733
- safe: options && options.safe
7734
- });
7735
- }
7736
- /**
7737
- * @description Scans and filters an object for forbidden prototype properties.
7738
- * @param {Object} obj - The object being scanned.
7739
- * @param {import('./types').ParseOptions} [options] - Optional configuration object.
7740
- * @returns {Object|null} The filtered object, or `null` if safe mode is enabled and issues are found.
7741
- * @throws {SyntaxError} If a forbidden prototype property is found and `options.protoAction` or
7742
- * `options.constructorAction` is `'error'`.
7743
- */
7744
- function filter(obj, { protoAction = "error", constructorAction = "error", safe } = {}) {
7745
- let next = [obj];
7746
- while (next.length) {
7747
- const nodes = next;
7748
- next = [];
7749
- for (const node of nodes) {
7750
- if (protoAction !== "ignore" && Object.prototype.hasOwnProperty.call(node, "__proto__")) {
7751
- if (safe === true) return null;
7752
- else if (protoAction === "error") throw new SyntaxError("Object contains forbidden prototype property");
7753
- delete node.__proto__;
7754
- }
7755
- if (constructorAction !== "ignore" && Object.prototype.hasOwnProperty.call(node, "constructor") && node.constructor !== null && typeof node.constructor === "object" && Object.prototype.hasOwnProperty.call(node.constructor, "prototype")) {
7756
- if (safe === true) return null;
7757
- else if (constructorAction === "error") throw new SyntaxError("Object contains forbidden prototype property");
7758
- delete node.constructor;
7759
- }
7760
- for (const key in node) {
7761
- const value = node[key];
7762
- if (value && typeof value === "object") next.push(value);
7763
- }
7764
- }
7765
- }
7766
- return obj;
7767
- }
7768
- /**
7769
- * @description Parses a given JSON-formatted text into an object.
7770
- * @param {string|Buffer} text - The JSON text string or Buffer to parse.
7771
- * @param {Function} [reviver] - The `JSON.parse()` optional reviver argument, or options object.
7772
- * @param {import('./types').ParseOptions} [options] - Optional configuration object.
7773
- * @returns {*} The parsed object.
7774
- * @throws {SyntaxError} If the JSON text is malformed or contains forbidden prototype properties
7775
- * when `options.protoAction` or `options.constructorAction` is `'error'`.
7776
- */
7777
- function parse(text, reviver, options) {
7778
- const { stackTraceLimit } = Error;
7779
- Error.stackTraceLimit = 0;
7780
- try {
7781
- return _parse(text, reviver, options);
7782
- } finally {
7783
- Error.stackTraceLimit = stackTraceLimit;
7784
- }
7785
- }
7786
- /**
7787
- * @description Safely parses a given JSON-formatted text into an object.
7788
- * @param {string|Buffer} text - The JSON text string or Buffer to parse.
7789
- * @param {Function} [reviver] - The `JSON.parse()` optional reviver argument.
7790
- * @returns {*|null|undefined} The parsed object, `null` if security issues found, or `undefined` on parse error.
7791
- */
7792
- function safeParse(text, reviver) {
7793
- const { stackTraceLimit } = Error;
7794
- Error.stackTraceLimit = 0;
7795
- try {
7796
- return _parse(text, reviver, { safe: true });
7797
- } catch {
7798
- return;
7799
- } finally {
7800
- Error.stackTraceLimit = stackTraceLimit;
7801
- }
7802
- }
7803
- module.exports = parse;
7804
- module.exports.default = parse;
7805
- module.exports.parse = parse;
7806
- module.exports.safeParse = safeParse;
7807
- module.exports.scan = filter;
7808
- }));
7809
- //#endregion
7810
- //#region ../server/dist/app-BcKNAbK-.mjs
7811
- var import_multipart = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
7812
- const Busboy = require_main();
7813
- const os = __require("node:os");
7814
- const fp = require_plugin();
7815
- const { createWriteStream: createWriteStream$1 } = __require("node:fs");
7816
- const { unlink } = __require("node:fs/promises");
7817
- const path = __require("node:path");
7818
- const { generateId } = require_generateId();
7819
- const createError = require_error();
7820
- const streamToNull = require_stream_consumer();
7821
- const deepmergeAll = require_deepmerge()({ all: true });
7822
- const { PassThrough, Readable } = __require("node:stream");
7823
- const { pipeline: pump } = __require("node:stream/promises");
7824
- const secureJSON = require_secure_json_parse();
7825
- const kMultipart = Symbol("multipart");
7826
- const kMultipartHandler = Symbol("multipartHandler");
7827
- const kSavedRequestFilesResult = Symbol("savedRequestFilesResult");
7828
- const PartsLimitError = createError("FST_PARTS_LIMIT", "reach parts limit", 413);
7829
- const FilesLimitError = createError("FST_FILES_LIMIT", "reach files limit", 413);
7830
- const FieldsLimitError = createError("FST_FIELDS_LIMIT", "reach fields limit", 413);
7831
- const RequestFileTooLargeError = createError("FST_REQ_FILE_TOO_LARGE", "request file too large", 413);
7832
- const PrototypeViolationError = createError("FST_PROTO_VIOLATION", "prototype property is not allowed as field name", 400);
7833
- const InvalidMultipartContentTypeError = createError("FST_INVALID_MULTIPART_CONTENT_TYPE", "the request is not multipart", 406);
7834
- const InvalidJSONFieldError = createError("FST_INVALID_JSON_FIELD_ERROR", "a request field is not a valid JSON as declared by its Content-Type", 406);
7835
- const FileBufferNotFoundError = createError("FST_FILE_BUFFER_NOT_FOUND", "the file buffer was not found", 500);
7836
- const NoFormData = createError("FST_NO_FORM_DATA", "FormData is not available", 500);
7837
- function setMultipart(req, _payload, done) {
7838
- req[kMultipart] = true;
7839
- done();
7840
- }
7841
- function busboy(options) {
7842
- try {
7843
- return new Busboy(options);
7844
- } catch (error) {
7845
- const errorEmitter = new PassThrough();
7846
- process.nextTick(function() {
7847
- errorEmitter.emit("error", error);
7848
- });
7849
- return errorEmitter;
7850
- }
7851
- }
7852
- function fastifyMultipart(fastify, options, done) {
7853
- options.limits = {
7854
- ...options.limits,
7855
- parts: options.limits?.parts || 1e3,
7856
- fileSize: options.limits?.fileSize || fastify.initialConfig.bodyLimit
7857
- };
7858
- const attachFieldsToBody = options.attachFieldsToBody;
7859
- if (attachFieldsToBody === true || attachFieldsToBody === "keyValues") {
7860
- if (typeof options.sharedSchemaId === "string" && attachFieldsToBody === true) fastify.addSchema({
7861
- $id: options.sharedSchemaId,
7862
- type: "object",
7863
- properties: {
7864
- fieldname: { type: "string" },
7865
- encoding: { type: "string" },
7866
- filename: { type: "string" },
7867
- mimetype: { type: "string" }
7868
- }
7869
- });
7870
- fastify.addHook("preValidation", async function(req) {
7871
- if (!req.isMultipart()) return;
7872
- for await (const part of req.parts(req.routeOptions.config.multipartOptions)) {
7873
- req.body = part.fields;
7874
- if (part.file) if (options.onFile) await options.onFile.call(req, part);
7875
- else await part.toBuffer();
7876
- }
7877
- if (attachFieldsToBody === "keyValues") {
7878
- const body = {};
7879
- if (req.body) {
7880
- const reqBodyKeys = Object.keys(req.body);
7881
- for (let i = 0; i < reqBodyKeys.length; ++i) {
7882
- const key = reqBodyKeys[i];
7883
- const field = req.body[key];
7884
- if (field.value !== void 0) body[key] = field.value;
7885
- else if (field._buf) body[key] = field._buf;
7886
- else if (Array.isArray(field)) {
7887
- const items = [];
7888
- for (let i = 0; i < field.length; ++i) {
7889
- const item = field[i];
7890
- if (item.value !== void 0) items.push(item.value);
7891
- else if (item._buf) items.push(item._buf);
7892
- }
7893
- if (items.length) body[key] = items;
7894
- }
7895
- }
7896
- }
7897
- req.body = body;
7898
- }
7899
- });
7900
- /* istanbul ignore next */
7901
- if (globalThis.FormData && !fastify.hasRequestDecorator("formData")) fastify.decorateRequest("formData", async function() {
7902
- const formData = new FormData();
7903
- for (const key in this.body) {
7904
- const value = this.body[key];
7905
- if (Array.isArray(value)) for (const item of value) await append(key, item);
7906
- else await append(key, value);
7907
- }
7908
- async function append(key, entry) {
7909
- /* c8 ignore next: Buffer.isBuffer is not covered and causing `npm test` to fail */
7910
- if (entry.type === "file" || attachFieldsToBody === "keyValues" && Buffer.isBuffer(entry)) formData.append(key, new Blob([await entry.toBuffer()], { type: entry.mimetype }), entry.filename);
7911
- else formData.append(key, entry.value);
7912
- }
7913
- return formData;
7914
- });
7915
- }
7916
- /* istanbul ignore next */
7917
- if (!fastify.hasRequestDecorator("formData")) fastify.decorateRequest("formData", async function() {
7918
- /* c8 ignore next: Next line is not covered and causing `npm test` to fail */
7919
- throw new NoFormData();
7920
- });
7921
- const defaultThrowFileSizeLimit = typeof options.throwFileSizeLimit === "boolean" ? options.throwFileSizeLimit : true;
7922
- fastify.decorate("multipartErrors", {
7923
- PartsLimitError,
7924
- FilesLimitError,
7925
- FieldsLimitError,
7926
- PrototypeViolationError,
7927
- InvalidMultipartContentTypeError,
7928
- RequestFileTooLargeError,
7929
- FileBufferNotFoundError
7930
- });
7931
- fastify.addContentTypeParser("multipart/form-data", setMultipart);
7932
- fastify.decorateRequest(kMultipart, false);
7933
- fastify.decorateRequest(kMultipartHandler, handleMultipart);
7934
- fastify.decorateRequest(kSavedRequestFilesResult, null);
7935
- fastify.decorateRequest("parts", getMultipartIterator);
7936
- fastify.decorateRequest("isMultipart", isMultipart);
7937
- fastify.decorateRequest("tmpUploads", null);
7938
- fastify.decorateRequest("savedRequestFiles", null);
7939
- fastify.decorateRequest("file", getMultipartFile);
7940
- fastify.decorateRequest("files", getMultipartFiles);
7941
- fastify.decorateRequest("saveRequestFiles", saveRequestFiles);
7942
- fastify.decorateRequest("cleanRequestFiles", cleanRequestFiles);
7943
- fastify.addHook("onResponse", async (request) => {
7944
- await request.cleanRequestFiles();
7945
- });
7946
- function isMultipart() {
7947
- return this[kMultipart];
7948
- }
7949
- function handleMultipart(opts = {}) {
7950
- if (!this.isMultipart()) throw new InvalidMultipartContentTypeError();
7951
- this.log.debug("starting multipart parsing");
7952
- let values = [];
7953
- let pendingHandler = null;
7954
- const ch = (val) => {
7955
- if (pendingHandler) {
7956
- pendingHandler(val);
7957
- pendingHandler = null;
7958
- } else values.push(val);
7959
- };
7960
- const handle = (handler) => {
7961
- if (values.length > 0) {
7962
- const value = values[0];
7963
- values = values.slice(1);
7964
- handler(value);
7965
- } else pendingHandler = handler;
7966
- };
7967
- const parts = () => {
7968
- return new Promise((resolve, reject) => {
7969
- handle((val) => {
7970
- if (val instanceof Error) if (val.message === "Unexpected end of multipart data") resolve(null);
7971
- else reject(val);
7972
- else resolve(val);
7973
- });
7974
- });
7975
- };
7976
- const body = {};
7977
- let lastError = null;
7978
- let currentFile = null;
7979
- const request = this.raw;
7980
- const busboyOptions = deepmergeAll({ headers: request.headers }, options, opts);
7981
- this.log.trace({ busboyOptions }, "Providing options to busboy");
7982
- const bb = busboy(busboyOptions);
7983
- request.on("close", cleanup);
7984
- request.on("error", cleanup);
7985
- bb.on("field", onField).on("file", onFile).on("end", cleanup).on("finish", cleanup).on("close", cleanup).on("error", cleanup);
7986
- bb.on("partsLimit", function() {
7987
- const err = new PartsLimitError();
7988
- onError(err);
7989
- process.nextTick(() => cleanup(err));
7990
- });
7991
- bb.on("filesLimit", function() {
7992
- const err = new FilesLimitError();
7993
- onError(err);
7994
- process.nextTick(() => cleanup(err));
7995
- });
7996
- bb.on("fieldsLimit", function() {
7997
- const err = new FieldsLimitError();
7998
- onError(err);
7999
- process.nextTick(() => cleanup(err));
8000
- });
8001
- request.pipe(bb);
8002
- function onField(name, fieldValue, fieldnameTruncated, valueTruncated, encoding, contentType) {
8003
- if (name in Object.prototype) {
8004
- onError(new PrototypeViolationError());
8005
- return;
8006
- }
8007
- if (contentType.startsWith("application/json")) {
8008
- if (valueTruncated) {
8009
- onError(new InvalidJSONFieldError());
8010
- return;
8011
- }
8012
- try {
8013
- fieldValue = secureJSON.parse(fieldValue);
8014
- contentType = "application/json";
8015
- } catch {
8016
- onError(new InvalidJSONFieldError());
8017
- return;
8018
- }
8019
- }
8020
- const value = {
8021
- type: "field",
8022
- fieldname: name,
8023
- mimetype: contentType,
8024
- encoding,
8025
- value: fieldValue,
8026
- fieldnameTruncated,
8027
- valueTruncated,
8028
- fields: body
8029
- };
8030
- if (body[name] === void 0) body[name] = value;
8031
- else if (Array.isArray(body[name])) body[name].push(value);
8032
- else body[name] = [body[name], value];
8033
- ch(value);
8034
- }
8035
- function onFile(name, file, filename, encoding, mimetype) {
8036
- if (name in Object.prototype) {
8037
- streamToNull(file).catch(() => {});
8038
- onError(new PrototypeViolationError());
8039
- return;
8040
- }
8041
- const throwFileSizeLimit = typeof opts.throwFileSizeLimit === "boolean" ? opts.throwFileSizeLimit : defaultThrowFileSizeLimit;
8042
- const value = {
8043
- type: "file",
8044
- fieldname: name,
8045
- filename,
8046
- encoding,
8047
- mimetype,
8048
- file,
8049
- fields: body,
8050
- _buf: null,
8051
- async toBuffer() {
8052
- if (this._buf) return this._buf;
8053
- const fileChunks = [];
8054
- let err;
8055
- for await (const chunk of this.file) {
8056
- fileChunks.push(chunk);
8057
- if (throwFileSizeLimit && this.file.truncated) {
8058
- err = new RequestFileTooLargeError();
8059
- err.part = this;
8060
- onError(err);
8061
- fileChunks.length = 0;
8062
- }
8063
- }
8064
- if (err) throw err;
8065
- this._buf = Buffer.concat(fileChunks);
8066
- return this._buf;
8067
- }
8068
- };
8069
- file.on("error", function(err) {
8070
- if (err.message && err.message.includes("terminated early")) onError(err);
8071
- });
8072
- if (throwFileSizeLimit) file.on("limit", function() {
8073
- const err = new RequestFileTooLargeError();
8074
- err.part = value;
8075
- onError(err);
8076
- });
8077
- if (body[name] === void 0) body[name] = value;
8078
- else if (Array.isArray(body[name])) body[name].push(value);
8079
- else body[name] = [body[name], value];
8080
- currentFile = file;
8081
- ch(value);
8082
- }
8083
- function onError(err) {
8084
- lastError = err;
8085
- currentFile = null;
8086
- }
8087
- function cleanup(err) {
8088
- request.unpipe(bb);
8089
- if ((err || request.aborted) && currentFile) {
8090
- currentFile.destroy();
8091
- currentFile = null;
8092
- }
8093
- ch(err || lastError || null);
8094
- }
8095
- return parts;
8096
- }
8097
- async function saveRequestFiles(options) {
8098
- if (this[kSavedRequestFilesResult]) return this[kSavedRequestFilesResult];
8099
- let parts;
8100
- let values = {};
8101
- if (attachFieldsToBody === true || attachFieldsToBody === "keyValues") {
8102
- parts = this.body ? filesFromFields.call(this, this.body) : [];
8103
- values = this.body || {};
8104
- } else parts = this.parts(options);
8105
- this.savedRequestFiles = [];
8106
- const tmpdir = options?.tmpdir || os.tmpdir();
8107
- this.tmpUploads = [];
8108
- let i = 0;
8109
- for await (const part of parts) {
8110
- values = part.fields;
8111
- if (!part.file) continue;
8112
- const filepath = path.join(tmpdir, generateId() + path.extname(part.filename || "file" + i++));
8113
- const target = createWriteStream$1(filepath);
8114
- try {
8115
- this.tmpUploads.push(filepath);
8116
- await pump(part.file, target);
8117
- this.savedRequestFiles.push({
8118
- ...part,
8119
- filepath
8120
- });
8121
- } catch (err) {
8122
- target.destroy();
8123
- await this.cleanRequestFiles();
8124
- this.log.error({ err }, "save request file");
8125
- throw err;
8126
- }
8127
- }
8128
- this[kSavedRequestFilesResult] = {
8129
- files: this.savedRequestFiles,
8130
- values
8131
- };
8132
- return this[kSavedRequestFilesResult];
8133
- }
8134
- function* filesFromFields(container) {
8135
- try {
8136
- const fields = Array.isArray(container) ? container : Object.values(container);
8137
- for (let i = 0; i < fields.length; ++i) {
8138
- const field = fields[i];
8139
- if (Array.isArray(field)) for (const subField of filesFromFields.call(this, field)) yield subField;
8140
- if (!field.file) continue;
8141
- if (!field._buf) throw new FileBufferNotFoundError();
8142
- field.file = Readable.from(field._buf);
8143
- yield field;
8144
- }
8145
- } catch (err) {
8146
- this.log.error({ err }, "save request file failed");
8147
- throw err;
8148
- }
8149
- }
8150
- async function cleanRequestFiles() {
8151
- if (!this.tmpUploads) return;
8152
- for (let i = 0; i < this.tmpUploads.length; ++i) {
8153
- const filepath = this.tmpUploads[i];
8154
- try {
8155
- await unlink(filepath);
8156
- } /* c8 ignore start */catch (error) {
8157
- this.log.error(error, "Could not delete file");
8158
- }
8159
- }
8160
- }
8161
- async function getMultipartFile(options) {
8162
- const parts = this[kMultipartHandler](options);
8163
- let part;
8164
- while ((part = await parts()) != null) if (part.file) return part;
8165
- }
8166
- async function* getMultipartFiles(options) {
8167
- const parts = this[kMultipartHandler](options);
8168
- let part;
8169
- while ((part = await parts()) != null) if (part.file) yield part;
8170
- }
8171
- async function* getMultipartIterator(options) {
8172
- const parts = this[kMultipartHandler](options);
8173
- let part;
8174
- while ((part = await parts()) != null) yield part;
8175
- }
8176
- done();
8177
- }
8178
- /**
8179
- * Adds a new type `isFile` to help @fastify/swagger generate the correct schema.
8180
- */
8181
- function ajvFilePlugin(ajv) {
8182
- return ajv.addKeyword({
8183
- keyword: "isFile",
8184
- compile: (_schema, parent) => {
8185
- parent.type = "string";
8186
- parent.format = "binary";
8187
- delete parent.isFile;
8188
- return (field) => !!field.file;
8189
- },
8190
- error: { message: "should be a file" }
8191
- });
8192
- }
8193
- /**
8194
- * These export configurations enable JS and TS developers
8195
- * to consumer fastify in whatever way best suits their needs.
8196
- */
8197
- module.exports = fp(fastifyMultipart, {
8198
- fastify: "5.x",
8199
- name: "@fastify/multipart"
8200
- });
8201
- module.exports.default = fastifyMultipart;
8202
- module.exports.fastifyMultipart = fastifyMultipart;
8203
- module.exports.ajvFilePlugin = ajvFilePlugin;
8204
- })))(), 1);
5808
+ //#region ../server/dist/app-Frne_Mbn.mjs
8205
5809
  var __defProp = Object.defineProperty;
8206
5810
  var __exportAll = (all, no_symbols) => {
8207
5811
  let target = {};
@@ -8996,7 +6600,7 @@ async function deleteAdapterConfig(db, id) {
8996
6600
  const [row] = await db.delete(adapterConfigs).where(eq(adapterConfigs.id, id)).returning();
8997
6601
  if (!row) throw new NotFoundError(`Adapter config "${id}" not found`);
8998
6602
  }
8999
- const log$4 = createLogger("AdminAdapters");
6603
+ const log$4 = createLogger$1("AdminAdapters");
9000
6604
  function parseId(raw) {
9001
6605
  const id = Number(raw);
9002
6606
  if (!Number.isInteger(id) || id <= 0) throw new BadRequestError(`Invalid adapter ID: "${raw}"`);
@@ -9101,8 +6705,7 @@ async function adminAgentClientStatusRoutes(app) {
9101
6705
  }
9102
6706
  async function adminAgentConfigRoutes(app) {
9103
6707
  app.get("/:uuid/config", async (request) => {
9104
- const scope = memberScope(request);
9105
- await assertAgentVisible(app.db, scope, request.params.uuid);
6708
+ await assertCanManage(app.db, memberScope(request), request.params.uuid);
9106
6709
  return await app.configService.get(request.params.uuid);
9107
6710
  });
9108
6711
  app.patch("/:uuid/config", async (request) => {
@@ -12313,99 +9916,6 @@ async function adminTaskRoutes(app) {
12313
9916
  return getTaskHealth(app.db, request.params.taskId);
12314
9917
  });
12315
9918
  }
12316
- const UPLOADS_DIR = join(DEFAULT_DATA_DIR$1, "uploads");
12317
- const MAX_FILE_SIZE = 10 * 1024 * 1024;
12318
- const ALLOWED_MIME_TYPES = new Set([
12319
- "image/png",
12320
- "image/jpeg",
12321
- "image/gif",
12322
- "image/webp",
12323
- "image/svg+xml"
12324
- ]);
12325
- function ensureUploadsDir() {
12326
- if (!existsSync(UPLOADS_DIR)) mkdirSync(UPLOADS_DIR, { recursive: true });
12327
- }
12328
- async function adminUploadRoutes(app) {
12329
- ensureUploadsDir();
12330
- /** POST /admin/uploads — upload a file, returns URL */
12331
- app.post("/", async (request, reply) => {
12332
- requireMember(request);
12333
- const data = await request.file();
12334
- if (!data) return reply.status(400).send({ error: "No file provided" });
12335
- const mimeType = data.mimetype;
12336
- if (!ALLOWED_MIME_TYPES.has(mimeType)) return reply.status(400).send({ error: `Unsupported file type: ${mimeType}. Allowed: ${[...ALLOWED_MIME_TYPES].join(", ")}` });
12337
- const ext = extname(data.filename) || mimeExtension(mimeType);
12338
- const uniqueName = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, "").slice(0, 14)}_${randomUUID().slice(0, 8)}${ext}`;
12339
- const filePath = join(UPLOADS_DIR, uniqueName);
12340
- let totalSize = 0;
12341
- const writeStream = createWriteStream(filePath);
12342
- try {
12343
- const fileStream = data.file;
12344
- for await (const chunk of fileStream) {
12345
- totalSize += chunk.length;
12346
- if (totalSize > MAX_FILE_SIZE) {
12347
- writeStream.destroy();
12348
- try {
12349
- unlinkSync(filePath);
12350
- } catch {}
12351
- return reply.status(400).send({ error: `File too large. Maximum size: ${MAX_FILE_SIZE / 1024 / 1024}MB` });
12352
- }
12353
- writeStream.write(chunk);
12354
- }
12355
- writeStream.end();
12356
- await new Promise((resolve, reject) => {
12357
- writeStream.on("finish", resolve);
12358
- writeStream.on("error", reject);
12359
- });
12360
- } catch (err) {
12361
- writeStream.destroy();
12362
- throw err;
12363
- }
12364
- const url = `/api/v1/uploads/${uniqueName}`;
12365
- return reply.status(201).send({
12366
- url,
12367
- filename: data.filename,
12368
- storedName: uniqueName,
12369
- mimeType,
12370
- size: totalSize
12371
- });
12372
- });
12373
- }
12374
- /** Public routes — GET uploaded files (URL contains random UUID, not guessable) */
12375
- async function publicUploadRoutes(app) {
12376
- ensureUploadsDir();
12377
- /** GET /uploads/:filename — serve uploaded file without auth */
12378
- app.get("/:filename", async (request, reply) => {
12379
- const { filename } = request.params;
12380
- if (filename.includes("/") || filename.includes("..")) return reply.status(400).send({ error: "Invalid filename" });
12381
- const filePath = join(UPLOADS_DIR, filename);
12382
- if (!existsSync(filePath)) return reply.status(404).send({ error: "File not found" });
12383
- const contentType = extensionToMime(extname(filename).toLowerCase()) ?? "application/octet-stream";
12384
- const stream = createReadStream(filePath);
12385
- return reply.type(contentType).send(stream);
12386
- });
12387
- }
12388
- function mimeExtension(mime) {
12389
- switch (mime) {
12390
- case "image/png": return ".png";
12391
- case "image/jpeg": return ".jpg";
12392
- case "image/gif": return ".gif";
12393
- case "image/webp": return ".webp";
12394
- case "image/svg+xml": return ".svg";
12395
- default: return "";
12396
- }
12397
- }
12398
- function extensionToMime(ext) {
12399
- switch (ext) {
12400
- case ".png": return "image/png";
12401
- case ".jpg":
12402
- case ".jpeg": return "image/jpeg";
12403
- case ".gif": return "image/gif";
12404
- case ".webp": return "image/webp";
12405
- case ".svg": return "image/svg+xml";
12406
- default: return null;
12407
- }
12408
- }
12409
9919
  async function loadVisibleAgentIds(db, organizationId, memberId) {
12410
9920
  const rows = await db.select({ id: agents.uuid }).from(agents).where(and(eq(agents.organizationId, organizationId), ne(agents.status, AGENT_STATUSES.DELETED), or(eq(agents.visibility, AGENT_VISIBILITY.ORGANIZATION), eq(agents.managerId, memberId))));
12411
9921
  return new Set(rows.map((r) => r.id));
@@ -12574,7 +10084,7 @@ async function agentConfigRoutes(app) {
12574
10084
  return await app.configService.getDecrypted(identity.uuid);
12575
10085
  });
12576
10086
  }
12577
- const log$3 = createLogger("AgentFeishuBot");
10087
+ const log$3 = createLogger$1("AgentFeishuBot");
12578
10088
  async function agentFeishuBotRoutes(app) {
12579
10089
  /**
12580
10090
  * PUT /agent/me/feishu-bot
@@ -12839,7 +10349,7 @@ async function agentMeRoutes(app) {
12839
10349
  };
12840
10350
  });
12841
10351
  }
12842
- const log$2 = createLogger("AgentMessages");
10352
+ const log$2 = createLogger$1("AgentMessages");
12843
10353
  const editMessageSchema = z.object({
12844
10354
  format: z.string().optional(),
12845
10355
  content: z.unknown()
@@ -13819,7 +11329,7 @@ async function memberRoutes(app) {
13819
11329
  return reply.status(204).send();
13820
11330
  });
13821
11331
  }
13822
- const log$1 = createLogger("GithubWebhook");
11332
+ const log$1 = createLogger$1("GithubWebhook");
13823
11333
  const GITHUB_ADAPTER_ID = "github-adapter";
13824
11334
  function verifySignature(secret, rawBody, signatureHeader) {
13825
11335
  const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`;
@@ -14886,7 +12396,7 @@ function formatForFeishu(format, content) {
14886
12396
  content: JSON.stringify({ text })
14887
12397
  };
14888
12398
  }
14889
- const log = createLogger("BackgroundTasks");
12399
+ const log = createLogger$1("BackgroundTasks");
14890
12400
  function createBackgroundTasks(app, instanceId, adapterManager, kaelRuntime) {
14891
12401
  let inboxTimer = null;
14892
12402
  let heartbeatTimer = null;
@@ -15529,7 +13039,6 @@ async function buildApp(config) {
15529
13039
  const listenClient = postgres(config.database.url, { max: 1 });
15530
13040
  const notifier = createNotifier(listenClient);
15531
13041
  await app.register(websocket);
15532
- await app.register(import_multipart.default, { limits: { fileSize: 10 * 1024 * 1024 } });
15533
13042
  const corsOrigin = config.cors?.origin;
15534
13043
  const isDev = process.env.NODE_ENV !== "production";
15535
13044
  await app.register(cors, {
@@ -15568,14 +13077,12 @@ async function buildApp(config) {
15568
13077
  await api.register(authRoutes, { prefix: "/auth" });
15569
13078
  await api.register(contextTreeInfoRoutes, { prefix: "/context-tree" });
15570
13079
  await api.register(bootstrapConfigRoutes, { prefix: "/bootstrap" });
15571
- await api.register(publicUploadRoutes, { prefix: "/uploads" });
15572
13080
  await api.register(async (adminApp) => {
15573
13081
  adminApp.addHook("onRequest", memberAuth);
15574
13082
  await adminApp.register(adminAgentRoutes);
15575
13083
  }, { prefix: "/admin/agents" });
15576
13084
  await api.register(async (adminApp) => {
15577
13085
  adminApp.addHook("onRequest", memberAuth);
15578
- adminApp.addHook("onRequest", adminOnly);
15579
13086
  await adminApp.register(adminAgentConfigRoutes);
15580
13087
  }, { prefix: "/admin/agents" });
15581
13088
  await api.register(async (adminApp) => {
@@ -15615,10 +13122,6 @@ async function buildApp(config) {
15615
13122
  adminApp.addHook("onRequest", memberAuth);
15616
13123
  await adminApp.register(adminChatRoutes);
15617
13124
  }, { prefix: "/admin/chats" });
15618
- await api.register(async (adminApp) => {
15619
- adminApp.addHook("onRequest", memberAuth);
15620
- await adminApp.register(adminUploadRoutes);
15621
- }, { prefix: "/admin/uploads" });
15622
13125
  await api.register(async (adminApp) => {
15623
13126
  adminApp.addHook("onRequest", memberAuth);
15624
13127
  await adminApp.register(adminClientRoutes);
@@ -15695,7 +13198,7 @@ async function buildApp(config) {
15695
13198
  notifier,
15696
13199
  broadcast: broadcastToAdmins
15697
13200
  });
15698
- const hotReloadLog = createLogger("HotReload");
13201
+ const hotReloadLog = createLogger$1("HotReload");
15699
13202
  notifier.onConfigChange((configType) => {
15700
13203
  if (configType === "adapter_configs") {
15701
13204
  adapterManager.reload().catch((err) => hotReloadLog.error({ err }, "adapter hot-reload failed (PG NOTIFY)"));
@@ -15763,7 +13266,7 @@ function resolveCommandVersion(moduleUrl = import.meta.url) {
15763
13266
  const code = err.code;
15764
13267
  if (code !== "ENOENT" && code !== "ENOTDIR") {
15765
13268
  const message = err instanceof Error ? err.message : String(err);
15766
- process.stderr.write(`[first-tree-hub] warning: could not read ${dir}/package.json: ${message}\n`);
13269
+ print.line(`[first-tree-hub] warning: could not read ${dir}/package.json: ${message}\n`);
15767
13270
  }
15768
13271
  }
15769
13272
  const parent = dirname(dir);
@@ -15786,7 +13289,7 @@ const COMMAND_VERSION = resolveCommandVersion();
15786
13289
  * 7. Start Fastify server
15787
13290
  */
15788
13291
  async function startServer(options) {
15789
- process.stderr.write(`\n First Tree Hub v${COMMAND_VERSION}\n\n`);
13292
+ print.line(`\n First Tree Hub v${COMMAND_VERSION}\n\n`);
15790
13293
  const cliArgs = {};
15791
13294
  if (options.port !== void 0) cliArgs.server = { port: options.port };
15792
13295
  if (options.host !== void 0) cliArgs.server = {
@@ -15828,11 +13331,11 @@ async function startServer(options) {
15828
13331
  instanceId: `srv_${randomUUID().slice(0, 8)}`,
15829
13332
  commandVersion: COMMAND_VERSION
15830
13333
  };
15831
- const { initTelemetry, shutdownTelemetry } = await import("./observability-Xi-sEZI7.mjs");
13334
+ const { initTelemetry, shutdownTelemetry } = await import("./observability-hDEdrmMS.mjs");
15832
13335
  await initTelemetry(serverConfig.observability.tracing, config.instanceId);
15833
13336
  const app = await buildApp(config);
15834
13337
  const shutdown = async () => {
15835
- process.stderr.write("\n Shutting down...\n");
13338
+ print.line("\n Shutting down...\n");
15836
13339
  try {
15837
13340
  await app.close();
15838
13341
  } finally {
@@ -15849,8 +13352,8 @@ async function startServer(options) {
15849
13352
  blank();
15850
13353
  status("Server", `running at http://${config.server.host}:${config.server.port}`);
15851
13354
  blank();
15852
- process.stderr.write(" Open the URL above in your browser to get started.\n");
15853
- process.stderr.write(" Press Ctrl+C to stop.\n\n");
13355
+ print.line(" Open the URL above in your browser to get started.\n");
13356
+ print.line(" Press Ctrl+C to stop.\n\n");
15854
13357
  }
15855
13358
  /**
15856
13359
  * Resolve web dist path.
@@ -15878,6 +13381,175 @@ function resolveWebDist() {
15878
13381
  } catch {}
15879
13382
  }
15880
13383
  //#endregion
13384
+ //#region src/core/service-logs.ts
13385
+ const LOG_DIR = join(DEFAULT_HOME_DIR$1, "logs");
13386
+ const PRIMARY_LOG = join(LOG_DIR, "client.log");
13387
+ const FALLBACK_STDOUT = join(LOG_DIR, "client.stdout.log");
13388
+ const FALLBACK_STDERR = join(LOG_DIR, "client.stderr.log");
13389
+ /**
13390
+ * Duration string → milliseconds. Accepts `10s`, `5m`, `2h`, `1d`; rejects
13391
+ * everything else. Keeps the parser tiny rather than pulling in a library —
13392
+ * the `--since` flag is the only consumer.
13393
+ */
13394
+ function parseDuration(input) {
13395
+ const match = /^(\d+)\s*(s|m|h|d)$/.exec(input.trim());
13396
+ if (!match) throw new Error(`invalid duration "${input}" (expected e.g. 30s, 5m, 2h, 1d)`);
13397
+ return Number(match[1]) * ({
13398
+ s: 1e3,
13399
+ m: 6e4,
13400
+ h: 36e5,
13401
+ d: 864e5
13402
+ }[match[2]] ?? 0);
13403
+ }
13404
+ const LEVEL_RANK = {
13405
+ trace: 10,
13406
+ debug: 20,
13407
+ info: 30,
13408
+ warn: 40,
13409
+ error: 50,
13410
+ fatal: 60
13411
+ };
13412
+ /** Rotated log files, newest-first. Missing files are silently skipped. */
13413
+ function listLogFilesNewestFirst() {
13414
+ const files = [];
13415
+ if (existsSync(PRIMARY_LOG)) files.push(PRIMARY_LOG);
13416
+ for (let i = 1;; i++) {
13417
+ const p = `${PRIMARY_LOG}.${i}`;
13418
+ if (!existsSync(p)) break;
13419
+ files.push(p);
13420
+ }
13421
+ return files;
13422
+ }
13423
+ /** Supervisor fallback files (raw stdout/stderr, not NDJSON). Missing files skipped. */
13424
+ function listFallbackFiles() {
13425
+ const files = [];
13426
+ if (existsSync(FALLBACK_STDERR)) files.push(FALLBACK_STDERR);
13427
+ if (existsSync(FALLBACK_STDOUT)) files.push(FALLBACK_STDOUT);
13428
+ return files;
13429
+ }
13430
+ function matchesFilters(obj, minLevel, cutoffMs) {
13431
+ if (minLevel !== void 0) {
13432
+ const lvl = typeof obj.level === "number" ? obj.level : NaN;
13433
+ if (!Number.isFinite(lvl) || lvl < minLevel) return false;
13434
+ }
13435
+ if (cutoffMs !== void 0) {
13436
+ const t = parseLogTime(obj.time);
13437
+ if (t === null || t < cutoffMs) return false;
13438
+ }
13439
+ return true;
13440
+ }
13441
+ /** Logger writes `time` as a local-ish string (`YYYY-MM-DD HH:mm:ss`). */
13442
+ function parseLogTime(value) {
13443
+ if (typeof value === "number") return value;
13444
+ if (typeof value !== "string") return null;
13445
+ const iso = value.replace(" ", "T");
13446
+ const ms = Date.parse(iso);
13447
+ return Number.isFinite(ms) ? ms : null;
13448
+ }
13449
+ function renderLine(line, json) {
13450
+ if (!line.trim()) return null;
13451
+ if (json) return `${line}\n`;
13452
+ try {
13453
+ return formatPrettyEntry$1(line);
13454
+ } catch {
13455
+ return `${line}\n`;
13456
+ }
13457
+ }
13458
+ function processLogLine(line, minLevel, cutoffMs, json) {
13459
+ let obj;
13460
+ try {
13461
+ obj = JSON.parse(line);
13462
+ } catch {
13463
+ return json ? null : `${line}\n`;
13464
+ }
13465
+ if (!matchesFilters(obj, minLevel, cutoffMs)) return null;
13466
+ return renderLine(line, json);
13467
+ }
13468
+ async function readFileLines(path, minLevel, cutoffMs, json) {
13469
+ const rl = createInterface({ input: createReadStream(path, { encoding: "utf8" }) });
13470
+ for await (const line of rl) {
13471
+ const rendered = processLogLine(line, minLevel, cutoffMs, json);
13472
+ if (rendered) process.stdout.write(rendered);
13473
+ }
13474
+ }
13475
+ /**
13476
+ * Read a supervisor fallback file (launchd / systemd stdout/stderr capture).
13477
+ * These are plain text, not NDJSON: level and time filters don't apply, so we
13478
+ * honour `--since` by dropping the whole file when its mtime predates the
13479
+ * cutoff and otherwise pass every line through. In pretty mode each line is
13480
+ * tagged with the source so operators can tell it apart from pino output; in
13481
+ * `--json` mode we emit a synthetic record so NDJSON consumers keep one
13482
+ * object per line.
13483
+ */
13484
+ async function readFallbackFile(path, cutoffMs, json) {
13485
+ try {
13486
+ const mtime = statSync(path).mtimeMs;
13487
+ if (cutoffMs !== void 0 && mtime < cutoffMs) return;
13488
+ } catch {
13489
+ return;
13490
+ }
13491
+ const source = path.endsWith(".stderr.log") ? "supervisor:stderr" : "supervisor:stdout";
13492
+ const rl = createInterface({ input: createReadStream(path, { encoding: "utf8" }) });
13493
+ for await (const line of rl) {
13494
+ if (!line.trim()) continue;
13495
+ if (json) process.stdout.write(`${JSON.stringify({
13496
+ source,
13497
+ line
13498
+ })}\n`);
13499
+ else process.stdout.write(`[${source}] ${line}\n`);
13500
+ }
13501
+ }
13502
+ /**
13503
+ * Print existing log history, applying filters. `--tail` then switches to
13504
+ * follow mode and keeps printing new lines as the active file grows; rotation
13505
+ * is not handled during the tail (a follow-up rotation will simply stop
13506
+ * emitting new lines — operator can re-run the command).
13507
+ */
13508
+ async function showServiceLogs(options) {
13509
+ if (!existsSync(LOG_DIR)) {
13510
+ print.status("logs", `directory not found: ${LOG_DIR}`);
13511
+ return;
13512
+ }
13513
+ const minLevel = options.level ? LEVEL_RANK[options.level] : void 0;
13514
+ const cutoffMs = options.sinceMs !== void 0 ? Date.now() - options.sinceMs : void 0;
13515
+ for (const f of listFallbackFiles()) await readFallbackFile(f, cutoffMs, options.json);
13516
+ const files = listLogFilesNewestFirst().reverse();
13517
+ for (const f of files) await readFileLines(f, minLevel, cutoffMs, options.json);
13518
+ if (!options.tail) return;
13519
+ if (!existsSync(PRIMARY_LOG)) print.status("tail", "waiting for client.log to appear...");
13520
+ await new Promise((resolve) => {
13521
+ let position = existsSync(PRIMARY_LOG) ? statSync(PRIMARY_LOG).size : 0;
13522
+ const onChange = () => {
13523
+ if (!existsSync(PRIMARY_LOG)) return;
13524
+ const current = statSync(PRIMARY_LOG).size;
13525
+ if (current < position) position = 0;
13526
+ if (current <= position) return;
13527
+ const stream = createReadStream(PRIMARY_LOG, {
13528
+ start: position,
13529
+ end: current - 1,
13530
+ encoding: "utf8"
13531
+ });
13532
+ position = current;
13533
+ createInterface({ input: stream }).on("line", (line) => {
13534
+ const rendered = processLogLine(line, minLevel, cutoffMs, options.json);
13535
+ if (rendered) process.stdout.write(rendered);
13536
+ });
13537
+ };
13538
+ watchFile(PRIMARY_LOG, { interval: 500 }, onChange);
13539
+ process.once("SIGINT", () => {
13540
+ unwatchFile(PRIMARY_LOG, onChange);
13541
+ resolve();
13542
+ });
13543
+ });
13544
+ }
13545
+ /** Validated flag parsers the CLI layer can reuse without re-doing the work. */
13546
+ function validateLevel(value) {
13547
+ if (value === void 0) return void 0;
13548
+ const parsed = parseLogLevel$1(value);
13549
+ if (parsed.fellBack) throw new Error(`invalid --level "${value}" (expected one of ${LOG_LEVELS$1.join(", ")})`);
13550
+ return parsed.level;
13551
+ }
13552
+ //#endregion
15881
13553
  //#region src/core/update.ts
15882
13554
  const PACKAGE_NAME = "@agent-team-foundation/first-tree-hub";
15883
13555
  /**
@@ -15947,7 +13619,7 @@ async function installGlobalLatest() {
15947
13619
  child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
15948
13620
  child.stderr.on("data", (chunk) => {
15949
13621
  stderrChunks.push(chunk);
15950
- process.stderr.write(chunk);
13622
+ print.line(chunk.toString("utf8"));
15951
13623
  });
15952
13624
  child.on("error", (err) => {
15953
13625
  resolvePromise({
@@ -16031,27 +13703,27 @@ function createExecuteUpdate({ managed }) {
16031
13703
  return async () => {
16032
13704
  const mode = detectInstallMode();
16033
13705
  if (mode === "source") {
16034
- process.stderr.write(" [update] Running from source checkout — self-update skipped. Use `git pull` instead.\n");
13706
+ print.line(" [update] Running from source checkout — self-update skipped. Use `git pull` instead.\n");
16035
13707
  return { installed: false };
16036
13708
  }
16037
13709
  if (mode === "npx") {
16038
- process.stderr.write(" [update] Cannot self-update — not launched from a global npm install.\n Run `npm i -g @agent-team-foundation/first-tree-hub` manually.\n");
13710
+ print.line(" [update] Cannot self-update — not launched from a global npm install.\n Run `npm i -g @agent-team-foundation/first-tree-hub` manually.\n");
16039
13711
  return { installed: false };
16040
13712
  }
16041
- process.stderr.write(" [update] Running `npm install -g @agent-team-foundation/first-tree-hub@latest`...\n");
13713
+ print.line(" [update] Running `npm install -g @agent-team-foundation/first-tree-hub@latest`...\n");
16042
13714
  const result = await installGlobalLatest();
16043
13715
  if (!result.ok) {
16044
- process.stderr.write(` [update] Install failed: ${result.reason}\n`);
13716
+ print.line(` [update] Install failed: ${result.reason}\n`);
16045
13717
  return { installed: false };
16046
13718
  }
16047
13719
  const installed = result.installedVersion ?? "latest";
16048
13720
  if (managed) {
16049
- process.stderr.write(` [update] Installed ${installed}. Restarting (exit 75).\n`);
13721
+ print.line(` [update] Installed ${installed}. Restarting (exit 75).\n`);
16050
13722
  process.exit(75);
16051
13723
  }
16052
- process.stderr.write(` [update] Installed ${installed}. Restart the client manually (Ctrl+C then \`first-tree-hub client start\`) to pick up the new version.\n`);
13724
+ print.line(` [update] Installed ${installed}. Restart the client manually (Ctrl+C then \`first-tree-hub client start\`) to pick up the new version.\n`);
16053
13725
  return { installed: true };
16054
13726
  };
16055
13727
  }
16056
13728
  //#endregion
16057
- export { printResults as A, SdkError as B, checkDatabase as C, checkServerHealth as D, checkServerConfig as E, stopPostgres as F, cleanWorkspaces as H, ClientRuntime as I, createOwner as L, status as M, ensurePostgres as N, checkServerReachable as O, isDockerAvailable as P, hasUser as R, checkClientConfig as S, checkNodeVersion as T, applyClientLoggerConfig as U, SessionRegistry as V, isServiceSupported as _, COMMAND_VERSION as a, runMigrations as b, promptMissingFields as c, onboardCheck as d, onboardCreate as f, installClientService as g, getClientServiceStatus as h, startServer as i, blank as j, checkWebSocket as k, formatCheckReport as l, runHomeMigration as m, declineUpdate as n, isInteractive as o, saveOnboardState as p, promptUpdate as r, promptAddAgent as s, createExecuteUpdate as t, loadOnboardState as u, resolveCliInvocation as v, checkDocker as w, checkAgentConfigs as x, uninstallClientService as y, FirstTreeHubSDK as z };
13729
+ export { checkServerHealth as A, blank as B, runMigrations as C, checkDocker as D, checkDatabase as E, isDockerAvailable as F, SdkError as G, setJsonMode as H, stopPostgres as I, applyClientLoggerConfig as J, SessionRegistry as K, ClientRuntime as L, checkWebSocket as M, printResults as N, checkNodeVersion as O, ensurePostgres as P, createOwner as R, uninstallClientService as S, checkClientConfig as T, status as U, print as V, FirstTreeHubSDK as W, configureClientLoggerForService as Y, runHomeMigration as _, showServiceLogs as a, isServiceSupported as b, COMMAND_VERSION as c, promptMissingFields as d, formatCheckReport as f, saveOnboardState as g, onboardCreate as h, parseDuration as i, checkServerReachable as j, checkServerConfig as k, isInteractive as l, onboardCheck as m, declineUpdate as n, validateLevel as o, loadOnboardState as p, cleanWorkspaces as q, promptUpdate as r, startServer as s, createExecuteUpdate as t, promptAddAgent as u, getClientServiceStatus as v, checkAgentConfigs as w, resolveCliInvocation as x, installClientService as y, hasUser as z };