@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.
- package/letta.js +1166 -358
- 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.
|
|
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
|
|
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 (!
|
|
43138
|
+
if (!existsSync14(path2))
|
|
42678
43139
|
return;
|
|
42679
43140
|
try {
|
|
42680
|
-
const text =
|
|
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
|
-
|
|
43173
|
+
mkdirSync11(dir, { recursive: true });
|
|
42713
43174
|
const routes = getRoutesForChannel(channelId);
|
|
42714
43175
|
const data = { routes };
|
|
42715
|
-
|
|
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
|
|
43266
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "node:fs";
|
|
42806
43267
|
function getStore3(channelId) {
|
|
42807
|
-
let
|
|
42808
|
-
if (!
|
|
42809
|
-
|
|
42810
|
-
stores3.set(channelId,
|
|
43268
|
+
let store2 = stores3.get(channelId);
|
|
43269
|
+
if (!store2) {
|
|
43270
|
+
store2 = { targets: [] };
|
|
43271
|
+
stores3.set(channelId, store2);
|
|
42811
43272
|
}
|
|
42812
|
-
return
|
|
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 (!
|
|
43281
|
+
if (!existsSync15(path2)) {
|
|
42821
43282
|
return;
|
|
42822
43283
|
}
|
|
42823
43284
|
try {
|
|
42824
|
-
const text =
|
|
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
|
-
|
|
42838
|
-
|
|
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
|
|
43307
|
+
const store2 = getStore3(channelId);
|
|
42847
43308
|
const normalizedAccountId = normalizeAccountId3(target.accountId);
|
|
42848
|
-
const existingIndex =
|
|
43309
|
+
const existingIndex = store2.targets.findIndex((candidate) => candidate.targetId === target.targetId && normalizeAccountId3(candidate.accountId) === normalizedAccountId);
|
|
42849
43310
|
if (existingIndex >= 0) {
|
|
42850
|
-
const existing =
|
|
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
|
-
|
|
43322
|
+
store2.targets[existingIndex] = merged;
|
|
42862
43323
|
saveTargetStore(channelId);
|
|
42863
43324
|
return merged;
|
|
42864
43325
|
}
|
|
42865
|
-
|
|
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
|
|
43337
|
+
const store2 = getStore3(channelId);
|
|
42877
43338
|
const normalizedAccountId = normalizeAccountId3(accountId);
|
|
42878
|
-
const nextTargets =
|
|
42879
|
-
if (nextTargets.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
|
-
|
|
43343
|
+
store2.targets = nextTargets;
|
|
42883
43344
|
saveTargetStore(channelId);
|
|
42884
43345
|
return true;
|
|
42885
43346
|
}
|
|
42886
43347
|
function removeChannelTargetsForAccount(channelId, accountId) {
|
|
42887
|
-
const
|
|
43348
|
+
const store2 = getStore3(channelId);
|
|
42888
43349
|
const normalizedAccountId = normalizeAccountId3(accountId);
|
|
42889
|
-
const nextTargets =
|
|
42890
|
-
const removed =
|
|
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
|
-
|
|
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
|
|
44171
|
-
mkdirSync as
|
|
44785
|
+
existsSync as existsSync16,
|
|
44786
|
+
mkdirSync as mkdirSync13,
|
|
44172
44787
|
readdirSync as readdirSync3,
|
|
44173
|
-
readFileSync as
|
|
44788
|
+
readFileSync as readFileSync13,
|
|
44174
44789
|
statSync as statSync2,
|
|
44175
44790
|
unlinkSync as unlinkSync3,
|
|
44176
|
-
writeFileSync as
|
|
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 =
|
|
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 (!
|
|
44449
|
-
|
|
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 (!
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
46242
|
-
|
|
46856
|
+
if (!existsSync17(root)) {
|
|
46857
|
+
mkdirSync14(root, { recursive: true });
|
|
46243
46858
|
}
|
|
46244
|
-
if (!
|
|
46245
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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 (
|
|
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(
|
|
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 (
|
|
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 (
|
|
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(
|
|
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 (!
|
|
53549
|
+
if (!existsSync19(memoryDir)) {
|
|
52934
53550
|
throw new Error(`memory: memory directory does not exist: ${memoryDir}`);
|
|
52935
53551
|
}
|
|
52936
|
-
if (!
|
|
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
|
|
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
|
|
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(
|
|
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 (!
|
|
54100
|
+
if (!existsSync20(memoryDir)) {
|
|
53485
54101
|
throw new Error(`memory_apply_patch: memory directory does not exist: ${memoryDir}`);
|
|
53486
54102
|
}
|
|
53487
|
-
if (!
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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:
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
66536
|
-
this.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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 (!
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
68113
|
-
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
68801
|
+
store2.agents.set(id, agent);
|
|
68186
68802
|
notifyListeners();
|
|
68187
68803
|
}
|
|
68188
68804
|
function updateSubagent(id, updates) {
|
|
68189
|
-
const agent =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
68840
|
+
store2.agents.set(subagentId, updatedAgent);
|
|
68225
68841
|
notifyListeners();
|
|
68226
68842
|
}
|
|
68227
68843
|
function completeSubagent(id, result) {
|
|
68228
|
-
const agent =
|
|
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
|
-
|
|
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
|
-
|
|
68863
|
+
store2.expanded = !store2.expanded;
|
|
68248
68864
|
notifyListeners();
|
|
68249
68865
|
}
|
|
68250
68866
|
function getSubagents() {
|
|
68251
|
-
return Array.from(
|
|
68867
|
+
return Array.from(store2.agents.values());
|
|
68252
68868
|
}
|
|
68253
68869
|
function getActiveBackgroundAgents() {
|
|
68254
|
-
return Array.from(
|
|
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
|
|
68874
|
+
for (const [id, agent] of store2.agents.entries()) {
|
|
68259
68875
|
if (agent.status === "completed" || agent.status === "error") {
|
|
68260
68876
|
clearCompletedSubagentCleanup(id);
|
|
68261
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
68923
|
+
store2.listeners.add(listener);
|
|
68308
68924
|
return () => {
|
|
68309
|
-
|
|
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
|
|
68942
|
+
var store2, cachedSnapshot, DEFAULT_COMPLETED_SUBAGENT_RETENTION_MS = 30000, completedSubagentRetentionMs, completedSubagentCleanupTimers, subagentCounter = 0, streamEventListeners;
|
|
68327
68943
|
var init_subagentState = __esm(() => {
|
|
68328
|
-
|
|
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
|
|
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) :
|
|
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 =
|
|
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
|
|
77239
|
-
mkdirSync as
|
|
77240
|
-
readFileSync as
|
|
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
|
|
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 (!
|
|
77889
|
+
if (!existsSync23(path20))
|
|
77264
77890
|
return emptyFile();
|
|
77265
77891
|
try {
|
|
77266
|
-
const raw =
|
|
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 (!
|
|
77279
|
-
|
|
77904
|
+
if (!existsSync23(dir)) {
|
|
77905
|
+
mkdirSync17(dir, { recursive: true });
|
|
77280
77906
|
}
|
|
77281
77907
|
const tmp = `${path20}.tmp`;
|
|
77282
|
-
|
|
77908
|
+
writeFileSync15(tmp, JSON.stringify(data, null, 2), { flush: true });
|
|
77283
77909
|
renameSync2(tmp, path20);
|
|
77284
77910
|
}
|
|
77285
|
-
function
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
77487
|
-
|
|
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
|
|
83131
|
-
mkdirSync as
|
|
83816
|
+
existsSync as existsSync25,
|
|
83817
|
+
mkdirSync as mkdirSync19,
|
|
83132
83818
|
readdirSync as readdirSync8,
|
|
83133
83819
|
unlinkSync as unlinkSync7,
|
|
83134
|
-
writeFileSync as
|
|
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 (!
|
|
83232
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
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 (
|
|
84290
|
-
const raw =
|
|
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" &&
|
|
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 (!
|
|
85011
|
+
if (!existsSync26(legacyPath))
|
|
84326
85012
|
return {};
|
|
84327
|
-
const raw =
|
|
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" &&
|
|
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
|
|
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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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:
|
|
94013
|
+
existsSync: existsSync27,
|
|
93215
94014
|
lstatSync: lstatSync2,
|
|
93216
|
-
mkdirSync:
|
|
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 (!
|
|
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 (!
|
|
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
|
-
|
|
93248
|
-
if (
|
|
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 (!
|
|
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:
|
|
94384
|
-
const content = await
|
|
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:
|
|
95221
|
+
const { readFile: readFile12 } = await import("node:fs/promises");
|
|
94415
95222
|
let currentContent = null;
|
|
94416
95223
|
try {
|
|
94417
|
-
currentContent = await
|
|
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:
|
|
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
|
|
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
|
|
95317
|
-
mkdirSync as
|
|
96124
|
+
existsSync as existsSync28,
|
|
96125
|
+
mkdirSync as mkdirSync21,
|
|
95318
96126
|
readdirSync as readdirSync10,
|
|
95319
|
-
readFileSync as
|
|
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 (!
|
|
96179
|
+
if (!existsSync28(this.logPath))
|
|
95372
96180
|
return;
|
|
95373
|
-
const content =
|
|
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 (!
|
|
95387
|
-
|
|
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 (!
|
|
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
|
|
95456
|
-
import { readdir as readdir8, readFile as
|
|
95457
|
-
import { dirname as
|
|
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 =
|
|
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 (!
|
|
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
|
|
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: () =>
|
|
96454
|
+
readFile: () => readFile13,
|
|
95647
96455
|
mkdir: () => mkdir9,
|
|
95648
96456
|
exists: () => exists2
|
|
95649
96457
|
});
|
|
95650
96458
|
import {
|
|
95651
|
-
existsSync as
|
|
96459
|
+
existsSync as existsSync30,
|
|
95652
96460
|
readFileSync as fsReadFileSync2,
|
|
95653
96461
|
writeFileSync as fsWriteFileSync2,
|
|
95654
|
-
mkdirSync as
|
|
96462
|
+
mkdirSync as mkdirSync22
|
|
95655
96463
|
} from "node:fs";
|
|
95656
|
-
import { dirname as
|
|
95657
|
-
async function
|
|
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 =
|
|
95662
|
-
if (!
|
|
95663
|
-
|
|
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
|
|
96476
|
+
return existsSync30(path24);
|
|
95669
96477
|
}
|
|
95670
96478
|
async function mkdir9(path24, options) {
|
|
95671
|
-
|
|
96479
|
+
mkdirSync22(path24, options);
|
|
95672
96480
|
}
|
|
95673
96481
|
async function readJsonFile(path24) {
|
|
95674
|
-
const text = await
|
|
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
|
|
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 (
|
|
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
|
-
|
|
95815
|
-
|
|
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
|
|
97514
|
-
import { dirname as
|
|
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
|
|
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(
|
|
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:
|
|
118344
|
+
const { existsSync: existsSync34 } = __require("node:fs");
|
|
117537
118345
|
try {
|
|
117538
|
-
if (
|
|
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:
|
|
119123
|
+
const { existsSync: existsSync34 } = __require("node:fs");
|
|
118316
119124
|
try {
|
|
118317
|
-
if (
|
|
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
|
|
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 (!
|
|
120416
|
-
|
|
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
|
-
|
|
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
|
|
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) &&
|
|
122831
|
-
const buf =
|
|
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 || !
|
|
123679
|
+
if (!uti || !existsSync35(tempPath))
|
|
122872
123680
|
return null;
|
|
122873
123681
|
return { tempPath, uti };
|
|
122874
123682
|
} catch {
|
|
122875
|
-
if (
|
|
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 =
|
|
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 (
|
|
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
|
|
123599
|
-
mkdirSync as
|
|
123600
|
-
readFileSync as
|
|
123601
|
-
writeFileSync as
|
|
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
|
|
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 (!
|
|
124475
|
+
if (!existsSync36(keybindingsPath))
|
|
123668
124476
|
return false;
|
|
123669
124477
|
try {
|
|
123670
|
-
const content =
|
|
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 (!
|
|
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 =
|
|
123696
|
-
if (!
|
|
123697
|
-
|
|
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 (
|
|
124509
|
+
if (existsSync36(keybindingsPath)) {
|
|
123702
124510
|
backupPath = createBackup(keybindingsPath);
|
|
123703
|
-
const content =
|
|
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
|
-
|
|
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 (!
|
|
124539
|
+
if (!existsSync36(keybindingsPath)) {
|
|
123732
124540
|
return { success: true };
|
|
123733
124541
|
}
|
|
123734
|
-
const content =
|
|
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
|
-
|
|
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 (
|
|
124607
|
+
if (existsSync36(xdgPath))
|
|
123800
124608
|
return xdgPath;
|
|
123801
124609
|
}
|
|
123802
124610
|
const configPath = join43(homedir33(), ".config", "wezterm", "wezterm.lua");
|
|
123803
|
-
if (
|
|
124611
|
+
if (existsSync36(configPath))
|
|
123804
124612
|
return configPath;
|
|
123805
124613
|
return join43(homedir33(), ".wezterm.lua");
|
|
123806
124614
|
}
|
|
123807
124615
|
function wezTermDeleteFixExists(configPath) {
|
|
123808
|
-
if (!
|
|
124616
|
+
if (!existsSync36(configPath))
|
|
123809
124617
|
return false;
|
|
123810
124618
|
try {
|
|
123811
|
-
const content =
|
|
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 (
|
|
124633
|
+
if (existsSync36(configPath)) {
|
|
123826
124634
|
backupPath = `${configPath}.letta-backup`;
|
|
123827
124635
|
copyFileSync(configPath, backupPath);
|
|
123828
|
-
content =
|
|
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 =
|
|
123855
|
-
if (!
|
|
123856
|
-
|
|
124662
|
+
const parentDir = dirname17(configPath);
|
|
124663
|
+
if (!existsSync36(parentDir)) {
|
|
124664
|
+
mkdirSync27(parentDir, { recursive: true });
|
|
123857
124665
|
}
|
|
123858
|
-
|
|
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
|
|
124443
|
-
import { readdir as readdir10, readFile as
|
|
124444
|
-
import { basename as basename11, dirname as
|
|
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 (!
|
|
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
|
|
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 =
|
|
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
|
|
129665
|
-
mkdirSync as
|
|
130472
|
+
existsSync as existsSync38,
|
|
130473
|
+
mkdirSync as mkdirSync28,
|
|
129666
130474
|
mkdtempSync,
|
|
129667
|
-
readFileSync as
|
|
130475
|
+
readFileSync as readFileSync23,
|
|
129668
130476
|
rmSync as rmSync4,
|
|
129669
|
-
writeFileSync as
|
|
130477
|
+
writeFileSync as writeFileSync22
|
|
129670
130478
|
} from "node:fs";
|
|
129671
130479
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
129672
|
-
import { dirname as
|
|
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 (!
|
|
129920
|
-
|
|
130727
|
+
if (!existsSync38(dirname19(absolutePath))) {
|
|
130728
|
+
mkdirSync28(dirname19(absolutePath), { recursive: true });
|
|
129921
130729
|
}
|
|
129922
130730
|
const next = `${content.trimEnd()}
|
|
129923
130731
|
`;
|
|
129924
|
-
if (
|
|
129925
|
-
const previous =
|
|
130732
|
+
if (existsSync38(absolutePath)) {
|
|
130733
|
+
const previous = readFileSync23(absolutePath, "utf8");
|
|
129926
130734
|
if (previous === next) {
|
|
129927
130735
|
return false;
|
|
129928
130736
|
}
|
|
129929
130737
|
}
|
|
129930
|
-
|
|
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
|
|
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 (!
|
|
134483
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
138050
|
+
const content = await readFile16(credentialsPath, "utf-8");
|
|
137243
138051
|
parseIniFile(content, profiles, false);
|
|
137244
138052
|
} catch {}
|
|
137245
138053
|
try {
|
|
137246
|
-
const content = await
|
|
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
|
|
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 (!
|
|
143160
|
+
if (!existsSync41(systemDir)) {
|
|
142353
143161
|
return 0;
|
|
142354
143162
|
}
|
|
142355
143163
|
const walkMarkdownFiles = (dir) => {
|
|
142356
|
-
if (!
|
|
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 =
|
|
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
|
|
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 (!
|
|
143997
|
+
if (!existsSync42(filePath)) {
|
|
143190
143998
|
return aliases;
|
|
143191
143999
|
}
|
|
143192
144000
|
try {
|
|
143193
|
-
const content =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 &&
|
|
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 (!
|
|
145175
|
+
if (!existsSync43(planFilePath)) {
|
|
144368
145176
|
return `Plan file not found at ${planFilePath}`;
|
|
144369
145177
|
}
|
|
144370
145178
|
try {
|
|
144371
|
-
return
|
|
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:
|
|
145719
|
-
if (!
|
|
146526
|
+
const { readFileSync: readFileSync27, existsSync: existsSync44 } = __require("node:fs");
|
|
146527
|
+
if (!existsSync44(planFilePath))
|
|
145720
146528
|
return;
|
|
145721
|
-
const planContent =
|
|
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:
|
|
146955
|
+
const { existsSync: existsSync44 } = await import("node:fs");
|
|
146148
146956
|
const memRoot = getMemoryFilesystemRoot(agentId);
|
|
146149
|
-
if (!
|
|
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) =>
|
|
149498
|
+
const personaPath = personaCandidates.find((candidate) => existsSync43(candidate));
|
|
148691
149499
|
if (personaPath) {
|
|
148692
|
-
const personaContent =
|
|
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
|
-
|
|
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 (!
|
|
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 (
|
|
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
|
|
153918
|
-
mkdirSync as
|
|
153919
|
-
readFileSync as
|
|
153920
|
-
writeFileSync as
|
|
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
|
|
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 (!
|
|
154794
|
+
if (!existsSync44(keybindingsPath))
|
|
153987
154795
|
return false;
|
|
153988
154796
|
try {
|
|
153989
|
-
const content =
|
|
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 (!
|
|
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 =
|
|
154015
|
-
if (!
|
|
154016
|
-
|
|
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 (
|
|
154828
|
+
if (existsSync44(keybindingsPath)) {
|
|
154021
154829
|
backupPath = createBackup2(keybindingsPath);
|
|
154022
|
-
const content =
|
|
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
|
-
|
|
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 (!
|
|
154858
|
+
if (!existsSync44(keybindingsPath)) {
|
|
154051
154859
|
return { success: true };
|
|
154052
154860
|
}
|
|
154053
|
-
const content =
|
|
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
|
-
|
|
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 (
|
|
154926
|
+
if (existsSync44(xdgPath))
|
|
154119
154927
|
return xdgPath;
|
|
154120
154928
|
}
|
|
154121
154929
|
const configPath = join52(homedir39(), ".config", "wezterm", "wezterm.lua");
|
|
154122
|
-
if (
|
|
154930
|
+
if (existsSync44(configPath))
|
|
154123
154931
|
return configPath;
|
|
154124
154932
|
return join52(homedir39(), ".wezterm.lua");
|
|
154125
154933
|
}
|
|
154126
154934
|
function wezTermDeleteFixExists2(configPath) {
|
|
154127
|
-
if (!
|
|
154935
|
+
if (!existsSync44(configPath))
|
|
154128
154936
|
return false;
|
|
154129
154937
|
try {
|
|
154130
|
-
const content =
|
|
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 (
|
|
154952
|
+
if (existsSync44(configPath)) {
|
|
154145
154953
|
backupPath = `${configPath}.letta-backup`;
|
|
154146
154954
|
copyFileSync2(configPath, backupPath);
|
|
154147
|
-
content =
|
|
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 =
|
|
154174
|
-
if (!
|
|
154175
|
-
|
|
154981
|
+
const parentDir = dirname20(configPath);
|
|
154982
|
+
if (!existsSync44(parentDir)) {
|
|
154983
|
+
mkdirSync30(parentDir, { recursive: true });
|
|
154176
154984
|
}
|
|
154177
|
-
|
|
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
|
|
154743
|
-
import { dirname as
|
|
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
|
|
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(
|
|
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
|
|
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 (!
|
|
154924
|
-
|
|
155731
|
+
if (!existsSync45(root)) {
|
|
155732
|
+
mkdirSync31(root, { recursive: true });
|
|
154925
155733
|
}
|
|
154926
|
-
if (!
|
|
154927
|
-
|
|
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
|
|
159582
|
-
mkdirSync as
|
|
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 (!
|
|
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 (!
|
|
159648
|
-
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
161162
|
+
if (!existsSync27(root)) {
|
|
160355
161163
|
console.error(`Memory directory not found for agent ${agentId}.`);
|
|
160356
161164
|
return 1;
|
|
160357
161165
|
}
|
|
160358
|
-
if (
|
|
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
|
-
|
|
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:
|
|
164160
|
+
const { existsSync: existsSync46 } = await import("fs");
|
|
163353
164161
|
const resolvedPath = resolve34(fromAfFile);
|
|
163354
|
-
if (!
|
|
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=
|
|
165041
|
+
//# debugId=D837155EA6C28D1764756E2164756E21
|