@letta-ai/letta-code 0.23.6 → 0.23.8

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 +1166 -358
  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.23.6",
3272
+ version: "0.23.8",
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: {
@@ -39657,6 +39657,9 @@ var init_personality = __esm(() => {
39657
39657
  import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
39658
39658
  import { homedir as homedir7 } from "node:os";
39659
39659
  import { join as join9 } from "node:path";
39660
+ function getChannelsRoot() {
39661
+ return CHANNELS_ROOT;
39662
+ }
39660
39663
  function getChannelDir(channelId) {
39661
39664
  return join9(CHANNELS_ROOT, channelId);
39662
39665
  }
@@ -39675,6 +39678,9 @@ function getChannelPairingPath(channelId) {
39675
39678
  function getChannelTargetsPath(channelId) {
39676
39679
  return join9(getChannelDir(channelId), "targets.json");
39677
39680
  }
39681
+ function getPendingChannelControlRequestsPath() {
39682
+ return join9(getChannelsRoot(), "pending-control-requests.json");
39683
+ }
39678
39684
  function parseSimpleYaml(text) {
39679
39685
  const result = {};
39680
39686
  const lines = text.split(`
@@ -40138,6 +40144,357 @@ var init_types = __esm(() => {
40138
40144
  SUPPORTED_CHANNEL_IDS = ["telegram", "slack"];
40139
40145
  });
40140
40146
 
40147
+ // src/channels/interactive.ts
40148
+ function normalizeWhitespace(text) {
40149
+ return text.replace(/\s+/g, " ").trim();
40150
+ }
40151
+ function isAffirmativeResponse(text) {
40152
+ const normalized = normalizeWhitespace(text).toLowerCase();
40153
+ return [
40154
+ "approve",
40155
+ "approved",
40156
+ "allow",
40157
+ "yes",
40158
+ "y",
40159
+ "ok",
40160
+ "okay",
40161
+ "continue",
40162
+ "go ahead",
40163
+ "looks good",
40164
+ "lgtm",
40165
+ "sgtm",
40166
+ "ship it"
40167
+ ].includes(normalized);
40168
+ }
40169
+ function isNegativeResponse(text) {
40170
+ const normalized = normalizeWhitespace(text).toLowerCase();
40171
+ return [
40172
+ "deny",
40173
+ "denied",
40174
+ "reject",
40175
+ "rejected",
40176
+ "no",
40177
+ "n",
40178
+ "cancel",
40179
+ "skip",
40180
+ "keep planning"
40181
+ ].includes(normalized);
40182
+ }
40183
+ function stripApprovalPrefix(text) {
40184
+ return normalizeWhitespace(text.replace(/^(approve|allow|yes|y|ok|okay|deny|reject|no|n)\s*[:-]?\s*/i, ""));
40185
+ }
40186
+ function summarizeControlRequestInput(input) {
40187
+ const serialized = JSON.stringify(input, null, 2);
40188
+ if (!serialized || serialized === "{}") {
40189
+ return null;
40190
+ }
40191
+ if (serialized.length <= 1200) {
40192
+ return serialized;
40193
+ }
40194
+ return `${serialized.slice(0, 1197).trimEnd()}...`;
40195
+ }
40196
+ function summarizePlanPreview(planContent) {
40197
+ const normalized = planContent.trim();
40198
+ if (!normalized) {
40199
+ return "";
40200
+ }
40201
+ const maxLength = 1800;
40202
+ if (normalized.length <= maxLength) {
40203
+ return normalized;
40204
+ }
40205
+ return `${normalized.slice(0, maxLength).trimEnd()}
40206
+
40207
+ [Plan preview truncated for channel delivery.]`;
40208
+ }
40209
+ function buildQuestionPrompt(question, index) {
40210
+ const lines = [
40211
+ `${index + 1}. ${question.question ?? `Question ${index + 1}`}`
40212
+ ];
40213
+ const options = question.options ?? [];
40214
+ options.forEach((option, optionIndex) => {
40215
+ const label = option.label?.trim() || `Option ${optionIndex + 1}`;
40216
+ const description = option.description?.trim();
40217
+ lines.push(description ? ` ${optionIndex + 1}) ${label} — ${description}` : ` ${optionIndex + 1}) ${label}`);
40218
+ });
40219
+ if (question.multiSelect) {
40220
+ lines.push(" Choose one or more options. Separate multiple answers with commas.");
40221
+ }
40222
+ return lines;
40223
+ }
40224
+ function matchQuestionOption(question, text) {
40225
+ const trimmed = normalizeWhitespace(text);
40226
+ const options = question.options ?? [];
40227
+ if (!trimmed || options.length === 0) {
40228
+ return trimmed;
40229
+ }
40230
+ const numberMatch = trimmed.match(/^(\d+)$/);
40231
+ if (numberMatch?.[1]) {
40232
+ const option = options[Number(numberMatch[1]) - 1];
40233
+ if (option?.label?.trim()) {
40234
+ return option.label.trim();
40235
+ }
40236
+ }
40237
+ const exactLabel = options.find((option) => option.label && normalizeWhitespace(option.label).toLowerCase() === trimmed.toLowerCase());
40238
+ if (exactLabel?.label?.trim()) {
40239
+ return exactLabel.label.trim();
40240
+ }
40241
+ return trimmed;
40242
+ }
40243
+ function matchQuestionAnswer(question, text) {
40244
+ if (!question.multiSelect) {
40245
+ return matchQuestionOption(question, text);
40246
+ }
40247
+ const normalized = normalizeWhitespace(text);
40248
+ if (!normalized) {
40249
+ return normalized;
40250
+ }
40251
+ const selections = normalized.replace(/\band\b/gi, ",").split(/\s*(?:,|\/|;)\s*/).map((entry) => normalizeWhitespace(entry)).filter(Boolean);
40252
+ if (selections.length <= 1) {
40253
+ return matchQuestionOption(question, normalized);
40254
+ }
40255
+ const matchedSelections = Array.from(new Set(selections.map((selection) => matchQuestionOption(question, selection)).filter(Boolean)));
40256
+ return matchedSelections.length > 0 ? matchedSelections.join(", ") : normalized;
40257
+ }
40258
+ function parseNumberedAnswers(rawText, questions) {
40259
+ const matches = Array.from(rawText.matchAll(/(?:^|\n)\s*(\d+)[).:-]\s*(.+?)(?=(?:\n\s*\d+[).:-]\s*)|$)/gs));
40260
+ if (matches.length === 0) {
40261
+ return null;
40262
+ }
40263
+ const answers = {};
40264
+ for (const match of matches) {
40265
+ const questionIndex = Number(match[1]) - 1;
40266
+ const question = questions[questionIndex];
40267
+ const answerText = match[2]?.trim();
40268
+ if (!question?.question || !answerText) {
40269
+ continue;
40270
+ }
40271
+ answers[question.question] = matchQuestionAnswer(question, answerText);
40272
+ }
40273
+ return Object.keys(answers).length > 0 ? answers : null;
40274
+ }
40275
+ function buildAllowResponse(requestId, decision) {
40276
+ return {
40277
+ request_id: requestId,
40278
+ decision
40279
+ };
40280
+ }
40281
+ function buildDenyResponse(requestId, message) {
40282
+ return {
40283
+ request_id: requestId,
40284
+ decision: {
40285
+ behavior: "deny",
40286
+ message
40287
+ }
40288
+ };
40289
+ }
40290
+ function getAskUserQuestionInput(input) {
40291
+ return input;
40292
+ }
40293
+ function formatAskUserQuestionPrompt(event) {
40294
+ const input = getAskUserQuestionInput(event.input);
40295
+ const questions = (input.questions ?? []).filter((question) => normalizeWhitespace(question.question ?? ""));
40296
+ const lines = [
40297
+ "The agent needs an answer before it can continue.",
40298
+ "",
40299
+ ...questions.flatMap((question, index) => buildQuestionPrompt(question, index)),
40300
+ ""
40301
+ ];
40302
+ if (questions.length <= 1) {
40303
+ const singleQuestion = questions[0];
40304
+ lines.push(singleQuestion?.multiSelect ? "Reply with one or more option numbers/labels separated by commas, or just send a freeform answer in your next message." : "Reply with an option number/label, or just send a freeform answer in your next message.");
40305
+ } else {
40306
+ lines.push("Reply with numbered lines, for example:", "1: your answer", "2: your answer", "", "You can also use option numbers or option labels. For multi-select questions, separate multiple answers with commas.");
40307
+ }
40308
+ return lines.join(`
40309
+ `);
40310
+ }
40311
+ function formatEnterPlanModePrompt() {
40312
+ return [
40313
+ "The agent wants to enter plan mode before making changes.",
40314
+ "",
40315
+ "Reply `approve` to let it plan first, or reply `deny` to skip planning and continue normally."
40316
+ ].join(`
40317
+ `);
40318
+ }
40319
+ function formatExitPlanModePrompt(event) {
40320
+ const lines = [
40321
+ "The agent is ready to leave plan mode and start implementing."
40322
+ ];
40323
+ if (event.planContent?.trim()) {
40324
+ lines.push("", "Proposed plan:", summarizePlanPreview(event.planContent));
40325
+ if (event.planFilePath?.trim()) {
40326
+ lines.push("", `Plan file: ${event.planFilePath.trim()}`);
40327
+ }
40328
+ }
40329
+ lines.push("", "Reply `approve` to accept the plan and start coding.", "Reply with feedback instead if you want the agent to keep planning.");
40330
+ return lines.join(`
40331
+ `);
40332
+ }
40333
+ function formatGenericToolApprovalPrompt(event) {
40334
+ const inputSummary = summarizeControlRequestInput(event.input);
40335
+ const lines = [`The agent wants approval to run \`${event.toolName}\`.`];
40336
+ if (inputSummary) {
40337
+ lines.push("", "Tool input:", inputSummary);
40338
+ }
40339
+ lines.push("", "Reply `approve` to allow it.", "Reply with feedback instead if you want to deny it.");
40340
+ return lines.join(`
40341
+ `);
40342
+ }
40343
+ function formatChannelControlRequestPrompt(event) {
40344
+ switch (event.kind) {
40345
+ case "ask_user_question":
40346
+ return formatAskUserQuestionPrompt(event);
40347
+ case "enter_plan_mode":
40348
+ return formatEnterPlanModePrompt();
40349
+ case "exit_plan_mode":
40350
+ return formatExitPlanModePrompt(event);
40351
+ case "generic_tool_approval":
40352
+ return formatGenericToolApprovalPrompt(event);
40353
+ default: {
40354
+ const exhaustiveCheck = event.kind;
40355
+ return exhaustiveCheck;
40356
+ }
40357
+ }
40358
+ }
40359
+ function parseAskUserQuestionResponse(event, rawText) {
40360
+ const input = getAskUserQuestionInput(event.input);
40361
+ const questions = (input.questions ?? []).filter((question) => normalizeWhitespace(question.question ?? ""));
40362
+ if (questions.length === 0) {
40363
+ return {
40364
+ type: "reprompt",
40365
+ message: "I couldn't find the original question payload. Please ask the agent to try again."
40366
+ };
40367
+ }
40368
+ if (questions.length === 1) {
40369
+ const [question] = questions;
40370
+ if (!question?.question) {
40371
+ return {
40372
+ type: "reprompt",
40373
+ message: "I couldn't find the original question text. Please ask the agent to try again."
40374
+ };
40375
+ }
40376
+ const answer = matchQuestionAnswer(question, rawText);
40377
+ return {
40378
+ type: "response",
40379
+ response: buildAllowResponse(event.requestId, {
40380
+ behavior: "allow",
40381
+ updated_input: {
40382
+ ...event.input,
40383
+ answers: {
40384
+ ...input.answers ?? {},
40385
+ [question.question]: answer
40386
+ }
40387
+ }
40388
+ })
40389
+ };
40390
+ }
40391
+ const numberedAnswers = parseNumberedAnswers(rawText, questions);
40392
+ if (!numberedAnswers) {
40393
+ return {
40394
+ type: "reprompt",
40395
+ message: `Please answer with numbered lines so I can map each reply to the right question.
40396
+ Example:
40397
+ 1: your answer
40398
+ 2: your answer`
40399
+ };
40400
+ }
40401
+ const missingQuestions = questions.filter((question) => question.question && !Object.hasOwn(numberedAnswers, question.question));
40402
+ if (missingQuestions.length > 0) {
40403
+ return {
40404
+ type: "reprompt",
40405
+ message: `I still need answers for: ${missingQuestions.map((question) => question.question).join(", ")}`
40406
+ };
40407
+ }
40408
+ return {
40409
+ type: "response",
40410
+ response: buildAllowResponse(event.requestId, {
40411
+ behavior: "allow",
40412
+ updated_input: {
40413
+ ...event.input,
40414
+ answers: {
40415
+ ...input.answers ?? {},
40416
+ ...numberedAnswers
40417
+ }
40418
+ }
40419
+ })
40420
+ };
40421
+ }
40422
+ function parseEnterPlanModeResponse(event, rawText) {
40423
+ if (isAffirmativeResponse(rawText)) {
40424
+ return {
40425
+ type: "response",
40426
+ response: buildAllowResponse(event.requestId, {
40427
+ behavior: "allow"
40428
+ })
40429
+ };
40430
+ }
40431
+ if (isNegativeResponse(rawText)) {
40432
+ return {
40433
+ type: "response",
40434
+ response: buildDenyResponse(event.requestId, "User chose to skip plan mode and continue implementing directly.")
40435
+ };
40436
+ }
40437
+ return {
40438
+ type: "reprompt",
40439
+ message: "Reply `approve` to let the agent enter plan mode, or `deny` to skip planning."
40440
+ };
40441
+ }
40442
+ function parseExitPlanModeResponse(event, rawText) {
40443
+ if (isAffirmativeResponse(rawText)) {
40444
+ return {
40445
+ type: "response",
40446
+ response: buildAllowResponse(event.requestId, {
40447
+ behavior: "allow"
40448
+ })
40449
+ };
40450
+ }
40451
+ const feedback = stripApprovalPrefix(rawText);
40452
+ return {
40453
+ type: "response",
40454
+ response: buildDenyResponse(event.requestId, feedback || "Please keep planning and revise the proposal.")
40455
+ };
40456
+ }
40457
+ function parseGenericToolApprovalResponse(event, rawText) {
40458
+ if (isAffirmativeResponse(rawText)) {
40459
+ const message = stripApprovalPrefix(rawText);
40460
+ return {
40461
+ type: "response",
40462
+ response: buildAllowResponse(event.requestId, {
40463
+ behavior: "allow",
40464
+ ...message ? { message } : {}
40465
+ })
40466
+ };
40467
+ }
40468
+ const feedback = stripApprovalPrefix(rawText);
40469
+ return {
40470
+ type: "response",
40471
+ response: buildDenyResponse(event.requestId, feedback || "Denied by channel user.")
40472
+ };
40473
+ }
40474
+ function parseChannelControlRequestResponse(event, rawText) {
40475
+ const trimmed = rawText.trim();
40476
+ if (!trimmed) {
40477
+ return {
40478
+ type: "reprompt",
40479
+ message: formatChannelControlRequestPrompt(event)
40480
+ };
40481
+ }
40482
+ switch (event.kind) {
40483
+ case "ask_user_question":
40484
+ return parseAskUserQuestionResponse(event, trimmed);
40485
+ case "enter_plan_mode":
40486
+ return parseEnterPlanModeResponse(event, trimmed);
40487
+ case "exit_plan_mode":
40488
+ return parseExitPlanModeResponse(event, trimmed);
40489
+ case "generic_tool_approval":
40490
+ return parseGenericToolApprovalResponse(event, trimmed);
40491
+ default: {
40492
+ const exhaustiveCheck = event.kind;
40493
+ return exhaustiveCheck;
40494
+ }
40495
+ }
40496
+ }
40497
+
40141
40498
  // src/channels/telegram/media.ts
40142
40499
  import { randomUUID as randomUUID2 } from "node:crypto";
40143
40500
  import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
@@ -41121,6 +41478,13 @@ function createTelegramAdapter(config) {
41121
41478
  } : undefined;
41122
41479
  await telegramBot.api.sendMessage(chatId, text, reply_parameters ? { reply_parameters } : {});
41123
41480
  },
41481
+ async handleControlRequestEvent(event) {
41482
+ const telegramBot = await ensureBot();
41483
+ const reply_parameters = event.source.messageId || event.source.threadId ? {
41484
+ message_id: Number(event.source.threadId ?? event.source.messageId)
41485
+ } : undefined;
41486
+ await telegramBot.api.sendMessage(event.source.chatId, formatChannelControlRequestPrompt(event), reply_parameters ? { reply_parameters } : {});
41487
+ },
41124
41488
  onMessage: undefined
41125
41489
  };
41126
41490
  return adapter;
@@ -42280,6 +42644,16 @@ function createSlackAdapter(config) {
42280
42644
  });
42281
42645
  rememberMessageThread(response.ts, options?.replyToMessageId ?? response.ts ?? null);
42282
42646
  },
42647
+ async handleControlRequestEvent(event) {
42648
+ await ensureApp();
42649
+ const slackClient = await ensureWriteClient();
42650
+ const response = await slackClient.chat.postMessage({
42651
+ channel: event.source.chatId,
42652
+ text: formatChannelControlRequestPrompt(event),
42653
+ ...event.source.threadId ?? event.source.messageId ? { thread_ts: event.source.threadId ?? event.source.messageId } : {}
42654
+ });
42655
+ rememberMessageThread(response.ts, event.source.threadId ?? event.source.messageId ?? response.ts ?? null);
42656
+ },
42283
42657
  async prepareInboundMessage(msg, options) {
42284
42658
  if (!options?.isFirstRouteTurn || msg.channel !== "slack" || msg.chatType !== "channel" || !isNonEmptyString2(msg.threadId) || !isNonEmptyString2(msg.messageId)) {
42285
42659
  return msg;
@@ -42614,6 +42988,93 @@ var init_pluginRegistry = __esm(() => {
42614
42988
  };
42615
42989
  });
42616
42990
 
42991
+ // src/channels/pendingControlRequests.ts
42992
+ import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "node:fs";
42993
+ import { dirname as dirname4 } from "node:path";
42994
+ function cloneEvent(event) {
42995
+ return structuredClone(event);
42996
+ }
42997
+ function cloneStore(nextStore) {
42998
+ return {
42999
+ requests: nextStore.requests.map((event) => cloneEvent(event))
43000
+ };
43001
+ }
43002
+ function isChannelControlRequestEvent(value) {
43003
+ if (!value || typeof value !== "object") {
43004
+ return false;
43005
+ }
43006
+ const candidate = value;
43007
+ return typeof candidate.requestId === "string" && candidate.source !== undefined && typeof candidate.source === "object" && candidate.source !== null && typeof candidate.source.channel === "string" && typeof candidate.source.chatId === "string" && typeof candidate.source.agentId === "string" && typeof candidate.source.conversationId === "string" && typeof candidate.toolName === "string" && candidate.input !== null && typeof candidate.input === "object";
43008
+ }
43009
+ function ensureStoreLoaded() {
43010
+ if (storeLoaded) {
43011
+ return;
43012
+ }
43013
+ storeLoaded = true;
43014
+ if (loadPendingControlRequestStoreOverride) {
43015
+ const overridden = loadPendingControlRequestStoreOverride();
43016
+ store = overridden ? cloneStore(overridden) : EMPTY_STORE();
43017
+ return;
43018
+ }
43019
+ const storePath = getPendingChannelControlRequestsPath();
43020
+ if (!existsSync13(storePath)) {
43021
+ store = EMPTY_STORE();
43022
+ return;
43023
+ }
43024
+ try {
43025
+ const text = readFileSync10(storePath, "utf-8");
43026
+ const parsed = JSON.parse(text);
43027
+ store = {
43028
+ requests: Array.isArray(parsed.requests) ? parsed.requests.filter(isChannelControlRequestEvent).map(cloneEvent) : []
43029
+ };
43030
+ } catch {
43031
+ store = EMPTY_STORE();
43032
+ }
43033
+ }
43034
+ function saveStore() {
43035
+ ensureStoreLoaded();
43036
+ const snapshot = cloneStore(store);
43037
+ if (savePendingControlRequestStoreOverride) {
43038
+ savePendingControlRequestStoreOverride(snapshot);
43039
+ return;
43040
+ }
43041
+ const storePath = getPendingChannelControlRequestsPath();
43042
+ mkdirSync10(dirname4(storePath), { recursive: true });
43043
+ writeFileSync8(storePath, `${JSON.stringify(snapshot, null, 2)}
43044
+ `, "utf-8");
43045
+ }
43046
+ function listPendingControlRequests() {
43047
+ ensureStoreLoaded();
43048
+ return store.requests.map((event) => cloneEvent(event));
43049
+ }
43050
+ function upsertPendingControlRequest(event) {
43051
+ ensureStoreLoaded();
43052
+ const nextEvent = cloneEvent(event);
43053
+ const existingIndex = store.requests.findIndex((candidate) => candidate.requestId === event.requestId);
43054
+ if (existingIndex >= 0) {
43055
+ store.requests[existingIndex] = nextEvent;
43056
+ } else {
43057
+ store.requests.push(nextEvent);
43058
+ }
43059
+ saveStore();
43060
+ return cloneEvent(nextEvent);
43061
+ }
43062
+ function removePendingControlRequest(requestId) {
43063
+ ensureStoreLoaded();
43064
+ const nextRequests = store.requests.filter((candidate) => candidate.requestId !== requestId);
43065
+ if (nextRequests.length === store.requests.length) {
43066
+ return false;
43067
+ }
43068
+ store.requests = nextRequests;
43069
+ saveStore();
43070
+ return true;
43071
+ }
43072
+ var EMPTY_STORE = () => ({ requests: [] }), store, storeLoaded = false, loadPendingControlRequestStoreOverride = null, savePendingControlRequestStoreOverride = null;
43073
+ var init_pendingControlRequests = __esm(() => {
43074
+ init_config();
43075
+ store = EMPTY_STORE();
43076
+ });
43077
+
42617
43078
  // src/channels/routing.ts
42618
43079
  var exports_routing = {};
42619
43080
  __export(exports_routing, {
@@ -42633,7 +43094,7 @@ __export(exports_routing, {
42633
43094
  __testOverrideSaveRoutes: () => __testOverrideSaveRoutes,
42634
43095
  __testOverrideLoadRoutes: () => __testOverrideLoadRoutes
42635
43096
  });
42636
- import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "node:fs";
43097
+ import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
42637
43098
  function normalizeAccountId2(accountId) {
42638
43099
  return accountId ?? LEGACY_CHANNEL_ACCOUNT_ID;
42639
43100
  }
@@ -42674,10 +43135,10 @@ function loadRoutes(channelId) {
42674
43135
  return;
42675
43136
  }
42676
43137
  const path2 = getChannelRoutingPath(channelId);
42677
- if (!existsSync13(path2))
43138
+ if (!existsSync14(path2))
42678
43139
  return;
42679
43140
  try {
42680
- const text = readFileSync10(path2, "utf-8");
43141
+ const text = readFileSync11(path2, "utf-8");
42681
43142
  const parsed = JSON.parse(text);
42682
43143
  const routes = parsed.routes ?? [];
42683
43144
  for (const route of routes) {
@@ -42709,10 +43170,10 @@ function saveRoutes(channelId) {
42709
43170
  return;
42710
43171
  }
42711
43172
  const dir = getChannelDir(channelId);
42712
- mkdirSync10(dir, { recursive: true });
43173
+ mkdirSync11(dir, { recursive: true });
42713
43174
  const routes = getRoutesForChannel(channelId);
42714
43175
  const data = { routes };
42715
- writeFileSync8(getChannelRoutingPath(channelId), `${JSON.stringify(data, null, 2)}
43176
+ writeFileSync9(getChannelRoutingPath(channelId), `${JSON.stringify(data, null, 2)}
42716
43177
  `, "utf-8");
42717
43178
  }
42718
43179
  function getRoute(channel, chatId, accountId, threadId) {
@@ -42802,14 +43263,14 @@ var init_routing = __esm(() => {
42802
43263
  });
42803
43264
 
42804
43265
  // src/channels/targets.ts
42805
- import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
43266
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "node:fs";
42806
43267
  function getStore3(channelId) {
42807
- let store = stores3.get(channelId);
42808
- if (!store) {
42809
- store = { targets: [] };
42810
- stores3.set(channelId, store);
43268
+ let store2 = stores3.get(channelId);
43269
+ if (!store2) {
43270
+ store2 = { targets: [] };
43271
+ stores3.set(channelId, store2);
42811
43272
  }
42812
- return store;
43273
+ return store2;
42813
43274
  }
42814
43275
  function loadTargetStore(channelId) {
42815
43276
  if (loadTargetStoreOverride) {
@@ -42817,11 +43278,11 @@ function loadTargetStore(channelId) {
42817
43278
  return;
42818
43279
  }
42819
43280
  const path2 = getChannelTargetsPath(channelId);
42820
- if (!existsSync14(path2)) {
43281
+ if (!existsSync15(path2)) {
42821
43282
  return;
42822
43283
  }
42823
43284
  try {
42824
- const text = readFileSync11(path2, "utf-8");
43285
+ const text = readFileSync12(path2, "utf-8");
42825
43286
  const parsed = JSON.parse(text);
42826
43287
  stores3.set(channelId, {
42827
43288
  targets: parsed.targets ?? []
@@ -42834,8 +43295,8 @@ function saveTargetStore(channelId) {
42834
43295
  return;
42835
43296
  }
42836
43297
  const dir = getChannelDir(channelId);
42837
- mkdirSync11(dir, { recursive: true });
42838
- writeFileSync9(getChannelTargetsPath(channelId), `${JSON.stringify(getStore3(channelId), null, 2)}
43298
+ mkdirSync12(dir, { recursive: true });
43299
+ writeFileSync10(getChannelTargetsPath(channelId), `${JSON.stringify(getStore3(channelId), null, 2)}
42839
43300
  `, "utf-8");
42840
43301
  }
42841
43302
  function listChannelTargets(channelId, accountId) {
@@ -42843,11 +43304,11 @@ function listChannelTargets(channelId, accountId) {
42843
43304
  return getStore3(channelId).targets.filter((target) => normalizedAccountId === undefined || normalizeAccountId3(target.accountId) === normalizedAccountId);
42844
43305
  }
42845
43306
  function upsertChannelTarget(channelId, target) {
42846
- const store = getStore3(channelId);
43307
+ const store2 = getStore3(channelId);
42847
43308
  const normalizedAccountId = normalizeAccountId3(target.accountId);
42848
- const existingIndex = store.targets.findIndex((candidate) => candidate.targetId === target.targetId && normalizeAccountId3(candidate.accountId) === normalizedAccountId);
43309
+ const existingIndex = store2.targets.findIndex((candidate) => candidate.targetId === target.targetId && normalizeAccountId3(candidate.accountId) === normalizedAccountId);
42849
43310
  if (existingIndex >= 0) {
42850
- const existing = store.targets[existingIndex];
43311
+ const existing = store2.targets[existingIndex];
42851
43312
  if (!existing) {
42852
43313
  throw new Error(`Target index ${existingIndex} missing for ${target.targetId}`);
42853
43314
  }
@@ -42858,11 +43319,11 @@ function upsertChannelTarget(channelId, target) {
42858
43319
  discoveredAt: existing.discoveredAt,
42859
43320
  lastSeenAt: target.lastSeenAt
42860
43321
  };
42861
- store.targets[existingIndex] = merged;
43322
+ store2.targets[existingIndex] = merged;
42862
43323
  saveTargetStore(channelId);
42863
43324
  return merged;
42864
43325
  }
42865
- store.targets.push({
43326
+ store2.targets.push({
42866
43327
  ...target,
42867
43328
  accountId: normalizedAccountId
42868
43329
  });
@@ -42873,25 +43334,25 @@ function upsertChannelTarget(channelId, target) {
42873
43334
  };
42874
43335
  }
42875
43336
  function removeChannelTarget(channelId, targetId, accountId) {
42876
- const store = getStore3(channelId);
43337
+ const store2 = getStore3(channelId);
42877
43338
  const normalizedAccountId = normalizeAccountId3(accountId);
42878
- const nextTargets = store.targets.filter((target) => !(target.targetId === targetId && normalizeAccountId3(target.accountId) === normalizedAccountId));
42879
- if (nextTargets.length === store.targets.length) {
43339
+ const nextTargets = store2.targets.filter((target) => !(target.targetId === targetId && normalizeAccountId3(target.accountId) === normalizedAccountId));
43340
+ if (nextTargets.length === store2.targets.length) {
42880
43341
  return false;
42881
43342
  }
42882
- store.targets = nextTargets;
43343
+ store2.targets = nextTargets;
42883
43344
  saveTargetStore(channelId);
42884
43345
  return true;
42885
43346
  }
42886
43347
  function removeChannelTargetsForAccount(channelId, accountId) {
42887
- const store = getStore3(channelId);
43348
+ const store2 = getStore3(channelId);
42888
43349
  const normalizedAccountId = normalizeAccountId3(accountId);
42889
- const nextTargets = store.targets.filter((target) => normalizeAccountId3(target.accountId) !== normalizedAccountId);
42890
- const removed = store.targets.length - nextTargets.length;
43350
+ const nextTargets = store2.targets.filter((target) => normalizeAccountId3(target.accountId) !== normalizedAccountId);
43351
+ const removed = store2.targets.length - nextTargets.length;
42891
43352
  if (removed === 0) {
42892
43353
  return 0;
42893
43354
  }
42894
- store.targets = nextTargets;
43355
+ store2.targets = nextTargets;
42895
43356
  saveTargetStore(channelId);
42896
43357
  return removed;
42897
43358
  }
@@ -43347,6 +43808,14 @@ function buildChannelTurnSource(route, msg) {
43347
43808
  conversationId: route.conversationId
43348
43809
  };
43349
43810
  }
43811
+ function getChannelApprovalScopeKey(params) {
43812
+ return [
43813
+ params.channel,
43814
+ params.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID,
43815
+ params.chatId,
43816
+ params.threadId ?? ""
43817
+ ].join(":");
43818
+ }
43350
43819
  function getChannelRegistry() {
43351
43820
  return instance;
43352
43821
  }
@@ -43364,12 +43833,16 @@ class ChannelRegistry {
43364
43833
  ready = false;
43365
43834
  messageHandler = null;
43366
43835
  eventHandler = null;
43836
+ approvalResponseHandler = null;
43367
43837
  buffer = [];
43838
+ pendingControlRequestsById = new Map;
43839
+ pendingControlRequestIdByScope = new Map;
43368
43840
  constructor() {
43369
43841
  if (instance) {
43370
43842
  throw new Error("ChannelRegistry is a singleton — use getChannelRegistry()");
43371
43843
  }
43372
43844
  instance = this;
43845
+ this.primePersistedPendingControlRequests();
43373
43846
  }
43374
43847
  getAdapterKey(channelId, accountId = LEGACY_CHANNEL_ACCOUNT_ID) {
43375
43848
  return `${channelId}:${accountId}`;
@@ -43434,9 +43907,99 @@ class ChannelRegistry {
43434
43907
  setMessageHandler(handler) {
43435
43908
  this.messageHandler = handler;
43436
43909
  }
43910
+ setApprovalResponseHandler(handler) {
43911
+ this.approvalResponseHandler = handler;
43912
+ }
43437
43913
  setEventHandler(handler) {
43438
43914
  this.eventHandler = handler;
43439
43915
  }
43916
+ hasPendingControlRequest(requestId) {
43917
+ return this.pendingControlRequestsById.has(requestId);
43918
+ }
43919
+ getPendingControlRequests() {
43920
+ return Array.from(this.pendingControlRequestsById.values()).map((pending) => ({
43921
+ event: structuredClone(pending.event),
43922
+ deliveredThisProcess: pending.deliveredThisProcess
43923
+ }));
43924
+ }
43925
+ primePersistedPendingControlRequests() {
43926
+ for (const event of listPendingControlRequests()) {
43927
+ this.pendingControlRequestsById.set(event.requestId, {
43928
+ event,
43929
+ deliveredThisProcess: false
43930
+ });
43931
+ this.pendingControlRequestIdByScope.set(getChannelApprovalScopeKey({
43932
+ channel: event.source.channel,
43933
+ accountId: event.source.accountId,
43934
+ chatId: event.source.chatId,
43935
+ threadId: event.source.threadId
43936
+ }), event.requestId);
43937
+ }
43938
+ }
43939
+ async deliverPendingControlRequest(requestId) {
43940
+ const pending = this.pendingControlRequestsById.get(requestId);
43941
+ if (!pending) {
43942
+ return false;
43943
+ }
43944
+ const event = pending.event;
43945
+ const adapter = this.getAdapter(event.source.channel, event.source.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID);
43946
+ if (!adapter) {
43947
+ return false;
43948
+ }
43949
+ try {
43950
+ if (adapter.handleControlRequestEvent) {
43951
+ await adapter.handleControlRequestEvent(event);
43952
+ } else {
43953
+ await adapter.sendDirectReply(event.source.chatId, formatChannelControlRequestPrompt(event), {
43954
+ replyToMessageId: event.source.threadId ?? event.source.messageId
43955
+ });
43956
+ }
43957
+ pending.deliveredThisProcess = true;
43958
+ return true;
43959
+ } catch (error) {
43960
+ console.error(`[Channels] Failed to deliver control request prompt for ${event.source.channel}/${event.source.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID}:`, error instanceof Error ? error.message : error);
43961
+ return false;
43962
+ }
43963
+ }
43964
+ async registerPendingControlRequest(event) {
43965
+ const scopeKey = getChannelApprovalScopeKey({
43966
+ channel: event.source.channel,
43967
+ accountId: event.source.accountId,
43968
+ chatId: event.source.chatId,
43969
+ threadId: event.source.threadId
43970
+ });
43971
+ const existingRequestId = this.pendingControlRequestIdByScope.get(scopeKey);
43972
+ if (existingRequestId) {
43973
+ this.clearPendingControlRequest(existingRequestId);
43974
+ }
43975
+ this.pendingControlRequestsById.set(event.requestId, {
43976
+ event,
43977
+ deliveredThisProcess: false
43978
+ });
43979
+ this.pendingControlRequestIdByScope.set(scopeKey, event.requestId);
43980
+ upsertPendingControlRequest(event);
43981
+ await this.deliverPendingControlRequest(event.requestId);
43982
+ }
43983
+ async redeliverPendingControlRequest(requestId) {
43984
+ return this.deliverPendingControlRequest(requestId);
43985
+ }
43986
+ clearPendingControlRequest(requestId) {
43987
+ removePendingControlRequest(requestId);
43988
+ const pending = this.pendingControlRequestsById.get(requestId);
43989
+ if (!pending) {
43990
+ return;
43991
+ }
43992
+ this.pendingControlRequestsById.delete(requestId);
43993
+ const scopeKey = getChannelApprovalScopeKey({
43994
+ channel: pending.event.source.channel,
43995
+ accountId: pending.event.source.accountId,
43996
+ chatId: pending.event.source.chatId,
43997
+ threadId: pending.event.source.threadId
43998
+ });
43999
+ if (this.pendingControlRequestIdByScope.get(scopeKey) === requestId) {
44000
+ this.pendingControlRequestIdByScope.delete(scopeKey);
44001
+ }
44002
+ }
43440
44003
  setReady() {
43441
44004
  this.ready = true;
43442
44005
  this.flushBuffer();
@@ -43528,6 +44091,7 @@ class ChannelRegistry {
43528
44091
  this.ready = false;
43529
44092
  this.messageHandler = null;
43530
44093
  this.eventHandler = null;
44094
+ this.approvalResponseHandler = null;
43531
44095
  }
43532
44096
  async stopAll() {
43533
44097
  for (const adapter of Array.from(this.adapters.values())) {
@@ -43538,13 +44102,63 @@ class ChannelRegistry {
43538
44102
  this.ready = false;
43539
44103
  this.messageHandler = null;
43540
44104
  this.eventHandler = null;
44105
+ this.approvalResponseHandler = null;
44106
+ this.pendingControlRequestsById.clear();
44107
+ this.pendingControlRequestIdByScope.clear();
43541
44108
  instance = null;
43542
44109
  }
44110
+ async tryHandlePendingControlRequest(adapter, msg) {
44111
+ const scopeKey = getChannelApprovalScopeKey({
44112
+ channel: msg.channel,
44113
+ accountId: msg.accountId,
44114
+ chatId: msg.chatId,
44115
+ threadId: msg.threadId
44116
+ });
44117
+ const requestId = this.pendingControlRequestIdByScope.get(scopeKey);
44118
+ if (!requestId) {
44119
+ return false;
44120
+ }
44121
+ const pending = this.pendingControlRequestsById.get(requestId);
44122
+ if (!pending) {
44123
+ this.pendingControlRequestIdByScope.delete(scopeKey);
44124
+ return false;
44125
+ }
44126
+ const parsed = parseChannelControlRequestResponse(pending.event, msg.text);
44127
+ if (parsed.type === "reprompt") {
44128
+ await adapter.sendDirectReply(msg.chatId, parsed.message, {
44129
+ replyToMessageId: msg.threadId ?? msg.messageId
44130
+ });
44131
+ return true;
44132
+ }
44133
+ if (!this.approvalResponseHandler) {
44134
+ await adapter.sendDirectReply(msg.chatId, "I’m reconnecting to Letta Code right now, so I couldn’t use that reply yet. Please send it again in a moment.", {
44135
+ replyToMessageId: msg.threadId ?? msg.messageId
44136
+ });
44137
+ return true;
44138
+ }
44139
+ const handled = await this.approvalResponseHandler({
44140
+ runtime: {
44141
+ agent_id: pending.event.source.agentId,
44142
+ conversation_id: pending.event.source.conversationId
44143
+ },
44144
+ response: parsed.response
44145
+ });
44146
+ this.clearPendingControlRequest(requestId);
44147
+ if (!handled) {
44148
+ await adapter.sendDirectReply(msg.chatId, "That approval prompt expired before I could use your reply. Please ask the agent to try again.", {
44149
+ replyToMessageId: msg.threadId ?? msg.messageId
44150
+ });
44151
+ }
44152
+ return true;
44153
+ }
43543
44154
  async handleInboundMessage(msg) {
43544
44155
  const accountId = msg.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID;
43545
44156
  const adapter = this.getAdapter(msg.channel, accountId);
43546
44157
  if (!adapter)
43547
44158
  return;
44159
+ if (await this.tryHandlePendingControlRequest(adapter, msg)) {
44160
+ return;
44161
+ }
43548
44162
  const config = getChannelAccount(msg.channel, accountId);
43549
44163
  if (!config)
43550
44164
  return;
@@ -43772,6 +44386,7 @@ var init_registry = __esm(() => {
43772
44386
  init_memory();
43773
44387
  init_accounts();
43774
44388
  init_pairing();
44389
+ init_pendingControlRequests();
43775
44390
  init_pluginRegistry();
43776
44391
  init_routing();
43777
44392
  init_targets();
@@ -44167,13 +44782,13 @@ var init_messageTool = __esm(() => {
44167
44782
  // src/cli/helpers/fileIndex.ts
44168
44783
  import { createHash as createHash2 } from "node:crypto";
44169
44784
  import {
44170
- existsSync as existsSync15,
44171
- mkdirSync as mkdirSync12,
44785
+ existsSync as existsSync16,
44786
+ mkdirSync as mkdirSync13,
44172
44787
  readdirSync as readdirSync3,
44173
- readFileSync as readFileSync12,
44788
+ readFileSync as readFileSync13,
44174
44789
  statSync as statSync2,
44175
44790
  unlinkSync as unlinkSync3,
44176
- writeFileSync as writeFileSync10
44791
+ writeFileSync as writeFileSync11
44177
44792
  } from "node:fs";
44178
44793
  import { homedir as homedir8 } from "node:os";
44179
44794
  import { join as join13, normalize as normalize3, relative as relative2, sep as sep2 } from "node:path";
@@ -44192,7 +44807,7 @@ function hashFile2(fullPath, entryPath, stat) {
44192
44807
  return hashValue2(`meta:${entryPath}:${stat.size}:${stat.mtimeMs}:${stat.ino ?? 0}`);
44193
44808
  }
44194
44809
  try {
44195
- const content = readFileSync12(fullPath);
44810
+ const content = readFileSync13(fullPath);
44196
44811
  return createHash2("sha256").update(content).digest("hex");
44197
44812
  } catch (err) {
44198
44813
  debugLog("file-index", `Cannot read file for hashing ${fullPath}: ${err}`);
@@ -44445,8 +45060,8 @@ function getProjectStorageDir2() {
44445
45060
  }
44446
45061
  function ensureProjectStorageDir2() {
44447
45062
  const storageDir = getProjectStorageDir2();
44448
- if (!existsSync15(storageDir)) {
44449
- mkdirSync12(storageDir, { recursive: true });
45063
+ if (!existsSync16(storageDir)) {
45064
+ mkdirSync13(storageDir, { recursive: true });
44450
45065
  }
44451
45066
  return storageDir;
44452
45067
  }
@@ -44455,7 +45070,7 @@ function getProjectIndexPath2() {
44455
45070
  }
44456
45071
  function loadCachedIndex2() {
44457
45072
  const indexPath = getProjectIndexPath2();
44458
- if (!existsSync15(indexPath)) {
45073
+ if (!existsSync16(indexPath)) {
44459
45074
  return null;
44460
45075
  }
44461
45076
  try {
@@ -44470,7 +45085,7 @@ function loadCachedIndex2() {
44470
45085
  }
44471
45086
  return null;
44472
45087
  }
44473
- const content = readFileSync12(indexPath, "utf-8");
45088
+ const content = readFileSync13(indexPath, "utf-8");
44474
45089
  const parsed = JSON.parse(content);
44475
45090
  if (parsed?.metadata && typeof parsed.metadata.rootHash === "string" && Array.isArray(parsed.entries) && parsed.merkle && typeof parsed.merkle === "object") {
44476
45091
  if (parsed.metadata.version !== CACHE_VERSION2) {
@@ -44550,7 +45165,7 @@ function cacheProjectIndex2(result) {
44550
45165
  merkle: cappedMerkle,
44551
45166
  stats: cappedStats
44552
45167
  };
44553
- writeFileSync10(indexPath, JSON.stringify(payload), "utf-8");
45168
+ writeFileSync11(indexPath, JSON.stringify(payload), "utf-8");
44554
45169
  } catch (err) {
44555
45170
  debugLog("file-index", `Failed to persist index cache: ${err}`);
44556
45171
  }
@@ -46226,7 +46841,7 @@ __export(exports_memoryFilesystem, {
46226
46841
  MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR,
46227
46842
  MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR
46228
46843
  });
46229
- import { existsSync as existsSync16, mkdirSync as mkdirSync13 } from "node:fs";
46844
+ import { existsSync as existsSync17, mkdirSync as mkdirSync14 } from "node:fs";
46230
46845
  import { homedir as homedir10 } from "node:os";
46231
46846
  import { join as join14 } from "node:path";
46232
46847
  function getMemoryFilesystemRoot(agentId, homeDir = homedir10()) {
@@ -46238,11 +46853,11 @@ function getMemorySystemDir(agentId, homeDir = homedir10()) {
46238
46853
  function ensureMemoryFilesystemDirs(agentId, homeDir = homedir10()) {
46239
46854
  const root = getMemoryFilesystemRoot(agentId, homeDir);
46240
46855
  const systemDir = getMemorySystemDir(agentId, homeDir);
46241
- if (!existsSync16(root)) {
46242
- mkdirSync13(root, { recursive: true });
46856
+ if (!existsSync17(root)) {
46857
+ mkdirSync14(root, { recursive: true });
46243
46858
  }
46244
- if (!existsSync16(systemDir)) {
46245
- mkdirSync13(systemDir, { recursive: true });
46859
+ if (!existsSync17(systemDir)) {
46860
+ mkdirSync14(systemDir, { recursive: true });
46246
46861
  }
46247
46862
  }
46248
46863
  async function isMemfsEnabledOnServer(agentId) {
@@ -46468,7 +47083,7 @@ var init_memoryFilesystem = __esm(() => {
46468
47083
 
46469
47084
  // src/permissions/memoryScope.ts
46470
47085
  import { homedir as homedir11 } from "node:os";
46471
- import { basename as basename5, dirname as dirname4, isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
47086
+ import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
46472
47087
  function normalizeScopedPath(path3) {
46473
47088
  const resolvedPath = resolve4(expandHomePath(path3));
46474
47089
  const normalized = resolvedPath.replace(/\\/g, "/");
@@ -46515,7 +47130,7 @@ function addRootAndSiblingWorktree(root, acc) {
46515
47130
  acc.add(normalizedRoot);
46516
47131
  const leaf = basename5(normalizedRoot);
46517
47132
  if (leaf === "memory") {
46518
- acc.add(normalizeScopedPath(resolve4(dirname4(normalizedRoot), "memory-worktrees")));
47133
+ acc.add(normalizeScopedPath(resolve4(dirname5(normalizedRoot), "memory-worktrees")));
46519
47134
  }
46520
47135
  }
46521
47136
  function getExplicitEnvRoots(env3) {
@@ -50445,7 +51060,7 @@ __export(exports_shellEnv, {
50445
51060
  getShellEnv: () => getShellEnv,
50446
51061
  ensureLettaShimDir: () => ensureLettaShimDir
50447
51062
  });
50448
- import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync11 } from "node:fs";
51063
+ import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync12 } from "node:fs";
50449
51064
  import { createRequire as createRequire3 } from "node:module";
50450
51065
  import { tmpdir } from "node:os";
50451
51066
  import * as path4 from "node:path";
@@ -50531,19 +51146,19 @@ function ensureLettaShimDir(invocation) {
50531
51146
  if (!invocation.command)
50532
51147
  return null;
50533
51148
  const shimDir = path4.join(tmpdir(), "letta-code-shell-shim");
50534
- mkdirSync14(shimDir, { recursive: true });
51149
+ mkdirSync15(shimDir, { recursive: true });
50535
51150
  if (process.platform === "win32") {
50536
51151
  const cmdPath = path4.join(shimDir, "letta.cmd");
50537
51152
  const quotedCommand = `"${invocation.command.replaceAll('"', '""')}"`;
50538
51153
  const quotedArgs = invocation.args.map((arg) => `"${arg.replaceAll('"', '""')}"`).join(" ");
50539
- writeFileSync11(cmdPath, `@echo off\r
51154
+ writeFileSync12(cmdPath, `@echo off\r
50540
51155
  ${quotedCommand} ${quotedArgs} %*\r
50541
51156
  `);
50542
51157
  return shimDir;
50543
51158
  }
50544
51159
  const shimPath = path4.join(shimDir, "letta");
50545
51160
  const commandWithArgs = [invocation.command, ...invocation.args].map(shellEscape).join(" ");
50546
- writeFileSync11(shimPath, `#!/bin/sh
51161
+ writeFileSync12(shimPath, `#!/bin/sh
50547
51162
  exec ${commandWithArgs} "$@"
50548
51163
  `, {
50549
51164
  mode: 493
@@ -51199,7 +51814,7 @@ var init_Bash2 = __esm(() => {
51199
51814
  });
51200
51815
 
51201
51816
  // src/tools/impl/BashOutput.ts
51202
- import { readFileSync as readFileSync13, statSync as statSync4 } from "node:fs";
51817
+ import { readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
51203
51818
  function sleep2(ms) {
51204
51819
  return new Promise((resolve8) => setTimeout(resolve8, ms));
51205
51820
  }
@@ -51216,7 +51831,7 @@ function readOutputFile(filePath) {
51216
51831
  fallbackNotice: `[Output file too large to load fully here (${stats.size.toLocaleString()} bytes). Showing the bounded in-memory buffer instead. Full transcript: ${filePath}]`
51217
51832
  };
51218
51833
  }
51219
- return { content: readFileSync13(filePath, "utf-8") };
51834
+ return { content: readFileSync14(filePath, "utf-8") };
51220
51835
  } catch {
51221
51836
  return { content: null };
51222
51837
  }
@@ -52599,6 +53214,7 @@ function createConversationRuntime(listener, agentId, conversationId) {
52599
53214
  key: runtimeKey,
52600
53215
  agentId: normalizedAgentId,
52601
53216
  conversationId: normalizedConversationId,
53217
+ activeChannelTurnSources: null,
52602
53218
  messageQueue: Promise.resolve(),
52603
53219
  pendingApprovalResolvers: new Map,
52604
53220
  recoveredApprovalState: null,
@@ -52748,7 +53364,7 @@ var init_runtime3 = () => {};
52748
53364
 
52749
53365
  // src/tools/impl/Memory.ts
52750
53366
  import { execFile as execFileCb3 } from "node:child_process";
52751
- import { existsSync as existsSync18 } from "node:fs";
53367
+ import { existsSync as existsSync19 } from "node:fs";
52752
53368
  import {
52753
53369
  mkdir as mkdir5,
52754
53370
  readFile as readFile5,
@@ -52759,7 +53375,7 @@ import {
52759
53375
  writeFile as writeFile5
52760
53376
  } from "node:fs/promises";
52761
53377
  import { homedir as homedir16 } from "node:os";
52762
- import { dirname as dirname7, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve13 } from "node:path";
53378
+ import { dirname as dirname8, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve13 } from "node:path";
52763
53379
  import { promisify as promisify6 } from "node:util";
52764
53380
  async function getAgentIdentity() {
52765
53381
  const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
@@ -52801,14 +53417,14 @@ async function memory(args) {
52801
53417
  const label = normalizeMemoryLabel(memoryDir, pathArg, "file_path");
52802
53418
  const filePath = resolveMemoryFilePath(memoryDir, label);
52803
53419
  const relPath = toRepoRelative(memoryDir, filePath);
52804
- if (existsSync18(filePath)) {
53420
+ if (existsSync19(filePath)) {
52805
53421
  throw new Error(`memory create: block already exists at ${pathArg}`);
52806
53422
  }
52807
53423
  const body = args.file_text ?? "";
52808
53424
  const rendered = renderMemoryFile({
52809
53425
  description
52810
53426
  }, body);
52811
- await mkdir5(dirname7(filePath), { recursive: true });
53427
+ await mkdir5(dirname8(filePath), { recursive: true });
52812
53428
  await writeFile5(filePath, rendered, "utf8");
52813
53429
  affectedPaths = [relPath];
52814
53430
  } else if (command === "str_replace") {
@@ -52853,7 +53469,7 @@ async function memory(args) {
52853
53469
  const pathArg = requireString(args.file_path, "file_path", "delete");
52854
53470
  const label = normalizeMemoryLabel(memoryDir, pathArg, "file_path");
52855
53471
  const targetPath = resolveMemoryPath(memoryDir, label);
52856
- if (existsSync18(targetPath) && (await stat2(targetPath)).isDirectory()) {
53472
+ if (existsSync19(targetPath) && (await stat2(targetPath)).isDirectory()) {
52857
53473
  const relPath = toRepoRelative(memoryDir, targetPath);
52858
53474
  await rm(targetPath, { recursive: true, force: false });
52859
53475
  affectedPaths = [relPath];
@@ -52873,11 +53489,11 @@ async function memory(args) {
52873
53489
  const newFilePath = resolveMemoryFilePath(memoryDir, newLabel);
52874
53490
  const oldRelPath = toRepoRelative(memoryDir, oldFilePath);
52875
53491
  const newRelPath = toRepoRelative(memoryDir, newFilePath);
52876
- if (existsSync18(newFilePath)) {
53492
+ if (existsSync19(newFilePath)) {
52877
53493
  throw new Error(`memory rename: destination already exists at ${newPathArg}`);
52878
53494
  }
52879
53495
  await loadEditableMemoryFile(oldFilePath, oldPathArg);
52880
- await mkdir5(dirname7(newFilePath), { recursive: true });
53496
+ await mkdir5(dirname8(newFilePath), { recursive: true });
52881
53497
  await rename(oldFilePath, newFilePath);
52882
53498
  affectedPaths = [oldRelPath, newRelPath];
52883
53499
  } else if (command === "update_description") {
@@ -52930,10 +53546,10 @@ function resolveMemoryDir() {
52930
53546
  throw new Error("memory: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
52931
53547
  }
52932
53548
  function ensureMemoryRepo(memoryDir) {
52933
- if (!existsSync18(memoryDir)) {
53549
+ if (!existsSync19(memoryDir)) {
52934
53550
  throw new Error(`memory: memory directory does not exist: ${memoryDir}`);
52935
53551
  }
52936
- if (!existsSync18(resolve13(memoryDir, ".git"))) {
53552
+ if (!existsSync19(resolve13(memoryDir, ".git"))) {
52937
53553
  throw new Error(`memory: ${memoryDir} is not a git repository. This tool requires a git-backed memory filesystem.`);
52938
53554
  }
52939
53555
  }
@@ -53178,7 +53794,7 @@ var init_Memory2 = __esm(() => {
53178
53794
 
53179
53795
  // src/tools/impl/MemoryApplyPatch.ts
53180
53796
  import { execFile as execFileCb4 } from "node:child_process";
53181
- import { existsSync as existsSync19 } from "node:fs";
53797
+ import { existsSync as existsSync20 } from "node:fs";
53182
53798
  import {
53183
53799
  access,
53184
53800
  mkdir as mkdir6,
@@ -53189,7 +53805,7 @@ import {
53189
53805
  writeFile as writeFile6
53190
53806
  } from "node:fs/promises";
53191
53807
  import { homedir as homedir17 } from "node:os";
53192
- import { dirname as dirname8, isAbsolute as isAbsolute10, relative as relative6, resolve as resolve14 } from "node:path";
53808
+ import { dirname as dirname9, isAbsolute as isAbsolute10, relative as relative6, resolve as resolve14 } from "node:path";
53193
53809
  import { promisify as promisify7 } from "node:util";
53194
53810
  async function getAgentIdentity2() {
53195
53811
  const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
@@ -53302,7 +53918,7 @@ async function memory_apply_patch(args) {
53302
53918
  }
53303
53919
  }
53304
53920
  for (const [absPath, content] of pendingWrites.entries()) {
53305
- await mkdir6(dirname8(absPath), { recursive: true });
53921
+ await mkdir6(dirname9(absPath), { recursive: true });
53306
53922
  await writeFile6(absPath, content, "utf8");
53307
53923
  }
53308
53924
  for (const absPath of pendingDeletes) {
@@ -53481,10 +54097,10 @@ function resolveMemoryDir2() {
53481
54097
  throw new Error("memory_apply_patch: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
53482
54098
  }
53483
54099
  function ensureMemoryRepo2(memoryDir) {
53484
- if (!existsSync19(memoryDir)) {
54100
+ if (!existsSync20(memoryDir)) {
53485
54101
  throw new Error(`memory_apply_patch: memory directory does not exist: ${memoryDir}`);
53486
54102
  }
53487
- if (!existsSync19(resolve14(memoryDir, ".git"))) {
54103
+ if (!existsSync20(resolve14(memoryDir, ".git"))) {
53488
54104
  throw new Error(`memory_apply_patch: ${memoryDir} is not a git repository. This tool requires a git-backed memory filesystem.`);
53489
54105
  }
53490
54106
  }
@@ -54246,12 +54862,12 @@ __export(exports_imageResize_magick, {
54246
54862
  MAX_IMAGE_BYTES: () => MAX_IMAGE_BYTES
54247
54863
  });
54248
54864
  import { execSync } from "node:child_process";
54249
- import { readFileSync as readFileSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync13 } from "node:fs";
54865
+ import { readFileSync as readFileSync15, unlinkSync as unlinkSync5, writeFileSync as writeFileSync14 } from "node:fs";
54250
54866
  import { tmpdir as tmpdir2 } from "node:os";
54251
54867
  import { join as join21 } from "node:path";
54252
54868
  async function getImageDimensions(buffer) {
54253
54869
  const tempInput = join21(tmpdir2(), `image-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
54254
- writeFileSync13(tempInput, buffer);
54870
+ writeFileSync14(tempInput, buffer);
54255
54871
  try {
54256
54872
  const output = execSync(`magick identify -format "%w %h %m" "${tempInput}"`, {
54257
54873
  encoding: "utf-8"
@@ -54274,7 +54890,7 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
54274
54890
  return null;
54275
54891
  }
54276
54892
  const tempInput = join21(tmpdir2(), `compress-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
54277
- writeFileSync13(tempInput, buffer);
54893
+ writeFileSync14(tempInput, buffer);
54278
54894
  try {
54279
54895
  const qualities = [85, 70, 55, 40];
54280
54896
  for (const quality of qualities) {
@@ -54283,7 +54899,7 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
54283
54899
  execSync(`magick "${tempInput}" -quality ${quality} "${tempOutput}"`, {
54284
54900
  stdio: "ignore"
54285
54901
  });
54286
- const compressed = readFileSync14(tempOutput);
54902
+ const compressed = readFileSync15(tempOutput);
54287
54903
  if (compressed.length <= MAX_IMAGE_BYTES) {
54288
54904
  const { width, height } = await getImageDimensions(compressed);
54289
54905
  return {
@@ -54309,7 +54925,7 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
54309
54925
  execSync(`magick "${tempInput}" -resize ${scaledWidth}x${scaledHeight} -quality 70 "${tempOutput}"`, {
54310
54926
  stdio: "ignore"
54311
54927
  });
54312
- const reduced = readFileSync14(tempOutput);
54928
+ const reduced = readFileSync15(tempOutput);
54313
54929
  if (reduced.length <= MAX_IMAGE_BYTES) {
54314
54930
  const { width, height } = await getImageDimensions(reduced);
54315
54931
  return {
@@ -54349,7 +54965,7 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
54349
54965
  };
54350
54966
  }
54351
54967
  const tempInput = join21(tmpdir2(), `resize-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
54352
- writeFileSync13(tempInput, buffer);
54968
+ writeFileSync14(tempInput, buffer);
54353
54969
  try {
54354
54970
  if (needsResize) {
54355
54971
  const tempOutput2 = join21(tmpdir2(), `resize-output-${Date.now()}-${Math.random().toString(36).slice(2)}`);
@@ -54359,14 +54975,14 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
54359
54975
  execSync(`magick "${tempInput}" -resize ${MAX_IMAGE_WIDTH}x${MAX_IMAGE_HEIGHT}> -quality 85 "${tempOutput2}.jpg"`, {
54360
54976
  stdio: "ignore"
54361
54977
  });
54362
- outputBuffer2 = readFileSync14(`${tempOutput2}.jpg`);
54978
+ outputBuffer2 = readFileSync15(`${tempOutput2}.jpg`);
54363
54979
  outputMediaType = "image/jpeg";
54364
54980
  unlinkSync5(`${tempOutput2}.jpg`);
54365
54981
  } else {
54366
54982
  execSync(`magick "${tempInput}" -resize ${MAX_IMAGE_WIDTH}x${MAX_IMAGE_HEIGHT}> "${tempOutput2}.png"`, {
54367
54983
  stdio: "ignore"
54368
54984
  });
54369
- outputBuffer2 = readFileSync14(`${tempOutput2}.png`);
54985
+ outputBuffer2 = readFileSync15(`${tempOutput2}.png`);
54370
54986
  outputMediaType = "image/png";
54371
54987
  unlinkSync5(`${tempOutput2}.png`);
54372
54988
  }
@@ -54387,7 +55003,7 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
54387
55003
  execSync(`magick "${tempInput}" "${tempOutput}"`, {
54388
55004
  stdio: "ignore"
54389
55005
  });
54390
- const outputBuffer = readFileSync14(tempOutput);
55006
+ const outputBuffer = readFileSync15(tempOutput);
54391
55007
  unlinkSync5(tempOutput);
54392
55008
  const compressed = await compressToFitByteLimit(outputBuffer, width, height);
54393
55009
  if (compressed) {
@@ -54494,7 +55110,7 @@ var require_filesystem = __commonJS((exports, module) => {
54494
55110
  var LDD_PATH = "/usr/bin/ldd";
54495
55111
  var SELF_PATH = "/proc/self/exe";
54496
55112
  var MAX_LENGTH = 2048;
54497
- var readFileSync15 = (path11) => {
55113
+ var readFileSync16 = (path11) => {
54498
55114
  const fd = fs7.openSync(path11, "r");
54499
55115
  const buffer = Buffer.alloc(MAX_LENGTH);
54500
55116
  const bytesRead = fs7.readSync(fd, buffer, 0, MAX_LENGTH, 0);
@@ -54517,7 +55133,7 @@ var require_filesystem = __commonJS((exports, module) => {
54517
55133
  module.exports = {
54518
55134
  LDD_PATH,
54519
55135
  SELF_PATH,
54520
- readFileSync: readFileSync15,
55136
+ readFileSync: readFileSync16,
54521
55137
  readFile: readFile7
54522
55138
  };
54523
55139
  });
@@ -54560,7 +55176,7 @@ var require_elf = __commonJS((exports, module) => {
54560
55176
  var require_detect_libc = __commonJS((exports, module) => {
54561
55177
  var childProcess = __require("child_process");
54562
55178
  var { isLinux: isLinux2, getReport } = require_process();
54563
- var { LDD_PATH, SELF_PATH, readFile: readFile7, readFileSync: readFileSync15 } = require_filesystem();
55179
+ var { LDD_PATH, SELF_PATH, readFile: readFile7, readFileSync: readFileSync16 } = require_filesystem();
54564
55180
  var { interpreterPath } = require_elf();
54565
55181
  var cachedFamilyInterpreter;
54566
55182
  var cachedFamilyFilesystem;
@@ -54651,7 +55267,7 @@ var require_detect_libc = __commonJS((exports, module) => {
54651
55267
  }
54652
55268
  cachedFamilyFilesystem = null;
54653
55269
  try {
54654
- const lddContent = readFileSync15(LDD_PATH);
55270
+ const lddContent = readFileSync16(LDD_PATH);
54655
55271
  cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
54656
55272
  } catch (e) {}
54657
55273
  return cachedFamilyFilesystem;
@@ -54674,7 +55290,7 @@ var require_detect_libc = __commonJS((exports, module) => {
54674
55290
  }
54675
55291
  cachedFamilyInterpreter = null;
54676
55292
  try {
54677
- const selfContent = readFileSync15(SELF_PATH);
55293
+ const selfContent = readFileSync16(SELF_PATH);
54678
55294
  const path11 = interpreterPath(selfContent);
54679
55295
  cachedFamilyInterpreter = familyFromInterpreterPath(path11);
54680
55296
  } catch (e) {}
@@ -54736,7 +55352,7 @@ var require_detect_libc = __commonJS((exports, module) => {
54736
55352
  }
54737
55353
  cachedVersionFilesystem = null;
54738
55354
  try {
54739
- const lddContent = readFileSync15(LDD_PATH);
55355
+ const lddContent = readFileSync16(LDD_PATH);
54740
55356
  const versionMatch = lddContent.match(RE_GLIBC_VERSION);
54741
55357
  if (versionMatch) {
54742
55358
  cachedVersionFilesystem = versionMatch[1];
@@ -66532,8 +67148,8 @@ var init_ignore = __esm(() => {
66532
67148
  // node_modules/glob/dist/esm/processor.js
66533
67149
  class HasWalkedCache {
66534
67150
  store;
66535
- constructor(store = new Map) {
66536
- this.store = store;
67151
+ constructor(store2 = new Map) {
67152
+ this.store = store2;
66537
67153
  }
66538
67154
  copy() {
66539
67155
  return new HasWalkedCache(new Map(this.store));
@@ -67434,7 +68050,7 @@ var init_ReplaceGemini2 = __esm(() => {
67434
68050
  });
67435
68051
 
67436
68052
  // src/tools/impl/Shell.ts
67437
- import { existsSync as existsSync20, statSync as statSync5 } from "node:fs";
68053
+ import { existsSync as existsSync21, statSync as statSync5 } from "node:fs";
67438
68054
  import * as path15 from "node:path";
67439
68055
  function resolveShellWorkdir(workdir) {
67440
68056
  const defaultCwd = process.env.USER_CWD || process.cwd();
@@ -67528,7 +68144,7 @@ function arraysEqual(a, b) {
67528
68144
  }
67529
68145
  function isUsableDirectory(candidate) {
67530
68146
  try {
67531
- return existsSync20(candidate) && statSync5(candidate).isDirectory();
68147
+ return existsSync21(candidate) && statSync5(candidate).isDirectory();
67532
68148
  } catch {
67533
68149
  return false;
67534
68150
  }
@@ -67783,12 +68399,12 @@ __export(exports_skills, {
67783
68399
  SKILLS_DIR: () => SKILLS_DIR,
67784
68400
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR
67785
68401
  });
67786
- import { existsSync as existsSync21 } from "node:fs";
68402
+ import { existsSync as existsSync22 } from "node:fs";
67787
68403
  import { readdir as readdir4, readFile as readFile7, realpath as realpath2, stat as stat4 } from "node:fs/promises";
67788
- import { dirname as dirname9, join as join22 } from "node:path";
68404
+ import { dirname as dirname10, join as join22 } from "node:path";
67789
68405
  import { fileURLToPath as fileURLToPath6 } from "node:url";
67790
68406
  function getBundledSkillsPath() {
67791
- const thisDir = dirname9(fileURLToPath6(import.meta.url));
68407
+ const thisDir = dirname10(fileURLToPath6(import.meta.url));
67792
68408
  if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
67793
68409
  return join22(thisDir, "../skills/builtin");
67794
68410
  }
@@ -67807,7 +68423,7 @@ async function getBundledSkills() {
67807
68423
  }
67808
68424
  async function discoverSkillsFromDir(skillsPath, source) {
67809
68425
  const errors = [];
67810
- if (!existsSync21(skillsPath)) {
68426
+ if (!existsSync22(skillsPath)) {
67811
68427
  return { skills: [], errors: [] };
67812
68428
  }
67813
68429
  const skills = [];
@@ -67990,7 +68606,7 @@ var init_skillContentRegistry = __esm(() => {
67990
68606
  // src/tools/impl/Skill.ts
67991
68607
  import { readdirSync as readdirSync6 } from "node:fs";
67992
68608
  import { readFile as readFile8 } from "node:fs/promises";
67993
- import { dirname as dirname10, join as join23 } from "node:path";
68609
+ import { dirname as dirname11, join as join23 } from "node:path";
67994
68610
  function getMemorySkillsDirs(agentId) {
67995
68611
  const dirs = new Set;
67996
68612
  const memoryDir = process.env.MEMORY_DIR || process.env.LETTA_MEMORY_DIR;
@@ -68004,7 +68620,7 @@ function getMemorySkillsDirs(agentId) {
68004
68620
  }
68005
68621
  function hasAdditionalFiles(skillMdPath) {
68006
68622
  try {
68007
- const skillDir = dirname10(skillMdPath);
68623
+ const skillDir = dirname11(skillMdPath);
68008
68624
  const entries = readdirSync6(skillDir);
68009
68625
  return entries.some((e) => e.toUpperCase() !== "SKILL.MD");
68010
68626
  } catch {
@@ -68080,7 +68696,7 @@ async function skill(args) {
68080
68696
  const agentId = getResolvedAgentId(args);
68081
68697
  const skillsDir = await getResolvedSkillsDir();
68082
68698
  const { content: skillContent, path: skillPath } = await readSkillContent(skillName, skillsDir, agentId);
68083
- const skillDir = dirname10(skillPath);
68699
+ const skillDir = dirname11(skillPath);
68084
68700
  const hasExtras = hasAdditionalFiles(skillPath);
68085
68701
  const processedContent = hasExtras ? skillContent.replace(/<SKILL_DIR>/g, skillDir) : skillContent;
68086
68702
  const dirHeader = hasExtras ? `# Skill Directory: ${skillDir}
@@ -68109,13 +68725,13 @@ var init_Skill2 = __esm(() => {
68109
68725
  // src/cli/helpers/subagentState.ts
68110
68726
  function updateSnapshot() {
68111
68727
  cachedSnapshot = {
68112
- agents: Array.from(store.agents.values()),
68113
- expanded: store.expanded
68728
+ agents: Array.from(store2.agents.values()),
68729
+ expanded: store2.expanded
68114
68730
  };
68115
68731
  }
68116
68732
  function notifyListeners() {
68117
68733
  updateSnapshot();
68118
- for (const listener of store.listeners) {
68734
+ for (const listener of store2.listeners) {
68119
68735
  listener();
68120
68736
  }
68121
68737
  }
@@ -68133,18 +68749,18 @@ function unrefTimer2(timer) {
68133
68749
  }
68134
68750
  }
68135
68751
  function scheduleCompletedSubagentCleanup(id) {
68136
- const agent = store.agents.get(id);
68752
+ const agent = store2.agents.get(id);
68137
68753
  if (!agent || agent.status !== "completed" && agent.status !== "error") {
68138
68754
  return;
68139
68755
  }
68140
68756
  clearCompletedSubagentCleanup(id);
68141
68757
  const timer = setTimeout(() => {
68142
- const current = store.agents.get(id);
68758
+ const current = store2.agents.get(id);
68143
68759
  if (!current || current.status !== "completed" && current.status !== "error") {
68144
68760
  completedSubagentCleanupTimers.delete(id);
68145
68761
  return;
68146
68762
  }
68147
- store.agents.delete(id);
68763
+ store2.agents.delete(id);
68148
68764
  completedSubagentCleanupTimers.delete(id);
68149
68765
  notifyListeners();
68150
68766
  }, completedSubagentRetentionMs);
@@ -68155,7 +68771,7 @@ function generateSubagentId() {
68155
68771
  return `subagent-${Date.now()}-${++subagentCounter}`;
68156
68772
  }
68157
68773
  function getSubagentByToolCallId(toolCallId) {
68158
- for (const agent of store.agents.values()) {
68774
+ for (const agent of store2.agents.values()) {
68159
68775
  if (agent.toolCallId === toolCallId) {
68160
68776
  return agent;
68161
68777
  }
@@ -68182,11 +68798,11 @@ function registerSubagent(id, type, description, toolCallId, isBackground, silen
68182
68798
  parentConversationId: parentScope?.conversationId && parentScope.conversationId.length > 0 ? parentScope.conversationId : undefined
68183
68799
  };
68184
68800
  clearCompletedSubagentCleanup(id);
68185
- store.agents.set(id, agent);
68801
+ store2.agents.set(id, agent);
68186
68802
  notifyListeners();
68187
68803
  }
68188
68804
  function updateSubagent(id, updates) {
68189
- const agent = store.agents.get(id);
68805
+ const agent = store2.agents.get(id);
68190
68806
  if (!agent)
68191
68807
  return;
68192
68808
  if (updates.agentURL && agent.status === "pending") {
@@ -68199,7 +68815,7 @@ function updateSubagent(id, updates) {
68199
68815
  if (isNoop)
68200
68816
  return;
68201
68817
  const updatedAgent = { ...agent, ...updates, maxToolCallsSeen: nextMax };
68202
- store.agents.set(id, updatedAgent);
68818
+ store2.agents.set(id, updatedAgent);
68203
68819
  if (updatedAgent.status === "completed" || updatedAgent.status === "error") {
68204
68820
  scheduleCompletedSubagentCleanup(id);
68205
68821
  } else {
@@ -68208,7 +68824,7 @@ function updateSubagent(id, updates) {
68208
68824
  notifyListeners();
68209
68825
  }
68210
68826
  function addToolCall(subagentId, toolCallId, toolName, toolArgs) {
68211
- const agent = store.agents.get(subagentId);
68827
+ const agent = store2.agents.get(subagentId);
68212
68828
  if (!agent)
68213
68829
  return;
68214
68830
  if (agent.toolCalls.some((tc) => tc.id === toolCallId))
@@ -68221,11 +68837,11 @@ function addToolCall(subagentId, toolCallId, toolName, toolArgs) {
68221
68837
  ],
68222
68838
  maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length + 1)
68223
68839
  };
68224
- store.agents.set(subagentId, updatedAgent);
68840
+ store2.agents.set(subagentId, updatedAgent);
68225
68841
  notifyListeners();
68226
68842
  }
68227
68843
  function completeSubagent(id, result) {
68228
- const agent = store.agents.get(id);
68844
+ const agent = store2.agents.get(id);
68229
68845
  if (!agent)
68230
68846
  return;
68231
68847
  const updatedAgent = {
@@ -68236,7 +68852,7 @@ function completeSubagent(id, result) {
68236
68852
  totalTokens: result.totalTokens ?? agent.totalTokens,
68237
68853
  maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length)
68238
68854
  };
68239
- store.agents.set(id, updatedAgent);
68855
+ store2.agents.set(id, updatedAgent);
68240
68856
  scheduleCompletedSubagentCleanup(id);
68241
68857
  notifyListeners();
68242
68858
  }
@@ -68244,21 +68860,21 @@ function getSubagentToolCount(agent) {
68244
68860
  return Math.max(agent.toolCalls.length, agent.maxToolCallsSeen);
68245
68861
  }
68246
68862
  function toggleExpanded() {
68247
- store.expanded = !store.expanded;
68863
+ store2.expanded = !store2.expanded;
68248
68864
  notifyListeners();
68249
68865
  }
68250
68866
  function getSubagents() {
68251
- return Array.from(store.agents.values());
68867
+ return Array.from(store2.agents.values());
68252
68868
  }
68253
68869
  function getActiveBackgroundAgents() {
68254
- return Array.from(store.agents.values()).filter((a) => a.silent === true && (a.status === "pending" || a.status === "running"));
68870
+ return Array.from(store2.agents.values()).filter((a) => a.silent === true && (a.status === "pending" || a.status === "running"));
68255
68871
  }
68256
68872
  function clearCompletedSubagents() {
68257
68873
  let removedAny = false;
68258
- for (const [id, agent] of store.agents.entries()) {
68874
+ for (const [id, agent] of store2.agents.entries()) {
68259
68875
  if (agent.status === "completed" || agent.status === "error") {
68260
68876
  clearCompletedSubagentCleanup(id);
68261
- store.agents.delete(id);
68877
+ store2.agents.delete(id);
68262
68878
  removedAny = true;
68263
68879
  }
68264
68880
  }
@@ -68270,14 +68886,14 @@ function clearSubagentsByIds(ids) {
68270
68886
  let removedAny = false;
68271
68887
  for (const id of ids) {
68272
68888
  clearCompletedSubagentCleanup(id);
68273
- removedAny = store.agents.delete(id) || removedAny;
68889
+ removedAny = store2.agents.delete(id) || removedAny;
68274
68890
  }
68275
68891
  if (removedAny) {
68276
68892
  notifyListeners();
68277
68893
  }
68278
68894
  }
68279
68895
  function hasActiveSubagents() {
68280
- for (const agent of store.agents.values()) {
68896
+ for (const agent of store2.agents.values()) {
68281
68897
  if (agent.status === "pending" || agent.status === "running") {
68282
68898
  return true;
68283
68899
  }
@@ -68286,7 +68902,7 @@ function hasActiveSubagents() {
68286
68902
  }
68287
68903
  function interruptActiveSubagents(errorMessage) {
68288
68904
  let anyInterrupted = false;
68289
- for (const [id, agent] of store.agents.entries()) {
68905
+ for (const [id, agent] of store2.agents.entries()) {
68290
68906
  if (agent.status === "pending" || agent.status === "running") {
68291
68907
  const updatedAgent = {
68292
68908
  ...agent,
@@ -68294,7 +68910,7 @@ function interruptActiveSubagents(errorMessage) {
68294
68910
  error: errorMessage,
68295
68911
  durationMs: Date.now() - agent.startTime
68296
68912
  };
68297
- store.agents.set(id, updatedAgent);
68913
+ store2.agents.set(id, updatedAgent);
68298
68914
  scheduleCompletedSubagentCleanup(id);
68299
68915
  anyInterrupted = true;
68300
68916
  }
@@ -68304,9 +68920,9 @@ function interruptActiveSubagents(errorMessage) {
68304
68920
  }
68305
68921
  }
68306
68922
  function subscribe2(listener) {
68307
- store.listeners.add(listener);
68923
+ store2.listeners.add(listener);
68308
68924
  return () => {
68309
- store.listeners.delete(listener);
68925
+ store2.listeners.delete(listener);
68310
68926
  };
68311
68927
  }
68312
68928
  function getSnapshot2() {
@@ -68323,9 +68939,9 @@ function emitStreamEvent(subagentId, event) {
68323
68939
  listener(subagentId, event);
68324
68940
  }
68325
68941
  }
68326
- var store, cachedSnapshot, DEFAULT_COMPLETED_SUBAGENT_RETENTION_MS = 30000, completedSubagentRetentionMs, completedSubagentCleanupTimers, subagentCounter = 0, streamEventListeners;
68942
+ var store2, cachedSnapshot, DEFAULT_COMPLETED_SUBAGENT_RETENTION_MS = 30000, completedSubagentRetentionMs, completedSubagentCleanupTimers, subagentCounter = 0, streamEventListeners;
68327
68943
  var init_subagentState = __esm(() => {
68328
- store = {
68944
+ store2 = {
68329
68945
  agents: new Map,
68330
68946
  expanded: false,
68331
68947
  listeners: new Set
@@ -68697,11 +69313,20 @@ function swapProviderPrefix(parentHandle, recommendedHandle) {
68697
69313
  const modelPortion = recommendedHandle.slice(recommendedProvider.length + 1);
68698
69314
  return `${parentProvider}/${modelPortion}`;
68699
69315
  }
69316
+ function isEnvFlagEnabled(name) {
69317
+ const value = process.env[name]?.trim();
69318
+ if (!value)
69319
+ return false;
69320
+ return value === "1" || value.toLowerCase() === "true";
69321
+ }
68700
69322
  async function resolveSubagentModel(options) {
68701
69323
  const { userModel, recommendedModel, parentModelHandle, billingTier } = options;
68702
69324
  const isFreeTier = billingTier?.toLowerCase() === "free";
68703
69325
  if (userModel)
68704
69326
  return userModel;
69327
+ if (options.subagentType === "reflection" && isEnvFlagEnabled("AUTO_MEMORY")) {
69328
+ return "letta/auto-memory";
69329
+ }
68705
69330
  let recommendedHandle = null;
68706
69331
  if (recommendedModel && recommendedModel !== "inherit") {
68707
69332
  recommendedHandle = resolveModel2(recommendedModel);
@@ -69187,7 +69812,8 @@ async function spawnSubagent(type, prompt, userModel, subagentId, signal, existi
69187
69812
  userModel,
69188
69813
  recommendedModel: config.recommendedModel,
69189
69814
  parentModelHandle,
69190
- billingTier
69815
+ billingTier,
69816
+ subagentType: type
69191
69817
  });
69192
69818
  const baseURL = getBaseURL();
69193
69819
  let finalPrompt = prompt;
@@ -73592,7 +74218,7 @@ __export(exports_analyzer, {
73592
74218
  analyzeApprovalContext: () => analyzeApprovalContext
73593
74219
  });
73594
74220
  import { homedir as homedir19 } from "node:os";
73595
- import { dirname as dirname12, relative as relative8, resolve as resolve23, win32 as win322 } from "node:path";
74221
+ import { dirname as dirname13, relative as relative8, resolve as resolve23, win32 as win322 } from "node:path";
73596
74222
  function normalizeOsPath(path19) {
73597
74223
  return path19.replace(/\\/g, "/");
73598
74224
  }
@@ -73618,7 +74244,7 @@ function isPathWithinDirectory(path19, directory) {
73618
74244
  return !relativePath.startsWith("../") && relativePath !== ".." && !relativePath.startsWith("/") && !/^[a-zA-Z]:\//.test(relativePath);
73619
74245
  }
73620
74246
  function dirnameForContext(path19) {
73621
- return isWindowsPath(path19) ? win322.dirname(path19) : dirname12(path19);
74247
+ return isWindowsPath(path19) ? win322.dirname(path19) : dirname13(path19);
73622
74248
  }
73623
74249
  function formatAbsoluteRulePath(path19) {
73624
74250
  const normalized = normalizeOsPath(path19).replace(/\/+$/, "");
@@ -73679,7 +74305,7 @@ function analyzeReadApproval(filePath, workingDir) {
73679
74305
  };
73680
74306
  }
73681
74307
  const relativePath = normalizeOsPath(relativePathForContext(workingDir, absolutePath));
73682
- const relativeDir = dirname12(relativePath);
74308
+ const relativeDir = dirname13(relativePath);
73683
74309
  const pattern = relativeDir === "." || relativeDir === "" ? "**" : `${relativeDir}/**`;
73684
74310
  return {
73685
74311
  recommendedRule: `Read(${pattern})`,
@@ -77235,13 +77861,13 @@ var init_parseInterval = __esm(() => {
77235
77861
  // src/cron/cronFile.ts
77236
77862
  import { randomBytes } from "node:crypto";
77237
77863
  import {
77238
- existsSync as existsSync22,
77239
- mkdirSync as mkdirSync16,
77240
- readFileSync as readFileSync15,
77864
+ existsSync as existsSync23,
77865
+ mkdirSync as mkdirSync17,
77866
+ readFileSync as readFileSync16,
77241
77867
  renameSync as renameSync2,
77242
77868
  rmSync as rmSync2,
77243
77869
  statSync as statSync6,
77244
- writeFileSync as writeFileSync14
77870
+ writeFileSync as writeFileSync15
77245
77871
  } from "node:fs";
77246
77872
  import { join as join25 } from "node:path";
77247
77873
  function getLettaDir() {
@@ -77260,10 +77886,10 @@ function emptyFile() {
77260
77886
  }
77261
77887
  function readCronFile() {
77262
77888
  const path20 = getCronFilePath();
77263
- if (!existsSync22(path20))
77889
+ if (!existsSync23(path20))
77264
77890
  return emptyFile();
77265
77891
  try {
77266
- const raw = readFileSync15(path20, "utf-8");
77892
+ const raw = readFileSync16(path20, "utf-8");
77267
77893
  const data = JSON.parse(raw);
77268
77894
  if (data.version !== 1)
77269
77895
  return emptyFile();
@@ -77275,31 +77901,76 @@ function readCronFile() {
77275
77901
  function writeCronFile(data) {
77276
77902
  const path20 = getCronFilePath();
77277
77903
  const dir = getLettaDir();
77278
- if (!existsSync22(dir)) {
77279
- mkdirSync16(dir, { recursive: true });
77904
+ if (!existsSync23(dir)) {
77905
+ mkdirSync17(dir, { recursive: true });
77280
77906
  }
77281
77907
  const tmp = `${path20}.tmp`;
77282
- writeFileSync14(tmp, JSON.stringify(data, null, 2), { flush: true });
77908
+ writeFileSync15(tmp, JSON.stringify(data, null, 2), { flush: true });
77283
77909
  renameSync2(tmp, path20);
77284
77910
  }
77285
- function isProcessAlive(pid) {
77911
+ function readLinuxProcessIdentity(pid) {
77912
+ try {
77913
+ const stat5 = readFileSync16(`/proc/${pid}/stat`, "utf8");
77914
+ const endCommand = stat5.lastIndexOf(")");
77915
+ if (endCommand === -1) {
77916
+ return null;
77917
+ }
77918
+ const fields = stat5.slice(endCommand + 2).trim().split(/\s+/);
77919
+ const startTicks = fields[19] ?? null;
77920
+ if (!startTicks) {
77921
+ return null;
77922
+ }
77923
+ let bootId = null;
77924
+ try {
77925
+ bootId = readFileSync16("/proc/sys/kernel/random/boot_id", "utf8").trim() || null;
77926
+ } catch {}
77927
+ return { startTicks, bootId };
77928
+ } catch {
77929
+ return null;
77930
+ }
77931
+ }
77932
+ function readProcessIdentity(pid) {
77933
+ if (readProcessIdentityOverride) {
77934
+ return readProcessIdentityOverride(pid);
77935
+ }
77936
+ return readLinuxProcessIdentity(pid);
77937
+ }
77938
+ function captureProcessIdentity(pid) {
77939
+ const identity = readProcessIdentity(pid);
77940
+ return {
77941
+ process_start_ticks: identity?.startTicks ?? null,
77942
+ boot_id: identity?.bootId ?? null
77943
+ };
77944
+ }
77945
+ function isProcessAlive(pid, owner) {
77286
77946
  try {
77287
77947
  process.kill(pid, 0);
77288
- return true;
77289
77948
  } catch {
77290
77949
  return false;
77291
77950
  }
77951
+ if (owner) {
77952
+ const identity = readProcessIdentity(pid);
77953
+ if (identity) {
77954
+ if (owner.boot_id && identity.bootId && owner.boot_id !== identity.bootId) {
77955
+ return false;
77956
+ }
77957
+ if (owner.process_start_ticks && identity.startTicks && owner.process_start_ticks !== identity.startTicks) {
77958
+ return false;
77959
+ }
77960
+ }
77961
+ }
77962
+ return true;
77292
77963
  }
77293
77964
  function readLockOwner(lockDir) {
77294
77965
  try {
77295
- const raw = readFileSync15(join25(lockDir, LOCK_TOKEN_FILE), "utf-8");
77966
+ const raw = readFileSync16(join25(lockDir, LOCK_TOKEN_FILE), "utf-8");
77296
77967
  return JSON.parse(raw);
77297
77968
  } catch {
77298
77969
  return null;
77299
77970
  }
77300
77971
  }
77301
77972
  function writeLockOwner(lockDir, owner) {
77302
- writeFileSync14(join25(lockDir, LOCK_TOKEN_FILE), JSON.stringify(owner));
77973
+ writeFileSync15(join25(lockDir, LOCK_TOKEN_FILE), JSON.stringify(owner));
77303
77974
  }
77304
77975
  function isLockStale(lockDir) {
77305
77976
  const owner = readLockOwner(lockDir);
@@ -77311,7 +77982,7 @@ function isLockStale(lockDir) {
77311
77982
  return true;
77312
77983
  }
77313
77984
  }
77314
- const pidDead = !isProcessAlive(owner.pid);
77985
+ const pidDead = !isProcessAlive(owner.pid, owner);
77315
77986
  const isOld = Date.now() - owner.acquired_at > LOCK_STALE_AGE_MS;
77316
77987
  return pidDead && isOld;
77317
77988
  }
@@ -77326,11 +77997,12 @@ function acquireLock() {
77326
77997
  const token = randomBytes(4).toString("hex");
77327
77998
  while (Date.now() < deadline) {
77328
77999
  try {
77329
- mkdirSync16(lockDir, { recursive: false });
78000
+ mkdirSync17(lockDir, { recursive: false });
77330
78001
  const owner = {
77331
78002
  pid: process.pid,
77332
78003
  token,
77333
- acquired_at: Date.now()
78004
+ acquired_at: Date.now(),
78005
+ ...captureProcessIdentity(process.pid)
77334
78006
  };
77335
78007
  writeLockOwner(lockDir, owner);
77336
78008
  return {
@@ -77435,7 +78107,7 @@ function addTask(input) {
77435
78107
  data.tasks.push(task2);
77436
78108
  writeCronFile(data);
77437
78109
  let warning;
77438
- if (!data.scheduler_owner || !isProcessAlive(data.scheduler_owner.pid)) {
78110
+ if (!data.scheduler_owner || !isProcessAlive(data.scheduler_owner.pid, data.scheduler_owner)) {
77439
78111
  warning = "No letta server is currently running. This task will only execute when a WS listener is active.";
77440
78112
  }
77441
78113
  return { task: task2, warning };
@@ -77483,15 +78155,17 @@ function claimSchedulerLease() {
77483
78155
  const data = readCronFile();
77484
78156
  const token = randomBytes(4).toString("hex");
77485
78157
  if (data.scheduler_owner) {
77486
- const { pid, token: existingToken } = data.scheduler_owner;
77487
- if (isProcessAlive(pid)) {
78158
+ const existingOwner = data.scheduler_owner;
78159
+ const { pid, token: existingToken } = existingOwner;
78160
+ if (isProcessAlive(pid, existingOwner)) {
77488
78161
  throw new Error(`Scheduler lease held by PID ${pid} (token ${existingToken}). Cannot claim.`);
77489
78162
  }
77490
78163
  }
77491
78164
  data.scheduler_owner = {
77492
78165
  pid: process.pid,
77493
78166
  token,
77494
- started_at: new Date().toISOString()
78167
+ started_at: new Date().toISOString(),
78168
+ ...captureProcessIdentity(process.pid)
77495
78169
  };
77496
78170
  writeCronFile(data);
77497
78171
  return token;
@@ -77551,7 +78225,7 @@ function getCronFileMtime() {
77551
78225
  return 0;
77552
78226
  }
77553
78227
  }
77554
- var CRON_FILE_NAME = "crons.json", LOCK_DIR_NAME = "crons.lock", LOCK_TOKEN_FILE = "owner.json", LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 50, LOCK_STALE_AGE_MS = 30000, MAX_ACTIVE_TASKS_PER_AGENT = 50, TASK_ID_BYTES = 4, GC_AGE_MS;
78228
+ var CRON_FILE_NAME = "crons.json", LOCK_DIR_NAME = "crons.lock", LOCK_TOKEN_FILE = "owner.json", LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 50, LOCK_STALE_AGE_MS = 30000, MAX_ACTIVE_TASKS_PER_AGENT = 50, TASK_ID_BYTES = 4, GC_AGE_MS, readProcessIdentityOverride = null;
77555
78229
  var init_cronFile = __esm(() => {
77556
78230
  init_parseInterval();
77557
78231
  GC_AGE_MS = 24 * 60 * 60 * 1000;
@@ -81837,6 +82511,18 @@ var MIN_SPLIT_LENGTH = 1500;
81837
82511
  function isInteractiveApprovalTool(toolName) {
81838
82512
  return INTERACTIVE_APPROVAL_TOOLS.has(toolName);
81839
82513
  }
82514
+ function getInteractiveApprovalKind(toolName) {
82515
+ switch (toolName) {
82516
+ case "AskUserQuestion":
82517
+ return "ask_user_question";
82518
+ case "EnterPlanMode":
82519
+ return "enter_plan_mode";
82520
+ case "ExitPlanMode":
82521
+ return "exit_plan_mode";
82522
+ default:
82523
+ return null;
82524
+ }
82525
+ }
81840
82526
  function isHeadlessAutoAllowTool(toolName) {
81841
82527
  return HEADLESS_AUTO_ALLOW_TOOLS.has(toolName);
81842
82528
  }
@@ -83127,11 +83813,11 @@ var init_reflectionTranscript = __esm(() => {
83127
83813
 
83128
83814
  // src/cli/helpers/chunkLog.ts
83129
83815
  import {
83130
- existsSync as existsSync24,
83131
- mkdirSync as mkdirSync18,
83816
+ existsSync as existsSync25,
83817
+ mkdirSync as mkdirSync19,
83132
83818
  readdirSync as readdirSync8,
83133
83819
  unlinkSync as unlinkSync7,
83134
- writeFileSync as writeFileSync15
83820
+ writeFileSync as writeFileSync16
83135
83821
  } from "node:fs";
83136
83822
  import { homedir as homedir22 } from "node:os";
83137
83823
  import { join as join29 } from "node:path";
@@ -83228,8 +83914,8 @@ class ChunkLog {
83228
83914
  if (this.dirCreated || !this.agentDir)
83229
83915
  return;
83230
83916
  try {
83231
- if (!existsSync24(this.agentDir)) {
83232
- mkdirSync18(this.agentDir, { recursive: true });
83917
+ if (!existsSync25(this.agentDir)) {
83918
+ mkdirSync19(this.agentDir, { recursive: true });
83233
83919
  }
83234
83920
  this.dirCreated = true;
83235
83921
  } catch (e) {
@@ -83243,7 +83929,7 @@ class ChunkLog {
83243
83929
  try {
83244
83930
  const content = this.buffer.map((entry) => JSON.stringify(entry)).join(`
83245
83931
  `);
83246
- writeFileSync15(this.logPath, `${content}
83932
+ writeFileSync16(this.logPath, `${content}
83247
83933
  `, "utf8");
83248
83934
  } catch (e) {
83249
83935
  debugWarn("chunkLog", `Failed to write ${this.logPath}: ${e instanceof Error ? e.message : String(e)}`);
@@ -83253,7 +83939,7 @@ class ChunkLog {
83253
83939
  if (!this.agentDir)
83254
83940
  return;
83255
83941
  try {
83256
- if (!existsSync24(this.agentDir))
83942
+ if (!existsSync25(this.agentDir))
83257
83943
  return;
83258
83944
  const files = readdirSync8(this.agentDir).filter((f) => f.endsWith(".jsonl")).sort();
83259
83945
  if (files.length >= MAX_SESSION_FILES2) {
@@ -84272,7 +84958,7 @@ var init_constants2 = __esm(() => {
84272
84958
  });
84273
84959
 
84274
84960
  // src/websocket/listener/remote-settings.ts
84275
- import { existsSync as existsSync25, readFileSync as readFileSync16 } from "node:fs";
84961
+ import { existsSync as existsSync26, readFileSync as readFileSync17 } from "node:fs";
84276
84962
  import { mkdir as mkdir8, writeFile as writeFile8 } from "node:fs/promises";
84277
84963
  import { homedir as homedir23 } from "node:os";
84278
84964
  import path20 from "node:path";
@@ -84286,8 +84972,8 @@ function loadRemoteSettings() {
84286
84972
  let loaded = {};
84287
84973
  try {
84288
84974
  const settingsPath = getRemoteSettingsPath();
84289
- if (existsSync25(settingsPath)) {
84290
- const raw = readFileSync16(settingsPath, "utf-8");
84975
+ if (existsSync26(settingsPath)) {
84976
+ const raw = readFileSync17(settingsPath, "utf-8");
84291
84977
  const parsed = JSON.parse(raw);
84292
84978
  loaded = parsed;
84293
84979
  }
@@ -84295,7 +84981,7 @@ function loadRemoteSettings() {
84295
84981
  if (loaded.cwdMap) {
84296
84982
  const validCwdMap = {};
84297
84983
  for (const [key, value] of Object.entries(loaded.cwdMap)) {
84298
- if (typeof value === "string" && existsSync25(value)) {
84984
+ if (typeof value === "string" && existsSync26(value)) {
84299
84985
  validCwdMap[key] = value;
84300
84986
  }
84301
84987
  }
@@ -84322,13 +85008,13 @@ function saveRemoteSettings(updates) {
84322
85008
  function loadLegacyCwdCache() {
84323
85009
  try {
84324
85010
  const legacyPath = path20.join(homedir23(), ".letta", "cwd-cache.json");
84325
- if (!existsSync25(legacyPath))
85011
+ if (!existsSync26(legacyPath))
84326
85012
  return {};
84327
- const raw = readFileSync16(legacyPath, "utf-8");
85013
+ const raw = readFileSync17(legacyPath, "utf-8");
84328
85014
  const parsed = JSON.parse(raw);
84329
85015
  const result = {};
84330
85016
  for (const [key, value] of Object.entries(parsed)) {
84331
- if (typeof value === "string" && existsSync25(value)) {
85017
+ if (typeof value === "string" && existsSync26(value)) {
84332
85018
  result[key] = value;
84333
85019
  }
84334
85020
  }
@@ -88493,7 +89179,46 @@ var init_send = __esm(async () => {
88493
89179
  });
88494
89180
 
88495
89181
  // src/websocket/listener/turn-approval.ts
89182
+ import { readFile as readFile11 } from "node:fs/promises";
88496
89183
  import WebSocket2 from "ws";
89184
+ function getChannelApprovalSourceScopeKey(source) {
89185
+ return [
89186
+ source.channel,
89187
+ source.accountId ?? "",
89188
+ source.chatId,
89189
+ source.threadId ?? ""
89190
+ ].join(":");
89191
+ }
89192
+ function resolveChannelApprovalSource(runtime) {
89193
+ const sources = runtime.activeChannelTurnSources ?? [];
89194
+ if (sources.length === 0) {
89195
+ return null;
89196
+ }
89197
+ const sourcesByScope = new Map;
89198
+ for (const source of sources) {
89199
+ sourcesByScope.set(getChannelApprovalSourceScopeKey(source), source);
89200
+ }
89201
+ if (sourcesByScope.size !== 1) {
89202
+ return null;
89203
+ }
89204
+ return [...sourcesByScope.values()].at(-1) ?? null;
89205
+ }
89206
+ async function maybeReadPlanPreview(toolName, turnPermissionModeState) {
89207
+ if (toolName !== "ExitPlanMode" || !turnPermissionModeState.planFilePath) {
89208
+ return {};
89209
+ }
89210
+ try {
89211
+ const planContent = await readFile11(turnPermissionModeState.planFilePath, "utf8");
89212
+ return {
89213
+ planFilePath: turnPermissionModeState.planFilePath,
89214
+ planContent
89215
+ };
89216
+ } catch {
89217
+ return {
89218
+ planFilePath: turnPermissionModeState.planFilePath
89219
+ };
89220
+ }
89221
+ }
88497
89222
  async function handleApprovalStop(params) {
88498
89223
  const {
88499
89224
  approvals,
@@ -88631,6 +89356,18 @@ async function handleApprovalStop(params) {
88631
89356
  agent_id: agentId,
88632
89357
  conversation_id: conversationId
88633
89358
  };
89359
+ const registry = getChannelRegistry();
89360
+ const channelSource = resolveChannelApprovalSource(runtime);
89361
+ if (registry && channelSource) {
89362
+ await registry.registerPendingControlRequest({
89363
+ requestId,
89364
+ kind: getInteractiveApprovalKind(ac.approval.toolName) ?? "generic_tool_approval",
89365
+ source: channelSource,
89366
+ toolName: ac.approval.toolName,
89367
+ input: ac.parsedArgs,
89368
+ ...await maybeReadPlanPreview(ac.approval.toolName, turnPermissionModeState)
89369
+ });
89370
+ }
88634
89371
  let responseBody;
88635
89372
  try {
88636
89373
  responseBody = await requestApprovalOverWS(runtime, socket, requestId, controlRequest);
@@ -88639,6 +89376,8 @@ async function handleApprovalStop(params) {
88639
89376
  return interruptTermination();
88640
89377
  }
88641
89378
  throw error;
89379
+ } finally {
89380
+ registry?.clearPendingControlRequest(requestId);
88642
89381
  }
88643
89382
  if (shouldInterrupt()) {
88644
89383
  return interruptTermination();
@@ -88841,6 +89580,7 @@ async function handleApprovalStop(params) {
88841
89580
  };
88842
89581
  }
88843
89582
  var init_turn_approval = __esm(async () => {
89583
+ init_registry();
88844
89584
  init_diffPreview();
88845
89585
  init_interactivePolicy();
88846
89586
  init_skill_injection();
@@ -90684,6 +91424,7 @@ async function drainQueuedMessages(runtime, socket, opts, processQueuedTurn) {
90684
91424
  }
90685
91425
  let turnError;
90686
91426
  let didThrow = false;
91427
+ runtime.activeChannelTurnSources = channelTurnSources;
90687
91428
  try {
90688
91429
  await processQueuedTurn(queuedTurn, dequeuedBatch);
90689
91430
  } catch (error) {
@@ -90691,6 +91432,7 @@ async function drainQueuedMessages(runtime, socket, opts, processQueuedTurn) {
90691
91432
  turnError = error instanceof Error ? error.message : String(error);
90692
91433
  throw error;
90693
91434
  } finally {
91435
+ runtime.activeChannelTurnSources = null;
90694
91436
  if (channelTurnSources.length > 0) {
90695
91437
  await dispatchChannelTurnLifecycleEvent({
90696
91438
  type: "finished",
@@ -91787,7 +92529,7 @@ __export(exports_memoryScanner, {
91787
92529
  readFileContent: () => readFileContent,
91788
92530
  getFileNodes: () => getFileNodes
91789
92531
  });
91790
- import { readdirSync as readdirSync9, readFileSync as readFileSync17, statSync as statSync7 } from "node:fs";
92532
+ import { readdirSync as readdirSync9, readFileSync as readFileSync18, statSync as statSync7 } from "node:fs";
91791
92533
  import { join as join30, relative as relative12 } from "node:path";
91792
92534
  function scanMemoryFilesystem(memoryRoot) {
91793
92535
  const nodes = [];
@@ -91852,7 +92594,7 @@ function getFileNodes(nodes) {
91852
92594
  }
91853
92595
  function readFileContent(fullPath) {
91854
92596
  try {
91855
- return readFileSync17(fullPath, "utf-8");
92597
+ return readFileSync18(fullPath, "utf-8");
91856
92598
  } catch {
91857
92599
  return "(unable to read file)";
91858
92600
  }
@@ -91915,6 +92657,63 @@ async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
91915
92657
  }
91916
92658
  emitStateSync(socket, listenerRuntime, scope);
91917
92659
  }
92660
+ async function recoverPendingChannelControlRequests(listener, opts) {
92661
+ const registry = getChannelRegistry();
92662
+ if (!registry) {
92663
+ return;
92664
+ }
92665
+ const pendingEntries = registry.getPendingControlRequests();
92666
+ if (pendingEntries.length === 0) {
92667
+ return;
92668
+ }
92669
+ const recoverFn = opts?.recoverApprovalStateForSync ?? recoverApprovalStateForSync;
92670
+ const entriesByScope = new Map;
92671
+ for (const entry of pendingEntries) {
92672
+ const scope = {
92673
+ agent_id: entry.event.source.agentId,
92674
+ conversation_id: entry.event.source.conversationId
92675
+ };
92676
+ const scopeKey = `${scope.agent_id}:${scope.conversation_id}`;
92677
+ const existing = entriesByScope.get(scopeKey);
92678
+ if (existing) {
92679
+ existing.entries.push(entry);
92680
+ continue;
92681
+ }
92682
+ entriesByScope.set(scopeKey, {
92683
+ scope,
92684
+ entries: [entry]
92685
+ });
92686
+ }
92687
+ for (const { scope, entries } of entriesByScope.values()) {
92688
+ const runtime = getOrCreateScopedRuntime(listener, scope.agent_id, scope.conversation_id);
92689
+ const livePendingRequestIds = new Set(runtime.pendingApprovalResolvers.keys());
92690
+ const shouldRecoverFromBackend = entries.some((entry) => !livePendingRequestIds.has(entry.event.requestId));
92691
+ if (shouldRecoverFromBackend) {
92692
+ try {
92693
+ await recoverFn(runtime, scope);
92694
+ } catch (error) {
92695
+ trackListenerError("listener_channel_control_request_recovery_failed", error, "listener_channel_control_request_recovery");
92696
+ if (isDebugEnabled()) {
92697
+ console.warn("[Listen] Channel control request recovery failed:", error);
92698
+ }
92699
+ continue;
92700
+ }
92701
+ }
92702
+ const recoveredPendingRequestIds = getRecoveredApprovalStateForScope(listener, scope)?.pendingRequestIds ?? new Set;
92703
+ for (const entry of entries) {
92704
+ const requestId = entry.event.requestId;
92705
+ const stillPending = livePendingRequestIds.has(requestId) || recoveredPendingRequestIds.has(requestId);
92706
+ if (!stillPending) {
92707
+ registry.clearPendingControlRequest(requestId);
92708
+ continue;
92709
+ }
92710
+ if (entry.deliveredThisProcess) {
92711
+ continue;
92712
+ }
92713
+ await registry.redeliverPendingControlRequest(requestId);
92714
+ }
92715
+ }
92716
+ }
91918
92717
  function getParsedRuntimeScope(parsed) {
91919
92718
  if (!parsed || typeof parsed !== "object" || !("runtime" in parsed)) {
91920
92719
  return null;
@@ -92215,10 +93014,10 @@ async function handleListMemoryCommand(parsed, socket, overrides = {}) {
92215
93014
  const isMemfsEnabledOnServer2 = overrides.isMemfsEnabledOnServer ?? actualIsMemfsEnabledOnServer;
92216
93015
  const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memoryScanner(), exports_memoryScanner));
92217
93016
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
92218
- const { existsSync: existsSync26 } = await import("node:fs");
93017
+ const { existsSync: existsSync27 } = await import("node:fs");
92219
93018
  const { join: join31, posix: posix2 } = await import("node:path");
92220
93019
  const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
92221
- let memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
93020
+ let memfsInitialized = existsSync27(join31(memoryRoot, ".git"));
92222
93021
  const memfsEnabled = memfsInitialized ? true : await isMemfsEnabledOnServer2(parsed.agent_id);
92223
93022
  if (!memfsEnabled) {
92224
93023
  safeSocketSend(socket, {
@@ -92235,7 +93034,7 @@ async function handleListMemoryCommand(parsed, socket, overrides = {}) {
92235
93034
  }
92236
93035
  if (!memfsInitialized) {
92237
93036
  await ensureLocalMemfsCheckout2(parsed.agent_id);
92238
- memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
93037
+ memfsInitialized = existsSync27(join31(memoryRoot, ".git"));
92239
93038
  }
92240
93039
  if (!memfsInitialized) {
92241
93040
  throw new Error("MemFS is enabled, but the local memory checkout could not be initialized.");
@@ -92852,7 +93651,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
92852
93651
  if (parsed.type === "channel_account_start") {
92853
93652
  try {
92854
93653
  const account = await startChannelAccountLive2(parsed.channel_id, parsed.account_id);
92855
- wireChannelIngress(runtime, socket, opts, processQueuedTurn);
93654
+ await wireChannelIngress(runtime, socket, opts, processQueuedTurn);
92856
93655
  safeSocketSend(socket, {
92857
93656
  type: "channel_account_start_response",
92858
93657
  request_id: parsed.request_id,
@@ -92934,7 +93733,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
92934
93733
  allowedUsers: parsed.config.allowed_users
92935
93734
  }, parsed.account_id);
92936
93735
  if (snapshot.enabled) {
92937
- wireChannelIngress(runtime, socket, opts, processQueuedTurn);
93736
+ await wireChannelIngress(runtime, socket, opts, processQueuedTurn);
92938
93737
  }
92939
93738
  safeSocketSend(socket, {
92940
93739
  type: "channel_set_config_response",
@@ -92961,7 +93760,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
92961
93760
  if (parsed.type === "channel_start") {
92962
93761
  try {
92963
93762
  const summary = await startChannelLive2(parsed.channel_id, parsed.account_id);
92964
- wireChannelIngress(runtime, socket, opts, processQueuedTurn);
93763
+ await wireChannelIngress(runtime, socket, opts, processQueuedTurn);
92965
93764
  safeSocketSend(socket, {
92966
93765
  type: "channel_start_response",
92967
93766
  request_id: parsed.request_id,
@@ -93211,9 +94010,9 @@ function emitSkillsUpdated(socket) {
93211
94010
  }
93212
94011
  async function handleSkillCommand(parsed, socket) {
93213
94012
  const {
93214
- existsSync: existsSync26,
94013
+ existsSync: existsSync27,
93215
94014
  lstatSync: lstatSync2,
93216
- mkdirSync: mkdirSync19,
94015
+ mkdirSync: mkdirSync20,
93217
94016
  rmdirSync,
93218
94017
  symlinkSync,
93219
94018
  unlinkSync: unlinkSync8
@@ -93223,7 +94022,7 @@ async function handleSkillCommand(parsed, socket) {
93223
94022
  const globalSkillsDir = join31(lettaHome, "skills");
93224
94023
  if (parsed.type === "skill_enable") {
93225
94024
  try {
93226
- if (!existsSync26(parsed.skill_path)) {
94025
+ if (!existsSync27(parsed.skill_path)) {
93227
94026
  safeSocketSend(socket, {
93228
94027
  type: "skill_enable_response",
93229
94028
  request_id: parsed.request_id,
@@ -93233,7 +94032,7 @@ async function handleSkillCommand(parsed, socket) {
93233
94032
  return true;
93234
94033
  }
93235
94034
  const skillMdPath = join31(parsed.skill_path, "SKILL.md");
93236
- if (!existsSync26(skillMdPath)) {
94035
+ if (!existsSync27(skillMdPath)) {
93237
94036
  safeSocketSend(socket, {
93238
94037
  type: "skill_enable_response",
93239
94038
  request_id: parsed.request_id,
@@ -93244,8 +94043,8 @@ async function handleSkillCommand(parsed, socket) {
93244
94043
  }
93245
94044
  const linkName = basename10(parsed.skill_path);
93246
94045
  const linkPath = join31(globalSkillsDir, linkName);
93247
- mkdirSync19(globalSkillsDir, { recursive: true });
93248
- if (existsSync26(linkPath)) {
94046
+ mkdirSync20(globalSkillsDir, { recursive: true });
94047
+ if (existsSync27(linkPath)) {
93249
94048
  const stat7 = lstatSync2(linkPath);
93250
94049
  if (stat7.isSymbolicLink()) {
93251
94050
  if (process.platform === "win32") {
@@ -93287,7 +94086,7 @@ async function handleSkillCommand(parsed, socket) {
93287
94086
  if (parsed.type === "skill_disable") {
93288
94087
  try {
93289
94088
  const linkPath = join31(globalSkillsDir, parsed.name);
93290
- if (!existsSync26(linkPath)) {
94089
+ if (!existsSync27(linkPath)) {
93291
94090
  safeSocketSend(socket, {
93292
94091
  type: "skill_disable_response",
93293
94092
  request_id: parsed.request_id,
@@ -93450,7 +94249,7 @@ async function handleReflectionSettingsCommand(parsed, socket, listener) {
93450
94249
  }
93451
94250
  return true;
93452
94251
  }
93453
- function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
94252
+ async function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
93454
94253
  const registry = getChannelRegistry();
93455
94254
  if (!registry)
93456
94255
  return;
@@ -93474,6 +94273,14 @@ function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
93474
94273
  registry.setEventHandler((event) => {
93475
94274
  handleChannelRegistryEvent(event, socket, listener);
93476
94275
  });
94276
+ await recoverPendingChannelControlRequests(listener);
94277
+ registry.setApprovalResponseHandler(async ({ runtime, response }) => handleApprovalResponseInput(listener, {
94278
+ runtime,
94279
+ response,
94280
+ socket,
94281
+ opts,
94282
+ processQueuedTurn
94283
+ }));
93477
94284
  registry.setReady();
93478
94285
  }
93479
94286
  function handleChannelRegistryEvent(event, socket, runtime) {
@@ -93996,7 +94803,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
93996
94803
  const scopedRuntime = getOrCreateScopedRuntime(runtime, queuedTurn.agentId, queuedTurn.conversationId);
93997
94804
  await handleIncomingMessage(queuedTurn, socket, scopedRuntime, opts.onStatusChange, opts.connectionId, dequeuedBatch.batchId);
93998
94805
  };
93999
- socket.on("open", () => {
94806
+ socket.on("open", async () => {
94000
94807
  if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
94001
94808
  return;
94002
94809
  }
@@ -94068,7 +94875,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
94068
94875
  }
94069
94876
  }, 30000);
94070
94877
  startScheduler(socket, opts, processQueuedTurn);
94071
- wireChannelIngress(runtime, socket, opts, processQueuedTurn);
94878
+ await wireChannelIngress(runtime, socket, opts, processQueuedTurn);
94072
94879
  });
94073
94880
  socket.on("message", async (data) => {
94074
94881
  const raw = data.toString();
@@ -94380,8 +95187,8 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
94380
95187
  console.log(`[Listen] Received read_file command: path=${parsed.path}, request_id=${parsed.request_id}`);
94381
95188
  runDetachedListenerTask("read_file", async () => {
94382
95189
  try {
94383
- const { readFile: readFile11 } = await import("node:fs/promises");
94384
- const content = await readFile11(parsed.path, "utf-8");
95190
+ const { readFile: readFile12 } = await import("node:fs/promises");
95191
+ const content = await readFile12(parsed.path, "utf-8");
94385
95192
  console.log(`[Listen] read_file success: ${parsed.path} (${content.length} bytes)`);
94386
95193
  safeSocketSend(socket, {
94387
95194
  type: "read_file_response",
@@ -94411,10 +95218,10 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
94411
95218
  try {
94412
95219
  const { edit: edit2 } = await Promise.resolve().then(() => (init_Edit2(), exports_Edit));
94413
95220
  const { write: write2 } = await Promise.resolve().then(() => (init_Write2(), exports_Write));
94414
- const { readFile: readFile11 } = await import("node:fs/promises");
95221
+ const { readFile: readFile12 } = await import("node:fs/promises");
94415
95222
  let currentContent = null;
94416
95223
  try {
94417
- currentContent = await readFile11(parsed.path, "utf-8");
95224
+ currentContent = await readFile12(parsed.path, "utf-8");
94418
95225
  } catch (readErr) {
94419
95226
  const e = readErr;
94420
95227
  if (e.code !== "ENOENT")
@@ -94522,7 +95329,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
94522
95329
  console.log(`[Listen] Received edit_file command: file_path=${parsed.file_path}, request_id=${parsed.request_id}`);
94523
95330
  runDetachedListenerTask("edit_file", async () => {
94524
95331
  try {
94525
- const { readFile: readFile11 } = await import("node:fs/promises");
95332
+ const { readFile: readFile12 } = await import("node:fs/promises");
94526
95333
  const { edit: edit2 } = await Promise.resolve().then(() => (init_Edit2(), exports_Edit));
94527
95334
  console.log(`[Listen] Executing edit: old_string="${parsed.old_string.slice(0, 50)}${parsed.old_string.length > 50 ? "..." : ""}"`);
94528
95335
  const result = await edit2({
@@ -94538,7 +95345,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
94538
95345
  }
94539
95346
  if (result.replacements > 0) {
94540
95347
  try {
94541
- const contentAfter = await readFile11(parsed.file_path, "utf-8");
95348
+ const contentAfter = await readFile12(parsed.file_path, "utf-8");
94542
95349
  safeSocketSend(socket, {
94543
95350
  type: "file_ops",
94544
95351
  path: parsed.file_path,
@@ -95280,6 +96087,7 @@ var init_client4 = __esm(async () => {
95280
96087
  enqueueChannelTurn,
95281
96088
  scheduleQueuePump,
95282
96089
  replaySyncStateForRuntime,
96090
+ recoverPendingChannelControlRequests,
95283
96091
  recoverApprovalStateForSync,
95284
96092
  clearRecoveredApprovalStateForScope: (runtime, scope) => clearRecoveredApprovalStateForScope(asListenerRuntimeForTests(runtime), scope),
95285
96093
  emitStateSync
@@ -95313,10 +96121,10 @@ __export(exports_debug2, {
95313
96121
  });
95314
96122
  import {
95315
96123
  appendFileSync as appendFileSync3,
95316
- existsSync as existsSync27,
95317
- mkdirSync as mkdirSync20,
96124
+ existsSync as existsSync28,
96125
+ mkdirSync as mkdirSync21,
95318
96126
  readdirSync as readdirSync10,
95319
- readFileSync as readFileSync18,
96127
+ readFileSync as readFileSync19,
95320
96128
  unlinkSync as unlinkSync8
95321
96129
  } from "node:fs";
95322
96130
  import { homedir as homedir27 } from "node:os";
@@ -95368,9 +96176,9 @@ class DebugLogFile2 {
95368
96176
  if (!this.logPath)
95369
96177
  return;
95370
96178
  try {
95371
- if (!existsSync27(this.logPath))
96179
+ if (!existsSync28(this.logPath))
95372
96180
  return;
95373
- const content = readFileSync18(this.logPath, "utf8");
96181
+ const content = readFileSync19(this.logPath, "utf8");
95374
96182
  const lines = content.trimEnd().split(`
95375
96183
  `);
95376
96184
  return lines.slice(-maxLines).join(`
@@ -95383,8 +96191,8 @@ class DebugLogFile2 {
95383
96191
  if (this.dirCreated || !this.agentDir)
95384
96192
  return;
95385
96193
  try {
95386
- if (!existsSync27(this.agentDir)) {
95387
- mkdirSync20(this.agentDir, { recursive: true });
96194
+ if (!existsSync28(this.agentDir)) {
96195
+ mkdirSync21(this.agentDir, { recursive: true });
95388
96196
  }
95389
96197
  this.dirCreated = true;
95390
96198
  } catch {}
@@ -95393,7 +96201,7 @@ class DebugLogFile2 {
95393
96201
  if (!this.agentDir)
95394
96202
  return;
95395
96203
  try {
95396
- if (!existsSync27(this.agentDir))
96204
+ if (!existsSync28(this.agentDir))
95397
96205
  return;
95398
96206
  const files = readdirSync10(this.agentDir).filter((f) => f.endsWith(".log")).sort();
95399
96207
  if (files.length >= MAX_SESSION_FILES3) {
@@ -95452,12 +96260,12 @@ __export(exports_skills2, {
95452
96260
  SKILLS_DIR: () => SKILLS_DIR2,
95453
96261
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
95454
96262
  });
95455
- import { existsSync as existsSync28 } from "node:fs";
95456
- import { readdir as readdir8, readFile as readFile11, realpath as realpath4, stat as stat7 } from "node:fs/promises";
95457
- import { dirname as dirname13, join as join35 } from "node:path";
96263
+ import { existsSync as existsSync29 } from "node:fs";
96264
+ import { readdir as readdir8, readFile as readFile12, realpath as realpath4, stat as stat7 } from "node:fs/promises";
96265
+ import { dirname as dirname14, join as join35 } from "node:path";
95458
96266
  import { fileURLToPath as fileURLToPath8 } from "node:url";
95459
96267
  function getBundledSkillsPath2() {
95460
- const thisDir = dirname13(fileURLToPath8(import.meta.url));
96268
+ const thisDir = dirname14(fileURLToPath8(import.meta.url));
95461
96269
  if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
95462
96270
  return join35(thisDir, "../skills/builtin");
95463
96271
  }
@@ -95476,7 +96284,7 @@ async function getBundledSkills2() {
95476
96284
  }
95477
96285
  async function discoverSkillsFromDir2(skillsPath, source) {
95478
96286
  const errors = [];
95479
- if (!existsSync28(skillsPath)) {
96287
+ if (!existsSync29(skillsPath)) {
95480
96288
  return { skills: [], errors: [] };
95481
96289
  }
95482
96290
  const skills = [];
@@ -95584,7 +96392,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors, source, vi
95584
96392
  }
95585
96393
  }
95586
96394
  async function parseSkillFile2(filePath, rootPath, source) {
95587
- const content = await readFile11(filePath, "utf-8");
96395
+ const content = await readFile12(filePath, "utf-8");
95588
96396
  const { frontmatter, body } = parseFrontmatter(content);
95589
96397
  const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
95590
96398
  const relativePath = filePath.slice(normalizedRoot.length + 1);
@@ -95643,35 +96451,35 @@ __export(exports_fs, {
95643
96451
  writeJsonFile: () => writeJsonFile,
95644
96452
  writeFile: () => writeFile10,
95645
96453
  readJsonFile: () => readJsonFile,
95646
- readFile: () => readFile12,
96454
+ readFile: () => readFile13,
95647
96455
  mkdir: () => mkdir9,
95648
96456
  exists: () => exists2
95649
96457
  });
95650
96458
  import {
95651
- existsSync as existsSync29,
96459
+ existsSync as existsSync30,
95652
96460
  readFileSync as fsReadFileSync2,
95653
96461
  writeFileSync as fsWriteFileSync2,
95654
- mkdirSync as mkdirSync21
96462
+ mkdirSync as mkdirSync22
95655
96463
  } from "node:fs";
95656
- import { dirname as dirname14 } from "node:path";
95657
- async function readFile12(path24) {
96464
+ import { dirname as dirname15 } from "node:path";
96465
+ async function readFile13(path24) {
95658
96466
  return fsReadFileSync2(path24, { encoding: "utf-8" });
95659
96467
  }
95660
96468
  async function writeFile10(path24, content) {
95661
- const dir = dirname14(path24);
95662
- if (!existsSync29(dir)) {
95663
- mkdirSync21(dir, { recursive: true });
96469
+ const dir = dirname15(path24);
96470
+ if (!existsSync30(dir)) {
96471
+ mkdirSync22(dir, { recursive: true });
95664
96472
  }
95665
96473
  fsWriteFileSync2(path24, content, { encoding: "utf-8", flush: true });
95666
96474
  }
95667
96475
  function exists2(path24) {
95668
- return existsSync29(path24);
96476
+ return existsSync30(path24);
95669
96477
  }
95670
96478
  async function mkdir9(path24, options) {
95671
- mkdirSync21(path24, options);
96479
+ mkdirSync22(path24, options);
95672
96480
  }
95673
96481
  async function readJsonFile(path24) {
95674
- const text = await readFile12(path24);
96482
+ const text = await readFile13(path24);
95675
96483
  return JSON.parse(text);
95676
96484
  }
95677
96485
  async function writeJsonFile(path24, data, options) {
@@ -95801,18 +96609,18 @@ var exports_bootstrap_tools = {};
95801
96609
  __export(exports_bootstrap_tools, {
95802
96610
  bootstrapBaseToolsIfNeeded: () => bootstrapBaseToolsIfNeeded
95803
96611
  });
95804
- import { existsSync as existsSync30, mkdirSync as mkdirSync22, writeFileSync as writeFileSync16 } from "node:fs";
96612
+ import { existsSync as existsSync31, mkdirSync as mkdirSync23, writeFileSync as writeFileSync17 } from "node:fs";
95805
96613
  import { homedir as homedir28 } from "node:os";
95806
96614
  import { join as join36 } from "node:path";
95807
96615
  async function bootstrapBaseToolsIfNeeded() {
95808
- if (existsSync30(MARKER_PATH))
96616
+ if (existsSync31(MARKER_PATH))
95809
96617
  return;
95810
96618
  debugLog("bootstrap", "No marker found, bootstrapping base tools...");
95811
96619
  try {
95812
96620
  const success = await addBaseToolsToServer();
95813
96621
  if (success) {
95814
- mkdirSync22(join36(homedir28(), ".letta"), { recursive: true });
95815
- writeFileSync16(MARKER_PATH, new Date().toISOString(), "utf-8");
96622
+ mkdirSync23(join36(homedir28(), ".letta"), { recursive: true });
96623
+ writeFileSync17(MARKER_PATH, new Date().toISOString(), "utf-8");
95816
96624
  }
95817
96625
  } catch (err) {
95818
96626
  debugWarn("bootstrap", `Failed to bootstrap base tools: ${err instanceof Error ? err.message : String(err)}`);
@@ -97510,8 +98318,8 @@ __export(exports_import, {
97510
98318
  extractSkillsFromAf: () => extractSkillsFromAf
97511
98319
  });
97512
98320
  import { createReadStream } from "node:fs";
97513
- import { chmod, mkdir as mkdir10, readFile as readFile13, writeFile as writeFile11 } from "node:fs/promises";
97514
- import { dirname as dirname15, resolve as resolve28 } from "node:path";
98321
+ import { chmod, mkdir as mkdir10, readFile as readFile14, writeFile as writeFile11 } from "node:fs/promises";
98322
+ import { dirname as dirname16, resolve as resolve28 } from "node:path";
97515
98323
  async function importAgentFromFile(options) {
97516
98324
  const client = await getClient();
97517
98325
  const resolvedPath = resolve28(options.filePath);
@@ -97543,7 +98351,7 @@ async function importAgentFromFile(options) {
97543
98351
  }
97544
98352
  async function extractSkillsFromAf(afPath, destDir) {
97545
98353
  const extracted = [];
97546
- const content = await readFile13(afPath, "utf-8");
98354
+ const content = await readFile14(afPath, "utf-8");
97547
98355
  const afData = JSON.parse(content);
97548
98356
  if (!afData.skills || !Array.isArray(afData.skills)) {
97549
98357
  return [];
@@ -97570,7 +98378,7 @@ async function writeSkillFiles(skillDir, files) {
97570
98378
  }
97571
98379
  async function writeSkillFile(skillDir, filePath, content) {
97572
98380
  const fullPath = resolve28(skillDir, filePath);
97573
- await mkdir10(dirname15(fullPath), { recursive: true });
98381
+ await mkdir10(dirname16(fullPath), { recursive: true });
97574
98382
  await writeFile11(fullPath, content, "utf-8");
97575
98383
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
97576
98384
  if (isScript) {
@@ -117533,9 +118341,9 @@ function getFileEditHeader(toolName, toolArgs) {
117533
118341
  const relPath = relative16(cwd2, filePath);
117534
118342
  const displayPath = relPath.startsWith("..") ? filePath : relPath;
117535
118343
  if (t === "write" || t === "write_file" || t === "writefile" || t === "write_file_gemini" || t === "writefilegemini") {
117536
- const { existsSync: existsSync33 } = __require("node:fs");
118344
+ const { existsSync: existsSync34 } = __require("node:fs");
117537
118345
  try {
117538
- if (existsSync33(filePath)) {
118346
+ if (existsSync34(filePath)) {
117539
118347
  return `Overwrite ${displayPath}?`;
117540
118348
  }
117541
118349
  } catch {}
@@ -118312,9 +119120,9 @@ function getHeaderText(fileEdit) {
118312
119120
  const relPath = relative16(cwd2, fileEdit.filePath);
118313
119121
  const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
118314
119122
  if (t === "write" || t === "write_file" || t === "writefile" || t === "write_file_gemini" || t === "writefilegemini") {
118315
- const { existsSync: existsSync33 } = __require("node:fs");
119123
+ const { existsSync: existsSync34 } = __require("node:fs");
118316
119124
  try {
118317
- if (existsSync33(fileEdit.filePath)) {
119125
+ if (existsSync34(fileEdit.filePath)) {
118318
119126
  return `Overwrite ${displayPath}?`;
118319
119127
  }
118320
119128
  } catch {}
@@ -120400,7 +121208,7 @@ html.dark .agent-name { color: var(--text-dim); }
120400
121208
  var init_plan_viewer_template = () => {};
120401
121209
 
120402
121210
  // src/web/generate-plan-viewer.ts
120403
- import { chmodSync as chmodSync2, existsSync as existsSync33, mkdirSync as mkdirSync25, writeFileSync as writeFileSync19 } from "node:fs";
121211
+ import { chmodSync as chmodSync2, existsSync as existsSync34, mkdirSync as mkdirSync26, writeFileSync as writeFileSync20 } from "node:fs";
120404
121212
  import { homedir as homedir32 } from "node:os";
120405
121213
  import { join as join41 } from "node:path";
120406
121214
  async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
@@ -120412,14 +121220,14 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
120412
121220
  };
120413
121221
  const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
120414
121222
  const html = plan_viewer_template_default.replace("<!--LETTA_PLAN_DATA_PLACEHOLDER-->", () => jsonPayload);
120415
- if (!existsSync33(VIEWERS_DIR)) {
120416
- mkdirSync25(VIEWERS_DIR, { recursive: true, mode: 448 });
121223
+ if (!existsSync34(VIEWERS_DIR)) {
121224
+ mkdirSync26(VIEWERS_DIR, { recursive: true, mode: 448 });
120417
121225
  }
120418
121226
  try {
120419
121227
  chmodSync2(VIEWERS_DIR, 448);
120420
121228
  } catch {}
120421
121229
  const filePath = join41(VIEWERS_DIR, "plan.html");
120422
- writeFileSync19(filePath, html);
121230
+ writeFileSync20(filePath, html);
120423
121231
  chmodSync2(filePath, 384);
120424
121232
  const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
120425
121233
  if (!skipOpen) {
@@ -122775,7 +123583,7 @@ var init_pasteRegistry = __esm(() => {
122775
123583
 
122776
123584
  // src/cli/helpers/clipboard.ts
122777
123585
  import { execFileSync as execFileSync3 } from "node:child_process";
122778
- import { existsSync as existsSync34, readFileSync as readFileSync20, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
123586
+ import { existsSync as existsSync35, readFileSync as readFileSync21, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
122779
123587
  import { tmpdir as tmpdir4 } from "node:os";
122780
123588
  import { basename as basename10, extname as extname8, isAbsolute as isAbsolute20, join as join42, resolve as resolve29 } from "node:path";
122781
123589
  function countLines2(text) {
@@ -122827,8 +123635,8 @@ function translatePasteForImages(paste) {
122827
123635
  if (!isAbsolute20(filePath))
122828
123636
  filePath = resolve29(process.cwd(), filePath);
122829
123637
  const ext3 = extname8(filePath || "").toLowerCase();
122830
- if (IMAGE_EXTS.has(ext3) && existsSync34(filePath) && statSync10(filePath).isFile()) {
122831
- const buf = readFileSync20(filePath);
123638
+ if (IMAGE_EXTS.has(ext3) && existsSync35(filePath) && statSync10(filePath).isFile()) {
123639
+ const buf = readFileSync21(filePath);
122832
123640
  const b64 = buf.toString("base64");
122833
123641
  const mt = ext3 === ".png" ? "image/png" : ext3 === ".jpg" || ext3 === ".jpeg" ? "image/jpeg" : ext3 === ".gif" ? "image/gif" : ext3 === ".webp" ? "image/webp" : ext3 === ".bmp" ? "image/bmp" : ext3 === ".svg" ? "image/svg+xml" : ext3 === ".tif" || ext3 === ".tiff" ? "image/tiff" : ext3 === ".heic" ? "image/heic" : ext3 === ".heif" ? "image/heif" : ext3 === ".avif" ? "image/avif" : "application/octet-stream";
122834
123642
  const id = allocateImage({
@@ -122868,11 +123676,11 @@ function getClipboardImageToTempFile() {
122868
123676
  encoding: "utf8",
122869
123677
  stdio: ["ignore", "pipe", "ignore"]
122870
123678
  }).trim();
122871
- if (!uti || !existsSync34(tempPath))
123679
+ if (!uti || !existsSync35(tempPath))
122872
123680
  return null;
122873
123681
  return { tempPath, uti };
122874
123682
  } catch {
122875
- if (existsSync34(tempPath)) {
123683
+ if (existsSync35(tempPath)) {
122876
123684
  try {
122877
123685
  unlinkSync10(tempPath);
122878
123686
  } catch {}
@@ -122888,7 +123696,7 @@ async function tryImportClipboardImageMac() {
122888
123696
  return null;
122889
123697
  const { tempPath, uti } = clipboardResult;
122890
123698
  try {
122891
- const buffer = readFileSync20(tempPath);
123699
+ const buffer = readFileSync21(tempPath);
122892
123700
  try {
122893
123701
  unlinkSync10(tempPath);
122894
123702
  } catch {}
@@ -122905,7 +123713,7 @@ async function tryImportClipboardImageMac() {
122905
123713
  height: resized.height
122906
123714
  };
122907
123715
  } catch (err) {
122908
- if (existsSync34(tempPath)) {
123716
+ if (existsSync35(tempPath)) {
122909
123717
  try {
122910
123718
  unlinkSync10(tempPath);
122911
123719
  } catch {}
@@ -123595,13 +124403,13 @@ __export(exports_terminalKeybindingInstaller, {
123595
124403
  });
123596
124404
  import {
123597
124405
  copyFileSync,
123598
- existsSync as existsSync35,
123599
- mkdirSync as mkdirSync26,
123600
- readFileSync as readFileSync21,
123601
- writeFileSync as writeFileSync20
124406
+ existsSync as existsSync36,
124407
+ mkdirSync as mkdirSync27,
124408
+ readFileSync as readFileSync22,
124409
+ writeFileSync as writeFileSync21
123602
124410
  } from "node:fs";
123603
124411
  import { homedir as homedir33, platform as platform6 } from "node:os";
123604
- import { dirname as dirname16, join as join43 } from "node:path";
124412
+ import { dirname as dirname17, join as join43 } from "node:path";
123605
124413
  function detectTerminalType() {
123606
124414
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
123607
124415
  return "cursor";
@@ -123664,10 +124472,10 @@ function parseKeybindings(content) {
123664
124472
  }
123665
124473
  }
123666
124474
  function keybindingExists(keybindingsPath) {
123667
- if (!existsSync35(keybindingsPath))
124475
+ if (!existsSync36(keybindingsPath))
123668
124476
  return false;
123669
124477
  try {
123670
- const content = readFileSync21(keybindingsPath, { encoding: "utf-8" });
124478
+ const content = readFileSync22(keybindingsPath, { encoding: "utf-8" });
123671
124479
  const keybindings = parseKeybindings(content);
123672
124480
  if (!keybindings)
123673
124481
  return false;
@@ -123677,7 +124485,7 @@ function keybindingExists(keybindingsPath) {
123677
124485
  }
123678
124486
  }
123679
124487
  function createBackup(keybindingsPath) {
123680
- if (!existsSync35(keybindingsPath))
124488
+ if (!existsSync36(keybindingsPath))
123681
124489
  return null;
123682
124490
  const backupPath = `${keybindingsPath}.letta-backup`;
123683
124491
  try {
@@ -123692,15 +124500,15 @@ function installKeybinding(keybindingsPath) {
123692
124500
  if (keybindingExists(keybindingsPath)) {
123693
124501
  return { success: true, alreadyExists: true };
123694
124502
  }
123695
- const parentDir = dirname16(keybindingsPath);
123696
- if (!existsSync35(parentDir)) {
123697
- mkdirSync26(parentDir, { recursive: true });
124503
+ const parentDir = dirname17(keybindingsPath);
124504
+ if (!existsSync36(parentDir)) {
124505
+ mkdirSync27(parentDir, { recursive: true });
123698
124506
  }
123699
124507
  let keybindings = [];
123700
124508
  let backupPath = null;
123701
- if (existsSync35(keybindingsPath)) {
124509
+ if (existsSync36(keybindingsPath)) {
123702
124510
  backupPath = createBackup(keybindingsPath);
123703
- const content = readFileSync21(keybindingsPath, { encoding: "utf-8" });
124511
+ const content = readFileSync22(keybindingsPath, { encoding: "utf-8" });
123704
124512
  const parsed = parseKeybindings(content);
123705
124513
  if (parsed === null) {
123706
124514
  return {
@@ -123713,7 +124521,7 @@ function installKeybinding(keybindingsPath) {
123713
124521
  keybindings.push(SHIFT_ENTER_KEYBINDING);
123714
124522
  const newContent = `${JSON.stringify(keybindings, null, 2)}
123715
124523
  `;
123716
- writeFileSync20(keybindingsPath, newContent, { encoding: "utf-8" });
124524
+ writeFileSync21(keybindingsPath, newContent, { encoding: "utf-8" });
123717
124525
  return {
123718
124526
  success: true,
123719
124527
  backupPath: backupPath ?? undefined
@@ -123728,10 +124536,10 @@ function installKeybinding(keybindingsPath) {
123728
124536
  }
123729
124537
  function removeKeybinding(keybindingsPath) {
123730
124538
  try {
123731
- if (!existsSync35(keybindingsPath)) {
124539
+ if (!existsSync36(keybindingsPath)) {
123732
124540
  return { success: true };
123733
124541
  }
123734
- const content = readFileSync21(keybindingsPath, { encoding: "utf-8" });
124542
+ const content = readFileSync22(keybindingsPath, { encoding: "utf-8" });
123735
124543
  const keybindings = parseKeybindings(content);
123736
124544
  if (!keybindings) {
123737
124545
  return {
@@ -123742,7 +124550,7 @@ function removeKeybinding(keybindingsPath) {
123742
124550
  const filtered = keybindings.filter((kb) => !(kb.key?.toLowerCase() === "shift+enter" && kb.command === "workbench.action.terminal.sendSequence" && kb.when?.includes("terminalFocus")));
123743
124551
  const newContent = `${JSON.stringify(filtered, null, 2)}
123744
124552
  `;
123745
- writeFileSync20(keybindingsPath, newContent, { encoding: "utf-8" });
124553
+ writeFileSync21(keybindingsPath, newContent, { encoding: "utf-8" });
123746
124554
  return { success: true };
123747
124555
  } catch (error) {
123748
124556
  const message = error instanceof Error ? error.message : String(error);
@@ -123796,19 +124604,19 @@ function getWezTermConfigPath() {
123796
124604
  const xdgConfig = process.env.XDG_CONFIG_HOME;
123797
124605
  if (xdgConfig) {
123798
124606
  const xdgPath = join43(xdgConfig, "wezterm", "wezterm.lua");
123799
- if (existsSync35(xdgPath))
124607
+ if (existsSync36(xdgPath))
123800
124608
  return xdgPath;
123801
124609
  }
123802
124610
  const configPath = join43(homedir33(), ".config", "wezterm", "wezterm.lua");
123803
- if (existsSync35(configPath))
124611
+ if (existsSync36(configPath))
123804
124612
  return configPath;
123805
124613
  return join43(homedir33(), ".wezterm.lua");
123806
124614
  }
123807
124615
  function wezTermDeleteFixExists(configPath) {
123808
- if (!existsSync35(configPath))
124616
+ if (!existsSync36(configPath))
123809
124617
  return false;
123810
124618
  try {
123811
- const content = readFileSync21(configPath, { encoding: "utf-8" });
124619
+ const content = readFileSync22(configPath, { encoding: "utf-8" });
123812
124620
  return content.includes("Letta Code: Fix Delete key") || content.includes("key = 'Delete'") && content.includes("SendString") && content.includes("\\x1b[3~");
123813
124621
  } catch {
123814
124622
  return false;
@@ -123822,10 +124630,10 @@ function installWezTermDeleteFix() {
123822
124630
  }
123823
124631
  let content = "";
123824
124632
  let backupPath = null;
123825
- if (existsSync35(configPath)) {
124633
+ if (existsSync36(configPath)) {
123826
124634
  backupPath = `${configPath}.letta-backup`;
123827
124635
  copyFileSync(configPath, backupPath);
123828
- content = readFileSync21(configPath, { encoding: "utf-8" });
124636
+ content = readFileSync22(configPath, { encoding: "utf-8" });
123829
124637
  }
123830
124638
  if (content.includes("return {") && !content.includes("local config")) {
123831
124639
  content = content.replace(/return\s*\{/, "local config = {");
@@ -123851,11 +124659,11 @@ return config`);
123851
124659
  ${WEZTERM_DELETE_FIX}
123852
124660
  `;
123853
124661
  }
123854
- const parentDir = dirname16(configPath);
123855
- if (!existsSync35(parentDir)) {
123856
- mkdirSync26(parentDir, { recursive: true });
124662
+ const parentDir = dirname17(configPath);
124663
+ if (!existsSync36(parentDir)) {
124664
+ mkdirSync27(parentDir, { recursive: true });
123857
124665
  }
123858
- writeFileSync20(configPath, content, { encoding: "utf-8" });
124666
+ writeFileSync21(configPath, content, { encoding: "utf-8" });
123859
124667
  return {
123860
124668
  success: true,
123861
124669
  backupPath: backupPath ?? undefined
@@ -124439,9 +125247,9 @@ __export(exports_custom, {
124439
125247
  GLOBAL_COMMANDS_DIR: () => GLOBAL_COMMANDS_DIR,
124440
125248
  COMMANDS_DIR: () => COMMANDS_DIR
124441
125249
  });
124442
- import { existsSync as existsSync36 } from "node:fs";
124443
- import { readdir as readdir10, readFile as readFile14 } from "node:fs/promises";
124444
- import { basename as basename11, dirname as dirname17, join as join44 } from "node:path";
125250
+ import { existsSync as existsSync37 } from "node:fs";
125251
+ import { readdir as readdir10, readFile as readFile15 } from "node:fs/promises";
125252
+ import { basename as basename11, dirname as dirname18, join as join44 } from "node:path";
124445
125253
  async function getCustomCommands() {
124446
125254
  if (cachedCommands !== null) {
124447
125255
  return cachedCommands;
@@ -124473,7 +125281,7 @@ async function discoverCustomCommands(projectPath = join44(process.cwd(), COMMAN
124473
125281
  return result;
124474
125282
  }
124475
125283
  async function discoverFromDirectory(dirPath, source2) {
124476
- if (!existsSync36(dirPath)) {
125284
+ if (!existsSync37(dirPath)) {
124477
125285
  return [];
124478
125286
  }
124479
125287
  const commands2 = [];
@@ -124499,10 +125307,10 @@ async function findCommandFiles(currentPath, rootPath, commands2, source2) {
124499
125307
  } catch (_error) {}
124500
125308
  }
124501
125309
  async function parseCommandFile(filePath, rootPath, source2) {
124502
- const content = await readFile14(filePath, "utf-8");
125310
+ const content = await readFile15(filePath, "utf-8");
124503
125311
  const { frontmatter, body } = parseFrontmatter(content);
124504
125312
  const id = basename11(filePath, ".md");
124505
- const relativePath = dirname17(filePath).slice(rootPath.length);
125313
+ const relativePath = dirname18(filePath).slice(rootPath.length);
124506
125314
  const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
124507
125315
  let description = getStringField(frontmatter, "description");
124508
125316
  if (!description) {
@@ -129661,15 +130469,15 @@ var init_InputRich = __esm(async () => {
129661
130469
  // src/cli/commands/install-github-app.ts
129662
130470
  import { execFileSync as execFileSync4 } from "node:child_process";
129663
130471
  import {
129664
- existsSync as existsSync37,
129665
- mkdirSync as mkdirSync27,
130472
+ existsSync as existsSync38,
130473
+ mkdirSync as mkdirSync28,
129666
130474
  mkdtempSync,
129667
- readFileSync as readFileSync22,
130475
+ readFileSync as readFileSync23,
129668
130476
  rmSync as rmSync4,
129669
- writeFileSync as writeFileSync21
130477
+ writeFileSync as writeFileSync22
129670
130478
  } from "node:fs";
129671
130479
  import { tmpdir as tmpdir5 } from "node:os";
129672
- import { dirname as dirname18, join as join46 } from "node:path";
130480
+ import { dirname as dirname19, join as join46 } from "node:path";
129673
130481
  function runCommand(command, args, cwd2, input) {
129674
130482
  try {
129675
130483
  return execFileSync4(command, args, {
@@ -129916,18 +130724,18 @@ function runGit6(args, cwd2) {
129916
130724
  }
129917
130725
  function writeWorkflow(repoDir, workflowPath, content) {
129918
130726
  const absolutePath = join46(repoDir, workflowPath);
129919
- if (!existsSync37(dirname18(absolutePath))) {
129920
- mkdirSync27(dirname18(absolutePath), { recursive: true });
130727
+ if (!existsSync38(dirname19(absolutePath))) {
130728
+ mkdirSync28(dirname19(absolutePath), { recursive: true });
129921
130729
  }
129922
130730
  const next = `${content.trimEnd()}
129923
130731
  `;
129924
- if (existsSync37(absolutePath)) {
129925
- const previous = readFileSync22(absolutePath, "utf8");
130732
+ if (existsSync38(absolutePath)) {
130733
+ const previous = readFileSync23(absolutePath, "utf8");
129926
130734
  if (previous === next) {
129927
130735
  return false;
129928
130736
  }
129929
130737
  }
129930
- writeFileSync21(absolutePath, next, "utf8");
130738
+ writeFileSync22(absolutePath, next, "utf8");
129931
130739
  return true;
129932
130740
  }
129933
130741
  function getDefaultBaseBranch(repoDir) {
@@ -134159,7 +134967,7 @@ __export(exports_generate_memory_viewer, {
134159
134967
  generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
134160
134968
  });
134161
134969
  import { execFile as execFileCb5 } from "node:child_process";
134162
- import { chmodSync as chmodSync3, existsSync as existsSync38, mkdirSync as mkdirSync28, writeFileSync as writeFileSync22 } from "node:fs";
134970
+ import { chmodSync as chmodSync3, existsSync as existsSync39, mkdirSync as mkdirSync29, writeFileSync as writeFileSync23 } from "node:fs";
134163
134971
  import { homedir as homedir35 } from "node:os";
134164
134972
  import { join as join47 } from "node:path";
134165
134973
  import { promisify as promisify15 } from "node:util";
@@ -134479,14 +135287,14 @@ async function generateAndOpenMemoryViewer(agentId, options) {
134479
135287
  }
134480
135288
  const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
134481
135289
  const html = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
134482
- if (!existsSync38(VIEWERS_DIR2)) {
134483
- mkdirSync28(VIEWERS_DIR2, { recursive: true, mode: 448 });
135290
+ if (!existsSync39(VIEWERS_DIR2)) {
135291
+ mkdirSync29(VIEWERS_DIR2, { recursive: true, mode: 448 });
134484
135292
  }
134485
135293
  try {
134486
135294
  chmodSync3(VIEWERS_DIR2, 448);
134487
135295
  } catch {}
134488
135296
  const filePath = join47(VIEWERS_DIR2, `memory-${encodeURIComponent(agentId)}.html`);
134489
- writeFileSync22(filePath, html);
135297
+ writeFileSync23(filePath, html);
134490
135298
  chmodSync3(filePath, 384);
134491
135299
  const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
134492
135300
  if (!skipOpen) {
@@ -134512,7 +135320,7 @@ var init_generate_memory_viewer = __esm(() => {
134512
135320
  });
134513
135321
 
134514
135322
  // src/cli/components/MemfsTreeViewer.tsx
134515
- import { existsSync as existsSync39 } from "node:fs";
135323
+ import { existsSync as existsSync40 } from "node:fs";
134516
135324
  function renderTreePrefix(node) {
134517
135325
  let prefix = "";
134518
135326
  for (let i = 0;i < node.depth; i++) {
@@ -134538,7 +135346,7 @@ function MemfsTreeViewer({
134538
135346
  const [status, setStatus] = import_react79.useState(null);
134539
135347
  const statusTimerRef = import_react79.useRef(null);
134540
135348
  const memoryRoot = getMemoryFilesystemRoot(agentId);
134541
- const memoryExists = existsSync39(memoryRoot);
135349
+ const memoryExists = existsSync40(memoryRoot);
134542
135350
  const hasGitRepo = import_react79.useMemo(() => isGitRepo(agentId), [agentId]);
134543
135351
  function showStatus(msg, durationMs) {
134544
135352
  if (statusTimerRef.current)
@@ -137231,7 +138039,7 @@ var init_PersonalitySelector = __esm(async () => {
137231
138039
  });
137232
138040
 
137233
138041
  // src/utils/aws-credentials.ts
137234
- import { readFile as readFile15 } from "node:fs/promises";
138042
+ import { readFile as readFile16 } from "node:fs/promises";
137235
138043
  import { homedir as homedir36 } from "node:os";
137236
138044
  import { join as join48 } from "node:path";
137237
138045
  async function parseAwsCredentials() {
@@ -137239,11 +138047,11 @@ async function parseAwsCredentials() {
137239
138047
  const configPath = join48(homedir36(), ".aws", "config");
137240
138048
  const profiles = new Map;
137241
138049
  try {
137242
- const content = await readFile15(credentialsPath, "utf-8");
138050
+ const content = await readFile16(credentialsPath, "utf-8");
137243
138051
  parseIniFile(content, profiles, false);
137244
138052
  } catch {}
137245
138053
  try {
137246
- const content = await readFile15(configPath, "utf-8");
138054
+ const content = await readFile16(configPath, "utf-8");
137247
138055
  parseIniFile(content, profiles, true);
137248
138056
  } catch {}
137249
138057
  return Array.from(profiles.values());
@@ -142342,18 +143150,18 @@ var init_reasoningTabToggle = __esm(() => {
142342
143150
  });
142343
143151
 
142344
143152
  // src/cli/helpers/startupSystemPromptWarning.ts
142345
- import { existsSync as existsSync40, readdirSync as readdirSync13, readFileSync as readFileSync23 } from "node:fs";
143153
+ import { existsSync as existsSync41, readdirSync as readdirSync13, readFileSync as readFileSync24 } from "node:fs";
142346
143154
  import { join as join49 } from "node:path";
142347
143155
  function estimateSystemTokens(text) {
142348
143156
  return Math.ceil(Buffer.byteLength(text, "utf8") / STARTUP_SYSTEM_PROMPT_ESTIMATED_BYTES_PER_TOKEN);
142349
143157
  }
142350
143158
  function estimateSystemPromptTokensFromMemoryDir(memoryDir) {
142351
143159
  const systemDir = join49(memoryDir, "system");
142352
- if (!existsSync40(systemDir)) {
143160
+ if (!existsSync41(systemDir)) {
142353
143161
  return 0;
142354
143162
  }
142355
143163
  const walkMarkdownFiles = (dir) => {
142356
- if (!existsSync40(dir)) {
143164
+ if (!existsSync41(dir)) {
142357
143165
  return [];
142358
143166
  }
142359
143167
  const out = [];
@@ -142377,7 +143185,7 @@ function estimateSystemPromptTokensFromMemoryDir(memoryDir) {
142377
143185
  return out;
142378
143186
  };
142379
143187
  return walkMarkdownFiles(systemDir).sort().reduce((sum, filePath) => {
142380
- const text = readFileSync23(filePath, "utf8");
143188
+ const text = readFileSync24(filePath, "utf8");
142381
143189
  return sum + estimateSystemTokens(text);
142382
143190
  }, 0);
142383
143191
  }
@@ -143181,16 +143989,16 @@ __export(exports_shellAliases, {
143181
143989
  expandAliases: () => expandAliases,
143182
143990
  clearAliasCache: () => clearAliasCache
143183
143991
  });
143184
- import { existsSync as existsSync41, readFileSync as readFileSync24 } from "node:fs";
143992
+ import { existsSync as existsSync42, readFileSync as readFileSync25 } from "node:fs";
143185
143993
  import { homedir as homedir37 } from "node:os";
143186
143994
  import { join as join50 } from "node:path";
143187
143995
  function parseAliasesFromFile(filePath) {
143188
143996
  const aliases = new Map;
143189
- if (!existsSync41(filePath)) {
143997
+ if (!existsSync42(filePath)) {
143190
143998
  return aliases;
143191
143999
  }
143192
144000
  try {
143193
- const content = readFileSync24(filePath, "utf-8");
144001
+ const content = readFileSync25(filePath, "utf-8");
143194
144002
  const lines = content.split(`
143195
144003
  `);
143196
144004
  let inFunction = false;
@@ -143908,7 +144716,7 @@ var exports_export = {};
143908
144716
  __export(exports_export, {
143909
144717
  packageSkills: () => packageSkills
143910
144718
  });
143911
- import { readdir as readdir11, readFile as readFile16 } from "node:fs/promises";
144719
+ import { readdir as readdir11, readFile as readFile17 } from "node:fs/promises";
143912
144720
  import { relative as relative17, resolve as resolve32 } from "node:path";
143913
144721
  async function packageSkills(agentId, skillsDir) {
143914
144722
  const skills = [];
@@ -143929,7 +144737,7 @@ async function packageSkills(agentId, skillsDir) {
143929
144737
  const skillDir = resolve32(baseDir, entry.name);
143930
144738
  const skillMdPath = resolve32(skillDir, "SKILL.md");
143931
144739
  try {
143932
- await readFile16(skillMdPath, "utf-8");
144740
+ await readFile17(skillMdPath, "utf-8");
143933
144741
  } catch {
143934
144742
  console.warn(`Skipping invalid skill ${entry.name}: missing SKILL.md`);
143935
144743
  continue;
@@ -143961,7 +144769,7 @@ async function readSkillFiles(skillDir) {
143961
144769
  if (entry.isDirectory()) {
143962
144770
  await walk(fullPath);
143963
144771
  } else {
143964
- const content = await readFile16(fullPath, "utf-8");
144772
+ const content = await readFile17(fullPath, "utf-8");
143965
144773
  const relativePath = relative17(skillDir, fullPath).replace(/\\/g, "/");
143966
144774
  files[relativePath] = content;
143967
144775
  }
@@ -144101,7 +144909,7 @@ __export(exports_App, {
144101
144909
  default: () => App2
144102
144910
  });
144103
144911
  import { randomUUID as randomUUID14 } from "node:crypto";
144104
- import { existsSync as existsSync42, readFileSync as readFileSync25, renameSync as renameSync3, writeFileSync as writeFileSync23 } from "node:fs";
144912
+ import { existsSync as existsSync43, readFileSync as readFileSync26, renameSync as renameSync3, writeFileSync as writeFileSync24 } from "node:fs";
144105
144913
  import { homedir as homedir38, tmpdir as tmpdir6 } from "node:os";
144106
144914
  import { join as join51, relative as relative18 } from "node:path";
144107
144915
  function deriveReasoningEffort(modelSettings, llmConfig) {
@@ -144357,18 +145165,18 @@ function saveLastSessionBeforeExit(conversationId) {
144357
145165
  }
144358
145166
  function planFileExists(fallbackPlanFilePath) {
144359
145167
  const planFilePath = permissionMode.getPlanFilePath() ?? fallbackPlanFilePath;
144360
- return !!planFilePath && existsSync42(planFilePath);
145168
+ return !!planFilePath && existsSync43(planFilePath);
144361
145169
  }
144362
145170
  function _readPlanFile(fallbackPlanFilePath) {
144363
145171
  const planFilePath = permissionMode.getPlanFilePath() ?? fallbackPlanFilePath;
144364
145172
  if (!planFilePath) {
144365
145173
  return "No plan file path set.";
144366
145174
  }
144367
- if (!existsSync42(planFilePath)) {
145175
+ if (!existsSync43(planFilePath)) {
144368
145176
  return `Plan file not found at ${planFilePath}`;
144369
145177
  }
144370
145178
  try {
144371
- return readFileSync25(planFilePath, "utf-8");
145179
+ return readFileSync26(planFilePath, "utf-8");
144372
145180
  } catch {
144373
145181
  return `Failed to read plan file at ${planFilePath}`;
144374
145182
  }
@@ -145715,10 +146523,10 @@ function App2({
145715
146523
  if (!planFilePath)
145716
146524
  return;
145717
146525
  try {
145718
- const { readFileSync: readFileSync26, existsSync: existsSync43 } = __require("node:fs");
145719
- if (!existsSync43(planFilePath))
146526
+ const { readFileSync: readFileSync27, existsSync: existsSync44 } = __require("node:fs");
146527
+ if (!existsSync44(planFilePath))
145720
146528
  return;
145721
- const planContent = readFileSync26(planFilePath, "utf-8");
146529
+ const planContent = readFileSync27(planFilePath, "utf-8");
145722
146530
  const previewItem = {
145723
146531
  kind: "approval_preview",
145724
146532
  id: `approval-preview-${toolCallId}`,
@@ -146144,9 +146952,9 @@ Memory may be stale. Try running: git -C ~/.letta/agents/${agentId}/memory pull`
146144
146952
  (async () => {
146145
146953
  try {
146146
146954
  const { watch: watch2 } = await import("node:fs");
146147
- const { existsSync: existsSync43 } = await import("node:fs");
146955
+ const { existsSync: existsSync44 } = await import("node:fs");
146148
146956
  const memRoot = getMemoryFilesystemRoot(agentId);
146149
- if (!existsSync43(memRoot))
146957
+ if (!existsSync44(memRoot))
146150
146958
  return;
146151
146959
  watcher = watch2(memRoot, { recursive: true }, () => {});
146152
146960
  memfsWatcherRef.current = watcher;
@@ -148687,9 +149495,9 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
148687
149495
  join51(memoryRoot, "system", "persona.md"),
148688
149496
  join51(memoryRoot, "memory", "system", "persona.md")
148689
149497
  ];
148690
- const personaPath = personaCandidates.find((candidate) => existsSync42(candidate));
149498
+ const personaPath = personaCandidates.find((candidate) => existsSync43(candidate));
148691
149499
  if (personaPath) {
148692
- const personaContent = readFileSync25(personaPath, "utf-8");
149500
+ const personaContent = readFileSync26(personaPath, "utf-8");
148693
149501
  setCurrentPersonalityId(detectPersonalityFromPersonaFile(personaContent));
148694
149502
  } else {
148695
149503
  setCurrentPersonalityId(null);
@@ -149883,7 +150691,7 @@ Press Enter to continue, or type anything to cancel.`, false, "running");
149883
150691
  fileContent.skills = skills;
149884
150692
  }
149885
150693
  const fileName = exportParams.conversation_id ? `${exportParams.conversation_id}.af` : `${agentId}.af`;
149886
- writeFileSync23(fileName, JSON.stringify(fileContent, null, 2));
150694
+ writeFileSync24(fileName, JSON.stringify(fileContent, null, 2));
149887
150695
  let summary = `AgentFile exported to ${fileName}`;
149888
150696
  if (skills.length > 0) {
149889
150697
  summary += `
@@ -149973,7 +150781,7 @@ Path: ${result2.memoryDir}`, true, msg);
149973
150781
  setCommandRunning(true);
149974
150782
  try {
149975
150783
  const memoryDir = getMemoryFilesystemRoot(agentId);
149976
- if (!existsSync42(memoryDir)) {
150784
+ if (!existsSync43(memoryDir)) {
149977
150785
  updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
149978
150786
  return { submitted: true };
149979
150787
  }
@@ -150005,7 +150813,7 @@ Run \`/memfs sync\` to repopulate from API.`, true, msg);
150005
150813
  await removeGitMemoryTag2(agentId);
150006
150814
  let backupInfo = "";
150007
150815
  const memoryDir = getMemoryFilesystemRoot(agentId);
150008
- if (existsSync42(memoryDir)) {
150816
+ if (existsSync43(memoryDir)) {
150009
150817
  const backupDir = join51(tmpdir6(), `letta-memfs-disable-${agentId}-${Date.now()}`);
150010
150818
  renameSync3(memoryDir, backupDir);
150011
150819
  backupInfo = `
@@ -153914,13 +154722,13 @@ __export(exports_terminalKeybindingInstaller2, {
153914
154722
  });
153915
154723
  import {
153916
154724
  copyFileSync as copyFileSync2,
153917
- existsSync as existsSync43,
153918
- mkdirSync as mkdirSync29,
153919
- readFileSync as readFileSync26,
153920
- writeFileSync as writeFileSync24
154725
+ existsSync as existsSync44,
154726
+ mkdirSync as mkdirSync30,
154727
+ readFileSync as readFileSync27,
154728
+ writeFileSync as writeFileSync25
153921
154729
  } from "node:fs";
153922
154730
  import { homedir as homedir39, platform as platform7 } from "node:os";
153923
- import { dirname as dirname19, join as join52 } from "node:path";
154731
+ import { dirname as dirname20, join as join52 } from "node:path";
153924
154732
  function detectTerminalType2() {
153925
154733
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
153926
154734
  return "cursor";
@@ -153983,10 +154791,10 @@ function parseKeybindings2(content) {
153983
154791
  }
153984
154792
  }
153985
154793
  function keybindingExists2(keybindingsPath) {
153986
- if (!existsSync43(keybindingsPath))
154794
+ if (!existsSync44(keybindingsPath))
153987
154795
  return false;
153988
154796
  try {
153989
- const content = readFileSync26(keybindingsPath, { encoding: "utf-8" });
154797
+ const content = readFileSync27(keybindingsPath, { encoding: "utf-8" });
153990
154798
  const keybindings = parseKeybindings2(content);
153991
154799
  if (!keybindings)
153992
154800
  return false;
@@ -153996,7 +154804,7 @@ function keybindingExists2(keybindingsPath) {
153996
154804
  }
153997
154805
  }
153998
154806
  function createBackup2(keybindingsPath) {
153999
- if (!existsSync43(keybindingsPath))
154807
+ if (!existsSync44(keybindingsPath))
154000
154808
  return null;
154001
154809
  const backupPath = `${keybindingsPath}.letta-backup`;
154002
154810
  try {
@@ -154011,15 +154819,15 @@ function installKeybinding2(keybindingsPath) {
154011
154819
  if (keybindingExists2(keybindingsPath)) {
154012
154820
  return { success: true, alreadyExists: true };
154013
154821
  }
154014
- const parentDir = dirname19(keybindingsPath);
154015
- if (!existsSync43(parentDir)) {
154016
- mkdirSync29(parentDir, { recursive: true });
154822
+ const parentDir = dirname20(keybindingsPath);
154823
+ if (!existsSync44(parentDir)) {
154824
+ mkdirSync30(parentDir, { recursive: true });
154017
154825
  }
154018
154826
  let keybindings = [];
154019
154827
  let backupPath = null;
154020
- if (existsSync43(keybindingsPath)) {
154828
+ if (existsSync44(keybindingsPath)) {
154021
154829
  backupPath = createBackup2(keybindingsPath);
154022
- const content = readFileSync26(keybindingsPath, { encoding: "utf-8" });
154830
+ const content = readFileSync27(keybindingsPath, { encoding: "utf-8" });
154023
154831
  const parsed = parseKeybindings2(content);
154024
154832
  if (parsed === null) {
154025
154833
  return {
@@ -154032,7 +154840,7 @@ function installKeybinding2(keybindingsPath) {
154032
154840
  keybindings.push(SHIFT_ENTER_KEYBINDING2);
154033
154841
  const newContent = `${JSON.stringify(keybindings, null, 2)}
154034
154842
  `;
154035
- writeFileSync24(keybindingsPath, newContent, { encoding: "utf-8" });
154843
+ writeFileSync25(keybindingsPath, newContent, { encoding: "utf-8" });
154036
154844
  return {
154037
154845
  success: true,
154038
154846
  backupPath: backupPath ?? undefined
@@ -154047,10 +154855,10 @@ function installKeybinding2(keybindingsPath) {
154047
154855
  }
154048
154856
  function removeKeybinding2(keybindingsPath) {
154049
154857
  try {
154050
- if (!existsSync43(keybindingsPath)) {
154858
+ if (!existsSync44(keybindingsPath)) {
154051
154859
  return { success: true };
154052
154860
  }
154053
- const content = readFileSync26(keybindingsPath, { encoding: "utf-8" });
154861
+ const content = readFileSync27(keybindingsPath, { encoding: "utf-8" });
154054
154862
  const keybindings = parseKeybindings2(content);
154055
154863
  if (!keybindings) {
154056
154864
  return {
@@ -154061,7 +154869,7 @@ function removeKeybinding2(keybindingsPath) {
154061
154869
  const filtered = keybindings.filter((kb) => !(kb.key?.toLowerCase() === "shift+enter" && kb.command === "workbench.action.terminal.sendSequence" && kb.when?.includes("terminalFocus")));
154062
154870
  const newContent = `${JSON.stringify(filtered, null, 2)}
154063
154871
  `;
154064
- writeFileSync24(keybindingsPath, newContent, { encoding: "utf-8" });
154872
+ writeFileSync25(keybindingsPath, newContent, { encoding: "utf-8" });
154065
154873
  return { success: true };
154066
154874
  } catch (error) {
154067
154875
  const message = error instanceof Error ? error.message : String(error);
@@ -154115,19 +154923,19 @@ function getWezTermConfigPath2() {
154115
154923
  const xdgConfig = process.env.XDG_CONFIG_HOME;
154116
154924
  if (xdgConfig) {
154117
154925
  const xdgPath = join52(xdgConfig, "wezterm", "wezterm.lua");
154118
- if (existsSync43(xdgPath))
154926
+ if (existsSync44(xdgPath))
154119
154927
  return xdgPath;
154120
154928
  }
154121
154929
  const configPath = join52(homedir39(), ".config", "wezterm", "wezterm.lua");
154122
- if (existsSync43(configPath))
154930
+ if (existsSync44(configPath))
154123
154931
  return configPath;
154124
154932
  return join52(homedir39(), ".wezterm.lua");
154125
154933
  }
154126
154934
  function wezTermDeleteFixExists2(configPath) {
154127
- if (!existsSync43(configPath))
154935
+ if (!existsSync44(configPath))
154128
154936
  return false;
154129
154937
  try {
154130
- const content = readFileSync26(configPath, { encoding: "utf-8" });
154938
+ const content = readFileSync27(configPath, { encoding: "utf-8" });
154131
154939
  return content.includes("Letta Code: Fix Delete key") || content.includes("key = 'Delete'") && content.includes("SendString") && content.includes("\\x1b[3~");
154132
154940
  } catch {
154133
154941
  return false;
@@ -154141,10 +154949,10 @@ function installWezTermDeleteFix2() {
154141
154949
  }
154142
154950
  let content = "";
154143
154951
  let backupPath = null;
154144
- if (existsSync43(configPath)) {
154952
+ if (existsSync44(configPath)) {
154145
154953
  backupPath = `${configPath}.letta-backup`;
154146
154954
  copyFileSync2(configPath, backupPath);
154147
- content = readFileSync26(configPath, { encoding: "utf-8" });
154955
+ content = readFileSync27(configPath, { encoding: "utf-8" });
154148
154956
  }
154149
154957
  if (content.includes("return {") && !content.includes("local config")) {
154150
154958
  content = content.replace(/return\s*\{/, "local config = {");
@@ -154170,11 +154978,11 @@ return config`);
154170
154978
  ${WEZTERM_DELETE_FIX2}
154171
154979
  `;
154172
154980
  }
154173
- const parentDir = dirname19(configPath);
154174
- if (!existsSync43(parentDir)) {
154175
- mkdirSync29(parentDir, { recursive: true });
154981
+ const parentDir = dirname20(configPath);
154982
+ if (!existsSync44(parentDir)) {
154983
+ mkdirSync30(parentDir, { recursive: true });
154176
154984
  }
154177
- writeFileSync24(configPath, content, { encoding: "utf-8" });
154985
+ writeFileSync25(configPath, content, { encoding: "utf-8" });
154178
154986
  return {
154179
154987
  success: true,
154180
154988
  backupPath: backupPath ?? undefined
@@ -154739,8 +155547,8 @@ __export(exports_import2, {
154739
155547
  extractSkillsFromAf: () => extractSkillsFromAf2
154740
155548
  });
154741
155549
  import { createReadStream as createReadStream2 } from "node:fs";
154742
- import { chmod as chmod2, mkdir as mkdir11, readFile as readFile17, writeFile as writeFile12 } from "node:fs/promises";
154743
- import { dirname as dirname20, resolve as resolve33 } from "node:path";
155550
+ import { chmod as chmod2, mkdir as mkdir11, readFile as readFile18, writeFile as writeFile12 } from "node:fs/promises";
155551
+ import { dirname as dirname21, resolve as resolve33 } from "node:path";
154744
155552
  async function importAgentFromFile2(options) {
154745
155553
  const client = await getClient();
154746
155554
  const resolvedPath = resolve33(options.filePath);
@@ -154772,7 +155580,7 @@ async function importAgentFromFile2(options) {
154772
155580
  }
154773
155581
  async function extractSkillsFromAf2(afPath, destDir) {
154774
155582
  const extracted = [];
154775
- const content = await readFile17(afPath, "utf-8");
155583
+ const content = await readFile18(afPath, "utf-8");
154776
155584
  const afData = JSON.parse(content);
154777
155585
  if (!afData.skills || !Array.isArray(afData.skills)) {
154778
155586
  return [];
@@ -154799,7 +155607,7 @@ async function writeSkillFiles2(skillDir, files) {
154799
155607
  }
154800
155608
  async function writeSkillFile2(skillDir, filePath, content) {
154801
155609
  const fullPath = resolve33(skillDir, filePath);
154802
- await mkdir11(dirname20(fullPath), { recursive: true });
155610
+ await mkdir11(dirname21(fullPath), { recursive: true });
154803
155611
  await writeFile12(fullPath, content, "utf-8");
154804
155612
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
154805
155613
  if (isScript) {
@@ -154908,7 +155716,7 @@ __export(exports_memoryFilesystem2, {
154908
155716
  MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR2,
154909
155717
  MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
154910
155718
  });
154911
- import { existsSync as existsSync44, mkdirSync as mkdirSync30 } from "node:fs";
155719
+ import { existsSync as existsSync45, mkdirSync as mkdirSync31 } from "node:fs";
154912
155720
  import { homedir as homedir41 } from "node:os";
154913
155721
  import { join as join54 } from "node:path";
154914
155722
  function getMemoryFilesystemRoot2(agentId, homeDir = homedir41()) {
@@ -154920,11 +155728,11 @@ function getMemorySystemDir2(agentId, homeDir = homedir41()) {
154920
155728
  function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir41()) {
154921
155729
  const root = getMemoryFilesystemRoot2(agentId, homeDir);
154922
155730
  const systemDir = getMemorySystemDir2(agentId, homeDir);
154923
- if (!existsSync44(root)) {
154924
- mkdirSync30(root, { recursive: true });
155731
+ if (!existsSync45(root)) {
155732
+ mkdirSync31(root, { recursive: true });
154925
155733
  }
154926
- if (!existsSync44(systemDir)) {
154927
- mkdirSync30(systemDir, { recursive: true });
155734
+ if (!existsSync45(systemDir)) {
155735
+ mkdirSync31(systemDir, { recursive: true });
154928
155736
  }
154929
155737
  }
154930
155738
  async function isMemfsEnabledOnServer2(agentId) {
@@ -159578,8 +160386,8 @@ import { parseArgs as parseArgs7 } from "node:util";
159578
160386
  // src/websocket/listen-log.ts
159579
160387
  import {
159580
160388
  appendFileSync as appendFileSync2,
159581
- existsSync as existsSync23,
159582
- mkdirSync as mkdirSync17,
160389
+ existsSync as existsSync24,
160390
+ mkdirSync as mkdirSync18,
159583
160391
  readdirSync as readdirSync7,
159584
160392
  unlinkSync as unlinkSync6
159585
160393
  } from "node:fs";
@@ -159597,7 +160405,7 @@ function formatTimestamp2() {
159597
160405
  }
159598
160406
  function pruneOldLogs() {
159599
160407
  try {
159600
- if (!existsSync23(REMOTE_LOG_DIR))
160408
+ if (!existsSync24(REMOTE_LOG_DIR))
159601
160409
  return;
159602
160410
  const files = readdirSync7(REMOTE_LOG_DIR).filter((f) => f.endsWith(".log")).sort();
159603
160411
  if (files.length >= MAX_LOG_FILES) {
@@ -159644,8 +160452,8 @@ class RemoteSessionLog {
159644
160452
  if (this.dirCreated)
159645
160453
  return;
159646
160454
  try {
159647
- if (!existsSync23(REMOTE_LOG_DIR)) {
159648
- mkdirSync17(REMOTE_LOG_DIR, { recursive: true });
160455
+ if (!existsSync24(REMOTE_LOG_DIR)) {
160456
+ mkdirSync18(REMOTE_LOG_DIR, { recursive: true });
159649
160457
  }
159650
160458
  this.dirCreated = true;
159651
160459
  } catch {}
@@ -160146,7 +160954,7 @@ async function runListenSubcommand(argv) {
160146
160954
 
160147
160955
  // src/cli/subcommands/memfs.ts
160148
160956
  init_memoryGit();
160149
- import { cpSync, existsSync as existsSync26, mkdirSync as mkdirSync19, rmSync as rmSync3, statSync as statSync8 } from "node:fs";
160957
+ import { cpSync, existsSync as existsSync27, mkdirSync as mkdirSync20, rmSync as rmSync3, statSync as statSync8 } from "node:fs";
160150
160958
  import { readdir as readdir7 } from "node:fs/promises";
160151
160959
  import { homedir as homedir24 } from "node:os";
160152
160960
  import { join as join31 } from "node:path";
@@ -160211,7 +161019,7 @@ function formatBackupTimestamp(date = new Date) {
160211
161019
  }
160212
161020
  async function listBackups(agentId) {
160213
161021
  const agentRoot = getAgentRoot(agentId);
160214
- if (!existsSync26(agentRoot)) {
161022
+ if (!existsSync27(agentRoot)) {
160215
161023
  return [];
160216
161024
  }
160217
161025
  const entries = await readdir7(agentRoot, { withFileTypes: true });
@@ -160298,14 +161106,14 @@ async function runMemfsSubcommand(argv) {
160298
161106
  }
160299
161107
  if (action === "backup") {
160300
161108
  const root = getMemoryRoot(agentId);
160301
- if (!existsSync26(root)) {
161109
+ if (!existsSync27(root)) {
160302
161110
  console.error(`Memory directory not found for agent ${agentId}.`);
160303
161111
  return 1;
160304
161112
  }
160305
161113
  const agentRoot = getAgentRoot(agentId);
160306
161114
  const backupName = `memory-backup-${formatBackupTimestamp()}`;
160307
161115
  const backupPath = join31(agentRoot, backupName);
160308
- if (existsSync26(backupPath)) {
161116
+ if (existsSync27(backupPath)) {
160309
161117
  console.error(`Backup already exists at ${backupPath}`);
160310
161118
  return 1;
160311
161119
  }
@@ -160329,7 +161137,7 @@ async function runMemfsSubcommand(argv) {
160329
161137
  return 1;
160330
161138
  }
160331
161139
  const backupPath = resolveBackupPath(agentId, from);
160332
- if (!existsSync26(backupPath)) {
161140
+ if (!existsSync27(backupPath)) {
160333
161141
  console.error(`Backup not found: ${backupPath}`);
160334
161142
  return 1;
160335
161143
  }
@@ -160351,11 +161159,11 @@ async function runMemfsSubcommand(argv) {
160351
161159
  return 1;
160352
161160
  }
160353
161161
  const root = getMemoryRoot(agentId);
160354
- if (!existsSync26(root)) {
161162
+ if (!existsSync27(root)) {
160355
161163
  console.error(`Memory directory not found for agent ${agentId}.`);
160356
161164
  return 1;
160357
161165
  }
160358
- if (existsSync26(out)) {
161166
+ if (existsSync27(out)) {
160359
161167
  const stat7 = statSync8(out);
160360
161168
  if (stat7.isDirectory()) {
160361
161169
  const contents = await readdir7(out);
@@ -160368,7 +161176,7 @@ async function runMemfsSubcommand(argv) {
160368
161176
  return 1;
160369
161177
  }
160370
161178
  } else {
160371
- mkdirSync19(out, { recursive: true });
161179
+ mkdirSync20(out, { recursive: true });
160372
161180
  }
160373
161181
  cpSync(root, out, { recursive: true });
160374
161182
  console.log(JSON.stringify({ exportedFrom: root, exportedTo: out, agentId }, null, 2));
@@ -163349,9 +164157,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
163349
164157
  }
163350
164158
  } else {
163351
164159
  const { resolve: resolve34 } = await import("path");
163352
- const { existsSync: existsSync45 } = await import("fs");
164160
+ const { existsSync: existsSync46 } = await import("fs");
163353
164161
  const resolvedPath = resolve34(fromAfFile);
163354
- if (!existsSync45(resolvedPath)) {
164162
+ if (!existsSync46(resolvedPath)) {
163355
164163
  console.error(`Error: AgentFile not found: ${resolvedPath}`);
163356
164164
  process.exit(1);
163357
164165
  }
@@ -164230,4 +165038,4 @@ Error during initialization: ${message}`);
164230
165038
  }
164231
165039
  main();
164232
165040
 
164233
- //# debugId=B587994115421B1064756E2164756E21
165041
+ //# debugId=D837155EA6C28D1764756E2164756E21