@rubytech/create-maxy 1.0.627 → 1.0.629

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.
@@ -2530,7 +2530,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
2530
2530
  });
2531
2531
  if (!chunk) {
2532
2532
  if (i === 1) {
2533
- await new Promise((resolve28) => setTimeout(resolve28));
2533
+ await new Promise((resolve29) => setTimeout(resolve29));
2534
2534
  maxReadCount = 3;
2535
2535
  continue;
2536
2536
  }
@@ -2897,7 +2897,7 @@ var serveStatic = (options = { root: "" }) => {
2897
2897
 
2898
2898
  // server/index.ts
2899
2899
  import { readFileSync as readFileSync26, existsSync as existsSync26, watchFile } from "fs";
2900
- import { resolve as resolve27, join as join13, basename as basename6 } from "path";
2900
+ import { resolve as resolve28, join as join13, basename as basename6 } from "path";
2901
2901
  import { homedir as homedir4 } from "os";
2902
2902
 
2903
2903
  // app/lib/vnc-logger.ts
@@ -2971,10 +2971,10 @@ var SCRYPT_R = 8;
2971
2971
  var SCRYPT_P = 1;
2972
2972
  var SCRYPT_KEYLEN = 64;
2973
2973
  function scryptAsync(password, salt) {
2974
- return new Promise((resolve28, reject) => {
2974
+ return new Promise((resolve29, reject) => {
2975
2975
  scrypt(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P }, (err, key) => {
2976
2976
  if (err) reject(err);
2977
- else resolve28(key);
2977
+ else resolve29(key);
2978
2978
  });
2979
2979
  });
2980
2980
  }
@@ -5146,7 +5146,7 @@ ${userContent}`;
5146
5146
  "dontAsk",
5147
5147
  prompt
5148
5148
  ];
5149
- return new Promise((resolve28) => {
5149
+ return new Promise((resolve29) => {
5150
5150
  let stdout = "";
5151
5151
  let stderr = "";
5152
5152
  const spawnFn = _spawnOverride ?? spawn;
@@ -5164,35 +5164,35 @@ ${userContent}`;
5164
5164
  const timer = setTimeout(() => {
5165
5165
  proc.kill("SIGTERM");
5166
5166
  console.error("[persist] autoLabel: haiku subprocess timed out");
5167
- resolve28(null);
5167
+ resolve29(null);
5168
5168
  }, SESSION_LABEL_TIMEOUT_MS);
5169
5169
  proc.on("error", (err) => {
5170
5170
  clearTimeout(timer);
5171
5171
  console.error(`[persist] autoLabel: subprocess error \u2014 ${err.message}`);
5172
- resolve28(null);
5172
+ resolve29(null);
5173
5173
  });
5174
5174
  proc.on("close", (code) => {
5175
5175
  clearTimeout(timer);
5176
5176
  if (code !== 0) {
5177
5177
  console.error(`[persist] autoLabel: subprocess exited code=${code}${stderr ? ` stderr=${stderr.trim().slice(0, 200)}` : ""}`);
5178
- resolve28(null);
5178
+ resolve29(null);
5179
5179
  return;
5180
5180
  }
5181
5181
  const text = stdout.trim();
5182
5182
  if (!text) {
5183
5183
  console.error("[persist] autoLabel: haiku returned empty response");
5184
- resolve28(null);
5184
+ resolve29(null);
5185
5185
  return;
5186
5186
  }
5187
5187
  if (text === "SKIP") {
5188
5188
  console.error("[persist] autoLabel: haiku returned SKIP \u2014 messages too vague");
5189
- resolve28(null);
5189
+ resolve29(null);
5190
5190
  return;
5191
5191
  }
5192
5192
  const words = text.split(/\s+/).slice(0, SESSION_LABEL_MAX_WORDS);
5193
5193
  const label = words.join(" ");
5194
5194
  console.error(`[persist] autoLabel: haiku response="${label}"`);
5195
- resolve28(label);
5195
+ resolve29(label);
5196
5196
  });
5197
5197
  });
5198
5198
  }
@@ -7512,12 +7512,30 @@ function consumeStalledSubagents(sessionKey) {
7512
7512
  delete session.stalledSubagents;
7513
7513
  return stalls && stalls.length > 0 ? stalls : void 0;
7514
7514
  }
7515
+ function streamLogPathFor(accountId, conversationId) {
7516
+ const logDir = resolve6(ACCOUNTS_DIR, accountId, "logs");
7517
+ const streamLogPath = resolve6(logDir, `claude-agent-stream-${conversationId}.log`);
7518
+ return { logDir, streamLogPath };
7519
+ }
7520
+ function buildSpawnEnv(accountId, accountDir, conversationId) {
7521
+ if (!conversationId) {
7522
+ throw new Error(`buildSpawnEnv: conversationId is required (accountId=${accountId.slice(0, 8)})`);
7523
+ }
7524
+ const { logDir, streamLogPath } = streamLogPathFor(accountId, conversationId);
7525
+ return {
7526
+ ...process.env,
7527
+ PLATFORM_ROOT: PLATFORM_ROOT4,
7528
+ ACCOUNT_DIR: accountDir,
7529
+ ACCOUNT_ID: accountId,
7530
+ LOG_DIR: logDir,
7531
+ STREAM_LOG_PATH: streamLogPath
7532
+ };
7533
+ }
7515
7534
  function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
7516
7535
  if (!conversationId) {
7517
7536
  throw new Error(`getMcpServers: conversationId is required (accountId=${accountId.slice(0, 8)})`);
7518
7537
  }
7519
- const LOG_DIR2 = resolve6(ACCOUNTS_DIR, accountId, "logs");
7520
- const STREAM_LOG_PATH = resolve6(LOG_DIR2, `claude-agent-stream-${conversationId}.log`);
7538
+ const { logDir: LOG_DIR2, streamLogPath: STREAM_LOG_PATH } = streamLogPathFor(accountId, conversationId);
7521
7539
  const baseEnv = { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2, STREAM_LOG_PATH };
7522
7540
  const servers = {
7523
7541
  "memory": {
@@ -7846,7 +7864,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
7846
7864
  return null;
7847
7865
  }
7848
7866
  const startMs = Date.now();
7849
- return new Promise((resolve28) => {
7867
+ return new Promise((resolve29) => {
7850
7868
  const proc = spawn2(process.execPath, [serverPath], {
7851
7869
  env: {
7852
7870
  ...process.env,
@@ -7875,7 +7893,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
7875
7893
  } else {
7876
7894
  console.error(`[fetchMemoryContext] failed: ${reason} (${elapsed}ms)${stderrBuf ? ` stderr: ${stderrBuf.slice(0, 500)}` : ""}`);
7877
7895
  }
7878
- resolve28(value);
7896
+ resolve29(value);
7879
7897
  };
7880
7898
  proc.stdout.on("data", (chunk) => {
7881
7899
  buffer += chunk.toString();
@@ -8286,15 +8304,10 @@ async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSes
8286
8304
  const proc = spawn2("claude", args, {
8287
8305
  cwd: accountDir,
8288
8306
  stdio: ["ignore", "pipe", "pipe"],
8289
- env: {
8290
- ...process.env,
8291
- PLATFORM_ROOT: PLATFORM_ROOT4,
8292
- ACCOUNT_DIR: accountDir
8293
- // Task 535: NODE_DEBUG removed. The Claude Code CLI is a bundled Bun
8294
- // binary and Bun ignores Node's NODE_DEBUG flag, so setting it here was
8295
- // a no-op that misled future readers. The [subproc-debug-unavailable]
8296
- // line below records the source-of-silence explicitly.
8297
- }
8307
+ // Task 556: STREAM_LOG_PATH is inherited by every Bash-tool subprocess
8308
+ // the Claude CLI spawns; opt-in shell scripts tee their cloudflared/etc.
8309
+ // output into the same per-conversation stream log the agent writes to.
8310
+ env: buildSpawnEnv(accountId, accountDir, conversationId)
8298
8311
  });
8299
8312
  const stderrLog = agentLogStream("claude-agent-compaction-stderr", accountDir, conversationId);
8300
8313
  stderrLog.on("error", () => {
@@ -8305,6 +8318,8 @@ async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSes
8305
8318
  });
8306
8319
  teeProcStderrToStreamLog(proc, streamLog);
8307
8320
  streamLog.write(`[${isoTs()}] [subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=${proc.pid} cli=claude
8321
+ `);
8322
+ streamLog.write(`[${isoTs()}] [spawn-env] STREAM_LOG_PATH=set pid=${proc.pid} conversationId=${conversationId} site=compaction
8308
8323
  `);
8309
8324
  streamLog.write(`[${isoTs()}] [compaction-start] resumeSessionId=${resumeSessionId}
8310
8325
  `);
@@ -9176,15 +9191,8 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
9176
9191
  const proc = spawn2("claude", args, {
9177
9192
  cwd: accountDir,
9178
9193
  stdio: ["ignore", "pipe", "pipe"],
9179
- env: {
9180
- ...process.env,
9181
- PLATFORM_ROOT: PLATFORM_ROOT4,
9182
- ACCOUNT_DIR: accountDir
9183
- // Task 535: NODE_DEBUG removed. The Claude Code CLI is a bundled Bun
9184
- // binary and Bun ignores Node's NODE_DEBUG flag, so setting it here was
9185
- // a no-op that misled future readers. The [subproc-debug-unavailable]
9186
- // line below records the source-of-silence explicitly.
9187
- }
9194
+ // Task 556: STREAM_LOG_PATH inherited by Bash-tool subprocesses.
9195
+ env: buildSpawnEnv(accountId, accountDir, spawnConvId)
9188
9196
  });
9189
9197
  const stderrLog = agentLogStream("claude-agent-stderr", accountDir, spawnConvId);
9190
9198
  stderrLog.on("error", () => {
@@ -9195,6 +9203,8 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
9195
9203
  });
9196
9204
  teeProcStderrToStreamLog(proc, streamLog);
9197
9205
  streamLog.write(`[${isoTs()}] [subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=${proc.pid} cli=claude
9206
+ `);
9207
+ streamLog.write(`[${isoTs()}] [spawn-env] STREAM_LOG_PATH=set pid=${proc.pid} conversationId=${spawnConvId} site=admin
9198
9208
  `);
9199
9209
  if (sessionKey) {
9200
9210
  const prev = activeProcesses.get(sessionKey);
@@ -9520,15 +9530,8 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
9520
9530
  const proc = spawn2("claude", args, {
9521
9531
  cwd: accountDir,
9522
9532
  stdio: ["ignore", "pipe", "pipe"],
9523
- env: {
9524
- ...process.env,
9525
- PLATFORM_ROOT: PLATFORM_ROOT4,
9526
- ACCOUNT_DIR: accountDir
9527
- // Task 535: NODE_DEBUG removed. The Claude Code CLI is a bundled Bun
9528
- // binary and Bun ignores Node's NODE_DEBUG flag, so setting it here was
9529
- // a no-op that misled future readers. The [subproc-debug-unavailable]
9530
- // line below records the source-of-silence explicitly.
9531
- }
9533
+ // Task 556: STREAM_LOG_PATH inherited by Bash-tool subprocesses.
9534
+ env: buildSpawnEnv(accountId, accountDir, managedConvId)
9532
9535
  });
9533
9536
  const stderrLog = agentLogStream("claude-agent-stderr", accountDir, managedConvId);
9534
9537
  stderrLog.on("error", () => {
@@ -9536,6 +9539,8 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
9536
9539
  proc.stderr?.pipe(stderrLog);
9537
9540
  teeProcStderrToStreamLog(proc, streamLog);
9538
9541
  streamLog.write(`[${isoTs()}] [subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=${proc.pid} cli=claude
9542
+ `);
9543
+ streamLog.write(`[${isoTs()}] [spawn-env] STREAM_LOG_PATH=set pid=${proc.pid} conversationId=${managedConvId} site=managed
9539
9544
  `);
9540
9545
  if (sessionKey) {
9541
9546
  const prev = activeProcesses.get(sessionKey);
@@ -26125,7 +26130,7 @@ var credsSaveQueue = Promise.resolve();
26125
26130
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
26126
26131
  console.error(`${TAG4} draining credential save queue\u2026`);
26127
26132
  const timer = new Promise(
26128
- (resolve28) => setTimeout(() => resolve28("timeout"), timeoutMs)
26133
+ (resolve29) => setTimeout(() => resolve29("timeout"), timeoutMs)
26129
26134
  );
26130
26135
  const result = await Promise.race([
26131
26136
  credsSaveQueue.then(() => "drained"),
@@ -26253,11 +26258,11 @@ async function createWaSocket(opts) {
26253
26258
  return sock;
26254
26259
  }
26255
26260
  async function waitForConnection(sock) {
26256
- return new Promise((resolve28, reject) => {
26261
+ return new Promise((resolve29, reject) => {
26257
26262
  const handler = (update) => {
26258
26263
  if (update.connection === "open") {
26259
26264
  sock.ev.off("connection.update", handler);
26260
- resolve28();
26265
+ resolve29();
26261
26266
  }
26262
26267
  if (update.connection === "close") {
26263
26268
  sock.ev.off("connection.update", handler);
@@ -26371,14 +26376,14 @@ ${inspected}`;
26371
26376
  return inspect2(err, INSPECT_OPTS2);
26372
26377
  }
26373
26378
  function withTimeout(label, promise2, timeoutMs) {
26374
- return new Promise((resolve28, reject) => {
26379
+ return new Promise((resolve29, reject) => {
26375
26380
  const timer = setTimeout(() => {
26376
26381
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
26377
26382
  }, timeoutMs);
26378
26383
  promise2.then(
26379
26384
  (value) => {
26380
26385
  clearTimeout(timer);
26381
- resolve28(value);
26386
+ resolve29(value);
26382
26387
  },
26383
26388
  (err) => {
26384
26389
  clearTimeout(timer);
@@ -27578,11 +27583,11 @@ async function connectWithReconnect(conn) {
27578
27583
  console.error(
27579
27584
  `${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
27580
27585
  );
27581
- await new Promise((resolve28) => {
27582
- const timer = setTimeout(resolve28, delay);
27586
+ await new Promise((resolve29) => {
27587
+ const timer = setTimeout(resolve29, delay);
27583
27588
  conn.abortController.signal.addEventListener("abort", () => {
27584
27589
  clearTimeout(timer);
27585
- resolve28();
27590
+ resolve29();
27586
27591
  }, { once: true });
27587
27592
  });
27588
27593
  }
@@ -27590,16 +27595,16 @@ async function connectWithReconnect(conn) {
27590
27595
  }
27591
27596
  }
27592
27597
  function waitForDisconnectEvent(conn) {
27593
- return new Promise((resolve28) => {
27598
+ return new Promise((resolve29) => {
27594
27599
  if (!conn.sock) {
27595
- resolve28();
27600
+ resolve29();
27596
27601
  return;
27597
27602
  }
27598
27603
  const sock = conn.sock;
27599
27604
  const handler = (update) => {
27600
27605
  if (update.connection === "close") {
27601
27606
  sock.ev.off("connection.update", handler);
27602
- resolve28();
27607
+ resolve29();
27603
27608
  }
27604
27609
  };
27605
27610
  sock.ev.on("connection.update", handler);
@@ -27809,8 +27814,8 @@ async function handleInboundMessage(conn, msg) {
27809
27814
  const conversationKey = isGroup ? remoteJid : senderPhone;
27810
27815
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
27811
27816
  let resolvePending;
27812
- const sttPending = new Promise((resolve28) => {
27813
- resolvePending = resolve28;
27817
+ const sttPending = new Promise((resolve29) => {
27818
+ resolvePending = resolve29;
27814
27819
  });
27815
27820
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
27816
27821
  try {
@@ -27917,20 +27922,20 @@ async function probeApiKey() {
27917
27922
  return result.status;
27918
27923
  }
27919
27924
  function checkPort(port2, timeoutMs = 500) {
27920
- return new Promise((resolve28) => {
27925
+ return new Promise((resolve29) => {
27921
27926
  const socket = createConnection3(port2, "127.0.0.1");
27922
27927
  socket.setTimeout(timeoutMs);
27923
27928
  socket.once("connect", () => {
27924
27929
  socket.destroy();
27925
- resolve28(true);
27930
+ resolve29(true);
27926
27931
  });
27927
27932
  socket.once("error", () => {
27928
27933
  socket.destroy();
27929
- resolve28(false);
27934
+ resolve29(false);
27930
27935
  });
27931
27936
  socket.once("timeout", () => {
27932
27937
  socket.destroy();
27933
- resolve28(false);
27938
+ resolve29(false);
27934
27939
  });
27935
27940
  });
27936
27941
  }
@@ -30121,8 +30126,8 @@ async function startLogin(opts) {
30121
30126
  resetActiveLogin(accountId);
30122
30127
  let resolveQr = null;
30123
30128
  let rejectQr = null;
30124
- const qrPromise = new Promise((resolve28, reject) => {
30125
- resolveQr = resolve28;
30129
+ const qrPromise = new Promise((resolve29, reject) => {
30130
+ resolveQr = resolve29;
30126
30131
  rejectQr = reject;
30127
30132
  });
30128
30133
  const qrTimer = setTimeout(
@@ -31199,6 +31204,106 @@ async function createAdminSession(accountId, thinkingView, userId, userName) {
31199
31204
  });
31200
31205
  }
31201
31206
 
31207
+ // app/api/admin/chat/route.ts
31208
+ import { resolve as resolve19 } from "path";
31209
+
31210
+ // app/lib/script-stream-tailer.ts
31211
+ import { createReadStream as createReadStream2, statSync as statSync7 } from "fs";
31212
+ import { StringDecoder as StringDecoder2 } from "string_decoder";
31213
+ var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[(setup-tunnel|reset-tunnel)((?::[^\]]+)?)\] (.*)$/;
31214
+ function parseLine(line) {
31215
+ const m = line.match(SCRIPT_STREAM_RE);
31216
+ if (!m) return void 0;
31217
+ const [, timestamp, scope, tagSuffix, rest] = m;
31218
+ return {
31219
+ type: "script_stream",
31220
+ source: scope + (tagSuffix ?? ""),
31221
+ timestamp,
31222
+ line: rest
31223
+ };
31224
+ }
31225
+ function startScriptStreamTailer(opts) {
31226
+ const { path: path2, onEvent, onError } = opts;
31227
+ let offset;
31228
+ try {
31229
+ offset = statSync7(path2).size;
31230
+ } catch {
31231
+ offset = 0;
31232
+ }
31233
+ const utf8 = new StringDecoder2("utf8");
31234
+ let buffer = "";
31235
+ let stopped = false;
31236
+ let pendingRead = false;
31237
+ let timer;
31238
+ const processLine = (line) => {
31239
+ const event = parseLine(line);
31240
+ if (event) onEvent(event);
31241
+ };
31242
+ const readDelta = async () => {
31243
+ if (pendingRead) return;
31244
+ pendingRead = true;
31245
+ try {
31246
+ let size;
31247
+ try {
31248
+ size = statSync7(path2).size;
31249
+ } catch {
31250
+ return;
31251
+ }
31252
+ if (size === offset) return;
31253
+ if (size < offset) {
31254
+ offset = 0;
31255
+ buffer = "";
31256
+ }
31257
+ await new Promise((res, rej) => {
31258
+ const stream = createReadStream2(path2, { start: offset, end: size - 1 });
31259
+ stream.on("data", (chunk) => {
31260
+ buffer += typeof chunk === "string" ? chunk : utf8.write(chunk);
31261
+ let idx;
31262
+ while ((idx = buffer.indexOf("\n")) !== -1) {
31263
+ const line = buffer.slice(0, idx);
31264
+ buffer = buffer.slice(idx + 1);
31265
+ if (line.length > 0) processLine(line);
31266
+ }
31267
+ });
31268
+ stream.on("end", () => {
31269
+ offset = size;
31270
+ res();
31271
+ });
31272
+ stream.on("error", rej);
31273
+ });
31274
+ } catch (err) {
31275
+ if (onError) onError(err instanceof Error ? err : new Error(String(err)));
31276
+ } finally {
31277
+ pendingRead = false;
31278
+ }
31279
+ };
31280
+ const tick = () => {
31281
+ if (stopped) return;
31282
+ readDelta().catch(() => {
31283
+ }).finally(() => {
31284
+ if (!stopped) timer = setTimeout(tick, 200);
31285
+ });
31286
+ };
31287
+ timer = setTimeout(tick, 0);
31288
+ return {
31289
+ async stop() {
31290
+ if (stopped) return;
31291
+ stopped = true;
31292
+ if (timer) clearTimeout(timer);
31293
+ while (pendingRead) {
31294
+ await new Promise((r) => setImmediate(r));
31295
+ }
31296
+ await readDelta();
31297
+ buffer += utf8.end();
31298
+ if (buffer.length > 0) {
31299
+ const event = parseLine(buffer);
31300
+ if (event) onEvent(event);
31301
+ buffer = "";
31302
+ }
31303
+ }
31304
+ };
31305
+ }
31306
+
31202
31307
  // app/api/admin/chat/route.ts
31203
31308
  function isComponentDone(parsed) {
31204
31309
  return typeof parsed === "object" && parsed !== null && parsed._componentDone === true && typeof parsed.component === "string" && typeof parsed.payload === "string";
@@ -31390,8 +31495,32 @@ async function POST21(req) {
31390
31495
  const sseConvId = getConversationIdForSession(session_key);
31391
31496
  const sseLog = sseConvId ? agentLogStream("sse-events", account.accountDir, sseConvId) : preConversationLogStream("sse-events", account.accountDir);
31392
31497
  const sk = sseConvId?.slice(0, 8) ?? session_key.slice(0, 8);
31498
+ let tailer = null;
31393
31499
  const readable = new ReadableStream({
31394
31500
  async start(controller) {
31501
+ let controllerOpen = true;
31502
+ if (sseConvId) {
31503
+ const streamLogPath = resolve19(account.accountDir, "logs", `claude-agent-stream-${sseConvId}.log`);
31504
+ tailer = startScriptStreamTailer({
31505
+ path: streamLogPath,
31506
+ onEvent: (event) => {
31507
+ if (!controllerOpen) return;
31508
+ const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
31509
+ sseLog.write(`[${ts}] [${sk}] admin: ${JSON.stringify(event)}
31510
+ `);
31511
+ try {
31512
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}
31513
+
31514
+ `));
31515
+ } catch {
31516
+ controllerOpen = false;
31517
+ }
31518
+ },
31519
+ onError: (err) => {
31520
+ console.error(`[script-stream-tailer] ${streamLogPath}: ${err.message}`);
31521
+ }
31522
+ });
31523
+ }
31395
31524
  try {
31396
31525
  for await (const event of invokeAgent(
31397
31526
  { type: "admin", skipTopicCheck },
@@ -31439,6 +31568,13 @@ async function POST21(req) {
31439
31568
  }
31440
31569
  }
31441
31570
  } finally {
31571
+ if (tailer) {
31572
+ try {
31573
+ await tailer.stop();
31574
+ } catch {
31575
+ }
31576
+ }
31577
+ controllerOpen = false;
31442
31578
  sseLog.end();
31443
31579
  try {
31444
31580
  controller.close();
@@ -31498,8 +31634,8 @@ async function POST22(req) {
31498
31634
  }
31499
31635
 
31500
31636
  // app/api/admin/logs/route.ts
31501
- import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync20, statSync as statSync7 } from "fs";
31502
- import { resolve as resolve19, basename as basename5 } from "path";
31637
+ import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync20, statSync as statSync8 } from "fs";
31638
+ import { resolve as resolve20, basename as basename5 } from "path";
31503
31639
  var TAIL_BYTES = 8192;
31504
31640
  async function GET9(request) {
31505
31641
  const { searchParams } = new URL(request.url);
@@ -31508,13 +31644,13 @@ async function GET9(request) {
31508
31644
  const conversationIdParam = searchParams.get("conversationId");
31509
31645
  const download = searchParams.get("download") === "1";
31510
31646
  const account = resolveAccount();
31511
- const accountLogDir2 = account ? resolve19(account.accountDir, "logs") : null;
31647
+ const accountLogDir2 = account ? resolve20(account.accountDir, "logs") : null;
31512
31648
  if (fileParam) {
31513
31649
  const safe = basename5(fileParam);
31514
31650
  const searched = [];
31515
31651
  for (const dir of [accountLogDir2, LOG_DIR]) {
31516
31652
  if (!dir) continue;
31517
- const filePath = resolve19(dir, safe);
31653
+ const filePath = resolve20(dir, safe);
31518
31654
  searched.push(filePath);
31519
31655
  try {
31520
31656
  const content = readFileSync20(filePath, "utf-8");
@@ -31556,7 +31692,7 @@ async function GET9(request) {
31556
31692
  const searched = [];
31557
31693
  for (const dir of [accountLogDir2, LOG_DIR]) {
31558
31694
  if (!dir) continue;
31559
- const filePath = resolve19(dir, fileName);
31695
+ const filePath = resolve20(dir, fileName);
31560
31696
  searched.push(filePath);
31561
31697
  try {
31562
31698
  const content = readFileSync20(filePath, "utf-8");
@@ -31583,10 +31719,10 @@ async function GET9(request) {
31583
31719
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
31584
31720
  continue;
31585
31721
  }
31586
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve19(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
31722
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync8(resolve20(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
31587
31723
  seen.add(name);
31588
31724
  try {
31589
- const content = readFileSync20(resolve19(dir, name));
31725
+ const content = readFileSync20(resolve20(dir, name));
31590
31726
  const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
31591
31727
  logs[name] = tail.trim() || "(empty)";
31592
31728
  } catch (err) {
@@ -31624,7 +31760,7 @@ async function GET10() {
31624
31760
  // app/api/admin/attachment/[attachmentId]/route.ts
31625
31761
  import { readFile as readFile3, readdir } from "fs/promises";
31626
31762
  import { existsSync as existsSync20 } from "fs";
31627
- import { resolve as resolve20 } from "path";
31763
+ import { resolve as resolve21 } from "path";
31628
31764
  async function GET11(req, attachmentId) {
31629
31765
  const sessionKey = new URL(req.url).searchParams.get("session_key") ?? "";
31630
31766
  if (!validateSession(sessionKey, "admin")) {
@@ -31637,11 +31773,11 @@ async function GET11(req, attachmentId) {
31637
31773
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
31638
31774
  return new Response("Not found", { status: 404 });
31639
31775
  }
31640
- const dir = resolve20(ATTACHMENTS_ROOT, accountId, attachmentId);
31776
+ const dir = resolve21(ATTACHMENTS_ROOT, accountId, attachmentId);
31641
31777
  if (!existsSync20(dir)) {
31642
31778
  return new Response("Not found", { status: 404 });
31643
31779
  }
31644
- const metaPath = resolve20(dir, `${attachmentId}.meta.json`);
31780
+ const metaPath = resolve21(dir, `${attachmentId}.meta.json`);
31645
31781
  if (!existsSync20(metaPath)) {
31646
31782
  return new Response("Not found", { status: 404 });
31647
31783
  }
@@ -31656,7 +31792,7 @@ async function GET11(req, attachmentId) {
31656
31792
  if (!dataFile) {
31657
31793
  return new Response("Not found", { status: 404 });
31658
31794
  }
31659
- const filePath = resolve20(dir, dataFile);
31795
+ const filePath = resolve21(dir, dataFile);
31660
31796
  const buffer = await readFile3(filePath);
31661
31797
  return new Response(buffer, {
31662
31798
  headers: {
@@ -31669,7 +31805,7 @@ async function GET11(req, attachmentId) {
31669
31805
 
31670
31806
  // app/api/admin/account/route.ts
31671
31807
  import { readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "fs";
31672
- import { resolve as resolve21 } from "path";
31808
+ import { resolve as resolve22 } from "path";
31673
31809
  var VALID_CONTEXT_MODES = ["managed", "claude-code"];
31674
31810
  async function PATCH(req) {
31675
31811
  let body;
@@ -31692,7 +31828,7 @@ async function PATCH(req) {
31692
31828
  if (!account) {
31693
31829
  return Response.json({ error: "No account configured" }, { status: 500 });
31694
31830
  }
31695
- const configPath2 = resolve21(account.accountDir, "account.json");
31831
+ const configPath2 = resolve22(account.accountDir, "account.json");
31696
31832
  try {
31697
31833
  const raw2 = readFileSync21(configPath2, "utf-8");
31698
31834
  const config2 = JSON.parse(raw2);
@@ -31707,14 +31843,14 @@ async function PATCH(req) {
31707
31843
  }
31708
31844
 
31709
31845
  // app/api/admin/agents/route.ts
31710
- import { resolve as resolve22 } from "path";
31846
+ import { resolve as resolve23 } from "path";
31711
31847
  import { readdirSync as readdirSync6, readFileSync as readFileSync22, existsSync as existsSync21 } from "fs";
31712
31848
  async function GET12() {
31713
31849
  const account = resolveAccount();
31714
31850
  if (!account) {
31715
31851
  return Response.json({ agents: [] });
31716
31852
  }
31717
- const agentsDir = resolve22(account.accountDir, "agents");
31853
+ const agentsDir = resolve23(account.accountDir, "agents");
31718
31854
  if (!existsSync21(agentsDir)) {
31719
31855
  return Response.json({ agents: [] });
31720
31856
  }
@@ -31724,7 +31860,7 @@ async function GET12() {
31724
31860
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
31725
31861
  if (!entry.isDirectory()) continue;
31726
31862
  if (entry.name === "admin") continue;
31727
- const configPath2 = resolve22(agentsDir, entry.name, "config.json");
31863
+ const configPath2 = resolve23(agentsDir, entry.name, "config.json");
31728
31864
  if (!existsSync21(configPath2)) continue;
31729
31865
  try {
31730
31866
  const config2 = JSON.parse(readFileSync22(configPath2, "utf-8"));
@@ -31745,7 +31881,7 @@ async function GET12() {
31745
31881
  }
31746
31882
 
31747
31883
  // app/api/admin/agents/[slug]/route.ts
31748
- import { resolve as resolve23 } from "path";
31884
+ import { resolve as resolve24 } from "path";
31749
31885
  import { existsSync as existsSync22, rmSync as rmSync2 } from "fs";
31750
31886
  async function DELETE2(_req, { params }) {
31751
31887
  const { slug } = await params;
@@ -31759,7 +31895,7 @@ async function DELETE2(_req, { params }) {
31759
31895
  if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
31760
31896
  return Response.json({ error: "Invalid agent slug" }, { status: 400 });
31761
31897
  }
31762
- const agentDir = resolve23(account.accountDir, "agents", slug);
31898
+ const agentDir = resolve24(account.accountDir, "agents", slug);
31763
31899
  if (!existsSync22(agentDir)) {
31764
31900
  return Response.json({ error: "Agent not found" }, { status: 404 });
31765
31901
  }
@@ -31775,8 +31911,8 @@ async function DELETE2(_req, { params }) {
31775
31911
 
31776
31912
  // app/api/admin/version/route.ts
31777
31913
  import { readFileSync as readFileSync23, existsSync as existsSync23 } from "fs";
31778
- import { resolve as resolve24, join as join10 } from "path";
31779
- var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
31914
+ import { resolve as resolve25, join as join10 } from "path";
31915
+ var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
31780
31916
  var brandHostname = "maxy";
31781
31917
  var brandNpmPackage = "@rubytech/create-maxy";
31782
31918
  var brandJsonPath = join10(PLATFORM_ROOT9, "config", "brand.json");
@@ -31788,7 +31924,7 @@ if (existsSync23(brandJsonPath)) {
31788
31924
  } catch {
31789
31925
  }
31790
31926
  }
31791
- var VERSION_FILE = resolve24(PLATFORM_ROOT9, `config/.${brandHostname}-version`);
31927
+ var VERSION_FILE = resolve25(PLATFORM_ROOT9, `config/.${brandHostname}-version`);
31792
31928
  var NPM_PACKAGE = brandNpmPackage;
31793
31929
  var REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE}/latest`;
31794
31930
  var FETCH_TIMEOUT_MS = 5e3;
@@ -31845,9 +31981,9 @@ async function GET13() {
31845
31981
 
31846
31982
  // app/api/admin/version/upgrade/route.ts
31847
31983
  import { spawn as spawn4 } from "child_process";
31848
- import { existsSync as existsSync24, statSync as statSync8, writeFileSync as writeFileSync16, readFileSync as readFileSync24, openSync as openSync4, closeSync as closeSync4 } from "fs";
31849
- import { resolve as resolve25, join as join11 } from "path";
31850
- var PLATFORM_ROOT10 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
31984
+ import { existsSync as existsSync24, statSync as statSync9, writeFileSync as writeFileSync16, readFileSync as readFileSync24, openSync as openSync4, closeSync as closeSync4 } from "fs";
31985
+ import { resolve as resolve26, join as join11 } from "path";
31986
+ var PLATFORM_ROOT10 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
31851
31987
  var upgradePkg = "@rubytech/create-maxy";
31852
31988
  var upgradeHostname = "maxy";
31853
31989
  var brandPath = join11(PLATFORM_ROOT10, "config", "brand.json");
@@ -31865,7 +32001,7 @@ var LOCK_MAX_AGE_MS = 20 * 60 * 1e3;
31865
32001
  function isLockFresh() {
31866
32002
  if (!existsSync24(LOCK_FILE)) return false;
31867
32003
  try {
31868
- const stat4 = statSync8(LOCK_FILE);
32004
+ const stat4 = statSync9(LOCK_FILE);
31869
32005
  return Date.now() - stat4.mtimeMs < LOCK_MAX_AGE_MS;
31870
32006
  } catch {
31871
32007
  return false;
@@ -31907,7 +32043,7 @@ async function POST23(req) {
31907
32043
  detached: true,
31908
32044
  stdio: ["ignore", logFd, logFd],
31909
32045
  env: { ...process.env, npm_config_yes: "true" },
31910
- cwd: resolve25(process.cwd(), "..")
32046
+ cwd: resolve26(process.cwd(), "..")
31911
32047
  });
31912
32048
  child.unref();
31913
32049
  closeSync4(logFd);
@@ -31924,8 +32060,8 @@ async function POST23(req) {
31924
32060
 
31925
32061
  // app/api/admin/version/upgrade/progress/route.ts
31926
32062
  import { existsSync as existsSync25, readFileSync as readFileSync25 } from "fs";
31927
- import { resolve as resolve26, join as join12 } from "path";
31928
- var PLATFORM_ROOT11 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
32063
+ import { resolve as resolve27, join as join12 } from "path";
32064
+ var PLATFORM_ROOT11 = process.env.MAXY_PLATFORM_ROOT ?? resolve27(process.cwd(), "..");
31929
32065
  var upgradeHostname2 = "maxy";
31930
32066
  var brandPath2 = join12(PLATFORM_ROOT11, "config", "brand.json");
31931
32067
  if (existsSync25(brandPath2)) {
@@ -32851,8 +32987,8 @@ app.get("/agent-assets/:slug/:filename", (c) => {
32851
32987
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
32852
32988
  return c.text("Not found", 404);
32853
32989
  }
32854
- const filePath = resolve27(account.accountDir, "agents", slug, "assets", filename);
32855
- const expectedDir = resolve27(account.accountDir, "agents", slug, "assets");
32990
+ const filePath = resolve28(account.accountDir, "agents", slug, "assets", filename);
32991
+ const expectedDir = resolve28(account.accountDir, "agents", slug, "assets");
32856
32992
  if (!filePath.startsWith(expectedDir + "/")) {
32857
32993
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
32858
32994
  return c.text("Forbidden", 403);
@@ -32881,8 +33017,8 @@ app.get("/generated/:filename", (c) => {
32881
33017
  console.error(`[generated] serve file=${filename} status=404`);
32882
33018
  return c.text("Not found", 404);
32883
33019
  }
32884
- const filePath = resolve27(account.accountDir, "generated", filename);
32885
- const expectedDir = resolve27(account.accountDir, "generated");
33020
+ const filePath = resolve28(account.accountDir, "generated", filename);
33021
+ const expectedDir = resolve28(account.accountDir, "generated");
32886
33022
  if (!filePath.startsWith(expectedDir + "/")) {
32887
33023
  console.error(`[generated] serve file=${filename} status=403`);
32888
33024
  return c.text("Forbidden", 403);
@@ -32922,7 +33058,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
32922
33058
  function cachedHtml(file2) {
32923
33059
  let html = htmlCache.get(file2);
32924
33060
  if (!html) {
32925
- html = readFileSync26(resolve27(process.cwd(), "public", file2), "utf-8");
33061
+ html = readFileSync26(resolve28(process.cwd(), "public", file2), "utf-8");
32926
33062
  html = html.replace("<title>Maxy</title>", `<title>${escapeHtml2(BRAND.productName)}</title>`);
32927
33063
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml2(brandFaviconPath)}"`);
32928
33064
  html = html.replace("</head>", `${brandScript}
@@ -33025,7 +33161,7 @@ app.use("/vnc-popout.html", logViewerFetch);
33025
33161
  app.get("/vnc-popout.html", (c) => {
33026
33162
  let html = htmlCache.get("vnc-popout.html");
33027
33163
  if (!html) {
33028
- html = readFileSync26(resolve27(process.cwd(), "public", "vnc-popout.html"), "utf-8");
33164
+ html = readFileSync26(resolve28(process.cwd(), "public", "vnc-popout.html"), "utf-8");
33029
33165
  const name = escapeHtml2(BRAND.productName);
33030
33166
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
33031
33167
  html = html.replace("</head>", ` ${brandScript}
@@ -33106,7 +33242,7 @@ if (bootAccountConfig?.whatsapp) {
33106
33242
  }
33107
33243
  init({
33108
33244
  configDir: configDirForWhatsApp,
33109
- platformRoot: resolve27(process.env.MAXY_PLATFORM_ROOT ?? join13(__dirname, "..")),
33245
+ platformRoot: resolve28(process.env.MAXY_PLATFORM_ROOT ?? join13(__dirname, "..")),
33110
33246
  accountConfig: bootAccountConfig,
33111
33247
  onMessage: async (msg) => {
33112
33248
  try {