lody 0.44.3-next.1 → 0.44.4-next.1

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.
Files changed (2) hide show
  1. package/dist/index.js +422 -181
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -45,13 +45,13 @@ import require$$1$6 from "string_decoder";
45
45
  import * as http$2 from "http";
46
46
  import http__default from "http";
47
47
  import require$$1$7 from "https";
48
- import require$$0$a, { execSync, exec, execFile as execFile$1 } from "child_process";
48
+ import require$$0$a, { execSync, exec, execFileSync, execFile as execFile$1 } from "child_process";
49
49
  import { randomFillSync, randomUUID as randomUUID$1, createHash as createHash$1 } from "node:crypto";
50
50
  import require$$0$b from "net";
51
51
  import require$$4$3 from "tls";
52
52
  import { i as imports, _ as __wbg_set_wasm$1, r as rawWasm, L as LoroDoc, E as EphemeralStoreWasm, U as UndoManager, c as callPendingEvents$3, a as LoroTree, b as LoroText, d as LoroMovableList, e as LoroList, f as LoroMap, g as __vite__initWasm, V as VersionVector, h as decodeImportBlobMeta, __tla as __tla_0 } from "./chunks/loro_wasm_bg-DgxHrrrp.js";
53
53
  import * as fs$5 from "fs/promises";
54
- import fs__default$1, { stat as stat$1, readFile as readFile$1 } from "fs/promises";
54
+ import fs__default$1, { stat as stat$1, readFile as readFile$1, statfs } from "fs/promises";
55
55
  import fsPromises, { stat, open } from "node:fs/promises";
56
56
  import { fileURLToPath } from "node:url";
57
57
  import require$$2$7 from "assert";
@@ -36820,7 +36820,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
36820
36820
  return client;
36821
36821
  }
36822
36822
  const name = "lody";
36823
- const version$4 = "0.44.3-next.1";
36823
+ const version$4 = "0.44.4-next.1";
36824
36824
  const description = "Lody Agent CLI tool for managing remote command execution";
36825
36825
  const type = "module";
36826
36826
  const main$3 = "dist/index.js";
@@ -78436,6 +78436,7 @@ Task description:
78436
78436
  "session_init_failed",
78437
78437
  "session_restore_failed",
78438
78438
  "session_not_found",
78439
+ "memory_pressure",
78439
78440
  "acp_not_ready",
78440
78441
  "agent_disconnected",
78441
78442
  "turn_pre_prompt_failed",
@@ -120216,6 +120217,221 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120216
120217
  }
120217
120218
  return resolveAgentConfigEnvForSessionResume(repo, options.agentConfigId);
120218
120219
  };
120220
+ function getMemoryPressureSnapshot() {
120221
+ const windowsStatus = getWindowsMemoryStatus();
120222
+ const systemAvailable = getSystemAvailableMemoryBytes(windowsStatus);
120223
+ const cgroupAvailable = getCgroupAvailableMemoryBytes();
120224
+ const availableMemoryBytes = cgroupAvailable !== null ? Math.min(systemAvailable, cgroupAvailable) : systemAvailable;
120225
+ const effectiveMemoryLimitBytes = getEffectiveMemoryLimitBytes();
120226
+ return {
120227
+ availableMemoryBytes,
120228
+ effectiveMemoryLimitBytes,
120229
+ ...windowsStatus ? {
120230
+ availableCommitBytes: windowsStatus.availableCommitBytes,
120231
+ commitLimitBytes: windowsStatus.commitLimitBytes,
120232
+ committedBytes: windowsStatus.committedBytes
120233
+ } : {}
120234
+ };
120235
+ }
120236
+ function getEffectiveMemoryLimitBytes() {
120237
+ const totalMem = os__default.totalmem();
120238
+ const cgroupMax = getCgroupMemoryMaxBytes();
120239
+ if (cgroupMax !== null) {
120240
+ return Math.min(totalMem, cgroupMax);
120241
+ }
120242
+ return totalMem;
120243
+ }
120244
+ function getSystemAvailableMemoryBytes(windowsStatus) {
120245
+ if (windowsStatus) {
120246
+ return Math.max(windowsStatus.availableBytes, os__default.freemem());
120247
+ }
120248
+ const darwinAvailable = getDarwinAvailableMemoryBytes();
120249
+ if (darwinAvailable !== null) {
120250
+ return darwinAvailable;
120251
+ }
120252
+ try {
120253
+ const meminfo = readFileSync("/proc/meminfo", "utf8");
120254
+ const match5 = meminfo.match(/MemAvailable:\s+(\d+)/);
120255
+ if (match5?.[1]) {
120256
+ return parseInt(match5[1], 10) * 1024;
120257
+ }
120258
+ } catch {
120259
+ }
120260
+ return os__default.freemem();
120261
+ }
120262
+ function getWindowsMemoryStatus() {
120263
+ if (process.platform !== "win32") {
120264
+ return null;
120265
+ }
120266
+ try {
120267
+ const script = `
120268
+ $mem = Get-CimInstance -ClassName Win32_PerfFormattedData_PerfOS_Memory |
120269
+ Select-Object AvailableBytes, CommitLimit, CommittedBytes
120270
+ $mem | ConvertTo-Json -Compress
120271
+ `;
120272
+ const output = execFileSync("powershell.exe", [
120273
+ "-NoProfile",
120274
+ "-NonInteractive",
120275
+ "-ExecutionPolicy",
120276
+ "Bypass",
120277
+ "-Command",
120278
+ script
120279
+ ], {
120280
+ encoding: "utf8"
120281
+ });
120282
+ return parseWindowsMemoryStatus(output);
120283
+ } catch {
120284
+ return null;
120285
+ }
120286
+ }
120287
+ function parseWindowsMemoryStatus(rawJson) {
120288
+ try {
120289
+ const parsed = JSON.parse(rawJson);
120290
+ const availableBytes = Number(parsed.AvailableBytes);
120291
+ const commitLimitBytes = Number(parsed.CommitLimit);
120292
+ const committedBytes = Number(parsed.CommittedBytes);
120293
+ if (!Number.isFinite(availableBytes) || availableBytes < 0 || !Number.isFinite(commitLimitBytes) || commitLimitBytes <= 0 || !Number.isFinite(committedBytes) || committedBytes < 0) {
120294
+ return null;
120295
+ }
120296
+ return {
120297
+ availableBytes,
120298
+ commitLimitBytes,
120299
+ committedBytes,
120300
+ availableCommitBytes: Math.max(0, commitLimitBytes - committedBytes)
120301
+ };
120302
+ } catch {
120303
+ return null;
120304
+ }
120305
+ }
120306
+ function getDarwinAvailableMemoryBytes() {
120307
+ if (process.platform !== "darwin") {
120308
+ return null;
120309
+ }
120310
+ try {
120311
+ const vmStatOutput = execFileSync("vm_stat", {
120312
+ encoding: "utf8"
120313
+ });
120314
+ const parsed = parseDarwinAvailableMemoryBytes(vmStatOutput);
120315
+ if (parsed !== null) {
120316
+ return Math.max(parsed, os__default.freemem());
120317
+ }
120318
+ } catch {
120319
+ }
120320
+ return null;
120321
+ }
120322
+ function parseDarwinAvailableMemoryBytes(vmStatOutput) {
120323
+ const pageSizeMatch = vmStatOutput.match(/page size of\s+(\d+)\s+bytes/i);
120324
+ if (!pageSizeMatch?.[1]) {
120325
+ return null;
120326
+ }
120327
+ const pageSize = parseInt(pageSizeMatch[1], 10);
120328
+ if (!Number.isFinite(pageSize) || pageSize <= 0) {
120329
+ return null;
120330
+ }
120331
+ const counters = /* @__PURE__ */ new Map();
120332
+ for (const rawLine of vmStatOutput.split("\n")) {
120333
+ const line3 = rawLine.trim();
120334
+ const match5 = line3.match(/^"?([^":]+?)"?:\s+(\d+)\.?$/);
120335
+ if (!match5?.[1] || !match5[2]) {
120336
+ continue;
120337
+ }
120338
+ counters.set(match5[1].toLowerCase(), parseInt(match5[2], 10));
120339
+ }
120340
+ const freePages = counters.get("pages free") ?? 0;
120341
+ const speculativePages = counters.get("pages speculative") ?? 0;
120342
+ const purgeablePages = counters.get("pages purgeable") ?? 0;
120343
+ const inactivePages = counters.get("pages inactive") ?? 0;
120344
+ const fileBackedPages = counters.get("file-backed pages");
120345
+ if (freePages === 0 && speculativePages === 0 && purgeablePages === 0 && inactivePages === 0) {
120346
+ return null;
120347
+ }
120348
+ const reclaimableCachedPages = fileBackedPages !== void 0 ? Math.min(fileBackedPages, inactivePages) : inactivePages;
120349
+ const availablePages = freePages + speculativePages + purgeablePages + reclaimableCachedPages;
120350
+ return availablePages * pageSize;
120351
+ }
120352
+ function getCgroupMemoryMaxBytes() {
120353
+ try {
120354
+ const cgroupPath = readSelfCgroupPath();
120355
+ if (cgroupPath === null) return null;
120356
+ let tightest = null;
120357
+ let current2 = cgroupPath;
120358
+ for (let depth = 0; depth < 20; depth++) {
120359
+ const memMaxPath = `/sys/fs/cgroup${current2 === "/" ? "" : current2}/memory.max`;
120360
+ const raw = readFileSafe(memMaxPath);
120361
+ if (raw !== null) {
120362
+ const trimmed = raw.trim();
120363
+ if (trimmed !== "max") {
120364
+ const value = parseInt(trimmed, 10);
120365
+ if (Number.isFinite(value) && value > 0) {
120366
+ tightest = tightest === null ? value : Math.min(tightest, value);
120367
+ }
120368
+ }
120369
+ }
120370
+ if (current2 === "/" || current2 === "") break;
120371
+ const parent = current2.substring(0, current2.lastIndexOf("/")) || "/";
120372
+ if (parent === current2) break;
120373
+ current2 = parent;
120374
+ }
120375
+ return tightest;
120376
+ } catch {
120377
+ return null;
120378
+ }
120379
+ }
120380
+ function getCgroupAvailableMemoryBytes() {
120381
+ try {
120382
+ const cgroupPath = readSelfCgroupPath();
120383
+ if (cgroupPath === null) return null;
120384
+ let tightestMax = null;
120385
+ let tightestPath = null;
120386
+ let current2 = cgroupPath;
120387
+ for (let depth = 0; depth < 20; depth++) {
120388
+ const prefix = `/sys/fs/cgroup${current2 === "/" ? "" : current2}`;
120389
+ const raw = readFileSafe(`${prefix}/memory.max`);
120390
+ if (raw !== null) {
120391
+ const trimmed = raw.trim();
120392
+ if (trimmed !== "max") {
120393
+ const value = parseInt(trimmed, 10);
120394
+ if (Number.isFinite(value) && value > 0) {
120395
+ if (tightestMax === null || value < tightestMax) {
120396
+ tightestMax = value;
120397
+ tightestPath = prefix;
120398
+ }
120399
+ }
120400
+ }
120401
+ }
120402
+ if (current2 === "/" || current2 === "") break;
120403
+ const parent = current2.substring(0, current2.lastIndexOf("/")) || "/";
120404
+ if (parent === current2) break;
120405
+ current2 = parent;
120406
+ }
120407
+ if (tightestMax === null || tightestPath === null) return null;
120408
+ const currentRaw = readFileSafe(`${tightestPath}/memory.current`);
120409
+ if (currentRaw === null) return null;
120410
+ const currentUsage = parseInt(currentRaw.trim(), 10);
120411
+ if (!Number.isFinite(currentUsage)) return null;
120412
+ return Math.max(0, tightestMax - currentUsage);
120413
+ } catch {
120414
+ return null;
120415
+ }
120416
+ }
120417
+ function readSelfCgroupPath() {
120418
+ try {
120419
+ const content = readFileSync("/proc/self/cgroup", "utf8");
120420
+ const line3 = content.split("\n").map((l) => l.trim()).find((l) => l.startsWith("0::"));
120421
+ if (!line3) return null;
120422
+ const cgroupPath = line3.slice(3).trim();
120423
+ return cgroupPath || "/";
120424
+ } catch {
120425
+ return null;
120426
+ }
120427
+ }
120428
+ function readFileSafe(filePath) {
120429
+ try {
120430
+ return readFileSync(filePath, "utf8");
120431
+ } catch {
120432
+ return null;
120433
+ }
120434
+ }
120219
120435
  class SessionTurnCancelled extends TaggedError("SessionTurnCancelled") {
120220
120436
  }
120221
120437
  class SessionTurnHalted extends TaggedError("SessionTurnHalted") {
@@ -120236,6 +120452,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120236
120452
  AUTH_REQUIRED: -32e3,
120237
120453
  RESOURCE_NOT_FOUND: -32002
120238
120454
  };
120455
+ const BYTES_PER_GIB = 1024 * 1024 * 1024;
120239
120456
  const shouldRedactEnvKey = (key2) => /token|secret|password|passwd|key/i.test(key2);
120240
120457
  const redactEnvForLog = (env2) => {
120241
120458
  if (!env2) {
@@ -120271,6 +120488,46 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120271
120488
  canceledTurnBySession = /* @__PURE__ */ new Map();
120272
120489
  currentTurnBySession = /* @__PURE__ */ new Map();
120273
120490
  turnRuntimeBySession = /* @__PURE__ */ new Map();
120491
+ formatGiB(bytes) {
120492
+ if (bytes === null || !Number.isFinite(bytes) || bytes < 0) {
120493
+ return "unavailable";
120494
+ }
120495
+ return `${(bytes / BYTES_PER_GIB).toFixed(1)}GB`;
120496
+ }
120497
+ formatPercent(value) {
120498
+ if (value === null || !Number.isFinite(value) || value < 0) {
120499
+ return "unavailable";
120500
+ }
120501
+ return `${value.toFixed(1)}%`;
120502
+ }
120503
+ async getFreeDiskBytes() {
120504
+ try {
120505
+ const stats = await statfs(os__default.homedir());
120506
+ const bsize = typeof stats.bsize === "bigint" ? Number(stats.bsize) : stats.bsize;
120507
+ const bavail = typeof stats.bavail === "bigint" ? Number(stats.bavail) : stats.bavail;
120508
+ if (!Number.isFinite(bsize) || !Number.isFinite(bavail) || bsize <= 0 || bavail < 0) {
120509
+ return null;
120510
+ }
120511
+ return bsize * bavail;
120512
+ } catch {
120513
+ return null;
120514
+ }
120515
+ }
120516
+ async logTurnStartResources(sessionId, mode2) {
120517
+ try {
120518
+ const memorySnapshot = getMemoryPressureSnapshot();
120519
+ const availableMemoryBytes = memorySnapshot.availableMemoryBytes;
120520
+ const memoryFreePercent = memorySnapshot.effectiveMemoryLimitBytes > 0 ? availableMemoryBytes / memorySnapshot.effectiveMemoryLimitBytes * 100 : null;
120521
+ const [resources, freeDiskBytes] = await Promise.all([
120522
+ this.deps.collectMachineResources().catch(() => null),
120523
+ this.getFreeDiskBytes()
120524
+ ]);
120525
+ const cpuUsagePercent = resources?.cpuUsagePercent ?? null;
120526
+ this.deps.logger.info(`[${sessionId}] Turn start resources (mode=${mode2}): memoryAvailable=${this.formatGiB(availableMemoryBytes)} memoryAvailablePercent=${this.formatPercent(memoryFreePercent)} cpuUsage=${this.formatPercent(cpuUsagePercent)} diskFree=${this.formatGiB(freeDiskBytes)}`);
120527
+ } catch (error2) {
120528
+ this.deps.logger.debug(`[${sessionId}] Failed to log turn start resources: ${formatErrorMessage(error2)}`);
120529
+ }
120530
+ }
120274
120531
  createTurnRuntime(sessionId, turnId, userTurnId, session) {
120275
120532
  return {
120276
120533
  sessionId,
@@ -120453,10 +120710,19 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120453
120710
  async recordKnownChatFailure(options) {
120454
120711
  await this.deps.recordChatFailure(options.sessionDoc, options.reason, options.message);
120455
120712
  if (options.userTurnId) {
120456
- await this.setDispatchError(options.sessionId, options.sessionDoc, options.userTurnId, options.code ?? options.reason, options.message);
120713
+ await this.markTurnFailed(options.sessionId, options.sessionDoc, options.userTurnId);
120457
120714
  }
120458
120715
  await options.sessionDoc.setStatus(SessionStatusFactory.idle());
120459
120716
  }
120717
+ formatMemoryPressureWarningMessage(result) {
120718
+ const availableMb = Math.round(result.availableMemoryBytes / 1024 / 1024);
120719
+ const thresholdMb = Math.round(result.thresholdBytes / 1024 / 1024);
120720
+ const commitText = result.availableCommitBytes !== void 0 && (result.pressureReason === "commit" || result.pressureReason === "physical_and_commit") && result.commitThresholdBytes !== void 0 ? ` Commit headroom is ${Math.round(result.availableCommitBytes / 1024 / 1024)}MB (threshold: ${Math.round(result.commitThresholdBytes / 1024 / 1024)}MB).` : "";
120721
+ return `The machine is under memory pressure (${availableMb}MB available, ${thresholdMb}MB required to start a turn). Proceeding anyway because the new turn may be used to free resources.${commitText}`;
120722
+ }
120723
+ warnOnMemoryPressure(sessionId, result) {
120724
+ this.deps.logger.warn(`[${sessionId}] ${this.formatMemoryPressureWarningMessage(result)}`);
120725
+ }
120460
120726
  recordKnownChatFailureAndHaltEffect(options) {
120461
120727
  return this.tryPromise(() => this.recordKnownChatFailure(options)).pipe(flatMap$1(() => fail(new SessionTurnHalted({
120462
120728
  sessionId: options.sessionId,
@@ -120480,7 +120746,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120480
120746
  }
120481
120747
  this.deps.logger.error(options.describe(options.error), options.error);
120482
120748
  if (options.userTurnId) {
120483
- await this.setDispatchError(options.sessionId, options.sessionDoc, options.userTurnId, options.code, formatErrorMessage(options.error));
120749
+ await this.markTurnFailed(options.sessionId, options.sessionDoc, options.userTurnId);
120484
120750
  }
120485
120751
  await this.handleTurnError(options.sessionId, options.sessionDoc, options.error);
120486
120752
  await options.onUnhandledError?.(options.error);
@@ -120816,8 +121082,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120816
121082
  await this.setUserTurnStatus(sessionDoc, userTurnId, "processing");
120817
121083
  await this.upsertSessionMeta(sessionId, {
120818
121084
  latestUserMsgId: userTurnId,
120819
- processingUserMsgId: userTurnId,
120820
- dispatchError: void 0
121085
+ processingUserMsgId: userTurnId
120821
121086
  });
120822
121087
  }
120823
121088
  async clearDispatchProcessing(sessionId) {
@@ -120866,34 +121131,31 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120866
121131
  await this.upsertSessionMeta(sessionId, {
120867
121132
  latestUserMsgId: existingMeta?.latestUserMsgId ?? cancelledUserMsgId,
120868
121133
  lastHandledUserMsgId: cancelledUserMsgId,
120869
- processingUserMsgId: void 0,
120870
- dispatchError: void 0
121134
+ processingUserMsgId: void 0
120871
121135
  });
120872
121136
  return;
120873
121137
  }
120874
121138
  await this.clearDispatchProcessing(sessionId);
120875
121139
  }
121140
+ resolveLatestUserMsgIdForTerminalTurn(meta, terminalUserTurnId) {
121141
+ return meta?.latestUserMsgId && meta.latestUserMsgId !== terminalUserTurnId ? meta.latestUserMsgId : terminalUserTurnId;
121142
+ }
120876
121143
  async setDispatchHandled(sessionId, sessionDoc, userTurnId) {
121144
+ const existingMeta = await this.getSessionMeta(sessionId);
120877
121145
  await this.setUserTurnStatus(sessionDoc, userTurnId, "handled");
120878
121146
  await this.upsertSessionMeta(sessionId, {
120879
- latestUserMsgId: userTurnId,
121147
+ latestUserMsgId: this.resolveLatestUserMsgIdForTerminalTurn(existingMeta, userTurnId),
120880
121148
  lastHandledUserMsgId: userTurnId,
120881
- processingUserMsgId: void 0,
120882
- dispatchError: void 0
121149
+ processingUserMsgId: void 0
120883
121150
  });
120884
121151
  }
120885
- async setDispatchError(sessionId, sessionDoc, userTurnId, code2, message) {
121152
+ async markTurnFailed(sessionId, sessionDoc, userTurnId) {
121153
+ const existingMeta = await this.getSessionMeta(sessionId);
120886
121154
  await this.setUserTurnStatus(sessionDoc, userTurnId, "failed");
120887
121155
  await this.upsertSessionMeta(sessionId, {
120888
- latestUserMsgId: userTurnId,
120889
- processingUserMsgId: void 0,
120890
- dispatchError: {
120891
- code: code2,
120892
- ...message ? {
120893
- message
120894
- } : {},
120895
- at: getServerNow()
120896
- }
121156
+ latestUserMsgId: this.resolveLatestUserMsgIdForTerminalTurn(existingMeta, userTurnId),
121157
+ lastHandledUserMsgId: userTurnId,
121158
+ processingUserMsgId: void 0
120897
121159
  });
120898
121160
  }
120899
121161
  resolveGitHubProjectBranch(meta, preferredBranch) {
@@ -120987,15 +121249,18 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
120987
121249
  }
120988
121250
  async continueSession(message) {
120989
121251
  const { sessionId, acpSessionConfig, userId, userName, userEmail, userTurnId } = message;
120990
- await this.deps.evictForMemoryPressure(sessionId);
121252
+ const memoryPressureResult = await this.deps.evictForMemoryPressure(sessionId);
121253
+ if (memoryPressureResult.stillUnderPressure) {
121254
+ this.warnOnMemoryPressure(sessionId, memoryPressureResult);
121255
+ }
121256
+ await this.logTurnStartResources(sessionId, "continue");
121257
+ const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(sessionId);
120991
121258
  this.deps.touchSession(sessionId);
120992
121259
  this.deps.logger.info(`Session chat received: ${sessionId}`);
120993
121260
  this.deps.logger.debug(`[${sessionId}] Received chat request (userTurnId=${userTurnId})`);
120994
121261
  await this.upsertSessionMeta(sessionId, {
120995
- latestUserMsgId: userTurnId,
120996
- dispatchError: void 0
121262
+ latestUserMsgId: userTurnId
120997
121263
  });
120998
- const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(sessionId);
120999
121264
  const incomingProjectBranch = message.project?.branch?.trim();
121000
121265
  if (incomingProjectBranch) {
121001
121266
  await sessionDoc.setBaseBranch(incomingProjectBranch);
@@ -121332,7 +121597,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
121332
121597
  }));
121333
121598
  }
121334
121599
  async startSession(message) {
121335
- await this.deps.evictForMemoryPressure(message.sessionId);
121600
+ const memoryPressureResult = await this.deps.evictForMemoryPressure(message.sessionId);
121336
121601
  const { sessionId, acpSessionConfig, workspaceId, env: env2 } = message;
121337
121602
  const userTurnId = typeof message.userTurnId === "string" && message.userTurnId.trim() ? message.userTurnId.trim() : void 0;
121338
121603
  const project = message.project;
@@ -121345,6 +121610,10 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
121345
121610
  const promptText = agentConfig.prompt ?? "";
121346
121611
  const promptBytes = Buffer.byteLength(promptText, "utf8");
121347
121612
  const promptPreview = promptText.length > 200 ? `${promptText.slice(0, 200)}\u2026` : promptText;
121613
+ if (memoryPressureResult.stillUnderPressure) {
121614
+ this.warnOnMemoryPressure(sessionId, memoryPressureResult);
121615
+ }
121616
+ await this.logTurnStartResources(sessionId, "start");
121348
121617
  const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(sessionId);
121349
121618
  const existingMeta = await sessionDoc.getMetaState();
121350
121619
  const fromFeedbackPostId = message.meta?.fromFeedbackPostId?.trim() || existingMeta?.fromFeedbackPostId?.trim() || void 0;
@@ -121368,12 +121637,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
121368
121637
  fromFeedbackPostId
121369
121638
  };
121370
121639
  this.deps.logger.debug(`[${sessionId}] session/create summary`, configForLog);
121371
- if (userTurnId) {
121372
- await this.upsertSessionMeta(sessionId, {
121373
- latestUserMsgId: userTurnId,
121374
- dispatchError: void 0
121375
- });
121376
- }
121377
121640
  const sessionConfig = {
121378
121641
  sessionId,
121379
121642
  workspaceId,
@@ -121394,6 +121657,11 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
121394
121657
  if (project) {
121395
121658
  await sessionDoc.setProject(project);
121396
121659
  }
121660
+ if (userTurnId) {
121661
+ await this.upsertSessionMeta(sessionId, {
121662
+ latestUserMsgId: userTurnId
121663
+ });
121664
+ }
121397
121665
  if (branch) {
121398
121666
  await sessionDoc.setBaseBranch(branch);
121399
121667
  }
@@ -122057,9 +122325,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122057
122325
  if (meta.lastCanceledTurn && meta.lastCanceledTurn !== this.cancelSeenTurn.get(meta.id)) {
122058
122326
  return true;
122059
122327
  }
122060
- if (meta.dispatchError?.code === SessionDispatchWatcher.DISPATCH_HISTORY_SYNC_TIMEOUT_CODE) {
122061
- return false;
122062
- }
122063
122328
  if (!meta.lastHandledUserMsgId) {
122064
122329
  return true;
122065
122330
  }
@@ -122155,12 +122420,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122155
122420
  await this.deps.workspaceDocument.repo.upsertDocMeta?.(getSessionRoomId(sessionId), {
122156
122421
  latestUserMsgId: userTurnId,
122157
122422
  lastHandledUserMsgId: userTurnId,
122158
- processingUserMsgId: void 0,
122159
- dispatchError: {
122160
- code: reason === "cli_token_invalid" ? "cli_token_invalid" : "machine_access_denied",
122161
- message,
122162
- at: getServerNow()
122163
- }
122423
+ processingUserMsgId: void 0
122164
122424
  });
122165
122425
  await sessionDoc.setStatus(SessionStatusFactory.idle());
122166
122426
  }
@@ -122290,7 +122550,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122290
122550
  static HISTORY_SYNC_WAIT_TIMEOUT_MS = 5 * 6e4;
122291
122551
  static HISTORY_RECONNECT_JITTER_MIN_MS = 500;
122292
122552
  static HISTORY_RECONNECT_JITTER_MAX_MS = 1500;
122293
- static DISPATCH_HISTORY_SYNC_TIMEOUT_CODE = "dispatch_recovery_unhealthy";
122294
122553
  static setUnrefTimeout(callback, delayMs) {
122295
122554
  const timer2 = setTimeout(callback, delayMs);
122296
122555
  if (typeof timer2 === "object" && "unref" in timer2) {
@@ -122450,12 +122709,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122450
122709
  }
122451
122710
  const pendingUserMsgId = meta.processingUserMsgId ?? meta.latestUserMsgId ?? meta.lastHandledUserMsgId;
122452
122711
  const recoveryPatch = {
122453
- status: SessionStatusFactory.idle(),
122454
- dispatchError: {
122455
- code: SessionDispatchWatcher.DISPATCH_HISTORY_SYNC_TIMEOUT_CODE,
122456
- message: "Dispatch recovery could not reconnect to this session after 5 minutes. Send a new message to retry.",
122457
- at: getServerNow()
122458
- }
122712
+ status: SessionStatusFactory.idle()
122459
122713
  };
122460
122714
  if (pendingUserMsgId) {
122461
122715
  recoveryPatch.lastHandledUserMsgId = pendingUserMsgId;
@@ -123208,8 +123462,14 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
123208
123462
  permissionRequestStartTimes = /* @__PURE__ */ new Map();
123209
123463
  machineHeartbeatTimer = null;
123210
123464
  static MACHINE_HEARTBEAT_INTERVAL_MS = 2e4;
123211
- evictForMemoryPressureFn = async () => {
123212
- };
123465
+ evictForMemoryPressureFn = async () => ({
123466
+ availableMemoryBytes: 0,
123467
+ thresholdBytes: 0,
123468
+ hadMemoryPressure: false,
123469
+ stillUnderPressure: false,
123470
+ evictedSessionIds: [],
123471
+ pressureReason: null
123472
+ });
123213
123473
  executionService;
123214
123474
  sessionDispatchWatcher;
123215
123475
  autoPromptRunner;
@@ -125221,6 +125481,16 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125221
125481
  hasPendingUpdates(sessionId) {
125222
125482
  return this.store.has(sessionId) && this.store.get(sessionId).acpUpdateBuffer.length > 0;
125223
125483
  }
125484
+ async hasPendingUserWork(sessionId) {
125485
+ const meta = (await this.workspaceDocument.repo.getDocMeta(getSessionRoomId(sessionId)))?.meta;
125486
+ if (!meta) {
125487
+ return false;
125488
+ }
125489
+ if (meta.processingUserMsgId) {
125490
+ return true;
125491
+ }
125492
+ return Boolean(meta.latestUserMsgId && meta.latestUserMsgId !== meta.lastHandledUserMsgId);
125493
+ }
125224
125494
  isArchiveInFlight(sessionId) {
125225
125495
  return this.archiveInFlight.has(sessionId);
125226
125496
  }
@@ -125577,116 +125847,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125577
125847
  }
125578
125848
  }
125579
125849
  }
125580
- function getAvailableMemoryBytes() {
125581
- const systemAvailable = getSystemAvailableMemoryBytes();
125582
- const cgroupAvailable = getCgroupAvailableMemoryBytes();
125583
- if (cgroupAvailable !== null) {
125584
- return Math.min(systemAvailable, cgroupAvailable);
125585
- }
125586
- return systemAvailable;
125587
- }
125588
- function getEffectiveMemoryLimitBytes() {
125589
- const totalMem = os__default.totalmem();
125590
- const cgroupMax = getCgroupMemoryMaxBytes();
125591
- if (cgroupMax !== null) {
125592
- return Math.min(totalMem, cgroupMax);
125593
- }
125594
- return totalMem;
125595
- }
125596
- function getSystemAvailableMemoryBytes() {
125597
- try {
125598
- const meminfo = readFileSync("/proc/meminfo", "utf8");
125599
- const match5 = meminfo.match(/MemAvailable:\s+(\d+)/);
125600
- if (match5?.[1]) {
125601
- return parseInt(match5[1], 10) * 1024;
125602
- }
125603
- } catch {
125604
- }
125605
- return os__default.freemem();
125606
- }
125607
- function getCgroupMemoryMaxBytes() {
125608
- try {
125609
- const cgroupPath = readSelfCgroupPath();
125610
- if (cgroupPath === null) return null;
125611
- let tightest = null;
125612
- let current2 = cgroupPath;
125613
- for (let depth = 0; depth < 20; depth++) {
125614
- const memMaxPath = `/sys/fs/cgroup${current2 === "/" ? "" : current2}/memory.max`;
125615
- const raw = readFileSafe(memMaxPath);
125616
- if (raw !== null) {
125617
- const trimmed = raw.trim();
125618
- if (trimmed !== "max") {
125619
- const value = parseInt(trimmed, 10);
125620
- if (Number.isFinite(value) && value > 0) {
125621
- tightest = tightest === null ? value : Math.min(tightest, value);
125622
- }
125623
- }
125624
- }
125625
- if (current2 === "/" || current2 === "") break;
125626
- const parent = current2.substring(0, current2.lastIndexOf("/")) || "/";
125627
- if (parent === current2) break;
125628
- current2 = parent;
125629
- }
125630
- return tightest;
125631
- } catch {
125632
- return null;
125633
- }
125634
- }
125635
- function getCgroupAvailableMemoryBytes() {
125636
- try {
125637
- const cgroupPath = readSelfCgroupPath();
125638
- if (cgroupPath === null) return null;
125639
- let tightestMax = null;
125640
- let tightestPath = null;
125641
- let current2 = cgroupPath;
125642
- for (let depth = 0; depth < 20; depth++) {
125643
- const prefix = `/sys/fs/cgroup${current2 === "/" ? "" : current2}`;
125644
- const raw = readFileSafe(`${prefix}/memory.max`);
125645
- if (raw !== null) {
125646
- const trimmed = raw.trim();
125647
- if (trimmed !== "max") {
125648
- const value = parseInt(trimmed, 10);
125649
- if (Number.isFinite(value) && value > 0) {
125650
- if (tightestMax === null || value < tightestMax) {
125651
- tightestMax = value;
125652
- tightestPath = prefix;
125653
- }
125654
- }
125655
- }
125656
- }
125657
- if (current2 === "/" || current2 === "") break;
125658
- const parent = current2.substring(0, current2.lastIndexOf("/")) || "/";
125659
- if (parent === current2) break;
125660
- current2 = parent;
125661
- }
125662
- if (tightestMax === null || tightestPath === null) return null;
125663
- const currentRaw = readFileSafe(`${tightestPath}/memory.current`);
125664
- if (currentRaw === null) return null;
125665
- const currentUsage = parseInt(currentRaw.trim(), 10);
125666
- if (!Number.isFinite(currentUsage)) return null;
125667
- return Math.max(0, tightestMax - currentUsage);
125668
- } catch {
125669
- return null;
125670
- }
125671
- }
125672
- function readSelfCgroupPath() {
125673
- try {
125674
- const content = readFileSync("/proc/self/cgroup", "utf8");
125675
- const line3 = content.split("\n").map((l) => l.trim()).find((l) => l.startsWith("0::"));
125676
- if (!line3) return null;
125677
- const cgroupPath = line3.slice(3).trim();
125678
- return cgroupPath || "/";
125679
- } catch {
125680
- return null;
125681
- }
125682
- }
125683
- function readFileSafe(filePath) {
125684
- try {
125685
- return readFileSync(filePath, "utf8");
125686
- } catch {
125687
- return null;
125688
- }
125689
- }
125690
125850
  function readEnvNumber(key2, fallback2) {
125691
125851
  const raw = process.env[key2];
125692
125852
  if (!raw) return fallback2;
@@ -125694,6 +125854,8 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125694
125854
  return Number.isFinite(parsed) ? parsed : fallback2;
125695
125855
  }
125696
125856
  const GIB = 1024 * 1024 * 1024;
125857
+ const WINDOWS_COMMIT_THRESHOLD_FLOOR_BYTES = 512 * 1024 * 1024;
125858
+ const WINDOWS_COMMIT_THRESHOLD_CEILING_BYTES = 2 * GIB;
125697
125859
  function defaultMemoryThresholdBytes() {
125698
125860
  const tenPercent = Math.floor(getEffectiveMemoryLimitBytes() * 0.1);
125699
125861
  return Math.max(GIB, Math.min(4 * GIB, tenPercent));
@@ -125706,6 +125868,9 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125706
125868
  memoryThresholdBytes: readEnvNumber("LODY_SESSION_GC_MEMORY_THRESHOLD_BYTES", defaultMemoryThresholdBytes())
125707
125869
  };
125708
125870
  }
125871
+ function getWindowsCommitThresholdBytes(memoryThresholdBytes) {
125872
+ return Math.max(WINDOWS_COMMIT_THRESHOLD_FLOOR_BYTES, Math.min(WINDOWS_COMMIT_THRESHOLD_CEILING_BYTES, memoryThresholdBytes));
125873
+ }
125709
125874
  class SessionGCManager {
125710
125875
  constructor(config2, deps) {
125711
125876
  this.config = config2;
@@ -125729,7 +125894,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125729
125894
  }
125730
125895
  async sweep() {
125731
125896
  const sweepStart = Date.now();
125732
- const candidates = this.getIdleCandidates();
125897
+ const candidates = await this.getIdleCandidates();
125733
125898
  if (candidates.length === 0) {
125734
125899
  return;
125735
125900
  }
@@ -125737,7 +125902,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125737
125902
  let cleaned = 0;
125738
125903
  let skipped = 0;
125739
125904
  for (const { sessionId } of candidates) {
125740
- if (!this.isStillEligibleForGC(sessionId)) {
125905
+ if (!await this.isStillEligibleForGC(sessionId)) {
125741
125906
  skipped++;
125742
125907
  continue;
125743
125908
  }
@@ -125755,19 +125920,50 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125755
125920
  this.deps.logger.debug(`[GC] Sweep completed: cleaned ${cleaned}/${candidates.length} sessions in ${sweepDuration}ms`);
125756
125921
  }
125757
125922
  async evictForMemoryPressure(excludeSessionId) {
125923
+ const thresholdBytes = this.config.memoryThresholdBytes;
125924
+ const commitThresholdBytes = getWindowsCommitThresholdBytes(thresholdBytes);
125925
+ let memorySnapshot = getMemoryPressureSnapshot();
125926
+ let availableMemory = memorySnapshot.availableMemoryBytes;
125927
+ let pressureReason = this.getPressureReason(memorySnapshot, thresholdBytes, commitThresholdBytes);
125758
125928
  if (!this.config.enabled) {
125759
- return;
125929
+ return {
125930
+ availableMemoryBytes: availableMemory,
125931
+ thresholdBytes,
125932
+ hadMemoryPressure: false,
125933
+ stillUnderPressure: false,
125934
+ evictedSessionIds: [],
125935
+ pressureReason: null,
125936
+ ...memorySnapshot.availableCommitBytes !== void 0 ? {
125937
+ availableCommitBytes: memorySnapshot.availableCommitBytes,
125938
+ commitThresholdBytes,
125939
+ commitLimitBytes: memorySnapshot.commitLimitBytes,
125940
+ committedBytes: memorySnapshot.committedBytes
125941
+ } : {}
125942
+ };
125760
125943
  }
125761
- let availableMemory = getAvailableMemoryBytes();
125762
- if (availableMemory >= this.config.memoryThresholdBytes) {
125763
- return;
125944
+ if (pressureReason === null) {
125945
+ return {
125946
+ availableMemoryBytes: availableMemory,
125947
+ thresholdBytes,
125948
+ hadMemoryPressure: false,
125949
+ stillUnderPressure: false,
125950
+ evictedSessionIds: [],
125951
+ pressureReason: null,
125952
+ ...memorySnapshot.availableCommitBytes !== void 0 ? {
125953
+ availableCommitBytes: memorySnapshot.availableCommitBytes,
125954
+ commitThresholdBytes,
125955
+ commitLimitBytes: memorySnapshot.commitLimitBytes,
125956
+ committedBytes: memorySnapshot.committedBytes
125957
+ } : {}
125958
+ };
125764
125959
  }
125765
- this.deps.logger.debug(`[GC] Memory pressure detected: ${Math.round(availableMemory / 1024 / 1024)}MB available (threshold: ${Math.round(this.config.memoryThresholdBytes / 1024 / 1024)}MB)`);
125960
+ const commitText = memorySnapshot.availableCommitBytes !== void 0 ? `, commit headroom ${Math.round(memorySnapshot.availableCommitBytes / 1024 / 1024)}MB (threshold: ${Math.round(commitThresholdBytes / 1024 / 1024)}MB)` : "";
125961
+ this.deps.logger.debug(`[GC] Memory pressure detected: ${Math.round(availableMemory / 1024 / 1024)}MB available (threshold: ${Math.round(thresholdBytes / 1024 / 1024)}MB)${commitText}`);
125766
125962
  const sessions = this.getSessionsWithIdleTime();
125767
125963
  sessions.sort((a, b) => b.idleMs - a.idleMs);
125768
- let evicted = 0;
125964
+ const evictedSessionIds = [];
125769
125965
  for (const { sessionId, idleMs } of sessions) {
125770
- if (availableMemory >= this.config.memoryThresholdBytes) {
125966
+ if (pressureReason === null) {
125771
125967
  break;
125772
125968
  }
125773
125969
  if (excludeSessionId && sessionId === excludeSessionId) {
@@ -125776,30 +125972,63 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125776
125972
  if (idleMs === 0) {
125777
125973
  continue;
125778
125974
  }
125779
- if (!this.isEligibleForCleanup(sessionId)) {
125975
+ if (!await this.isEligibleForCleanup(sessionId)) {
125780
125976
  continue;
125781
125977
  }
125782
125978
  try {
125783
125979
  this.deps.logger.debug(`[GC] Evicting session ${sessionId} (idle ${Math.round(idleMs / 1e3)}s) due to memory pressure`);
125784
125980
  await this.deps.cleanSession(sessionId);
125785
- evicted++;
125786
- availableMemory = getAvailableMemoryBytes();
125981
+ evictedSessionIds.push(sessionId);
125982
+ memorySnapshot = getMemoryPressureSnapshot();
125983
+ availableMemory = memorySnapshot.availableMemoryBytes;
125984
+ pressureReason = this.getPressureReason(memorySnapshot, thresholdBytes, commitThresholdBytes);
125787
125985
  } catch (error2) {
125788
125986
  this.deps.logger.error(`[GC] Failed to evict session ${sessionId}: ${formatErrorMessage(error2)}`);
125789
125987
  }
125790
125988
  }
125791
- if (evicted > 0) {
125792
- this.deps.logger.debug(`[GC] Memory pressure eviction complete: evicted ${evicted} sessions, available memory now ${Math.round(availableMemory / 1024 / 1024)}MB`);
125989
+ const stillUnderPressure = pressureReason !== null;
125990
+ if (evictedSessionIds.length > 0) {
125991
+ this.deps.logger.debug(`[GC] Memory pressure eviction complete: evicted ${evictedSessionIds.length} sessions, available memory now ${Math.round(availableMemory / 1024 / 1024)}MB`);
125992
+ } else if (stillUnderPressure) {
125993
+ this.deps.logger.debug("[GC] Memory pressure persists but no idle sessions were eligible for eviction");
125793
125994
  }
125995
+ return {
125996
+ availableMemoryBytes: availableMemory,
125997
+ thresholdBytes,
125998
+ hadMemoryPressure: true,
125999
+ stillUnderPressure,
126000
+ evictedSessionIds,
126001
+ pressureReason,
126002
+ ...memorySnapshot.availableCommitBytes !== void 0 ? {
126003
+ availableCommitBytes: memorySnapshot.availableCommitBytes,
126004
+ commitThresholdBytes,
126005
+ commitLimitBytes: memorySnapshot.commitLimitBytes,
126006
+ committedBytes: memorySnapshot.committedBytes
126007
+ } : {}
126008
+ };
126009
+ }
126010
+ getPressureReason(snapshot, thresholdBytes, commitThresholdBytes) {
126011
+ const physicalPressure = snapshot.availableMemoryBytes < thresholdBytes;
126012
+ const commitPressure = snapshot.availableCommitBytes !== void 0 && snapshot.availableCommitBytes < commitThresholdBytes;
126013
+ if (physicalPressure && commitPressure) {
126014
+ return "physical_and_commit";
126015
+ }
126016
+ if (physicalPressure) {
126017
+ return "physical";
126018
+ }
126019
+ if (commitPressure) {
126020
+ return "commit";
126021
+ }
126022
+ return null;
125794
126023
  }
125795
- getIdleCandidates() {
126024
+ async getIdleCandidates() {
125796
126025
  const sessions = this.getSessionsWithIdleTime();
125797
126026
  const candidates = [];
125798
126027
  for (const session of sessions) {
125799
126028
  if (session.idleMs < this.config.idleTimeoutMs) {
125800
126029
  continue;
125801
126030
  }
125802
- if (!this.isEligibleForCleanup(session.sessionId)) {
126031
+ if (!await this.isEligibleForCleanup(session.sessionId)) {
125803
126032
  continue;
125804
126033
  }
125805
126034
  candidates.push(session);
@@ -125827,20 +126056,23 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125827
126056
  }
125828
126057
  return result;
125829
126058
  }
125830
- isEligibleForCleanup(sessionId) {
126059
+ async isEligibleForCleanup(sessionId) {
125831
126060
  if (this.deps.hasActiveTurn(sessionId)) {
125832
126061
  return false;
125833
126062
  }
125834
126063
  if (this.deps.hasPendingUpdates(sessionId)) {
125835
126064
  return false;
125836
126065
  }
126066
+ if (await this.deps.hasPendingUserWork(sessionId)) {
126067
+ return false;
126068
+ }
125837
126069
  if (this.deps.isArchiveInFlight(sessionId)) {
125838
126070
  return false;
125839
126071
  }
125840
126072
  return true;
125841
126073
  }
125842
- isStillEligibleForGC(sessionId) {
125843
- if (!this.isEligibleForCleanup(sessionId)) {
126074
+ async isStillEligibleForGC(sessionId) {
126075
+ if (!await this.isEligibleForCleanup(sessionId)) {
125844
126076
  return false;
125845
126077
  }
125846
126078
  const lastActivity = this.deps.getSessionLastActivity(sessionId);
@@ -125968,6 +126200,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125968
126200
  getSessionLastActivity: (sessionId) => handler.getLastActivity(sessionId),
125969
126201
  hasActiveTurn: (sessionId) => handler.hasActiveTurn(sessionId),
125970
126202
  hasPendingUpdates: (sessionId) => handler.hasPendingUpdates(sessionId),
126203
+ hasPendingUserWork: async (sessionId) => await handler.hasPendingUserWork(sessionId),
125971
126204
  isArchiveInFlight: (sessionId) => handler.isArchiveInFlight(sessionId),
125972
126205
  cleanSession: (sessionId) => handler.cleanSessionForGC(sessionId),
125973
126206
  getSessionIds: () => handler.getTrackedSessionIds(),
@@ -125976,8 +126209,16 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
125976
126209
  this.gcManager.start();
125977
126210
  handler.setEvictForMemoryPressure(async (excludeSessionId) => {
125978
126211
  if (this.gcManager) {
125979
- await this.gcManager.evictForMemoryPressure(excludeSessionId);
126212
+ return await this.gcManager.evictForMemoryPressure(excludeSessionId);
125980
126213
  }
126214
+ return {
126215
+ availableMemoryBytes: 0,
126216
+ thresholdBytes: 0,
126217
+ hadMemoryPressure: false,
126218
+ stillUnderPressure: false,
126219
+ evictedSessionIds: [],
126220
+ pressureReason: null
126221
+ };
125981
126222
  });
125982
126223
  }
125983
126224
  requireSessionManager() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lody",
3
- "version": "0.44.3-next.1",
3
+ "version": "0.44.4-next.1",
4
4
  "description": "Lody Agent CLI tool for managing remote command execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -72,11 +72,11 @@
72
72
  "winston-transport": "^4.7.1",
73
73
  "ws": "^8.18.3",
74
74
  "zod": "^4.1.5",
75
- "@lody/cli-supervisor": "0.0.1",
76
75
  "@lody/convex": "0.0.1",
77
- "@lody/loro-streams-rpc": "0.0.1",
78
76
  "@lody/shared": "0.0.1",
79
- "loro-code": "0.0.1"
77
+ "loro-code": "0.0.1",
78
+ "@lody/cli-supervisor": "0.0.1",
79
+ "@lody/loro-streams-rpc": "0.0.1"
80
80
  },
81
81
  "files": [
82
82
  "dist",