@letta-ai/letta-code 0.24.8 → 0.24.9

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/letta.js +326 -156
  2. package/package.json +1 -1
package/letta.js CHANGED
@@ -3269,7 +3269,7 @@ var package_default;
3269
3269
  var init_package = __esm(() => {
3270
3270
  package_default = {
3271
3271
  name: "@letta-ai/letta-code",
3272
- version: "0.24.8",
3272
+ version: "0.24.9",
3273
3273
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3274
3274
  type: "module",
3275
3275
  bin: {
@@ -9488,46 +9488,6 @@ var init_models2 = __esm(() => {
9488
9488
  parallel_tool_calls: true
9489
9489
  }
9490
9490
  },
9491
- {
9492
- id: "gpt-5.5-pro-medium",
9493
- handle: "openai/gpt-5.5-pro",
9494
- label: "GPT-5.5 Pro",
9495
- description: "GPT-5.5 Pro — max performance variant (med reasoning)",
9496
- updateArgs: {
9497
- reasoning_effort: "medium",
9498
- verbosity: "medium",
9499
- context_window: 272000,
9500
- max_output_tokens: 128000,
9501
- parallel_tool_calls: true
9502
- }
9503
- },
9504
- {
9505
- id: "gpt-5.5-pro-high",
9506
- handle: "openai/gpt-5.5-pro",
9507
- label: "GPT-5.5 Pro",
9508
- description: "GPT-5.5 Pro — max performance variant (high reasoning)",
9509
- updateArgs: {
9510
- reasoning_effort: "high",
9511
- verbosity: "medium",
9512
- context_window: 272000,
9513
- max_output_tokens: 128000,
9514
- parallel_tool_calls: true
9515
- },
9516
- isFeatured: true
9517
- },
9518
- {
9519
- id: "gpt-5.5-pro-xhigh",
9520
- handle: "openai/gpt-5.5-pro",
9521
- label: "GPT-5.5 Pro",
9522
- description: "GPT-5.5 Pro — max performance variant (max reasoning)",
9523
- updateArgs: {
9524
- reasoning_effort: "xhigh",
9525
- verbosity: "medium",
9526
- context_window: 272000,
9527
- max_output_tokens: 128000,
9528
- parallel_tool_calls: true
9529
- }
9530
- },
9531
9491
  {
9532
9492
  id: "gpt-5.4-pro-medium",
9533
9493
  handle: "openai/gpt-5.4-pro",
@@ -40145,12 +40105,14 @@ var init_config = __esm(() => {
40145
40105
  };
40146
40106
  discordConfigCodec = {
40147
40107
  parse(parsed) {
40108
+ const rawAllowedChannels = parsed.allowed_channels;
40148
40109
  return {
40149
40110
  channel: "discord",
40150
40111
  enabled: parsed.enabled !== false,
40151
40112
  token: String(parsed.token ?? ""),
40152
40113
  dmPolicy: parsed.dm_policy ?? "pairing",
40153
- allowedUsers: parsed.allowed_users ?? []
40114
+ allowedUsers: parsed.allowed_users ?? [],
40115
+ allowedChannels: Array.isArray(rawAllowedChannels) ? rawAllowedChannels : undefined
40154
40116
  };
40155
40117
  }
40156
40118
  };
@@ -40183,6 +40145,11 @@ function cloneAccount(account) {
40183
40145
  if (account.channel === "telegram") {
40184
40146
  cloned.binding = { ...account.binding };
40185
40147
  }
40148
+ if (account.channel === "discord" && account.allowedChannels) {
40149
+ cloned.allowedChannels = [
40150
+ ...account.allowedChannels
40151
+ ];
40152
+ }
40186
40153
  return cloned;
40187
40154
  }
40188
40155
  function normalizeLoadedAccount(account) {
@@ -40226,6 +40193,7 @@ function makeDefaultLegacyAccount(channelId) {
40226
40193
  token: config.token,
40227
40194
  dmPolicy: config.dmPolicy,
40228
40195
  allowedUsers: [...config.allowedUsers],
40196
+ allowedChannels: config.allowedChannels ? [...config.allowedChannels] : undefined,
40229
40197
  agentId: null,
40230
40198
  createdAt: now,
40231
40199
  updatedAt: now
@@ -44112,6 +44080,16 @@ var init_plugin2 = __esm(() => {
44112
44080
  };
44113
44081
  });
44114
44082
 
44083
+ // src/channels/discord/channelGating.ts
44084
+ function isDiscordGuildChannelAllowed(params) {
44085
+ const { channelId, parentChannelId, isThread, allowedChannels } = params;
44086
+ if (!allowedChannels || allowedChannels.length === 0) {
44087
+ return true;
44088
+ }
44089
+ const gateChannelId = isThread ? parentChannelId ?? channelId : channelId;
44090
+ return allowedChannels.includes(gateChannelId);
44091
+ }
44092
+
44115
44093
  // src/channels/discord/media.ts
44116
44094
  import { randomUUID as randomUUID6 } from "node:crypto";
44117
44095
  import { mkdirSync as mkdirSync11 } from "node:fs";
@@ -44594,6 +44572,13 @@ function createDiscordAdapter(config) {
44594
44572
  }
44595
44573
  if (!isThread && !wasMentioned)
44596
44574
  return;
44575
+ if (!isDiscordGuildChannelAllowed({
44576
+ channelId: message.channelId,
44577
+ parentChannelId: message.channel.parentId ?? null,
44578
+ isThread,
44579
+ allowedChannels: config.allowedChannels
44580
+ }))
44581
+ return;
44597
44582
  if (markIngressMessageSeen(message.channelId, message.id))
44598
44583
  return;
44599
44584
  let effectiveChatId = message.channelId;
@@ -44657,6 +44642,13 @@ function createDiscordAdapter(config) {
44657
44642
  const isThread = msg.channel && "isThread" in msg.channel && typeof msg.channel.isThread === "function" && msg.channel.isThread();
44658
44643
  if (chatType === "channel" && !isThread)
44659
44644
  return;
44645
+ if (chatType === "channel" && isThread && !isDiscordGuildChannelAllowed({
44646
+ channelId,
44647
+ parentChannelId: msg.channel.parentId ?? null,
44648
+ isThread: true,
44649
+ allowedChannels: config.allowedChannels
44650
+ }))
44651
+ return;
44660
44652
  const inbound = {
44661
44653
  channel: "discord",
44662
44654
  accountId: config.accountId,
@@ -44973,12 +44965,12 @@ Bind to agent ${envAgentId}? [Y/n]: `);
44973
44965
  }
44974
44966
  if (!agentId) {
44975
44967
  const agentInput = await rl.question(`
44976
- Agent ID to bind this bot to (required for @mention routing): `);
44968
+ Agent ID to bind this bot to (required for DM and @mention routing): `);
44977
44969
  agentId = agentInput.trim() || null;
44978
44970
  }
44979
44971
  if (!agentId) {
44980
44972
  console.log(`
44981
- Warning: No agent bound. DM pairing will still work, but guild @mentions won't route until you bind an agent.`);
44973
+ Warning: No agent bound. DM pairing will still work, but open/allowlist DMs and guild @mentions won't route until you bind an agent.`);
44982
44974
  console.log(" You can bind later: letta channels bind --channel discord --agent <id>");
44983
44975
  console.log(` Or set agentId in ~/.letta/channels/discord/accounts.json
44984
44976
  `);
@@ -45829,6 +45821,17 @@ function buildSlackConversationSummary(msg) {
45829
45821
  }
45830
45822
  return `[Slack] Thread${channelLabel || ` ${msg.chatId}`}`;
45831
45823
  }
45824
+ function buildDiscordConversationSummary(msg) {
45825
+ if (msg.chatType === "direct") {
45826
+ return `[Discord] DM with ${msg.senderName?.trim() || msg.senderId}`;
45827
+ }
45828
+ const preview = truncateChannelSummaryPreview(msg.text);
45829
+ const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
45830
+ if (preview) {
45831
+ return `[Discord] Thread${channelLabel}: ${preview}`;
45832
+ }
45833
+ return `[Discord] Thread${channelLabel || ` ${msg.chatId}`}`;
45834
+ }
45832
45835
  function buildChannelTurnSource(route, msg) {
45833
45836
  return {
45834
45837
  channel: msg.channel,
@@ -46212,7 +46215,7 @@ class ChannelRegistry {
46212
46215
  });
46213
46216
  return;
46214
46217
  }
46215
- if (msg.channel === "discord" && config.channel === "discord" && msg.chatType === "channel") {
46218
+ if (msg.channel === "discord" && config.channel === "discord" && (msg.chatType === "channel" || config.dmPolicy !== "pairing")) {
46216
46219
  const discordResult = await this.ensureDiscordRoute(adapter, msg, config);
46217
46220
  if (!discordResult) {
46218
46221
  return;
@@ -46361,7 +46364,7 @@ class ChannelRegistry {
46361
46364
  if (!config.agentId) {
46362
46365
  throw new Error("Discord bot is missing an agent binding.");
46363
46366
  }
46364
- const conversationId = await this.createConversationForAgent(config.agentId, `[Discord] Thread ${msg.chatLabel ?? msg.chatId}`);
46367
+ const conversationId = await this.createConversationForAgent(config.agentId, buildDiscordConversationSummary(msg));
46365
46368
  const now = new Date().toISOString();
46366
46369
  const route = {
46367
46370
  accountId: config.accountId,
@@ -46384,6 +46387,10 @@ class ChannelRegistry {
46384
46387
  ` + "Open Channels > Discord in Letta Code, choose which agent this bot should represent, and try again.");
46385
46388
  return null;
46386
46389
  }
46390
+ if (msg.chatType === "direct" && config.dmPolicy === "allowlist" && !config.allowedUsers.includes(msg.senderId)) {
46391
+ await adapter.sendDirectReply(msg.chatId, "You are not on the allowed users list for this Discord bot.");
46392
+ return null;
46393
+ }
46387
46394
  const accountId = msg.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID;
46388
46395
  const routeThreadId = msg.threadId ?? null;
46389
46396
  let route = getRoute(msg.channel, msg.chatId, accountId, routeThreadId);
@@ -46394,7 +46401,7 @@ class ChannelRegistry {
46394
46401
  if (route) {
46395
46402
  return { route, isFirstRouteTurn: false };
46396
46403
  }
46397
- if (!msg.isMention) {
46404
+ if (msg.chatType === "channel" && !msg.isMention) {
46398
46405
  return null;
46399
46406
  }
46400
46407
  return {
@@ -79479,6 +79486,7 @@ function toAccountSnapshot(account) {
79479
79486
  running,
79480
79487
  dmPolicy: account.dmPolicy,
79481
79488
  allowedUsers: [...account.allowedUsers],
79489
+ allowedChannels: [...account.allowedChannels ?? []],
79482
79490
  hasToken: account.token.trim().length > 0,
79483
79491
  agentId: account.agentId,
79484
79492
  createdAt: account.createdAt,
@@ -79533,6 +79541,7 @@ function createAccountFromPatch(channelId, accountId, patch) {
79533
79541
  agentId: patch.agentId ?? null,
79534
79542
  dmPolicy: patch.dmPolicy ?? "pairing",
79535
79543
  allowedUsers: patch.allowedUsers ?? [],
79544
+ allowedChannels: patch.allowedChannels ?? [],
79536
79545
  createdAt: now,
79537
79546
  updatedAt: now
79538
79547
  };
@@ -79576,6 +79585,7 @@ function mergeAccountPatch(existing, patch) {
79576
79585
  agentId: patch.agentId ?? existing.agentId,
79577
79586
  dmPolicy: patch.dmPolicy ?? existing.dmPolicy,
79578
79587
  allowedUsers: patch.allowedUsers ?? existing.allowedUsers,
79588
+ allowedChannels: patch.allowedChannels ?? existing.allowedChannels,
79579
79589
  updatedAt: nextUpdatedAt
79580
79590
  };
79581
79591
  }
@@ -79654,6 +79664,7 @@ function getChannelConfigSnapshot(channelId, accountId) {
79654
79664
  enabled: account.enabled,
79655
79665
  dmPolicy: account.dmPolicy,
79656
79666
  allowedUsers: [...account.allowedUsers],
79667
+ allowedChannels: [...account.allowedChannels ?? []],
79657
79668
  hasToken: account.token.trim().length > 0
79658
79669
  };
79659
79670
  }
@@ -79683,6 +79694,7 @@ async function setChannelConfigLive(channelId, patch, accountId) {
79683
79694
  mode: patch.mode,
79684
79695
  dmPolicy: patch.dmPolicy,
79685
79696
  allowedUsers: patch.allowedUsers,
79697
+ allowedChannels: patch.allowedChannels,
79686
79698
  displayName: existing.displayName
79687
79699
  });
79688
79700
  shouldRefreshDisplayName = channelId === "telegram" || channelId === "discord" ? patch.token !== undefined : patch.botToken !== undefined || patch.appToken !== undefined;
@@ -79694,7 +79706,8 @@ async function setChannelConfigLive(channelId, patch, accountId) {
79694
79706
  appToken: patch.appToken,
79695
79707
  mode: patch.mode,
79696
79708
  dmPolicy: patch.dmPolicy,
79697
- allowedUsers: patch.allowedUsers
79709
+ allowedUsers: patch.allowedUsers,
79710
+ allowedChannels: patch.allowedChannels
79698
79711
  }, accountId ? { accountId } : undefined);
79699
79712
  targetAccountId = created.accountId;
79700
79713
  shouldRefreshDisplayName = true;
@@ -89192,8 +89205,29 @@ var init_cwd = __esm(() => {
89192
89205
  init_remote_settings();
89193
89206
  });
89194
89207
 
89195
- // src/websocket/listener/approval.ts
89208
+ // src/websocket/listener/transport.ts
89196
89209
  import WebSocket from "ws";
89210
+
89211
+ class LocalListenerTransport {
89212
+ kind = "local";
89213
+ bufferedAmount = 0;
89214
+ isOpen() {
89215
+ return true;
89216
+ }
89217
+ send(_data) {}
89218
+ }
89219
+ function isListenerTransportOpen(transport) {
89220
+ if ("isOpen" in transport && typeof transport.isOpen === "function") {
89221
+ return transport.isOpen();
89222
+ }
89223
+ return transport.readyState === WebSocket.OPEN;
89224
+ }
89225
+ function getListenerTransportKind(transport) {
89226
+ return "kind" in transport ? transport.kind : "websocket";
89227
+ }
89228
+ var init_transport = () => {};
89229
+
89230
+ // src/websocket/listener/approval.ts
89197
89231
  function rememberPendingApprovalBatchIds(runtime, pendingApprovals, batchId) {
89198
89232
  for (const approval of pendingApprovals) {
89199
89233
  if (approval.toolCallId) {
@@ -89327,7 +89361,7 @@ function rejectPendingApprovalResolvers(runtime, reason) {
89327
89361
  evictConversationRuntimeIfIdle(runtime);
89328
89362
  }
89329
89363
  function requestApprovalOverWS(runtime, socket, requestId, controlRequest) {
89330
- if (socket.readyState !== WebSocket.OPEN) {
89364
+ if (!isListenerTransportOpen(socket)) {
89331
89365
  return Promise.reject(new Error("WebSocket not open"));
89332
89366
  }
89333
89367
  const abortSignal = runtime.activeAbortController?.signal ?? null;
@@ -89390,6 +89424,7 @@ function requestApprovalOverWS(runtime, socket, requestId, controlRequest) {
89390
89424
  }
89391
89425
  var init_approval = __esm(async () => {
89392
89426
  init_runtime4();
89427
+ init_transport();
89393
89428
  await init_protocol_outbound();
89394
89429
  });
89395
89430
 
@@ -93226,7 +93261,6 @@ var init_diffPreview = __esm(() => {
93226
93261
 
93227
93262
  // src/websocket/listener/turn-approval.ts
93228
93263
  import { readFile as readFile12 } from "node:fs/promises";
93229
- import WebSocket2 from "ws";
93230
93264
  function getChannelApprovalSourceScopeKey(source) {
93231
93265
  return [
93232
93266
  source.channel,
@@ -93512,7 +93546,7 @@ async function handleApprovalStop(params) {
93512
93546
  return interruptTermination();
93513
93547
  }
93514
93548
  const onFileWrite = (filePath, content) => {
93515
- if (socket.readyState === WebSocket2.OPEN) {
93549
+ if (isListenerTransportOpen(socket)) {
93516
93550
  socket.send(JSON.stringify({
93517
93551
  type: "file_ops",
93518
93552
  path: filePath,
@@ -93639,6 +93673,7 @@ var init_turn_approval = __esm(async () => {
93639
93673
  init_formatDenial();
93640
93674
  init_interactivePolicy();
93641
93675
  init_skill_injection();
93676
+ init_transport();
93642
93677
  await __promiseAll([
93643
93678
  init_approval_execution(),
93644
93679
  init_approval(),
@@ -94720,7 +94755,6 @@ var init_commands = __esm(async () => {
94720
94755
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync22 } from "node:fs";
94721
94756
  import { dirname as dirname16 } from "node:path";
94722
94757
  import { performance as performance2 } from "node:perf_hooks";
94723
- import WebSocket3 from "ws";
94724
94758
  function getProtocolPerfKey(message) {
94725
94759
  if (message.type === "stream_delta" && "delta" in message) {
94726
94760
  const delta = message.delta;
@@ -94942,10 +94976,11 @@ function buildDeviceStatus(runtime, params) {
94942
94976
  }
94943
94977
  })();
94944
94978
  const systemPromptDoctorState = scopedAgentId ? getSystemPromptDoctorState(scopedAgentId) : null;
94979
+ const transport = listener.transport ?? listener.socket;
94945
94980
  return {
94946
94981
  current_connection_id: listener.connectionId,
94947
94982
  connection_name: listener.connectionName,
94948
- is_online: listener.socket?.readyState === WebSocket3.OPEN,
94983
+ is_online: transport ? isListenerTransportOpen(transport) : false,
94949
94984
  is_processing: !!conversationRuntime?.isProcessing,
94950
94985
  current_permission_mode: conversationPermissionModeState.mode,
94951
94986
  current_working_directory: resolvedCwd,
@@ -95015,7 +95050,7 @@ function setLoopStatus(runtime, status, scope) {
95015
95050
  emitLoopStatusIfOpen(runtime, scope);
95016
95051
  }
95017
95052
  function emitProtocolV2Message(socket, runtime, message, scope) {
95018
- if (socket.readyState !== WebSocket3.OPEN) {
95053
+ if (!isListenerTransportOpen(socket)) {
95019
95054
  return;
95020
95055
  }
95021
95056
  const listener = getListenerRuntime(runtime);
@@ -95083,14 +95118,16 @@ function emitLoopStatusUpdate(socket, runtime, scope) {
95083
95118
  }
95084
95119
  function emitLoopStatusIfOpen(runtime, scope) {
95085
95120
  const listener = getListenerRuntime(runtime);
95086
- if (listener?.socket?.readyState === WebSocket3.OPEN) {
95087
- emitLoopStatusUpdate(listener.socket, runtime, scope);
95121
+ const transport = listener?.transport ?? listener?.socket;
95122
+ if (transport && isListenerTransportOpen(transport)) {
95123
+ emitLoopStatusUpdate(transport, runtime, scope);
95088
95124
  }
95089
95125
  }
95090
95126
  function emitDeviceStatusIfOpen(runtime, scope) {
95091
95127
  const listener = getListenerRuntime(runtime);
95092
- if (listener?.socket?.readyState === WebSocket3.OPEN) {
95093
- emitDeviceStatusUpdate(listener.socket, runtime, scope);
95128
+ const transport = listener?.transport ?? listener?.socket;
95129
+ if (transport && isListenerTransportOpen(transport)) {
95130
+ emitDeviceStatusUpdate(transport, runtime, scope);
95094
95131
  }
95095
95132
  }
95096
95133
  function emitQueueUpdate(socket, runtime, scope) {
@@ -95148,8 +95185,9 @@ function emitDequeuedUserMessage(socket, runtime, incoming, batch) {
95148
95185
  }
95149
95186
  function emitQueueUpdateIfOpen(runtime, scope) {
95150
95187
  const listener = getListenerRuntime(runtime);
95151
- if (listener?.socket?.readyState === WebSocket3.OPEN) {
95152
- emitQueueUpdate(listener.socket, runtime, scope);
95188
+ const transport = listener?.transport ?? listener?.socket;
95189
+ if (transport && isListenerTransportOpen(transport)) {
95190
+ emitQueueUpdate(transport, runtime, scope);
95153
95191
  }
95154
95192
  }
95155
95193
  function emitStateSync(socket, runtime, scope) {
@@ -95204,8 +95242,9 @@ function emitSubagentStateUpdate(socket, runtime, scope) {
95204
95242
  }
95205
95243
  function emitSubagentStateIfOpen(runtime, scope) {
95206
95244
  const listener = getListenerRuntime(runtime);
95207
- if (listener?.socket?.readyState === WebSocket3.OPEN) {
95208
- emitSubagentStateUpdate(listener.socket, runtime, scope);
95245
+ const transport = listener?.transport ?? listener?.socket;
95246
+ if (transport && isListenerTransportOpen(transport)) {
95247
+ emitSubagentStateUpdate(transport, runtime, scope);
95209
95248
  }
95210
95249
  }
95211
95250
  function scheduleQueueEmit(runtime, scope) {
@@ -95301,6 +95340,7 @@ var init_protocol_outbound = __esm(async () => {
95301
95340
  init_cwd();
95302
95341
  init_permissionMode();
95303
95342
  init_runtime4();
95343
+ init_transport();
95304
95344
  await init_commands();
95305
95345
  PROTOCOL_PERF_ENV_VALUES = new Set(["1", "true", "yes"]);
95306
95346
  PROTOCOL_PERF_ENABLED = PROTOCOL_PERF_ENV_VALUES.has((process.env.LETTA_LISTENER_PERF ?? "").toLowerCase());
@@ -95873,7 +95913,7 @@ var init_toolset_labels = __esm(() => {
95873
95913
 
95874
95914
  // src/websocket/terminalHandler.ts
95875
95915
  import * as os4 from "node:os";
95876
- import WebSocket4 from "ws";
95916
+ import WebSocket2 from "ws";
95877
95917
  function getDefaultShell() {
95878
95918
  if (os4.platform() === "win32") {
95879
95919
  return process.env.COMSPEC || "cmd.exe";
@@ -95881,7 +95921,7 @@ function getDefaultShell() {
95881
95921
  return process.env.SHELL || "/bin/zsh";
95882
95922
  }
95883
95923
  function sendTerminalMessage(socket, message) {
95884
- if (socket.readyState === WebSocket4.OPEN) {
95924
+ if (socket.readyState === WebSocket2.OPEN) {
95885
95925
  socket.send(JSON.stringify(message));
95886
95926
  }
95887
95927
  }
@@ -96596,9 +96636,10 @@ function isChannelId(value) {
96596
96636
  function hasValidChannelPolicyFields(config) {
96597
96637
  const hasValidDmPolicy = config.dm_policy === undefined || config.dm_policy === "pairing" || config.dm_policy === "allowlist" || config.dm_policy === "open";
96598
96638
  const hasValidAllowedUsers = config.allowed_users === undefined || Array.isArray(config.allowed_users) && config.allowed_users.every((entry) => typeof entry === "string");
96639
+ const hasValidAllowedChannels = config.allowed_channels === undefined || Array.isArray(config.allowed_channels) && config.allowed_channels.every((entry) => typeof entry === "string");
96599
96640
  const hasValidDisplayName = config.display_name === undefined || typeof config.display_name === "string";
96600
96641
  const hasValidEnabled = config.enabled === undefined || typeof config.enabled === "boolean";
96601
- return hasValidDmPolicy && hasValidAllowedUsers && hasValidDisplayName && hasValidEnabled;
96642
+ return hasValidDmPolicy && hasValidAllowedUsers && hasValidAllowedChannels && hasValidDisplayName && hasValidEnabled;
96602
96643
  }
96603
96644
  function isChannelsListCommand(value) {
96604
96645
  if (!value || typeof value !== "object")
@@ -97025,7 +97066,7 @@ import { execFile as execFile13 } from "node:child_process";
97025
97066
  import { lstat as lstat2, realpath as realpath3, stat as stat6 } from "node:fs/promises";
97026
97067
  import path25 from "node:path";
97027
97068
  import { promisify as promisify11 } from "node:util";
97028
- import WebSocket5 from "ws";
97069
+ import WebSocket3 from "ws";
97029
97070
  async function isGitWorktreeRoot(dir) {
97030
97071
  try {
97031
97072
  const stats = await lstat2(path25.join(dir, ".git"));
@@ -97048,7 +97089,7 @@ function trackListenerError(errorType, error, context3) {
97048
97089
  });
97049
97090
  }
97050
97091
  function safeSocketSend(socket, payload, errorType, context3) {
97051
- if (socket.readyState !== WebSocket5.OPEN) {
97092
+ if (socket.readyState !== WebSocket3.OPEN) {
97052
97093
  return false;
97053
97094
  }
97054
97095
  try {
@@ -97063,6 +97104,22 @@ function safeSocketSend(socket, payload, errorType, context3) {
97063
97104
  return false;
97064
97105
  }
97065
97106
  }
97107
+ function safeTransportSend(transport, payload, errorType, context3) {
97108
+ if (!isListenerTransportOpen(transport)) {
97109
+ return false;
97110
+ }
97111
+ try {
97112
+ const serialized = typeof payload === "string" ? payload : JSON.stringify(payload);
97113
+ transport.send(serialized);
97114
+ return true;
97115
+ } catch (error) {
97116
+ trackListenerError(errorType, error, context3);
97117
+ if (isDebugEnabled()) {
97118
+ console.error(`[Listen] ${context3} send failed:`, error);
97119
+ }
97120
+ return false;
97121
+ }
97122
+ }
97066
97123
  function runDetachedListenerTask(commandName, task2) {
97067
97124
  task2().catch((error) => {
97068
97125
  trackListenerError(`listener_${commandName}_failed`, error, `listener_${commandName}`);
@@ -97844,6 +97901,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
97844
97901
  enabled: snapshot.enabled,
97845
97902
  dm_policy: snapshot.dmPolicy,
97846
97903
  allowed_users: snapshot.allowedUsers,
97904
+ allowed_channels: snapshot.allowedChannels,
97847
97905
  has_token: snapshot.hasToken
97848
97906
  };
97849
97907
  }
@@ -97889,6 +97947,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
97889
97947
  running: snapshot.running,
97890
97948
  dm_policy: snapshot.dmPolicy,
97891
97949
  allowed_users: snapshot.allowedUsers,
97950
+ allowed_channels: snapshot.allowedChannels,
97892
97951
  has_token: snapshot.hasToken,
97893
97952
  agent_id: snapshot.agentId,
97894
97953
  created_at: snapshot.createdAt,
@@ -98004,7 +98063,8 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
98004
98063
  agentId: "agent_id" in parsed.account ? parsed.account.agent_id : undefined,
98005
98064
  defaultPermissionMode: "default_permission_mode" in parsed.account ? parsed.account.default_permission_mode : undefined,
98006
98065
  dmPolicy: parsed.account.dm_policy,
98007
- allowedUsers: parsed.account.allowed_users
98066
+ allowedUsers: parsed.account.allowed_users,
98067
+ allowedChannels: "allowed_channels" in parsed.account ? parsed.account.allowed_channels : undefined
98008
98068
  }, {
98009
98069
  accountId: "account_id" in parsed.account ? parsed.account.account_id : undefined
98010
98070
  });
@@ -98045,7 +98105,8 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
98045
98105
  agentId: "agent_id" in parsed.patch ? parsed.patch.agent_id : undefined,
98046
98106
  defaultPermissionMode: "default_permission_mode" in parsed.patch ? parsed.patch.default_permission_mode : undefined,
98047
98107
  dmPolicy: parsed.patch.dm_policy,
98048
- allowedUsers: parsed.patch.allowed_users
98108
+ allowedUsers: parsed.patch.allowed_users,
98109
+ allowedChannels: "allowed_channels" in parsed.patch ? parsed.patch.allowed_channels : undefined
98049
98110
  });
98050
98111
  const shouldRefreshDisplayName = !("display_name" in parsed.patch) && (parsed.channel_id === "telegram" ? "token" in parsed.patch : ("bot_token" in parsed.patch) || ("app_token" in parsed.patch));
98051
98112
  const account = shouldRefreshDisplayName ? await refreshChannelAccountDisplayNameLive2(parsed.channel_id, parsed.account_id, { force: true }) : updated;
@@ -98245,7 +98306,8 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
98245
98306
  appToken: "app_token" in parsed.config ? parsed.config.app_token : undefined,
98246
98307
  mode: "mode" in parsed.config ? parsed.config.mode : undefined,
98247
98308
  dmPolicy: parsed.config.dm_policy,
98248
- allowedUsers: parsed.config.allowed_users
98309
+ allowedUsers: parsed.config.allowed_users,
98310
+ allowedChannels: "allowed_channels" in parsed.config ? parsed.config.allowed_channels : undefined
98249
98311
  }, parsed.account_id);
98250
98312
  if (snapshot.enabled) {
98251
98313
  await wireChannelIngress(runtime, socket, opts, processQueuedTurn);
@@ -98833,13 +98895,17 @@ async function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
98833
98895
  }
98834
98896
  function handleChannelRegistryEvent(event, socket, runtime) {
98835
98897
  if (event.type === "pairings_updated") {
98836
- emitChannelPairingsUpdated(socket, event.channelId);
98837
- emitChannelsUpdated(socket, event.channelId);
98898
+ if (socket instanceof WebSocket3) {
98899
+ emitChannelPairingsUpdated(socket, event.channelId);
98900
+ emitChannelsUpdated(socket, event.channelId);
98901
+ }
98838
98902
  return;
98839
98903
  }
98840
98904
  if (event.type === "targets_updated") {
98841
- emitChannelTargetsUpdated(socket, event.channelId);
98842
- emitChannelsUpdated(socket, event.channelId);
98905
+ if (socket instanceof WebSocket3) {
98906
+ emitChannelTargetsUpdated(socket, event.channelId);
98907
+ emitChannelsUpdated(socket, event.channelId);
98908
+ }
98843
98909
  return;
98844
98910
  }
98845
98911
  const permissionModeState = getOrCreateConversationPermissionModeStateRef(runtime, event.agentId, event.conversationId);
@@ -99184,6 +99250,7 @@ function createRuntime() {
99184
99250
  const bootWorkingDirectory = getCurrentWorkingDirectory();
99185
99251
  return {
99186
99252
  socket: null,
99253
+ transport: null,
99187
99254
  heartbeatInterval: null,
99188
99255
  reconnectTimeout: null,
99189
99256
  intentionallyClosed: false,
@@ -99232,17 +99299,100 @@ function stopRuntime(runtime, suppressCallbacks) {
99232
99299
  runtime.queuedSystemPromptRecompileByConversation.clear();
99233
99300
  stopAllWorktreeWatchers(runtime);
99234
99301
  if (!runtime.socket) {
99302
+ runtime.transport = null;
99235
99303
  return;
99236
99304
  }
99237
99305
  const socket = runtime.socket;
99238
99306
  runtime.socket = null;
99307
+ runtime.transport = null;
99239
99308
  if (suppressCallbacks) {
99240
99309
  socket.removeAllListeners();
99241
99310
  }
99242
- if (socket.readyState === WebSocket5.OPEN || socket.readyState === WebSocket5.CONNECTING) {
99311
+ if (socket.readyState === WebSocket3.OPEN || socket.readyState === WebSocket3.CONNECTING) {
99243
99312
  socket.close();
99244
99313
  }
99245
99314
  }
99315
+ async function startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, options = {}) {
99316
+ if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
99317
+ return;
99318
+ }
99319
+ const shouldStartHeartbeat = options.startHeartbeat !== false;
99320
+ const shouldStartCronScheduler = options.startCronScheduler !== false;
99321
+ runtime.transport = transport;
99322
+ safeEmitWsEvent("recv", "lifecycle", {
99323
+ type: getListenerTransportKind(transport) === "websocket" ? "_ws_open" : "_local_open"
99324
+ });
99325
+ runtime.hasSuccessfulConnection = true;
99326
+ runtime.everConnected = true;
99327
+ opts.onConnected(opts.connectionId);
99328
+ if (runtime.conversationRuntimes.size === 0) {
99329
+ emitLoopStatusUpdate(transport, runtime);
99330
+ } else {
99331
+ for (const reminderState of runtime.reminderStateByConversation.values()) {
99332
+ resetSharedReminderState(reminderState);
99333
+ }
99334
+ for (const contextTracker of runtime.contextTrackerByConversation.values()) {
99335
+ resetContextHistory(contextTracker);
99336
+ }
99337
+ for (const conversationRuntime of runtime.conversationRuntimes.values()) {
99338
+ const scope = {
99339
+ agent_id: conversationRuntime.agentId,
99340
+ conversation_id: conversationRuntime.conversationId
99341
+ };
99342
+ emitDeviceStatusUpdate(transport, conversationRuntime, scope);
99343
+ emitLoopStatusUpdate(transport, conversationRuntime, scope);
99344
+ }
99345
+ }
99346
+ runtime._unsubscribeSubagentState?.();
99347
+ runtime._unsubscribeSubagentState = subscribe2(() => {
99348
+ if (runtime.conversationRuntimes.size === 0) {
99349
+ emitSubagentStateIfOpen(runtime);
99350
+ return;
99351
+ }
99352
+ for (const conversationRuntime of runtime.conversationRuntimes.values()) {
99353
+ emitSubagentStateIfOpen(runtime, {
99354
+ agent_id: conversationRuntime.agentId,
99355
+ conversation_id: conversationRuntime.conversationId
99356
+ });
99357
+ }
99358
+ });
99359
+ runtime._unsubscribeSubagentStreamEvents?.();
99360
+ runtime._unsubscribeSubagentStreamEvents = subscribeToStreamEvents((subagentId, event) => {
99361
+ if (!isListenerTransportOpen(transport))
99362
+ return;
99363
+ const subagent = getSubagents().find((entry) => entry.id === subagentId);
99364
+ if (subagent?.silent === true) {
99365
+ return;
99366
+ }
99367
+ emitStreamDelta(transport, runtime, event, subagent?.parentAgentId ? {
99368
+ agent_id: subagent.parentAgentId,
99369
+ conversation_id: subagent.parentConversationId ?? "default"
99370
+ } : undefined, subagentId);
99371
+ });
99372
+ setMessageQueueAdder((queuedMessage) => {
99373
+ const targetRuntime = queuedMessage.agentId && queuedMessage.conversationId ? getOrCreateScopedRuntime(runtime, queuedMessage.agentId, queuedMessage.conversationId) : findFallbackRuntime(runtime);
99374
+ if (!targetRuntime?.queueRuntime) {
99375
+ return;
99376
+ }
99377
+ targetRuntime.queueRuntime.enqueue({
99378
+ kind: "task_notification",
99379
+ source: "task_notification",
99380
+ text: queuedMessage.text,
99381
+ agentId: queuedMessage.agentId ?? targetRuntime.agentId ?? undefined,
99382
+ conversationId: queuedMessage.conversationId ?? targetRuntime.conversationId
99383
+ });
99384
+ scheduleQueuePump(targetRuntime, transport, opts, processQueuedTurn);
99385
+ });
99386
+ if (shouldStartHeartbeat) {
99387
+ runtime.heartbeatInterval = setInterval(() => {
99388
+ safeTransportSend(transport, { type: "ping" }, "listener_ping_send_failed", "listener_heartbeat");
99389
+ }, 30000);
99390
+ }
99391
+ if (shouldStartCronScheduler) {
99392
+ startScheduler(transport, opts, processQueuedTurn);
99393
+ }
99394
+ await wireChannelIngress(runtime, transport, opts, processQueuedTurn);
99395
+ }
99246
99396
  async function startListenerClient(opts) {
99247
99397
  const existingRuntime = getActiveRuntime();
99248
99398
  if (existingRuntime) {
@@ -99257,6 +99407,34 @@ async function startListenerClient(opts) {
99257
99407
  telemetry.init();
99258
99408
  await connectWithRetry(runtime, opts);
99259
99409
  }
99410
+ async function startLocalChannelListener(opts) {
99411
+ const existingRuntime = getActiveRuntime();
99412
+ if (existingRuntime) {
99413
+ stopRuntime(existingRuntime, true);
99414
+ }
99415
+ const runtime = createRuntime();
99416
+ runtime.onWsEvent = opts.onWsEvent;
99417
+ runtime.connectionId = opts.connectionId;
99418
+ runtime.connectionName = opts.connectionName;
99419
+ setActiveRuntime(runtime);
99420
+ telemetry.setSurface("websocket");
99421
+ telemetry.init();
99422
+ try {
99423
+ await loadTools();
99424
+ const transport = new LocalListenerTransport;
99425
+ const processQueuedTurn = async (queuedTurn, dequeuedBatch) => {
99426
+ const scopedRuntime = getOrCreateScopedRuntime(runtime, queuedTurn.agentId, queuedTurn.conversationId);
99427
+ await handleIncomingMessage(queuedTurn, transport, scopedRuntime, opts.onStatusChange, opts.connectionId, dequeuedBatch.batchId);
99428
+ };
99429
+ await startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, { startHeartbeat: false, startCronScheduler: true });
99430
+ } catch (error) {
99431
+ stopRuntime(runtime, true);
99432
+ if (getActiveRuntime() === runtime) {
99433
+ setActiveRuntime(null);
99434
+ }
99435
+ opts.onError(error instanceof Error ? error : new Error(String(error)));
99436
+ }
99437
+ }
99260
99438
  async function listDirectoryHybrid(absDir, indexRoot3, includeFiles) {
99261
99439
  let indexedNames;
99262
99440
  const indexedFolders = [];
@@ -99339,7 +99517,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
99339
99517
  const url = new URL(opts.wsUrl);
99340
99518
  url.searchParams.set("deviceId", opts.deviceId);
99341
99519
  url.searchParams.set("connectionName", opts.connectionName);
99342
- const socket = new WebSocket5(url.toString(), {
99520
+ const socket = new WebSocket3(url.toString(), {
99343
99521
  headers: {
99344
99522
  Authorization: `Bearer ${apiKey}`
99345
99523
  }
@@ -99348,83 +99526,13 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
99348
99526
  const watchDebounceTimers = new Map;
99349
99527
  const cancelledWatches = new Set;
99350
99528
  runtime.socket = socket;
99529
+ const transport = socket;
99351
99530
  const processQueuedTurn = async (queuedTurn, dequeuedBatch) => {
99352
99531
  const scopedRuntime = getOrCreateScopedRuntime(runtime, queuedTurn.agentId, queuedTurn.conversationId);
99353
- await handleIncomingMessage(queuedTurn, socket, scopedRuntime, opts.onStatusChange, opts.connectionId, dequeuedBatch.batchId);
99532
+ await handleIncomingMessage(queuedTurn, transport, scopedRuntime, opts.onStatusChange, opts.connectionId, dequeuedBatch.batchId);
99354
99533
  };
99355
99534
  socket.on("open", async () => {
99356
- if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
99357
- return;
99358
- }
99359
- safeEmitWsEvent("recv", "lifecycle", { type: "_ws_open" });
99360
- runtime.hasSuccessfulConnection = true;
99361
- runtime.everConnected = true;
99362
- opts.onConnected(opts.connectionId);
99363
- if (runtime.conversationRuntimes.size === 0) {
99364
- emitLoopStatusUpdate(socket, runtime);
99365
- } else {
99366
- for (const reminderState of runtime.reminderStateByConversation.values()) {
99367
- resetSharedReminderState(reminderState);
99368
- }
99369
- for (const contextTracker of runtime.contextTrackerByConversation.values()) {
99370
- resetContextHistory(contextTracker);
99371
- }
99372
- for (const conversationRuntime of runtime.conversationRuntimes.values()) {
99373
- const scope = {
99374
- agent_id: conversationRuntime.agentId,
99375
- conversation_id: conversationRuntime.conversationId
99376
- };
99377
- emitDeviceStatusUpdate(socket, conversationRuntime, scope);
99378
- emitLoopStatusUpdate(socket, conversationRuntime, scope);
99379
- }
99380
- }
99381
- runtime._unsubscribeSubagentState?.();
99382
- runtime._unsubscribeSubagentState = subscribe2(() => {
99383
- if (runtime.conversationRuntimes.size === 0) {
99384
- emitSubagentStateIfOpen(runtime);
99385
- return;
99386
- }
99387
- for (const conversationRuntime of runtime.conversationRuntimes.values()) {
99388
- emitSubagentStateIfOpen(runtime, {
99389
- agent_id: conversationRuntime.agentId,
99390
- conversation_id: conversationRuntime.conversationId
99391
- });
99392
- }
99393
- });
99394
- runtime._unsubscribeSubagentStreamEvents?.();
99395
- runtime._unsubscribeSubagentStreamEvents = subscribeToStreamEvents((subagentId, event) => {
99396
- if (socket.readyState !== WebSocket5.OPEN)
99397
- return;
99398
- const subagent = getSubagents().find((entry) => entry.id === subagentId);
99399
- if (subagent?.silent === true) {
99400
- return;
99401
- }
99402
- emitStreamDelta(socket, runtime, event, subagent?.parentAgentId ? {
99403
- agent_id: subagent.parentAgentId,
99404
- conversation_id: subagent.parentConversationId ?? "default"
99405
- } : undefined, subagentId);
99406
- });
99407
- setMessageQueueAdder((queuedMessage) => {
99408
- const targetRuntime = queuedMessage.agentId && queuedMessage.conversationId ? getOrCreateScopedRuntime(runtime, queuedMessage.agentId, queuedMessage.conversationId) : findFallbackRuntime(runtime);
99409
- if (!targetRuntime?.queueRuntime) {
99410
- return;
99411
- }
99412
- targetRuntime.queueRuntime.enqueue({
99413
- kind: "task_notification",
99414
- source: "task_notification",
99415
- text: queuedMessage.text,
99416
- agentId: queuedMessage.agentId ?? targetRuntime.agentId ?? undefined,
99417
- conversationId: queuedMessage.conversationId ?? targetRuntime.conversationId
99418
- });
99419
- scheduleQueuePump(targetRuntime, socket, opts, processQueuedTurn);
99420
- });
99421
- runtime.heartbeatInterval = setInterval(() => {
99422
- if (socket.readyState === WebSocket5.OPEN) {
99423
- safeSocketSend(socket, { type: "ping" }, "listener_ping_send_failed", "listener_heartbeat");
99424
- }
99425
- }, 30000);
99426
- startScheduler(socket, opts, processQueuedTurn);
99427
- await wireChannelIngress(runtime, socket, opts, processQueuedTurn);
99535
+ await startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, { startHeartbeat: true, startCronScheduler: true });
99428
99536
  });
99429
99537
  socket.on("message", async (data) => {
99430
99538
  const raw = data.toString();
@@ -100458,7 +100566,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
100458
100566
  }
100459
100567
  function isListenerActive() {
100460
100568
  const runtime = getActiveRuntime();
100461
- return runtime !== null && runtime.socket !== null;
100569
+ return runtime !== null && runtime.transport !== null;
100462
100570
  }
100463
100571
  function stopListenerClient() {
100464
100572
  const runtime = getActiveRuntime();
@@ -100686,6 +100794,7 @@ var init_client4 = __esm(async () => {
100686
100794
  init_grepInFiles();
100687
100795
  init_permissionMode();
100688
100796
  init_runtime4();
100797
+ init_transport();
100689
100798
  await __promiseAll([
100690
100799
  init_scheduler(),
100691
100800
  init_manager4(),
@@ -100781,6 +100890,7 @@ var init_client4 = __esm(async () => {
100781
100890
  var exports_listen_client = {};
100782
100891
  __export(exports_listen_client, {
100783
100892
  stopListenerClient: () => stopListenerClient,
100893
+ startLocalChannelListener: () => startLocalChannelListener,
100784
100894
  startListenerClient: () => startListenerClient,
100785
100895
  resolvePendingApprovalResolver: () => resolvePendingApprovalResolver,
100786
100896
  requestApprovalOverWS: () => requestApprovalOverWS,
@@ -165010,6 +165120,23 @@ function getListenerServerUrl(settings) {
165010
165120
  const oauthDeps = getListenerOAuthDeps();
165011
165121
  return process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || oauthDeps.LETTA_CLOUD_API_URL;
165012
165122
  }
165123
+ function normalizeListenerBaseUrl(url) {
165124
+ return url.trim().replace(/\/+$/, "");
165125
+ }
165126
+ function isCloudListenerServerUrl(serverUrl) {
165127
+ return normalizeListenerBaseUrl(serverUrl) === normalizeListenerBaseUrl(getListenerOAuthDeps().LETTA_CLOUD_API_URL);
165128
+ }
165129
+ async function resolveListenerStartupMode(channelNames) {
165130
+ const settings = await settingsManager.getSettingsWithSecureTokens();
165131
+ const serverUrl = getListenerServerUrl(settings);
165132
+ if (isCloudListenerServerUrl(serverUrl)) {
165133
+ return { kind: "remote", serverUrl };
165134
+ }
165135
+ if (channelNames.length > 0) {
165136
+ return { kind: "local-channels", serverUrl };
165137
+ }
165138
+ return { kind: "unsupported-self-hosted", serverUrl };
165139
+ }
165013
165140
  async function refreshListenerAccessToken(settings, deviceId, connectionName) {
165014
165141
  const oauthDeps = getListenerOAuthDeps();
165015
165142
  const now = Date.now();
@@ -165065,7 +165192,7 @@ async function resolveListenerRegistrationOptions(deviceId, connectionName) {
165065
165192
  };
165066
165193
  }
165067
165194
  let apiKey = settings.env?.LETTA_API_KEY;
165068
- if (serverUrl === LETTA_CLOUD_API_URL) {
165195
+ if (isCloudListenerServerUrl(serverUrl)) {
165069
165196
  const expiresAt = settings.tokenExpiresAt;
165070
165197
  if (settings.refreshToken && expiresAt) {
165071
165198
  const now = Date.now();
@@ -165190,6 +165317,52 @@ async function runListenSubcommand(argv) {
165190
165317
  console.log(`Log file: ${sessionLog.path}`);
165191
165318
  try {
165192
165319
  const deviceId = settingsManager.getOrCreateDeviceId();
165320
+ const startupMode = await resolveListenerStartupMode(channelNames);
165321
+ if (startupMode.kind === "unsupported-self-hosted") {
165322
+ console.error(`Self-hosted listener registration is not available for ${startupMode.serverUrl}.`);
165323
+ console.error("Start with --channels to run local channel adapters, or unset LETTA_BASE_URL to use Letta API remote environments.");
165324
+ await flushListenerTelemetryEnd("listener_self_hosted_no_channels");
165325
+ return 1;
165326
+ }
165327
+ sessionLog.log(`Session started (debug=${debugMode})`);
165328
+ sessionLog.log(`deviceId: ${deviceId}`);
165329
+ sessionLog.log(`connectionName: ${connectionName}`);
165330
+ if (startupMode.kind === "local-channels") {
165331
+ const connectionId2 = `local-${deviceId}`;
165332
+ sessionLog.log(`Starting local channel listener for ${startupMode.serverUrl}`);
165333
+ sessionLog.log("Skipping environment registration");
165334
+ console.log(`Starting local channel listener for self-hosted server ${startupMode.serverUrl}`);
165335
+ console.log(`Skipping environment registration. Press Ctrl+C to stop.
165336
+ `);
165337
+ const { startLocalChannelListener: startLocalChannelListener2 } = await init_listen_client().then(() => exports_listen_client);
165338
+ await startLocalChannelListener2({
165339
+ connectionId: connectionId2,
165340
+ deviceId,
165341
+ connectionName,
165342
+ onWsEvent: process.env.LETTA_LOG_WS_EVENTS === "1" ? (direction, label, event) => {
165343
+ sessionLog.wsEvent(direction, label, event);
165344
+ } : undefined,
165345
+ onStatusChange: (status) => {
165346
+ sessionLog.log(`status: ${status}`);
165347
+ if (debugMode) {
165348
+ console.log(`[${formatTimestamp3()}] status: ${status}`);
165349
+ }
165350
+ },
165351
+ onConnected: () => {
165352
+ sessionLog.log("Local channel listener ready.");
165353
+ if (debugMode) {
165354
+ console.log(`[${formatTimestamp3()}] Local channel listener ready.`);
165355
+ console.log("");
165356
+ }
165357
+ },
165358
+ onError: (error) => {
165359
+ sessionLog.log(`Error: ${error.message}`);
165360
+ console.error(`[${formatTimestamp3()}] Error: ${error.message}`);
165361
+ exitWithTelemetry(1, "listener_error");
165362
+ }
165363
+ });
165364
+ return new Promise(() => {});
165365
+ }
165193
165366
  let registerOptions;
165194
165367
  try {
165195
165368
  registerOptions = await resolveListenerRegistrationOptions(deviceId, connectionName);
@@ -165204,9 +165377,6 @@ async function runListenSubcommand(argv) {
165204
165377
  await flushListenerTelemetryEnd("listener_oauth_failed");
165205
165378
  return 1;
165206
165379
  }
165207
- sessionLog.log(`Session started (debug=${debugMode})`);
165208
- sessionLog.log(`deviceId: ${deviceId}`);
165209
- sessionLog.log(`connectionName: ${connectionName}`);
165210
165380
  if (debugMode) {
165211
165381
  console.log(`[${formatTimestamp3()}] Registering with ${registerOptions.serverUrl}/v1/environments/register`);
165212
165382
  console.log(`[${formatTimestamp3()}] deviceId: ${deviceId}`);
@@ -169599,4 +169769,4 @@ Error during initialization: ${message}`);
169599
169769
  }
169600
169770
  main();
169601
169771
 
169602
- //# debugId=C84A92912A26F4A364756E2164756E21
169772
+ //# debugId=5F460A87866AF15264756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.24.8",
3
+ "version": "0.24.9",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {