@letta-ai/letta-code 0.21.10 → 0.21.12
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 +1116 -362
- package/package.json +1 -1
- package/skills/working-in-parallel/SKILL.md +4 -0
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.21.
|
|
3272
|
+
version: "0.21.12",
|
|
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: {
|
|
@@ -6841,7 +6841,7 @@ skills:
|
|
|
6841
6841
|
model: auto
|
|
6842
6842
|
memoryBlocks: none
|
|
6843
6843
|
mode: stateless
|
|
6844
|
-
permissionMode:
|
|
6844
|
+
permissionMode: memory
|
|
6845
6845
|
---
|
|
6846
6846
|
|
|
6847
6847
|
You are a history analysis subagent. You create a git worktree from the agent's memory repo, read conversation history from Claude Code or Codex, then **directly create and update memory files** in your worktree based on what you learn.
|
|
@@ -6921,12 +6921,18 @@ Keep specific correction counts ("corrected 10+ times"), specific file paths, an
|
|
|
6921
6921
|
\`\`\`bash
|
|
6922
6922
|
MEMORY_DIR=~/.letta/agents/$LETTA_PARENT_AGENT_ID/memory
|
|
6923
6923
|
WORKTREE_DIR=~/.letta/agents/$LETTA_PARENT_AGENT_ID/memory-worktrees
|
|
6924
|
-
|
|
6924
|
+
# Run \`date +%s\` first, then paste that exact output below.
|
|
6925
|
+
BRANCH_NAME="migration-<epoch-seconds>"
|
|
6925
6926
|
mkdir -p "$WORKTREE_DIR"
|
|
6926
6927
|
cd "$MEMORY_DIR"
|
|
6927
6928
|
git worktree add "$WORKTREE_DIR/$BRANCH_NAME" -b "$BRANCH_NAME"
|
|
6928
6929
|
\`\`\`
|
|
6929
6930
|
|
|
6931
|
+
Use epoch seconds from a prior \`date +%s\` command so branch names match the
|
|
6932
|
+
old behavior. Do not use shell command substitution like \`$(date +%s)\` in the
|
|
6933
|
+
branch assignment because memory-mode shell permissions deny command
|
|
6934
|
+
substitution.
|
|
6935
|
+
|
|
6930
6936
|
If worktree creation fails (locked index), retry up to 3 times with backoff (sleep 2, 5, 10). Never delete \`.git/index.lock\` manually. All edits go in \`$WORKTREE_DIR/$BRANCH_NAME/\`.
|
|
6931
6937
|
|
|
6932
6938
|
### 2. Read existing memory
|
|
@@ -7043,7 +7049,7 @@ description: Fast initialization of agent memory — reads key project files and
|
|
|
7043
7049
|
tools: Read, Write, Edit, Bash, Glob
|
|
7044
7050
|
model: auto-fast
|
|
7045
7051
|
memoryBlocks: none
|
|
7046
|
-
permissionMode:
|
|
7052
|
+
permissionMode: memory
|
|
7047
7053
|
---
|
|
7048
7054
|
|
|
7049
7055
|
You are a fast memory initialization subagent. Your job is to quickly scan a project and create a **skeleton memory hierarchy** for the parent agent. This hierarchy starts minimal and gets fleshed out as the user keeps interacting with the agent.
|
|
@@ -7151,7 +7157,7 @@ description: Decompose and reorganize memory files into focused, single-purpose
|
|
|
7151
7157
|
tools: Read, Edit, Write, Glob, Grep, Bash, TaskOutput
|
|
7152
7158
|
model: auto
|
|
7153
7159
|
memoryBlocks: none
|
|
7154
|
-
permissionMode:
|
|
7160
|
+
permissionMode: memory
|
|
7155
7161
|
---
|
|
7156
7162
|
|
|
7157
7163
|
You are a memory defragmentation subagent. You work directly on the git-backed memory filesystem to decompose and reorganize memory files.
|
|
@@ -7226,12 +7232,18 @@ making changes.
|
|
|
7226
7232
|
**Create worktree:**
|
|
7227
7233
|
|
|
7228
7234
|
\`\`\`bash
|
|
7229
|
-
|
|
7235
|
+
# Run \`date +%s\` first, then paste that exact output below.
|
|
7236
|
+
BRANCH="defrag-<epoch-seconds>"
|
|
7230
7237
|
mkdir -p "$WORKTREE_DIR"
|
|
7231
7238
|
cd "$MEMORY_DIR"
|
|
7232
7239
|
git worktree add "$WORKTREE_DIR/$BRANCH" -b "$BRANCH"
|
|
7233
7240
|
\`\`\`
|
|
7234
7241
|
|
|
7242
|
+
Use epoch seconds from a prior \`date +%s\` command so branch names match the
|
|
7243
|
+
old behavior. Do not use shell command substitution like \`$(date +%s)\` in the
|
|
7244
|
+
branch assignment because memory-mode shell permissions deny command
|
|
7245
|
+
substitution.
|
|
7246
|
+
|
|
7235
7247
|
All subsequent file operations target the worktree:
|
|
7236
7248
|
\`$WORKTREE_DIR/$BRANCH/system/\` (not the main memory dir).
|
|
7237
7249
|
|
|
@@ -7506,7 +7518,7 @@ tools: Read, Edit, Write, Glob, Grep, Bash, TaskOutput
|
|
|
7506
7518
|
model: auto
|
|
7507
7519
|
memoryBlocks: none
|
|
7508
7520
|
mode: stateless
|
|
7509
|
-
permissionMode:
|
|
7521
|
+
permissionMode: memory
|
|
7510
7522
|
---
|
|
7511
7523
|
|
|
7512
7524
|
You are a reflection subagent — a background agent that asynchronously processes conversations after they occur, similar to a "sleep-time" memory consolidation process.
|
|
@@ -52238,9 +52250,138 @@ var init_hooks = __esm(async () => {
|
|
|
52238
52250
|
init_types();
|
|
52239
52251
|
});
|
|
52240
52252
|
|
|
52241
|
-
// src/permissions/
|
|
52253
|
+
// src/permissions/memoryScope.ts
|
|
52242
52254
|
import { homedir as homedir11 } from "node:os";
|
|
52243
|
-
import { resolve as resolve4 } from "node:path";
|
|
52255
|
+
import { basename, dirname as dirname4, isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
|
|
52256
|
+
function normalizeScopedPath(path4) {
|
|
52257
|
+
const resolvedPath = resolve4(expandHomePath(path4));
|
|
52258
|
+
const normalized = resolvedPath.replace(/\\/g, "/");
|
|
52259
|
+
return normalized.replace(/\/+$/, "") || "/";
|
|
52260
|
+
}
|
|
52261
|
+
function expandHomePath(path4) {
|
|
52262
|
+
const value = path4.trim();
|
|
52263
|
+
const homeDir = homedir11();
|
|
52264
|
+
if (value.startsWith("~/")) {
|
|
52265
|
+
return resolve4(homeDir, value.slice(2));
|
|
52266
|
+
}
|
|
52267
|
+
if (value.startsWith("$HOME/")) {
|
|
52268
|
+
return resolve4(homeDir, value.slice(6));
|
|
52269
|
+
}
|
|
52270
|
+
if (value.startsWith('"$HOME/')) {
|
|
52271
|
+
return resolve4(homeDir, value.slice(7).replace(/"$/, ""));
|
|
52272
|
+
}
|
|
52273
|
+
return value;
|
|
52274
|
+
}
|
|
52275
|
+
function resolveScopedTargetPath(targetPath, workingDirectory) {
|
|
52276
|
+
const trimmedPath = targetPath.trim();
|
|
52277
|
+
if (!trimmedPath)
|
|
52278
|
+
return null;
|
|
52279
|
+
if (trimmedPath.startsWith("~/") || trimmedPath.startsWith("$HOME/")) {
|
|
52280
|
+
return normalizeScopedPath(trimmedPath);
|
|
52281
|
+
}
|
|
52282
|
+
if (isAbsolute2(trimmedPath) || /^[a-zA-Z]:[\\/]/.test(trimmedPath)) {
|
|
52283
|
+
return normalizeScopedPath(trimmedPath);
|
|
52284
|
+
}
|
|
52285
|
+
return normalizeScopedPath(resolve4(workingDirectory, trimmedPath));
|
|
52286
|
+
}
|
|
52287
|
+
function isPathWithinRoots(path4, roots) {
|
|
52288
|
+
const normalizedPath = normalizeScopedPath(path4);
|
|
52289
|
+
return roots.some((root) => {
|
|
52290
|
+
const normalizedRoot = normalizeScopedPath(root);
|
|
52291
|
+
return normalizedPath === normalizedRoot || normalizedPath.startsWith(`${normalizedRoot}/`);
|
|
52292
|
+
});
|
|
52293
|
+
}
|
|
52294
|
+
function addRootAndSiblingWorktree(root, acc) {
|
|
52295
|
+
const normalizedRoot = normalizeScopedPath(root);
|
|
52296
|
+
if (!normalizedRoot) {
|
|
52297
|
+
return;
|
|
52298
|
+
}
|
|
52299
|
+
acc.add(normalizedRoot);
|
|
52300
|
+
const leaf = basename(normalizedRoot);
|
|
52301
|
+
if (leaf === "memory") {
|
|
52302
|
+
acc.add(normalizeScopedPath(resolve4(dirname4(normalizedRoot), "memory-worktrees")));
|
|
52303
|
+
}
|
|
52304
|
+
}
|
|
52305
|
+
function getExplicitEnvRoots(env3) {
|
|
52306
|
+
const orderedRoots = [
|
|
52307
|
+
env3.MEMORY_DIR,
|
|
52308
|
+
env3.LETTA_MEMORY_DIR,
|
|
52309
|
+
env3.PARENT_MEMORY_DIR
|
|
52310
|
+
].map((value) => value?.trim() ?? "").filter((value) => value.length > 0);
|
|
52311
|
+
const explicitRootSet = new Set;
|
|
52312
|
+
for (const root of orderedRoots) {
|
|
52313
|
+
addRootAndSiblingWorktree(root, explicitRootSet);
|
|
52314
|
+
}
|
|
52315
|
+
return {
|
|
52316
|
+
explicitRoots: [...explicitRootSet],
|
|
52317
|
+
primaryRoot: orderedRoots.length > 0 ? normalizeScopedPath(orderedRoots[0]) : null
|
|
52318
|
+
};
|
|
52319
|
+
}
|
|
52320
|
+
function deriveAgentId(env3, explicitAgentId) {
|
|
52321
|
+
const explicit = explicitAgentId?.trim();
|
|
52322
|
+
if (explicit) {
|
|
52323
|
+
return explicit;
|
|
52324
|
+
}
|
|
52325
|
+
const envAgentId = (env3.AGENT_ID || env3.LETTA_AGENT_ID || "").trim();
|
|
52326
|
+
if (envAgentId) {
|
|
52327
|
+
return envAgentId;
|
|
52328
|
+
}
|
|
52329
|
+
try {
|
|
52330
|
+
return getCurrentAgentId().trim();
|
|
52331
|
+
} catch {
|
|
52332
|
+
return null;
|
|
52333
|
+
}
|
|
52334
|
+
}
|
|
52335
|
+
function getFallbackRoots(env3, homeDir, currentAgentId, parentAgentId) {
|
|
52336
|
+
const fallbackRoots = new Set;
|
|
52337
|
+
const resolvedCurrentAgentId = deriveAgentId(env3, currentAgentId);
|
|
52338
|
+
const resolvedParentAgentId = (parentAgentId || env3.LETTA_PARENT_AGENT_ID || "").trim() || null;
|
|
52339
|
+
let primaryRoot = null;
|
|
52340
|
+
if (resolvedCurrentAgentId) {
|
|
52341
|
+
const currentRoot = getMemoryFilesystemRoot(resolvedCurrentAgentId, homeDir);
|
|
52342
|
+
addRootAndSiblingWorktree(currentRoot, fallbackRoots);
|
|
52343
|
+
primaryRoot = normalizeScopedPath(currentRoot);
|
|
52344
|
+
}
|
|
52345
|
+
if (resolvedParentAgentId && resolvedParentAgentId !== resolvedCurrentAgentId) {
|
|
52346
|
+
const parentRoot = getMemoryFilesystemRoot(resolvedParentAgentId, homeDir);
|
|
52347
|
+
addRootAndSiblingWorktree(parentRoot, fallbackRoots);
|
|
52348
|
+
if (!primaryRoot) {
|
|
52349
|
+
primaryRoot = normalizeScopedPath(parentRoot);
|
|
52350
|
+
}
|
|
52351
|
+
}
|
|
52352
|
+
return {
|
|
52353
|
+
roots: [...fallbackRoots],
|
|
52354
|
+
primaryRoot
|
|
52355
|
+
};
|
|
52356
|
+
}
|
|
52357
|
+
function resolveAllowedMemoryRoots(options = {}) {
|
|
52358
|
+
const env3 = options.env ?? process.env;
|
|
52359
|
+
const homeDir = options.homeDir ?? homedir11();
|
|
52360
|
+
const explicit = getExplicitEnvRoots(env3);
|
|
52361
|
+
if (explicit.explicitRoots.length > 0) {
|
|
52362
|
+
return {
|
|
52363
|
+
roots: explicit.explicitRoots,
|
|
52364
|
+
explicitRoots: explicit.explicitRoots,
|
|
52365
|
+
primaryRoot: explicit.primaryRoot,
|
|
52366
|
+
usedFallback: false
|
|
52367
|
+
};
|
|
52368
|
+
}
|
|
52369
|
+
const fallback = getFallbackRoots(env3, homeDir, options.currentAgentId, options.parentAgentId);
|
|
52370
|
+
return {
|
|
52371
|
+
roots: fallback.roots,
|
|
52372
|
+
explicitRoots: [],
|
|
52373
|
+
primaryRoot: fallback.primaryRoot,
|
|
52374
|
+
usedFallback: fallback.roots.length > 0
|
|
52375
|
+
};
|
|
52376
|
+
}
|
|
52377
|
+
var init_memoryScope = __esm(() => {
|
|
52378
|
+
init_context();
|
|
52379
|
+
init_memoryFilesystem();
|
|
52380
|
+
});
|
|
52381
|
+
|
|
52382
|
+
// src/permissions/readOnlyShell.ts
|
|
52383
|
+
import { homedir as homedir12 } from "node:os";
|
|
52384
|
+
import { resolve as resolve5 } from "node:path";
|
|
52244
52385
|
function splitShellSegments(input) {
|
|
52245
52386
|
const segments = [];
|
|
52246
52387
|
let current = "";
|
|
@@ -52312,6 +52453,13 @@ function splitShellSegments(input) {
|
|
|
52312
52453
|
i += 1;
|
|
52313
52454
|
continue;
|
|
52314
52455
|
}
|
|
52456
|
+
if (ch === `
|
|
52457
|
+
` || ch === "\r") {
|
|
52458
|
+
segments.push(current);
|
|
52459
|
+
current = "";
|
|
52460
|
+
i += 1;
|
|
52461
|
+
continue;
|
|
52462
|
+
}
|
|
52315
52463
|
if (ch === "|") {
|
|
52316
52464
|
segments.push(current);
|
|
52317
52465
|
current = "";
|
|
@@ -52503,7 +52651,7 @@ function isUnderAllowedPathRoot(value, allowedPathRoots) {
|
|
|
52503
52651
|
}
|
|
52504
52652
|
const resolvedValue = expandPath(value);
|
|
52505
52653
|
return allowedPathRoots.some((root) => {
|
|
52506
|
-
const normalizedRoot = normalizeSeparators(
|
|
52654
|
+
const normalizedRoot = normalizeSeparators(resolve5(root));
|
|
52507
52655
|
return resolvedValue === normalizedRoot || resolvedValue.startsWith(`${normalizedRoot}/`);
|
|
52508
52656
|
});
|
|
52509
52657
|
}
|
|
@@ -52546,14 +52694,14 @@ function parseGitInvocation(tokens, options) {
|
|
|
52546
52694
|
return { subcommand: null, isSafePath: true };
|
|
52547
52695
|
}
|
|
52548
52696
|
function getAllowedMemoryPrefixes(agentId) {
|
|
52549
|
-
const home =
|
|
52697
|
+
const home = homedir12();
|
|
52550
52698
|
const prefixes = [
|
|
52551
|
-
normalizeSeparators(
|
|
52552
|
-
normalizeSeparators(
|
|
52699
|
+
normalizeSeparators(resolve5(home, ".letta", "agents", agentId, "memory")),
|
|
52700
|
+
normalizeSeparators(resolve5(home, ".letta", "agents", agentId, "memory-worktrees"))
|
|
52553
52701
|
];
|
|
52554
52702
|
const parentId = process.env.LETTA_PARENT_AGENT_ID;
|
|
52555
52703
|
if (parentId && parentId !== agentId) {
|
|
52556
|
-
prefixes.push(normalizeSeparators(
|
|
52704
|
+
prefixes.push(normalizeSeparators(resolve5(home, ".letta", "agents", parentId, "memory")), normalizeSeparators(resolve5(home, ".letta", "agents", parentId, "memory-worktrees")));
|
|
52557
52705
|
}
|
|
52558
52706
|
return prefixes;
|
|
52559
52707
|
}
|
|
@@ -52561,122 +52709,315 @@ function normalizeSeparators(p) {
|
|
|
52561
52709
|
return p.replace(/\\/g, "/");
|
|
52562
52710
|
}
|
|
52563
52711
|
function expandPath(p) {
|
|
52564
|
-
|
|
52565
|
-
|
|
52566
|
-
|
|
52712
|
+
return normalizeScopedPath(p);
|
|
52713
|
+
}
|
|
52714
|
+
function expandScopedVariables(value, env3, shellVars) {
|
|
52715
|
+
let unresolved = false;
|
|
52716
|
+
const expanded = value.replace(/\$(?:{([A-Za-z_][A-Za-z0-9_]*)}|([A-Za-z_][A-Za-z0-9_]*))/g, (_match, bracedName, bareName) => {
|
|
52717
|
+
const name = bracedName || bareName;
|
|
52718
|
+
if (!name) {
|
|
52719
|
+
unresolved = true;
|
|
52720
|
+
return "";
|
|
52721
|
+
}
|
|
52722
|
+
if (name === "HOME") {
|
|
52723
|
+
return homedir12();
|
|
52724
|
+
}
|
|
52725
|
+
const scopedValue = shellVars[name];
|
|
52726
|
+
if (typeof scopedValue === "string") {
|
|
52727
|
+
return scopedValue;
|
|
52728
|
+
}
|
|
52729
|
+
const envValue = env3[name];
|
|
52730
|
+
if (typeof envValue === "string") {
|
|
52731
|
+
return envValue;
|
|
52732
|
+
}
|
|
52733
|
+
unresolved = true;
|
|
52734
|
+
return "";
|
|
52735
|
+
});
|
|
52736
|
+
return unresolved ? null : expanded;
|
|
52737
|
+
}
|
|
52738
|
+
function normalizeScopePath(path4, cwd2, env3, shellVars) {
|
|
52739
|
+
const expandedPath = expandScopedVariables(path4, env3, shellVars);
|
|
52740
|
+
if (!expandedPath) {
|
|
52741
|
+
return null;
|
|
52567
52742
|
}
|
|
52568
|
-
if (
|
|
52569
|
-
return
|
|
52743
|
+
if (expandedPath.startsWith("~/") || expandedPath.startsWith("$HOME/") || expandedPath.startsWith('"$HOME/') || expandedPath.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(expandedPath)) {
|
|
52744
|
+
return normalizeScopedPath(expandedPath);
|
|
52570
52745
|
}
|
|
52571
|
-
if (
|
|
52572
|
-
return
|
|
52746
|
+
if (cwd2) {
|
|
52747
|
+
return normalizeScopedPath(resolve5(cwd2, expandedPath));
|
|
52573
52748
|
}
|
|
52574
|
-
return
|
|
52749
|
+
return null;
|
|
52750
|
+
}
|
|
52751
|
+
function parseScopedAssignmentToken(token) {
|
|
52752
|
+
const match = token.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
52753
|
+
if (!match) {
|
|
52754
|
+
return null;
|
|
52755
|
+
}
|
|
52756
|
+
return {
|
|
52757
|
+
name: match[1] ?? "",
|
|
52758
|
+
value: stripQuotes(match[2] ?? "")
|
|
52759
|
+
};
|
|
52760
|
+
}
|
|
52761
|
+
function applyScopedAssignments(tokens, env3, shellVars) {
|
|
52762
|
+
if (tokens.length === 0) {
|
|
52763
|
+
return false;
|
|
52764
|
+
}
|
|
52765
|
+
for (const token of tokens) {
|
|
52766
|
+
const assignment = parseScopedAssignmentToken(token);
|
|
52767
|
+
if (!assignment) {
|
|
52768
|
+
return false;
|
|
52769
|
+
}
|
|
52770
|
+
const expandedValue = expandScopedVariables(assignment.value, env3, shellVars);
|
|
52771
|
+
if (expandedValue === null) {
|
|
52772
|
+
return false;
|
|
52773
|
+
}
|
|
52774
|
+
if (expandedValue.startsWith("~/") || expandedValue.startsWith("$HOME/") || expandedValue.startsWith('"$HOME/') || expandedValue.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(expandedValue)) {
|
|
52775
|
+
shellVars[assignment.name] = normalizeScopedPath(expandedValue);
|
|
52776
|
+
} else {
|
|
52777
|
+
shellVars[assignment.name] = expandedValue;
|
|
52778
|
+
}
|
|
52779
|
+
}
|
|
52780
|
+
return true;
|
|
52575
52781
|
}
|
|
52576
|
-
function
|
|
52577
|
-
|
|
52578
|
-
|
|
52782
|
+
function hasUnsafeRebaseOption(tokens, startIndex) {
|
|
52783
|
+
for (let i = startIndex;i < tokens.length; i += 1) {
|
|
52784
|
+
const token = tokens[i];
|
|
52785
|
+
if (!token) {
|
|
52786
|
+
continue;
|
|
52787
|
+
}
|
|
52788
|
+
const lower = token.toLowerCase();
|
|
52789
|
+
if (lower === "--exec" || lower.startsWith("--exec=") || lower === "-x" || lower.startsWith("-x") && lower.length > 2 || lower === "--interactive" || lower === "-i" || lower === "--edit-todo") {
|
|
52790
|
+
return true;
|
|
52791
|
+
}
|
|
52792
|
+
}
|
|
52793
|
+
return false;
|
|
52579
52794
|
}
|
|
52580
|
-
function
|
|
52795
|
+
function parseScopedGitInvocation(tokens, cwd2, allowedRoots, env3, shellVars) {
|
|
52796
|
+
let index = 1;
|
|
52797
|
+
let resolvedCwd = cwd2;
|
|
52798
|
+
while (index < tokens.length) {
|
|
52799
|
+
const token = tokens[index];
|
|
52800
|
+
if (!token) {
|
|
52801
|
+
index += 1;
|
|
52802
|
+
continue;
|
|
52803
|
+
}
|
|
52804
|
+
if (token === "-C") {
|
|
52805
|
+
const pathToken = tokens[index + 1];
|
|
52806
|
+
if (!pathToken) {
|
|
52807
|
+
return {
|
|
52808
|
+
subcommand: null,
|
|
52809
|
+
worktreeSubcommand: null,
|
|
52810
|
+
resolvedCwd,
|
|
52811
|
+
isSafe: false
|
|
52812
|
+
};
|
|
52813
|
+
}
|
|
52814
|
+
const nextCwd = normalizeScopePath(pathToken, resolvedCwd, env3, shellVars);
|
|
52815
|
+
if (!nextCwd || !isPathWithinRoots(nextCwd, allowedRoots)) {
|
|
52816
|
+
return {
|
|
52817
|
+
subcommand: null,
|
|
52818
|
+
worktreeSubcommand: null,
|
|
52819
|
+
resolvedCwd,
|
|
52820
|
+
isSafe: false
|
|
52821
|
+
};
|
|
52822
|
+
}
|
|
52823
|
+
resolvedCwd = nextCwd;
|
|
52824
|
+
index += 2;
|
|
52825
|
+
continue;
|
|
52826
|
+
}
|
|
52827
|
+
if (token === "-c") {
|
|
52828
|
+
const configToken = tokens[index + 1];
|
|
52829
|
+
if (!configToken) {
|
|
52830
|
+
return {
|
|
52831
|
+
subcommand: null,
|
|
52832
|
+
worktreeSubcommand: null,
|
|
52833
|
+
resolvedCwd,
|
|
52834
|
+
isSafe: false
|
|
52835
|
+
};
|
|
52836
|
+
}
|
|
52837
|
+
if (!/^http\.extraHeader=/.test(configToken)) {
|
|
52838
|
+
return {
|
|
52839
|
+
subcommand: null,
|
|
52840
|
+
worktreeSubcommand: null,
|
|
52841
|
+
resolvedCwd,
|
|
52842
|
+
isSafe: false
|
|
52843
|
+
};
|
|
52844
|
+
}
|
|
52845
|
+
index += 2;
|
|
52846
|
+
continue;
|
|
52847
|
+
}
|
|
52848
|
+
const subcommand = token;
|
|
52849
|
+
if (!SAFE_MEMORY_GIT_SUBCOMMANDS.has(subcommand)) {
|
|
52850
|
+
if (resolvedCwd && SAFE_MEMORY_COMMANDS.has("git")) {
|
|
52851
|
+
const rawSegment = tokens.join(" ");
|
|
52852
|
+
if (subcommand === "ls-tree" && !/\s-o\b/.test(rawSegment)) {
|
|
52853
|
+
return {
|
|
52854
|
+
subcommand,
|
|
52855
|
+
worktreeSubcommand: null,
|
|
52856
|
+
resolvedCwd,
|
|
52857
|
+
isSafe: true
|
|
52858
|
+
};
|
|
52859
|
+
}
|
|
52860
|
+
}
|
|
52861
|
+
return {
|
|
52862
|
+
subcommand,
|
|
52863
|
+
worktreeSubcommand: null,
|
|
52864
|
+
resolvedCwd,
|
|
52865
|
+
isSafe: false
|
|
52866
|
+
};
|
|
52867
|
+
}
|
|
52868
|
+
const worktreeSubcommand = subcommand === "worktree" ? tokens[index + 1] ?? null : null;
|
|
52869
|
+
if (subcommand === "worktree" && worktreeSubcommand && !new Set(["add", "remove", "list"]).has(worktreeSubcommand)) {
|
|
52870
|
+
return {
|
|
52871
|
+
subcommand,
|
|
52872
|
+
worktreeSubcommand,
|
|
52873
|
+
resolvedCwd,
|
|
52874
|
+
isSafe: false
|
|
52875
|
+
};
|
|
52876
|
+
}
|
|
52877
|
+
if (subcommand === "rebase" && hasUnsafeRebaseOption(tokens, index + 1)) {
|
|
52878
|
+
return {
|
|
52879
|
+
subcommand,
|
|
52880
|
+
worktreeSubcommand,
|
|
52881
|
+
resolvedCwd,
|
|
52882
|
+
isSafe: false
|
|
52883
|
+
};
|
|
52884
|
+
}
|
|
52885
|
+
return { subcommand, worktreeSubcommand, resolvedCwd, isSafe: true };
|
|
52886
|
+
}
|
|
52887
|
+
return {
|
|
52888
|
+
subcommand: null,
|
|
52889
|
+
worktreeSubcommand: null,
|
|
52890
|
+
resolvedCwd,
|
|
52891
|
+
isSafe: false
|
|
52892
|
+
};
|
|
52893
|
+
}
|
|
52894
|
+
function tokenLooksLikePath(token) {
|
|
52895
|
+
return token.includes("/") || token.includes("\\") || token === "." || token === ".." || token.startsWith("$") || token.startsWith("~") || token.startsWith("$HOME");
|
|
52896
|
+
}
|
|
52897
|
+
function validateScopedTokens(tokens, cwd2, allowedRoots, env3, shellVars) {
|
|
52898
|
+
return tokens.every((token, index) => {
|
|
52899
|
+
if (!tokenLooksLikePath(token)) {
|
|
52900
|
+
return true;
|
|
52901
|
+
}
|
|
52902
|
+
const previous = index > 0 ? tokens[index - 1] : null;
|
|
52903
|
+
if (previous && ["-m", "--message", "--author", "--format"].includes(previous)) {
|
|
52904
|
+
return true;
|
|
52905
|
+
}
|
|
52906
|
+
const resolved = normalizeScopePath(token, cwd2, env3, shellVars);
|
|
52907
|
+
return resolved ? isPathWithinRoots(resolved, allowedRoots) : false;
|
|
52908
|
+
});
|
|
52909
|
+
}
|
|
52910
|
+
function isAllowedMemorySegment(segment, cwd2, allowedRoots, env3, shellVars) {
|
|
52581
52911
|
const tokens = tokenize4(segment);
|
|
52582
|
-
if (tokens
|
|
52583
|
-
return
|
|
52912
|
+
if (tokens.length === 0) {
|
|
52913
|
+
return { nextCwd: cwd2, safe: false };
|
|
52584
52914
|
}
|
|
52585
|
-
|
|
52915
|
+
if (applyScopedAssignments(tokens, env3, shellVars)) {
|
|
52916
|
+
return { nextCwd: cwd2, safe: true };
|
|
52917
|
+
}
|
|
52918
|
+
const command = tokens[0];
|
|
52919
|
+
if (!command) {
|
|
52920
|
+
return { nextCwd: cwd2, safe: false };
|
|
52921
|
+
}
|
|
52922
|
+
if (command === "cd") {
|
|
52923
|
+
const target = tokens[1];
|
|
52924
|
+
if (!target) {
|
|
52925
|
+
return { nextCwd: cwd2, safe: false };
|
|
52926
|
+
}
|
|
52927
|
+
const resolved = normalizeScopePath(target, cwd2, env3, shellVars);
|
|
52928
|
+
return {
|
|
52929
|
+
nextCwd: resolved,
|
|
52930
|
+
safe: resolved ? isPathWithinRoots(resolved, allowedRoots) : false
|
|
52931
|
+
};
|
|
52932
|
+
}
|
|
52933
|
+
if (!SAFE_MEMORY_COMMANDS.has(command)) {
|
|
52934
|
+
return { nextCwd: cwd2, safe: false };
|
|
52935
|
+
}
|
|
52936
|
+
if (command === "git") {
|
|
52937
|
+
const parsed = parseScopedGitInvocation(tokens, cwd2, allowedRoots, env3, shellVars);
|
|
52938
|
+
if (!parsed.isSafe) {
|
|
52939
|
+
return { nextCwd: parsed.resolvedCwd, safe: false };
|
|
52940
|
+
}
|
|
52941
|
+
const effectiveCwd = parsed.resolvedCwd;
|
|
52942
|
+
if (!effectiveCwd || !isPathWithinRoots(effectiveCwd, allowedRoots)) {
|
|
52943
|
+
return { nextCwd: effectiveCwd, safe: false };
|
|
52944
|
+
}
|
|
52945
|
+
if (!validateScopedTokens(tokens, effectiveCwd, allowedRoots, env3, shellVars)) {
|
|
52946
|
+
return { nextCwd: effectiveCwd, safe: false };
|
|
52947
|
+
}
|
|
52948
|
+
return { nextCwd: effectiveCwd, safe: true };
|
|
52949
|
+
}
|
|
52950
|
+
if (tokens.some((token) => tokenLooksLikePath(token))) {
|
|
52951
|
+
if (!validateScopedTokens(tokens.slice(1), cwd2, allowedRoots, env3, shellVars)) {
|
|
52952
|
+
return { nextCwd: cwd2, safe: false };
|
|
52953
|
+
}
|
|
52954
|
+
return { nextCwd: cwd2, safe: true };
|
|
52955
|
+
}
|
|
52956
|
+
if (!cwd2 || !isPathWithinRoots(cwd2, allowedRoots)) {
|
|
52957
|
+
return { nextCwd: cwd2, safe: false };
|
|
52958
|
+
}
|
|
52959
|
+
if (command === "find" && /-delete|\s-exec\b/.test(segment)) {
|
|
52960
|
+
return { nextCwd: cwd2, safe: false };
|
|
52961
|
+
}
|
|
52962
|
+
if (command === "sort" && /\s-o\b/.test(segment)) {
|
|
52963
|
+
return { nextCwd: cwd2, safe: false };
|
|
52964
|
+
}
|
|
52965
|
+
if (!validateScopedTokens(tokens.slice(1), cwd2, allowedRoots, env3, shellVars)) {
|
|
52966
|
+
return { nextCwd: cwd2, safe: false };
|
|
52967
|
+
}
|
|
52968
|
+
return { nextCwd: cwd2, safe: true };
|
|
52586
52969
|
}
|
|
52587
|
-
function
|
|
52588
|
-
if (!command ||
|
|
52970
|
+
function isScopedMemoryShellCommand(command, allowedRoots, options = {}) {
|
|
52971
|
+
if (!command || allowedRoots.length === 0) {
|
|
52589
52972
|
return false;
|
|
52590
52973
|
}
|
|
52974
|
+
if (Array.isArray(command)) {
|
|
52975
|
+
if (command.length === 0) {
|
|
52976
|
+
return false;
|
|
52977
|
+
}
|
|
52978
|
+
const [executable, ...rest] = command;
|
|
52979
|
+
if (executable && isShellExecutor(executable)) {
|
|
52980
|
+
const nested = extractDashCArgument(rest);
|
|
52981
|
+
if (!nested) {
|
|
52982
|
+
return false;
|
|
52983
|
+
}
|
|
52984
|
+
return isScopedMemoryShellCommand(stripQuotes(nested), allowedRoots, options);
|
|
52985
|
+
}
|
|
52986
|
+
}
|
|
52591
52987
|
const commandStr = typeof command === "string" ? command : command.join(" ");
|
|
52592
52988
|
const trimmed = commandStr.trim();
|
|
52593
52989
|
if (!trimmed) {
|
|
52594
52990
|
return false;
|
|
52595
52991
|
}
|
|
52596
|
-
const
|
|
52597
|
-
|
|
52992
|
+
const segments = splitShellSegments(trimmed);
|
|
52993
|
+
if (!segments) {
|
|
52994
|
+
return false;
|
|
52995
|
+
}
|
|
52598
52996
|
if (segments.length === 0) {
|
|
52599
52997
|
return false;
|
|
52600
52998
|
}
|
|
52601
|
-
|
|
52999
|
+
const env3 = options.env ?? process.env;
|
|
53000
|
+
const shellVars = {};
|
|
53001
|
+
const initialCwd = options.workingDirectory ? normalizeScopePath(options.workingDirectory, null, env3, shellVars) : null;
|
|
53002
|
+
let cwd2 = initialCwd;
|
|
52602
53003
|
for (const segment of segments) {
|
|
52603
|
-
const
|
|
52604
|
-
|
|
52605
|
-
const cdTarget = extractCdTarget(part);
|
|
52606
|
-
if (cdTarget) {
|
|
52607
|
-
const resolved = cwd2 ? expandPath(resolve4(expandPath(cwd2), cdTarget)) : expandPath(cdTarget);
|
|
52608
|
-
if (!isUnderMemoryDir(resolved, prefixes)) {
|
|
52609
|
-
return false;
|
|
52610
|
-
}
|
|
52611
|
-
cwd2 = resolved;
|
|
52612
|
-
continue;
|
|
52613
|
-
}
|
|
52614
|
-
if (cwd2 && isUnderMemoryDir(cwd2, prefixes)) {
|
|
52615
|
-
const tokens2 = tokenize4(part);
|
|
52616
|
-
const currentCwd = cwd2;
|
|
52617
|
-
if (!currentCwd) {
|
|
52618
|
-
return false;
|
|
52619
|
-
}
|
|
52620
|
-
const hasExternalPath = tokens2.some((t) => {
|
|
52621
|
-
if (isAbsolutePathArg(t) || isHomeAnchoredPathArg(t)) {
|
|
52622
|
-
return !isUnderMemoryDir(t, prefixes);
|
|
52623
|
-
}
|
|
52624
|
-
if (hasAbsoluteOrTraversalPathArg(t)) {
|
|
52625
|
-
const resolved = expandPath(resolve4(expandPath(currentCwd), t));
|
|
52626
|
-
return !isUnderMemoryDir(resolved, prefixes);
|
|
52627
|
-
}
|
|
52628
|
-
return false;
|
|
52629
|
-
});
|
|
52630
|
-
if (hasExternalPath) {
|
|
52631
|
-
return false;
|
|
52632
|
-
}
|
|
52633
|
-
if (!MEMORY_DIR_APPROVE_ALL) {
|
|
52634
|
-
const cmd = tokens2[0];
|
|
52635
|
-
if (!cmd || !SAFE_MEMORY_DIR_COMMANDS.has(cmd)) {
|
|
52636
|
-
return false;
|
|
52637
|
-
}
|
|
52638
|
-
}
|
|
52639
|
-
continue;
|
|
52640
|
-
}
|
|
52641
|
-
const tokens = tokenize4(part);
|
|
52642
|
-
const hasMemoryPath = tokens.some((t) => t.includes(".letta/agents/") && t.includes("/memory") || t.includes(".letta/agents/") && t.includes("/memory-worktrees"));
|
|
52643
|
-
if (hasMemoryPath) {
|
|
52644
|
-
const agentPaths = tokens.filter((t) => t.includes(".letta/agents/"));
|
|
52645
|
-
if (agentPaths.every((p) => isUnderMemoryDir(p, prefixes))) {
|
|
52646
|
-
if (!MEMORY_DIR_APPROVE_ALL) {
|
|
52647
|
-
const cmd = tokens[0];
|
|
52648
|
-
if (!cmd || !SAFE_MEMORY_DIR_COMMANDS.has(cmd)) {
|
|
52649
|
-
return false;
|
|
52650
|
-
}
|
|
52651
|
-
}
|
|
52652
|
-
continue;
|
|
52653
|
-
}
|
|
52654
|
-
}
|
|
53004
|
+
const result = isAllowedMemorySegment(segment, cwd2, allowedRoots, env3, shellVars);
|
|
53005
|
+
if (!result.safe) {
|
|
52655
53006
|
return false;
|
|
52656
53007
|
}
|
|
53008
|
+
cwd2 = result.nextCwd;
|
|
52657
53009
|
}
|
|
52658
53010
|
return true;
|
|
52659
53011
|
}
|
|
52660
|
-
|
|
53012
|
+
function isMemoryDirCommand(command, agentId) {
|
|
53013
|
+
if (!command || !agentId) {
|
|
53014
|
+
return false;
|
|
53015
|
+
}
|
|
53016
|
+
return isScopedMemoryShellCommand(command, getAllowedMemoryPrefixes(agentId));
|
|
53017
|
+
}
|
|
53018
|
+
var ALWAYS_SAFE_COMMANDS, EXTERNAL_PATH_METADATA_COMMANDS, SAFE_GIT_SUBCOMMANDS, SAFE_MEMORY_GIT_SUBCOMMANDS, SAFE_MEMORY_COMMANDS, SAFE_LETTA_COMMANDS, SAFE_GH_COMMANDS;
|
|
52661
53019
|
var init_readOnlyShell = __esm(() => {
|
|
52662
|
-
|
|
52663
|
-
"git",
|
|
52664
|
-
"rm",
|
|
52665
|
-
"mv",
|
|
52666
|
-
"mkdir",
|
|
52667
|
-
"cp",
|
|
52668
|
-
"ls",
|
|
52669
|
-
"cat",
|
|
52670
|
-
"head",
|
|
52671
|
-
"tail",
|
|
52672
|
-
"tree",
|
|
52673
|
-
"find",
|
|
52674
|
-
"wc",
|
|
52675
|
-
"split",
|
|
52676
|
-
"echo",
|
|
52677
|
-
"sort",
|
|
52678
|
-
"cd"
|
|
52679
|
-
]);
|
|
53020
|
+
init_memoryScope();
|
|
52680
53021
|
ALWAYS_SAFE_COMMANDS = new Set([
|
|
52681
53022
|
"cat",
|
|
52682
53023
|
"head",
|
|
@@ -52749,6 +53090,42 @@ var init_readOnlyShell = __esm(() => {
|
|
|
52749
53090
|
"tag",
|
|
52750
53091
|
"remote"
|
|
52751
53092
|
]);
|
|
53093
|
+
SAFE_MEMORY_GIT_SUBCOMMANDS = new Set([
|
|
53094
|
+
"add",
|
|
53095
|
+
"commit",
|
|
53096
|
+
"push",
|
|
53097
|
+
"pull",
|
|
53098
|
+
"rebase",
|
|
53099
|
+
"status",
|
|
53100
|
+
"diff",
|
|
53101
|
+
"log",
|
|
53102
|
+
"show",
|
|
53103
|
+
"branch",
|
|
53104
|
+
"tag",
|
|
53105
|
+
"remote",
|
|
53106
|
+
"rm",
|
|
53107
|
+
"mv",
|
|
53108
|
+
"merge",
|
|
53109
|
+
"worktree"
|
|
53110
|
+
]);
|
|
53111
|
+
SAFE_MEMORY_COMMANDS = new Set([
|
|
53112
|
+
"git",
|
|
53113
|
+
"rm",
|
|
53114
|
+
"mv",
|
|
53115
|
+
"mkdir",
|
|
53116
|
+
"cp",
|
|
53117
|
+
"ls",
|
|
53118
|
+
"cat",
|
|
53119
|
+
"head",
|
|
53120
|
+
"tail",
|
|
53121
|
+
"find",
|
|
53122
|
+
"sort",
|
|
53123
|
+
"echo",
|
|
53124
|
+
"wc",
|
|
53125
|
+
"split",
|
|
53126
|
+
"cd",
|
|
53127
|
+
"sleep"
|
|
53128
|
+
]);
|
|
52752
53129
|
SAFE_LETTA_COMMANDS = {
|
|
52753
53130
|
memfs: new Set(["status", "help", "backups", "export"]),
|
|
52754
53131
|
agents: new Set(["list", "help"]),
|
|
@@ -52962,8 +53339,14 @@ var exports_mode = {};
|
|
|
52962
53339
|
__export(exports_mode, {
|
|
52963
53340
|
permissionMode: () => permissionMode
|
|
52964
53341
|
});
|
|
52965
|
-
import { homedir as
|
|
52966
|
-
import { isAbsolute as
|
|
53342
|
+
import { homedir as homedir13 } from "node:os";
|
|
53343
|
+
import { isAbsolute as isAbsolute3, join as join14, relative as relative3 } from "node:path";
|
|
53344
|
+
function everyResolvedTargetIsWithinRoots(candidatePaths, roots, workingDirectory) {
|
|
53345
|
+
return candidatePaths.length > 0 && candidatePaths.every((path4) => {
|
|
53346
|
+
const resolvedPath = resolveScopedTargetPath(path4, workingDirectory);
|
|
53347
|
+
return resolvedPath ? isPathWithinRoots(resolvedPath, roots) : false;
|
|
53348
|
+
});
|
|
53349
|
+
}
|
|
52967
53350
|
function getGlobalMode() {
|
|
52968
53351
|
const global2 = globalThis;
|
|
52969
53352
|
if (!global2[MODE_KEY]) {
|
|
@@ -52992,22 +53375,13 @@ function setGlobalModeBeforePlan(value) {
|
|
|
52992
53375
|
global2[MODE_BEFORE_PLAN_KEY] = value;
|
|
52993
53376
|
}
|
|
52994
53377
|
function resolvePlanTargetPath(targetPath, workingDirectory) {
|
|
52995
|
-
|
|
52996
|
-
if (!trimmedPath)
|
|
52997
|
-
return null;
|
|
52998
|
-
if (trimmedPath.startsWith("~/")) {
|
|
52999
|
-
return resolve5(homedir12(), trimmedPath.slice(2));
|
|
53000
|
-
}
|
|
53001
|
-
if (isAbsolute2(trimmedPath)) {
|
|
53002
|
-
return resolve5(trimmedPath);
|
|
53003
|
-
}
|
|
53004
|
-
return resolve5(workingDirectory, trimmedPath);
|
|
53378
|
+
return resolveScopedTargetPath(targetPath, workingDirectory);
|
|
53005
53379
|
}
|
|
53006
53380
|
function isPathInPlansDir(path4, plansDir) {
|
|
53007
53381
|
if (!path4.endsWith(".md"))
|
|
53008
53382
|
return false;
|
|
53009
53383
|
const rel = relative3(plansDir, path4);
|
|
53010
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
53384
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
|
|
53011
53385
|
}
|
|
53012
53386
|
function extractApplyPatchPaths(input) {
|
|
53013
53387
|
const paths = [];
|
|
@@ -53194,7 +53568,7 @@ class PermissionModeManager {
|
|
|
53194
53568
|
return "allow";
|
|
53195
53569
|
}
|
|
53196
53570
|
if (writeTools.includes(toolName)) {
|
|
53197
|
-
const plansDir = join14(
|
|
53571
|
+
const plansDir = join14(homedir13(), ".letta", "plans");
|
|
53198
53572
|
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
53199
53573
|
let candidatePaths = [];
|
|
53200
53574
|
if ((toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") && toolArgs?.input) {
|
|
@@ -53245,7 +53619,7 @@ class PermissionModeManager {
|
|
|
53245
53619
|
}
|
|
53246
53620
|
const planWritePath = extractPlanFileWritePathFromShellCommand(command);
|
|
53247
53621
|
if (planWritePath) {
|
|
53248
|
-
const plansDir = join14(
|
|
53622
|
+
const plansDir = join14(homedir13(), ".letta", "plans");
|
|
53249
53623
|
const resolvedPath = resolvePlanTargetPath(planWritePath, workingDirectory);
|
|
53250
53624
|
if (resolvedPath && isPathInPlansDir(resolvedPath, plansDir)) {
|
|
53251
53625
|
return "allow";
|
|
@@ -53254,6 +53628,94 @@ class PermissionModeManager {
|
|
|
53254
53628
|
}
|
|
53255
53629
|
return "deny";
|
|
53256
53630
|
}
|
|
53631
|
+
case "memory": {
|
|
53632
|
+
const allowedMemoryRoots = resolveAllowedMemoryRoots().roots;
|
|
53633
|
+
const allowedReadOnlyTools = [
|
|
53634
|
+
"Read",
|
|
53635
|
+
"Glob",
|
|
53636
|
+
"Grep",
|
|
53637
|
+
"NotebookRead",
|
|
53638
|
+
"ViewImage",
|
|
53639
|
+
"view_image",
|
|
53640
|
+
"TaskOutput",
|
|
53641
|
+
"task_output",
|
|
53642
|
+
"Skill",
|
|
53643
|
+
"skill",
|
|
53644
|
+
"read_file",
|
|
53645
|
+
"list_dir",
|
|
53646
|
+
"grep_files",
|
|
53647
|
+
"ReadFile",
|
|
53648
|
+
"ListDir",
|
|
53649
|
+
"GrepFiles",
|
|
53650
|
+
"read_file_gemini",
|
|
53651
|
+
"glob_gemini",
|
|
53652
|
+
"list_directory",
|
|
53653
|
+
"search_file_content",
|
|
53654
|
+
"read_many_files",
|
|
53655
|
+
"ReadFileGemini",
|
|
53656
|
+
"GlobGemini",
|
|
53657
|
+
"ListDirectory",
|
|
53658
|
+
"SearchFileContent",
|
|
53659
|
+
"ReadManyFiles"
|
|
53660
|
+
];
|
|
53661
|
+
const writeTools = [
|
|
53662
|
+
"Write",
|
|
53663
|
+
"Edit",
|
|
53664
|
+
"MultiEdit",
|
|
53665
|
+
"NotebookEdit",
|
|
53666
|
+
"apply_patch",
|
|
53667
|
+
"ApplyPatch",
|
|
53668
|
+
"replace",
|
|
53669
|
+
"Replace",
|
|
53670
|
+
"write_file",
|
|
53671
|
+
"WriteFile",
|
|
53672
|
+
"write_file_gemini",
|
|
53673
|
+
"WriteFileGemini"
|
|
53674
|
+
];
|
|
53675
|
+
const shellTools = [
|
|
53676
|
+
"Bash",
|
|
53677
|
+
"shell",
|
|
53678
|
+
"Shell",
|
|
53679
|
+
"shell_command",
|
|
53680
|
+
"ShellCommand",
|
|
53681
|
+
"run_shell_command",
|
|
53682
|
+
"RunShellCommand",
|
|
53683
|
+
"run_shell_command_gemini",
|
|
53684
|
+
"RunShellCommandGemini"
|
|
53685
|
+
];
|
|
53686
|
+
if (allowedReadOnlyTools.includes(toolName)) {
|
|
53687
|
+
return "allow";
|
|
53688
|
+
}
|
|
53689
|
+
if (toolName === "memory_apply_patch") {
|
|
53690
|
+
return allowedMemoryRoots.length > 0 ? "allow" : "deny";
|
|
53691
|
+
}
|
|
53692
|
+
if (writeTools.includes(toolName)) {
|
|
53693
|
+
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
53694
|
+
let candidatePaths = [];
|
|
53695
|
+
if ((toolName === "ApplyPatch" || toolName === "apply_patch") && toolArgs?.input) {
|
|
53696
|
+
candidatePaths = extractApplyPatchPaths(toolArgs.input);
|
|
53697
|
+
} else if (typeof targetPath === "string") {
|
|
53698
|
+
candidatePaths = [targetPath];
|
|
53699
|
+
}
|
|
53700
|
+
if (allowedMemoryRoots.length > 0 && everyResolvedTargetIsWithinRoots(candidatePaths, allowedMemoryRoots, workingDirectory)) {
|
|
53701
|
+
return "allow";
|
|
53702
|
+
}
|
|
53703
|
+
return "deny";
|
|
53704
|
+
}
|
|
53705
|
+
if (shellTools.includes(toolName)) {
|
|
53706
|
+
const command = toolArgs?.command;
|
|
53707
|
+
if (command && isReadOnlyShellCommand(command, { allowExternalPaths: true })) {
|
|
53708
|
+
return "allow";
|
|
53709
|
+
}
|
|
53710
|
+
if (command && allowedMemoryRoots.length > 0 && isScopedMemoryShellCommand(command, allowedMemoryRoots, {
|
|
53711
|
+
workingDirectory
|
|
53712
|
+
})) {
|
|
53713
|
+
return "allow";
|
|
53714
|
+
}
|
|
53715
|
+
return "deny";
|
|
53716
|
+
}
|
|
53717
|
+
return "deny";
|
|
53718
|
+
}
|
|
53257
53719
|
case "default":
|
|
53258
53720
|
return null;
|
|
53259
53721
|
default:
|
|
@@ -53268,6 +53730,7 @@ class PermissionModeManager {
|
|
|
53268
53730
|
}
|
|
53269
53731
|
var MODE_KEY, PLAN_FILE_KEY, MODE_BEFORE_PLAN_KEY, permissionMode;
|
|
53270
53732
|
var init_mode = __esm(() => {
|
|
53733
|
+
init_memoryScope();
|
|
53271
53734
|
init_readOnlyShell();
|
|
53272
53735
|
init_shell_command_normalization();
|
|
53273
53736
|
MODE_KEY = Symbol.for("@letta/permissionMode");
|
|
@@ -57340,8 +57803,8 @@ import {
|
|
|
57340
57803
|
unlink,
|
|
57341
57804
|
writeFile as writeFile2
|
|
57342
57805
|
} from "node:fs/promises";
|
|
57343
|
-
import { homedir as
|
|
57344
|
-
import { dirname as
|
|
57806
|
+
import { homedir as homedir15 } from "node:os";
|
|
57807
|
+
import { dirname as dirname7, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve12 } from "node:path";
|
|
57345
57808
|
import { promisify as promisify10 } from "node:util";
|
|
57346
57809
|
async function getAgentIdentity() {
|
|
57347
57810
|
const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
@@ -57390,7 +57853,7 @@ async function memory(args) {
|
|
|
57390
57853
|
const rendered = renderMemoryFile({
|
|
57391
57854
|
description
|
|
57392
57855
|
}, body);
|
|
57393
|
-
await mkdir2(
|
|
57856
|
+
await mkdir2(dirname7(filePath), { recursive: true });
|
|
57394
57857
|
await writeFile2(filePath, rendered, "utf8");
|
|
57395
57858
|
affectedPaths = [relPath];
|
|
57396
57859
|
} else if (command === "str_replace") {
|
|
@@ -57459,7 +57922,7 @@ async function memory(args) {
|
|
|
57459
57922
|
throw new Error(`memory rename: destination already exists at ${newPathArg}`);
|
|
57460
57923
|
}
|
|
57461
57924
|
await loadEditableMemoryFile(oldFilePath, oldPathArg);
|
|
57462
|
-
await mkdir2(
|
|
57925
|
+
await mkdir2(dirname7(newFilePath), { recursive: true });
|
|
57463
57926
|
await rename(oldFilePath, newFilePath);
|
|
57464
57927
|
affectedPaths = [oldRelPath, newRelPath];
|
|
57465
57928
|
} else if (command === "update_description") {
|
|
@@ -57507,7 +57970,7 @@ function resolveMemoryDir() {
|
|
|
57507
57970
|
})();
|
|
57508
57971
|
const agentId = contextAgentId || (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
57509
57972
|
if (agentId && agentId.trim().length > 0) {
|
|
57510
|
-
return resolve12(
|
|
57973
|
+
return resolve12(homedir15(), ".letta", "agents", agentId, "memory");
|
|
57511
57974
|
}
|
|
57512
57975
|
throw new Error("memory: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
|
|
57513
57976
|
}
|
|
@@ -57528,10 +57991,10 @@ function normalizeMemoryLabel(memoryDir, inputPath, fieldName) {
|
|
|
57528
57991
|
throw new Error(`memory: '${fieldName}' must be a memory-relative file path, not a home-relative filesystem path`);
|
|
57529
57992
|
}
|
|
57530
57993
|
const isWindowsAbsolute = /^[a-zA-Z]:[\\/]/.test(raw);
|
|
57531
|
-
if (
|
|
57994
|
+
if (isAbsolute9(raw) || isWindowsAbsolute) {
|
|
57532
57995
|
const absolutePath = resolve12(raw);
|
|
57533
57996
|
const relToMemory = relative5(memoryDir, absolutePath);
|
|
57534
|
-
if (relToMemory && !relToMemory.startsWith("..") && !
|
|
57997
|
+
if (relToMemory && !relToMemory.startsWith("..") && !isAbsolute9(relToMemory)) {
|
|
57535
57998
|
return normalizeRelativeMemoryLabel(relToMemory, fieldName);
|
|
57536
57999
|
}
|
|
57537
58000
|
throw new Error(memoryPrefixError(memoryDir));
|
|
@@ -57577,14 +58040,14 @@ function resolveMemoryFilePath(memoryDir, label) {
|
|
|
57577
58040
|
function resolveMemoryPath(memoryDir, path11) {
|
|
57578
58041
|
const absolute = resolve12(memoryDir, path11);
|
|
57579
58042
|
const rel = relative5(memoryDir, absolute);
|
|
57580
|
-
if (rel.startsWith("..") ||
|
|
58043
|
+
if (rel.startsWith("..") || isAbsolute9(rel)) {
|
|
57581
58044
|
throw new Error("memory: resolved path escapes memory directory");
|
|
57582
58045
|
}
|
|
57583
58046
|
return absolute;
|
|
57584
58047
|
}
|
|
57585
58048
|
function toRepoRelative(memoryDir, absolutePath) {
|
|
57586
58049
|
const rel = relative5(memoryDir, absolutePath);
|
|
57587
|
-
if (!rel || rel.startsWith("..") ||
|
|
58050
|
+
if (!rel || rel.startsWith("..") || isAbsolute9(rel)) {
|
|
57588
58051
|
throw new Error("memory: path is outside memory repository");
|
|
57589
58052
|
}
|
|
57590
58053
|
return rel.replace(/\\/g, "/");
|
|
@@ -57755,8 +58218,8 @@ import {
|
|
|
57755
58218
|
unlink as unlink2,
|
|
57756
58219
|
writeFile as writeFile3
|
|
57757
58220
|
} from "node:fs/promises";
|
|
57758
|
-
import { homedir as
|
|
57759
|
-
import { dirname as
|
|
58221
|
+
import { homedir as homedir16 } from "node:os";
|
|
58222
|
+
import { dirname as dirname8, isAbsolute as isAbsolute10, relative as relative6, resolve as resolve13 } from "node:path";
|
|
57760
58223
|
import { promisify as promisify11 } from "node:util";
|
|
57761
58224
|
async function getAgentIdentity2() {
|
|
57762
58225
|
const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
@@ -57869,7 +58332,7 @@ async function memory_apply_patch(args) {
|
|
|
57869
58332
|
}
|
|
57870
58333
|
}
|
|
57871
58334
|
for (const [absPath, content] of pendingWrites.entries()) {
|
|
57872
|
-
await mkdir3(
|
|
58335
|
+
await mkdir3(dirname8(absPath), { recursive: true });
|
|
57873
58336
|
await writeFile3(absPath, content, "utf8");
|
|
57874
58337
|
}
|
|
57875
58338
|
for (const absPath of pendingDeletes) {
|
|
@@ -58043,7 +58506,7 @@ function resolveMemoryDir2() {
|
|
|
58043
58506
|
})();
|
|
58044
58507
|
const agentId = contextAgentId || (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
58045
58508
|
if (agentId && agentId.trim().length > 0) {
|
|
58046
|
-
return resolve13(
|
|
58509
|
+
return resolve13(homedir16(), ".letta", "agents", agentId, "memory");
|
|
58047
58510
|
}
|
|
58048
58511
|
throw new Error("memory_apply_patch: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
|
|
58049
58512
|
}
|
|
@@ -58064,10 +58527,10 @@ function normalizeMemoryLabel2(memoryDir, inputPath, fieldName) {
|
|
|
58064
58527
|
throw new Error(`memory_apply_patch: '${fieldName}' must be a memory-relative file path, not a home-relative filesystem path`);
|
|
58065
58528
|
}
|
|
58066
58529
|
const isWindowsAbsolute = /^[a-zA-Z]:[\\/]/.test(raw);
|
|
58067
|
-
if (
|
|
58530
|
+
if (isAbsolute10(raw) || isWindowsAbsolute) {
|
|
58068
58531
|
const absolutePath = resolve13(raw);
|
|
58069
58532
|
const relToMemory = relative6(memoryDir, absolutePath);
|
|
58070
|
-
if (relToMemory && !relToMemory.startsWith("..") && !
|
|
58533
|
+
if (relToMemory && !relToMemory.startsWith("..") && !isAbsolute10(relToMemory)) {
|
|
58071
58534
|
return normalizeRelativeMemoryLabel2(relToMemory, fieldName);
|
|
58072
58535
|
}
|
|
58073
58536
|
throw new Error(memoryPrefixError2(memoryDir));
|
|
@@ -58109,7 +58572,7 @@ function memoryPrefixError2(memoryDir) {
|
|
|
58109
58572
|
function resolveMemoryPath2(memoryDir, path11) {
|
|
58110
58573
|
const absolute = resolve13(memoryDir, path11);
|
|
58111
58574
|
const rel = relative6(memoryDir, absolute);
|
|
58112
|
-
if (rel.startsWith("..") ||
|
|
58575
|
+
if (rel.startsWith("..") || isAbsolute10(rel)) {
|
|
58113
58576
|
throw new Error("memory_apply_patch: resolved path escapes memory directory");
|
|
58114
58577
|
}
|
|
58115
58578
|
return absolute;
|
|
@@ -58119,7 +58582,7 @@ function resolveMemoryFilePath2(memoryDir, label) {
|
|
|
58119
58582
|
}
|
|
58120
58583
|
function toRepoRelative2(memoryDir, absolutePath) {
|
|
58121
58584
|
const rel = relative6(memoryDir, absolutePath);
|
|
58122
|
-
if (!rel || rel.startsWith("..") ||
|
|
58585
|
+
if (!rel || rel.startsWith("..") || isAbsolute10(rel)) {
|
|
58123
58586
|
throw new Error("memory_apply_patch: path is outside memory repository");
|
|
58124
58587
|
}
|
|
58125
58588
|
return rel.replace(/\\/g, "/");
|
|
@@ -65158,10 +65621,10 @@ __export(exports_skills, {
|
|
|
65158
65621
|
});
|
|
65159
65622
|
import { existsSync as existsSync17 } from "node:fs";
|
|
65160
65623
|
import { readdir as readdir4, readFile as readFile5, realpath as realpath2, stat as stat4 } from "node:fs/promises";
|
|
65161
|
-
import { dirname as
|
|
65624
|
+
import { dirname as dirname9, join as join19 } from "node:path";
|
|
65162
65625
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
65163
65626
|
function getBundledSkillsPath() {
|
|
65164
|
-
const thisDir =
|
|
65627
|
+
const thisDir = dirname9(fileURLToPath7(import.meta.url));
|
|
65165
65628
|
if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
|
|
65166
65629
|
return join19(thisDir, "../skills/builtin");
|
|
65167
65630
|
}
|
|
@@ -65363,10 +65826,10 @@ var init_skillContentRegistry = __esm(() => {
|
|
|
65363
65826
|
// src/tools/impl/Skill.ts
|
|
65364
65827
|
import { readdirSync as readdirSync7 } from "node:fs";
|
|
65365
65828
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
65366
|
-
import { dirname as
|
|
65829
|
+
import { dirname as dirname10, join as join20 } from "node:path";
|
|
65367
65830
|
function hasAdditionalFiles(skillMdPath) {
|
|
65368
65831
|
try {
|
|
65369
|
-
const skillDir =
|
|
65832
|
+
const skillDir = dirname10(skillMdPath);
|
|
65370
65833
|
const entries = readdirSync7(skillDir);
|
|
65371
65834
|
return entries.some((e) => e.toUpperCase() !== "SKILL.MD");
|
|
65372
65835
|
} catch {
|
|
@@ -65425,7 +65888,7 @@ async function skill(args) {
|
|
|
65425
65888
|
const agentId = getCurrentAgentId();
|
|
65426
65889
|
const skillsDir = await getResolvedSkillsDir();
|
|
65427
65890
|
const { content: skillContent, path: skillPath } = await readSkillContent(skillName, skillsDir, agentId);
|
|
65428
|
-
const skillDir =
|
|
65891
|
+
const skillDir = dirname10(skillPath);
|
|
65429
65892
|
const hasExtras = hasAdditionalFiles(skillPath);
|
|
65430
65893
|
const processedContent = hasExtras ? skillContent.replace(/<SKILL_DIR>/g, skillDir) : skillContent;
|
|
65431
65894
|
const dirHeader = hasExtras ? `# Skill Directory: ${skillDir}
|
|
@@ -66009,15 +66472,32 @@ async function executeSubagent(type, config, model, userPrompt, baseURL, subagen
|
|
|
66009
66472
|
const inheritedApiKey = process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY;
|
|
66010
66473
|
const inheritedBaseUrl = process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL;
|
|
66011
66474
|
const subagentWorkingDirectory = resolveSubagentWorkingDirectory();
|
|
66475
|
+
const inheritedMemoryRoots = resolveAllowedMemoryRoots();
|
|
66476
|
+
const childEnv = {
|
|
66477
|
+
...process.env,
|
|
66478
|
+
...inheritedApiKey && { LETTA_API_KEY: inheritedApiKey },
|
|
66479
|
+
...inheritedBaseUrl && { LETTA_BASE_URL: inheritedBaseUrl },
|
|
66480
|
+
LETTA_CODE_AGENT_ROLE: "subagent",
|
|
66481
|
+
...parentAgentId && { LETTA_PARENT_AGENT_ID: parentAgentId }
|
|
66482
|
+
};
|
|
66483
|
+
if (config.permissionMode === "memory") {
|
|
66484
|
+
if (inheritedMemoryRoots.primaryRoot) {
|
|
66485
|
+
childEnv.MEMORY_DIR = inheritedMemoryRoots.primaryRoot;
|
|
66486
|
+
childEnv.LETTA_MEMORY_DIR = inheritedMemoryRoots.primaryRoot;
|
|
66487
|
+
} else {
|
|
66488
|
+
delete childEnv.MEMORY_DIR;
|
|
66489
|
+
delete childEnv.LETTA_MEMORY_DIR;
|
|
66490
|
+
}
|
|
66491
|
+
const parentMemoryDir = process.env.MEMORY_DIR || process.env.LETTA_MEMORY_DIR;
|
|
66492
|
+
if (parentMemoryDir && parentMemoryDir.trim().length > 0) {
|
|
66493
|
+
childEnv.PARENT_MEMORY_DIR = parentMemoryDir;
|
|
66494
|
+
} else {
|
|
66495
|
+
delete childEnv.PARENT_MEMORY_DIR;
|
|
66496
|
+
}
|
|
66497
|
+
}
|
|
66012
66498
|
const proc2 = spawn4(launcher.command, launcher.args, {
|
|
66013
66499
|
cwd: subagentWorkingDirectory,
|
|
66014
|
-
env:
|
|
66015
|
-
...process.env,
|
|
66016
|
-
...inheritedApiKey && { LETTA_API_KEY: inheritedApiKey },
|
|
66017
|
-
...inheritedBaseUrl && { LETTA_BASE_URL: inheritedBaseUrl },
|
|
66018
|
-
LETTA_CODE_AGENT_ROLE: "subagent",
|
|
66019
|
-
...parentAgentId && { LETTA_PARENT_AGENT_ID: parentAgentId }
|
|
66020
|
-
}
|
|
66500
|
+
env: childEnv
|
|
66021
66501
|
});
|
|
66022
66502
|
proc2.once("spawn", () => {
|
|
66023
66503
|
updateSubagent(subagentId, { status: "running" });
|
|
@@ -66196,6 +66676,7 @@ var init_manager2 = __esm(async () => {
|
|
|
66196
66676
|
init_subagentState();
|
|
66197
66677
|
init_constants();
|
|
66198
66678
|
init_cli();
|
|
66679
|
+
init_memoryScope();
|
|
66199
66680
|
init_mode();
|
|
66200
66681
|
init_session();
|
|
66201
66682
|
init_context();
|
|
@@ -69706,8 +70187,8 @@ function matchesFilePattern(query, pattern, workingDirectory, options) {
|
|
|
69706
70187
|
globPattern = globPattern.slice(2);
|
|
69707
70188
|
}
|
|
69708
70189
|
if (globPattern.startsWith("~/")) {
|
|
69709
|
-
const
|
|
69710
|
-
globPattern = globPattern.replace(/^~/,
|
|
70190
|
+
const homedir17 = __require("node:os").homedir();
|
|
70191
|
+
globPattern = globPattern.replace(/^~/, homedir17);
|
|
69711
70192
|
}
|
|
69712
70193
|
globPattern = normalizeAbsolutePattern(globPattern, workingDirectory);
|
|
69713
70194
|
const windowsContext = isWindowsContext(workingDirectory);
|
|
@@ -70220,7 +70701,7 @@ function getDefaultDecision(toolName, toolArgs) {
|
|
|
70220
70701
|
}
|
|
70221
70702
|
if (toolName === "Task" || toolName === "task") {
|
|
70222
70703
|
const subagentType = typeof toolArgs?.subagent_type === "string" ? toolArgs.subagent_type : "";
|
|
70223
|
-
if (
|
|
70704
|
+
if (SAFE_AUTO_APPROVE_SUBAGENT_TYPES.has(subagentType)) {
|
|
70224
70705
|
return "allow";
|
|
70225
70706
|
}
|
|
70226
70707
|
return "ask";
|
|
@@ -70251,7 +70732,7 @@ async function checkPermissionWithHooks(toolName, toolArgs, permissions, working
|
|
|
70251
70732
|
}
|
|
70252
70733
|
return result;
|
|
70253
70734
|
}
|
|
70254
|
-
var WORKING_DIRECTORY_TOOLS_V2, WORKING_DIRECTORY_TOOLS_V1, READ_ONLY_SHELL_TOOLS, FILE_TOOLS_V2, FILE_TOOLS_V1,
|
|
70735
|
+
var WORKING_DIRECTORY_TOOLS_V2, WORKING_DIRECTORY_TOOLS_V1, READ_ONLY_SHELL_TOOLS, FILE_TOOLS_V2, FILE_TOOLS_V1, SAFE_AUTO_APPROVE_SUBAGENT_TYPES;
|
|
70255
70736
|
var init_checker = __esm(async () => {
|
|
70256
70737
|
init_context();
|
|
70257
70738
|
init_canonical();
|
|
@@ -70318,7 +70799,7 @@ var init_checker = __esm(async () => {
|
|
|
70318
70799
|
"read_many_files",
|
|
70319
70800
|
"ReadManyFiles"
|
|
70320
70801
|
];
|
|
70321
|
-
|
|
70802
|
+
SAFE_AUTO_APPROVE_SUBAGENT_TYPES = new Set([
|
|
70322
70803
|
"explore",
|
|
70323
70804
|
"Explore",
|
|
70324
70805
|
"recall",
|
|
@@ -70336,10 +70817,10 @@ __export(exports_loader, {
|
|
|
70336
70817
|
loadPermissions: () => loadPermissions,
|
|
70337
70818
|
getUserSettingsPaths: () => getUserSettingsPaths
|
|
70338
70819
|
});
|
|
70339
|
-
import { homedir as
|
|
70820
|
+
import { homedir as homedir17 } from "node:os";
|
|
70340
70821
|
import { join as join21 } from "node:path";
|
|
70341
70822
|
function getUserSettingsPaths(options = {}) {
|
|
70342
|
-
const homeDir = options.homeDir ||
|
|
70823
|
+
const homeDir = options.homeDir || homedir17();
|
|
70343
70824
|
const xdgConfigHome = options.xdgConfigHome || process.env.XDG_CONFIG_HOME || join21(homeDir, ".config");
|
|
70344
70825
|
return {
|
|
70345
70826
|
canonical: join21(homeDir, ".letta", "settings.json"),
|
|
@@ -70461,8 +70942,8 @@ var exports_analyzer = {};
|
|
|
70461
70942
|
__export(exports_analyzer, {
|
|
70462
70943
|
analyzeApprovalContext: () => analyzeApprovalContext
|
|
70463
70944
|
});
|
|
70464
|
-
import { homedir as
|
|
70465
|
-
import { dirname as
|
|
70945
|
+
import { homedir as homedir18 } from "node:os";
|
|
70946
|
+
import { dirname as dirname12, relative as relative8, resolve as resolve22, win32 as win322 } from "node:path";
|
|
70466
70947
|
function normalizeOsPath(path20) {
|
|
70467
70948
|
return path20.replace(/\\/g, "/");
|
|
70468
70949
|
}
|
|
@@ -70488,7 +70969,7 @@ function isPathWithinDirectory(path20, directory) {
|
|
|
70488
70969
|
return !relativePath.startsWith("../") && relativePath !== ".." && !relativePath.startsWith("/") && !/^[a-zA-Z]:\//.test(relativePath);
|
|
70489
70970
|
}
|
|
70490
70971
|
function dirnameForContext(path20) {
|
|
70491
|
-
return isWindowsPath(path20) ? win322.dirname(path20) :
|
|
70972
|
+
return isWindowsPath(path20) ? win322.dirname(path20) : dirname12(path20);
|
|
70492
70973
|
}
|
|
70493
70974
|
function formatAbsoluteRulePath(path20) {
|
|
70494
70975
|
const normalized = normalizeOsPath(path20).replace(/\/+$/, "");
|
|
@@ -70498,7 +70979,7 @@ function formatAbsoluteRulePath(path20) {
|
|
|
70498
70979
|
return `//${normalized.replace(/^\/+/, "")}`;
|
|
70499
70980
|
}
|
|
70500
70981
|
function formatDisplayPath(path20) {
|
|
70501
|
-
return normalizeOsPath(path20).replace(normalizeOsPath(
|
|
70982
|
+
return normalizeOsPath(path20).replace(normalizeOsPath(homedir18()), "~");
|
|
70502
70983
|
}
|
|
70503
70984
|
function analyzeApprovalContext(toolName, toolArgs, workingDirectory) {
|
|
70504
70985
|
const canonicalTool = canonicalToolName(toolName);
|
|
@@ -70549,7 +71030,7 @@ function analyzeReadApproval(filePath, workingDir) {
|
|
|
70549
71030
|
};
|
|
70550
71031
|
}
|
|
70551
71032
|
const relativePath = normalizeOsPath(relativePathForContext(workingDir, absolutePath));
|
|
70552
|
-
const relativeDir =
|
|
71033
|
+
const relativeDir = dirname12(relativePath);
|
|
70553
71034
|
const pattern = relativeDir === "." || relativeDir === "" ? "**" : `${relativeDir}/**`;
|
|
70554
71035
|
return {
|
|
70555
71036
|
recommendedRule: `Read(${pattern})`,
|
|
@@ -70692,7 +71173,7 @@ function detectSkillScript(command, workingDir) {
|
|
|
70692
71173
|
return null;
|
|
70693
71174
|
}
|
|
70694
71175
|
const normalizedWorkingDir = normalizePathSeparators(workingDir).replace(/\/$/, "");
|
|
70695
|
-
const normalizedHomeDir = normalizePathSeparators(
|
|
71176
|
+
const normalizedHomeDir = normalizePathSeparators(homedir18()).replace(/\/$/, "");
|
|
70696
71177
|
const detect = (source, regex2) => {
|
|
70697
71178
|
for (const candidate of pathCandidates) {
|
|
70698
71179
|
const match3 = candidate.match(regex2);
|
|
@@ -72224,15 +72705,15 @@ __export(exports_memoryFilesystem, {
|
|
|
72224
72705
|
MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR
|
|
72225
72706
|
});
|
|
72226
72707
|
import { existsSync as existsSync18, mkdirSync as mkdirSync13 } from "node:fs";
|
|
72227
|
-
import { homedir as
|
|
72708
|
+
import { homedir as homedir19 } from "node:os";
|
|
72228
72709
|
import { join as join22 } from "node:path";
|
|
72229
|
-
function getMemoryFilesystemRoot(agentId, homeDir =
|
|
72710
|
+
function getMemoryFilesystemRoot(agentId, homeDir = homedir19()) {
|
|
72230
72711
|
return join22(homeDir, MEMORY_FS_ROOT, MEMORY_FS_AGENTS_DIR, agentId, MEMORY_FS_MEMORY_DIR);
|
|
72231
72712
|
}
|
|
72232
|
-
function getMemorySystemDir(agentId, homeDir =
|
|
72713
|
+
function getMemorySystemDir(agentId, homeDir = homedir19()) {
|
|
72233
72714
|
return join22(getMemoryFilesystemRoot(agentId, homeDir), MEMORY_SYSTEM_DIR);
|
|
72234
72715
|
}
|
|
72235
|
-
function ensureMemoryFilesystemDirs(agentId, homeDir =
|
|
72716
|
+
function ensureMemoryFilesystemDirs(agentId, homeDir = homedir19()) {
|
|
72236
72717
|
const root = getMemoryFilesystemRoot(agentId, homeDir);
|
|
72237
72718
|
const systemDir = getMemorySystemDir(agentId, homeDir);
|
|
72238
72719
|
if (!existsSync18(root)) {
|
|
@@ -73402,18 +73883,29 @@ var init_turn_recovery_policy = __esm(() => {
|
|
|
73402
73883
|
});
|
|
73403
73884
|
|
|
73404
73885
|
// src/agent/approval-recovery.ts
|
|
73405
|
-
async function
|
|
73886
|
+
async function fetchRunErrorInfo(runId) {
|
|
73406
73887
|
if (!runId)
|
|
73407
73888
|
return null;
|
|
73408
73889
|
try {
|
|
73409
73890
|
const client = await getClient();
|
|
73410
73891
|
const run = await client.runs.retrieve(runId);
|
|
73411
73892
|
const metaError = run.metadata?.error;
|
|
73412
|
-
|
|
73893
|
+
const nestedError = metaError?.error;
|
|
73894
|
+
const errorInfo = {
|
|
73895
|
+
error_type: metaError?.error_type ?? metaError?.type ?? nestedError?.error_type ?? nestedError?.type,
|
|
73896
|
+
message: metaError?.message ?? nestedError?.message,
|
|
73897
|
+
detail: metaError?.detail ?? nestedError?.detail,
|
|
73898
|
+
run_id: metaError?.run_id ?? nestedError?.run_id ?? runId
|
|
73899
|
+
};
|
|
73900
|
+
return errorInfo.error_type || errorInfo.message || errorInfo.detail ? errorInfo : null;
|
|
73413
73901
|
} catch {
|
|
73414
73902
|
return null;
|
|
73415
73903
|
}
|
|
73416
73904
|
}
|
|
73905
|
+
async function fetchRunErrorDetail(runId) {
|
|
73906
|
+
const errorInfo = await fetchRunErrorInfo(runId);
|
|
73907
|
+
return errorInfo?.detail ?? errorInfo?.message ?? null;
|
|
73908
|
+
}
|
|
73417
73909
|
var init_approval_recovery = __esm(async () => {
|
|
73418
73910
|
init_turn_recovery_policy();
|
|
73419
73911
|
await init_client2();
|
|
@@ -75287,7 +75779,7 @@ import {
|
|
|
75287
75779
|
readFile as readFile7,
|
|
75288
75780
|
writeFile as writeFile4
|
|
75289
75781
|
} from "node:fs/promises";
|
|
75290
|
-
import { homedir as
|
|
75782
|
+
import { homedir as homedir20, tmpdir as tmpdir3 } from "node:os";
|
|
75291
75783
|
import { join as join25 } from "node:path";
|
|
75292
75784
|
function buildReflectionSubagentPrompt(input) {
|
|
75293
75785
|
const lines = [];
|
|
@@ -75481,7 +75973,7 @@ function getTranscriptRoot() {
|
|
|
75481
75973
|
if (envRoot) {
|
|
75482
75974
|
return envRoot;
|
|
75483
75975
|
}
|
|
75484
|
-
return join25(
|
|
75976
|
+
return join25(homedir20(), ".letta", DEFAULT_TRANSCRIPT_DIR);
|
|
75485
75977
|
}
|
|
75486
75978
|
function defaultState() {
|
|
75487
75979
|
return { auto_cursor_line: 0 };
|
|
@@ -75670,7 +76162,7 @@ import {
|
|
|
75670
76162
|
unlinkSync as unlinkSync7,
|
|
75671
76163
|
writeFileSync as writeFileSync11
|
|
75672
76164
|
} from "node:fs";
|
|
75673
|
-
import { homedir as
|
|
76165
|
+
import { homedir as homedir21 } from "node:os";
|
|
75674
76166
|
import { join as join26 } from "node:path";
|
|
75675
76167
|
function truncateStr(value, maxLen) {
|
|
75676
76168
|
if (value === null || value === undefined)
|
|
@@ -75811,7 +76303,7 @@ class ChunkLog {
|
|
|
75811
76303
|
var MAX_ENTRIES = 100, CONTENT_TRUNCATE_LEN = 200, MAX_SESSION_FILES2 = 5, LOG_BASE_DIR, chunkLog;
|
|
75812
76304
|
var init_chunkLog = __esm(() => {
|
|
75813
76305
|
init_debug();
|
|
75814
|
-
LOG_BASE_DIR = join26(
|
|
76306
|
+
LOG_BASE_DIR = join26(homedir21(), ".letta", "logs", "chunk-logs");
|
|
75815
76307
|
chunkLog = new ChunkLog;
|
|
75816
76308
|
});
|
|
75817
76309
|
|
|
@@ -75857,6 +76349,7 @@ class StreamProcessor {
|
|
|
75857
76349
|
const errorDetail = chunkWithError.error.detail || "";
|
|
75858
76350
|
errorInfo = {
|
|
75859
76351
|
message: errorDetail ? `${errorText}: ${errorDetail}` : errorText,
|
|
76352
|
+
detail: errorDetail || undefined,
|
|
75860
76353
|
run_id: this.lastRunId || undefined
|
|
75861
76354
|
};
|
|
75862
76355
|
}
|
|
@@ -76827,6 +77320,7 @@ var init_engine = __esm(async () => {
|
|
|
76827
77320
|
default: "Normal approval flow.",
|
|
76828
77321
|
acceptEdits: "File edits auto-approved.",
|
|
76829
77322
|
plan: "Read-only mode. Focus on exploration and planning.",
|
|
77323
|
+
memory: "Memory-scoped mode. Reads are broad; mutations are limited to allowed memory roots.",
|
|
76830
77324
|
bypassPermissions: "All tools auto-approved. Bias toward action."
|
|
76831
77325
|
};
|
|
76832
77326
|
sharedReminderProviders = {
|
|
@@ -76939,10 +77433,10 @@ var init_constants2 = __esm(() => {
|
|
|
76939
77433
|
// src/websocket/listener/remote-settings.ts
|
|
76940
77434
|
import { existsSync as existsSync21, readFileSync as readFileSync12 } from "node:fs";
|
|
76941
77435
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
76942
|
-
import { homedir as
|
|
77436
|
+
import { homedir as homedir22 } from "node:os";
|
|
76943
77437
|
import path20 from "node:path";
|
|
76944
77438
|
function getRemoteSettingsPath() {
|
|
76945
|
-
return path20.join(
|
|
77439
|
+
return path20.join(homedir22(), ".letta", "remote-settings.json");
|
|
76946
77440
|
}
|
|
76947
77441
|
function loadRemoteSettings() {
|
|
76948
77442
|
if (_cache !== null) {
|
|
@@ -76986,7 +77480,7 @@ function saveRemoteSettings(updates) {
|
|
|
76986
77480
|
}
|
|
76987
77481
|
function loadLegacyCwdCache() {
|
|
76988
77482
|
try {
|
|
76989
|
-
const legacyPath = path20.join(
|
|
77483
|
+
const legacyPath = path20.join(homedir22(), ".letta", "cwd-cache.json");
|
|
76990
77484
|
if (!existsSync21(legacyPath))
|
|
76991
77485
|
return {};
|
|
76992
77486
|
const raw = readFileSync12(legacyPath, "utf-8");
|
|
@@ -77186,13 +77680,52 @@ function requestApprovalOverWS(runtime, socket, requestId, controlRequest) {
|
|
|
77186
77680
|
if (socket.readyState !== WebSocket.OPEN) {
|
|
77187
77681
|
return Promise.reject(new Error("WebSocket not open"));
|
|
77188
77682
|
}
|
|
77683
|
+
const abortSignal = runtime.activeAbortController?.signal ?? null;
|
|
77684
|
+
const isInterrupted = () => runtime.cancelRequested || abortSignal?.aborted === true;
|
|
77685
|
+
if (isInterrupted()) {
|
|
77686
|
+
return Promise.reject(new Error("Cancelled by user"));
|
|
77687
|
+
}
|
|
77189
77688
|
return new Promise((resolve23, reject) => {
|
|
77689
|
+
let settled = false;
|
|
77690
|
+
const cleanupAbortListener = () => {
|
|
77691
|
+
abortSignal?.removeEventListener("abort", handleAbort);
|
|
77692
|
+
};
|
|
77693
|
+
const wrappedResolve = (response) => {
|
|
77694
|
+
if (settled) {
|
|
77695
|
+
return;
|
|
77696
|
+
}
|
|
77697
|
+
settled = true;
|
|
77698
|
+
cleanupAbortListener();
|
|
77699
|
+
resolve23(response);
|
|
77700
|
+
};
|
|
77701
|
+
const wrappedReject = (error) => {
|
|
77702
|
+
if (settled) {
|
|
77703
|
+
return;
|
|
77704
|
+
}
|
|
77705
|
+
settled = true;
|
|
77706
|
+
cleanupAbortListener();
|
|
77707
|
+
reject(error);
|
|
77708
|
+
};
|
|
77709
|
+
const handleAbort = () => {
|
|
77710
|
+
runtime.pendingApprovalResolvers.delete(requestId);
|
|
77711
|
+
runtime.listener.approvalRuntimeKeyByRequestId.delete(requestId);
|
|
77712
|
+
wrappedReject(new Error("Cancelled by user"));
|
|
77713
|
+
};
|
|
77714
|
+
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
77715
|
+
if (isInterrupted()) {
|
|
77716
|
+
handleAbort();
|
|
77717
|
+
return;
|
|
77718
|
+
}
|
|
77190
77719
|
runtime.pendingApprovalResolvers.set(requestId, {
|
|
77191
|
-
resolve:
|
|
77192
|
-
reject,
|
|
77720
|
+
resolve: wrappedResolve,
|
|
77721
|
+
reject: wrappedReject,
|
|
77193
77722
|
controlRequest
|
|
77194
77723
|
});
|
|
77195
77724
|
runtime.listener.approvalRuntimeKeyByRequestId.set(requestId, runtime.key);
|
|
77725
|
+
if (isInterrupted()) {
|
|
77726
|
+
handleAbort();
|
|
77727
|
+
return;
|
|
77728
|
+
}
|
|
77196
77729
|
runtime.lastStopReason = "requires_approval";
|
|
77197
77730
|
setLoopStatus(runtime, "WAITING_ON_APPROVAL");
|
|
77198
77731
|
emitLoopStatusIfOpen(runtime.listener, {
|
|
@@ -77489,12 +78022,18 @@ function populateInterruptQueue(runtime, input) {
|
|
|
77489
78022
|
return false;
|
|
77490
78023
|
}
|
|
77491
78024
|
function consumeInterruptQueue(runtime, agentId, conversationId) {
|
|
78025
|
+
const ctx = runtime.pendingInterruptedContext;
|
|
78026
|
+
const matchingContext = !!ctx && ctx.agentId === agentId && ctx.conversationId === conversationId && ctx.continuationEpoch === runtime.continuationEpoch;
|
|
77492
78027
|
if (!runtime.pendingInterruptedResults || runtime.pendingInterruptedResults.length === 0) {
|
|
78028
|
+
if (matchingContext) {
|
|
78029
|
+
runtime.pendingInterruptedResults = null;
|
|
78030
|
+
runtime.pendingInterruptedContext = null;
|
|
78031
|
+
runtime.pendingInterruptedToolCallIds = null;
|
|
78032
|
+
}
|
|
77493
78033
|
return null;
|
|
77494
78034
|
}
|
|
77495
|
-
const ctx = runtime.pendingInterruptedContext;
|
|
77496
78035
|
let result = null;
|
|
77497
|
-
if (
|
|
78036
|
+
if (matchingContext) {
|
|
77498
78037
|
result = {
|
|
77499
78038
|
approvalMessage: {
|
|
77500
78039
|
type: "approval",
|
|
@@ -77691,6 +78230,104 @@ function mirrorRecoverableNoticeToDesktopDebugPanel(message) {
|
|
|
77691
78230
|
`);
|
|
77692
78231
|
} catch {}
|
|
77693
78232
|
}
|
|
78233
|
+
function toStructuredApiError(errorInfo) {
|
|
78234
|
+
if (!errorInfo?.error_type || !errorInfo.run_id) {
|
|
78235
|
+
return;
|
|
78236
|
+
}
|
|
78237
|
+
return {
|
|
78238
|
+
message_type: "error_message",
|
|
78239
|
+
message: errorInfo.message || errorInfo.detail || "An error occurred",
|
|
78240
|
+
error_type: errorInfo.error_type,
|
|
78241
|
+
run_id: errorInfo.run_id,
|
|
78242
|
+
...errorInfo.detail ? { detail: errorInfo.detail } : {}
|
|
78243
|
+
};
|
|
78244
|
+
}
|
|
78245
|
+
function getStructuredApiErrorFromError(error) {
|
|
78246
|
+
if (!(error instanceof Error)) {
|
|
78247
|
+
return;
|
|
78248
|
+
}
|
|
78249
|
+
const errorWithStructuredInfo = error;
|
|
78250
|
+
return errorWithStructuredInfo.apiError ?? toStructuredApiError(errorWithStructuredInfo.runErrorInfo);
|
|
78251
|
+
}
|
|
78252
|
+
function buildStructuredFormatInput(apiError) {
|
|
78253
|
+
return {
|
|
78254
|
+
error: {
|
|
78255
|
+
error: {
|
|
78256
|
+
type: apiError.error_type,
|
|
78257
|
+
message: apiError.message,
|
|
78258
|
+
...apiError.detail ? { detail: apiError.detail } : {}
|
|
78259
|
+
},
|
|
78260
|
+
run_id: apiError.run_id
|
|
78261
|
+
}
|
|
78262
|
+
};
|
|
78263
|
+
}
|
|
78264
|
+
function isAbortLikeError(error) {
|
|
78265
|
+
if (error instanceof APIUserAbortError) {
|
|
78266
|
+
return true;
|
|
78267
|
+
}
|
|
78268
|
+
if (!(error instanceof Error)) {
|
|
78269
|
+
return false;
|
|
78270
|
+
}
|
|
78271
|
+
const errorWithCode = error;
|
|
78272
|
+
return error.name === "AbortError" || error.message === "The operation was aborted" || errorWithCode.code === "ABORT_ERR";
|
|
78273
|
+
}
|
|
78274
|
+
function isTerminatedProcessNoise(message) {
|
|
78275
|
+
return message.trim().toLowerCase() === "terminated";
|
|
78276
|
+
}
|
|
78277
|
+
function isProxyTransportError(detail, error, message) {
|
|
78278
|
+
if (error instanceof APIError2 && error.status >= 500 && detail.toLowerCase().includes("trying to proxy")) {
|
|
78279
|
+
return true;
|
|
78280
|
+
}
|
|
78281
|
+
return detail.toLowerCase().includes("error occurred while trying to proxy") || message.toLowerCase().includes("error occurred while trying to proxy");
|
|
78282
|
+
}
|
|
78283
|
+
function getLoopErrorNoticeDecision(params) {
|
|
78284
|
+
const apiError = params.apiError ?? toStructuredApiError(params.errorInfo) ?? toStructuredApiError(params.runErrorInfo) ?? getStructuredApiErrorFromError(params.error);
|
|
78285
|
+
const detail = apiError?.detail ?? params.errorInfo?.detail ?? params.runErrorInfo?.detail ?? extractConflictDetail(params.error) ?? "";
|
|
78286
|
+
if (params.cancelRequested || params.abortSignal?.aborted || isAbortLikeError(params.error) || isTerminatedProcessNoise(params.message)) {
|
|
78287
|
+
return {
|
|
78288
|
+
visibility: "debug_only",
|
|
78289
|
+
message: params.message
|
|
78290
|
+
};
|
|
78291
|
+
}
|
|
78292
|
+
const cloudflareMessage = checkCloudflareEdgeError2(detail) ?? checkCloudflareEdgeError2(params.message);
|
|
78293
|
+
if (cloudflareMessage) {
|
|
78294
|
+
return {
|
|
78295
|
+
visibility: "transcript",
|
|
78296
|
+
message: cloudflareMessage,
|
|
78297
|
+
apiError
|
|
78298
|
+
};
|
|
78299
|
+
}
|
|
78300
|
+
if (isProxyTransportError(detail, params.error, params.message)) {
|
|
78301
|
+
return {
|
|
78302
|
+
visibility: "transcript",
|
|
78303
|
+
message: "Connection to Letta service failed. Please retry.",
|
|
78304
|
+
apiError
|
|
78305
|
+
};
|
|
78306
|
+
}
|
|
78307
|
+
const formattedMessage = formatErrorDetails2(apiError ? buildStructuredFormatInput(apiError) : params.error ?? params.message, params.agentId ?? undefined, params.conversationId ?? undefined);
|
|
78308
|
+
return {
|
|
78309
|
+
visibility: "transcript",
|
|
78310
|
+
message: formattedMessage,
|
|
78311
|
+
apiError
|
|
78312
|
+
};
|
|
78313
|
+
}
|
|
78314
|
+
function emitLoopErrorNotice(socket, runtime, params) {
|
|
78315
|
+
const decision = getLoopErrorNoticeDecision(params);
|
|
78316
|
+
if (decision.visibility === "debug_only") {
|
|
78317
|
+
debugLog("recovery", `Debug-only loop error (${params.stopReason}): ${params.message}`);
|
|
78318
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
78319
|
+
return;
|
|
78320
|
+
}
|
|
78321
|
+
emitLoopErrorDelta(socket, runtime, {
|
|
78322
|
+
message: decision.message,
|
|
78323
|
+
stopReason: params.stopReason,
|
|
78324
|
+
isTerminal: params.isTerminal,
|
|
78325
|
+
runId: params.runId,
|
|
78326
|
+
agentId: params.agentId,
|
|
78327
|
+
conversationId: params.conversationId,
|
|
78328
|
+
apiError: decision.apiError
|
|
78329
|
+
});
|
|
78330
|
+
}
|
|
77694
78331
|
function emitRecoverableStatusNotice(socket, runtime, params) {
|
|
77695
78332
|
const visibility = getRecoverableStatusNoticeVisibility(params.kind);
|
|
77696
78333
|
if (visibility === "debug_only") {
|
|
@@ -77726,6 +78363,9 @@ function emitRecoverableRetryNotice(socket, runtime, params) {
|
|
|
77726
78363
|
}
|
|
77727
78364
|
var DESKTOP_DEBUG_PANEL_INFO_PREFIX = "[LETTA_DESKTOP_DEBUG_PANEL_INFO]";
|
|
77728
78365
|
var init_recoverable_notices = __esm(async () => {
|
|
78366
|
+
init_error();
|
|
78367
|
+
init_turn_recovery_policy();
|
|
78368
|
+
init_errorFormatter();
|
|
77729
78369
|
init_debug();
|
|
77730
78370
|
await init_protocol_outbound();
|
|
77731
78371
|
});
|
|
@@ -78515,7 +79155,7 @@ __export(exports_diff, {
|
|
|
78515
79155
|
ADV_DIFF_IGNORE_WHITESPACE: () => ADV_DIFF_IGNORE_WHITESPACE,
|
|
78516
79156
|
ADV_DIFF_CONTEXT_LINES: () => ADV_DIFF_CONTEXT_LINES
|
|
78517
79157
|
});
|
|
78518
|
-
import { basename as
|
|
79158
|
+
import { basename as basename3 } from "node:path";
|
|
78519
79159
|
function readFileOrNull(p) {
|
|
78520
79160
|
try {
|
|
78521
79161
|
return __require("node:fs").readFileSync(p, "utf-8");
|
|
@@ -78539,7 +79179,7 @@ function applyAllOccurrences(content, oldStr, newStr) {
|
|
|
78539
79179
|
return { ok: true, out: content.split(oldStr).join(newStr) };
|
|
78540
79180
|
}
|
|
78541
79181
|
function computeAdvancedDiff(input, opts) {
|
|
78542
|
-
const fileName =
|
|
79182
|
+
const fileName = basename3(input.filePath || "");
|
|
78543
79183
|
const fileContent = opts?.oldStrOverride !== undefined ? opts.oldStrOverride : readFileOrNull(input.filePath);
|
|
78544
79184
|
if (fileContent === null && input.kind !== "write") {
|
|
78545
79185
|
return { mode: "fallback", reason: "File not readable" };
|
|
@@ -78605,7 +79245,7 @@ function computeAdvancedDiff(input, opts) {
|
|
|
78605
79245
|
return { mode: "advanced", fileName, oldStr, newStr, hunks };
|
|
78606
79246
|
}
|
|
78607
79247
|
function parsePatchToAdvancedDiff(patchLines, filePath) {
|
|
78608
|
-
const fileName =
|
|
79248
|
+
const fileName = basename3(filePath);
|
|
78609
79249
|
const hunks = [];
|
|
78610
79250
|
let currentHunk = null;
|
|
78611
79251
|
let oldLine = 1;
|
|
@@ -78932,7 +79572,7 @@ var init_formatArgsDisplay = __esm(async () => {
|
|
|
78932
79572
|
});
|
|
78933
79573
|
|
|
78934
79574
|
// src/helpers/diffPreview.ts
|
|
78935
|
-
import path21, { basename as
|
|
79575
|
+
import path21, { basename as basename4 } from "node:path";
|
|
78936
79576
|
function parseHunkLinePrefix(raw) {
|
|
78937
79577
|
if (raw.length === 0) {
|
|
78938
79578
|
return { type: "context", content: "" };
|
|
@@ -79038,7 +79678,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
79038
79678
|
filePath: resolvedFilePath,
|
|
79039
79679
|
content: toolArgs.content || ""
|
|
79040
79680
|
});
|
|
79041
|
-
previews.push(toDiffPreview(result,
|
|
79681
|
+
previews.push(toDiffPreview(result, basename4(filePath)));
|
|
79042
79682
|
}
|
|
79043
79683
|
} else if (isFileEditTool2(toolName)) {
|
|
79044
79684
|
const filePath = toolArgs.file_path;
|
|
@@ -79050,7 +79690,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
79050
79690
|
filePath: resolvedFilePath,
|
|
79051
79691
|
edits: toolArgs.edits
|
|
79052
79692
|
});
|
|
79053
|
-
previews.push(toDiffPreview(result,
|
|
79693
|
+
previews.push(toDiffPreview(result, basename4(filePath)));
|
|
79054
79694
|
} else {
|
|
79055
79695
|
const result = computeAdvancedDiff2({
|
|
79056
79696
|
kind: "edit",
|
|
@@ -79059,7 +79699,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
79059
79699
|
newString: toolArgs.new_string || "",
|
|
79060
79700
|
replaceAll: toolArgs.replace_all
|
|
79061
79701
|
});
|
|
79062
|
-
previews.push(toDiffPreview(result,
|
|
79702
|
+
previews.push(toDiffPreview(result, basename4(filePath)));
|
|
79063
79703
|
}
|
|
79064
79704
|
}
|
|
79065
79705
|
} else if (isPatchTool2(toolName) && toolArgs.input) {
|
|
@@ -79068,7 +79708,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
79068
79708
|
if (op.kind === "add" || op.kind === "update") {
|
|
79069
79709
|
const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
79070
79710
|
if (result) {
|
|
79071
|
-
previews.push(toDiffPreview(result,
|
|
79711
|
+
previews.push(toDiffPreview(result, basename4(op.path)));
|
|
79072
79712
|
}
|
|
79073
79713
|
}
|
|
79074
79714
|
}
|
|
@@ -79078,7 +79718,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
79078
79718
|
if (op.kind === "add" || op.kind === "update") {
|
|
79079
79719
|
const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
79080
79720
|
if (result) {
|
|
79081
|
-
previews.push(toDiffPreview(result,
|
|
79721
|
+
previews.push(toDiffPreview(result, basename4(op.path)));
|
|
79082
79722
|
}
|
|
79083
79723
|
}
|
|
79084
79724
|
}
|
|
@@ -79309,13 +79949,15 @@ async function drainRecoveryStreamWithEmission(recoveryStream, socket, runtime,
|
|
|
79309
79949
|
}
|
|
79310
79950
|
}
|
|
79311
79951
|
if (errorInfo) {
|
|
79312
|
-
|
|
79952
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
79313
79953
|
message: errorInfo.message || "Stream error",
|
|
79314
79954
|
stopReason: errorInfo.error_type || "error",
|
|
79315
79955
|
isTerminal: false,
|
|
79316
79956
|
runId: runtime.activeRunId || errorInfo.run_id,
|
|
79317
79957
|
agentId: params.agentId ?? undefined,
|
|
79318
|
-
conversationId: params.conversationId
|
|
79958
|
+
conversationId: params.conversationId,
|
|
79959
|
+
errorInfo,
|
|
79960
|
+
abortSignal: params.abortSignal
|
|
79319
79961
|
});
|
|
79320
79962
|
}
|
|
79321
79963
|
if (shouldOutput) {
|
|
@@ -79366,7 +80008,7 @@ function finalizeHandledRecoveryTurn(runtime, socket, params) {
|
|
|
79366
80008
|
const runId = runtime.activeRunId;
|
|
79367
80009
|
clearActiveRunState(runtime);
|
|
79368
80010
|
emitRuntimeStateUpdates(runtime, scope);
|
|
79369
|
-
|
|
80011
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
79370
80012
|
message: `Recovery continuation ended unexpectedly: ${terminalStopReason}`,
|
|
79371
80013
|
stopReason: terminalStopReason,
|
|
79372
80014
|
isTerminal: true,
|
|
@@ -79703,7 +80345,8 @@ var init_recovery = __esm(async () => {
|
|
|
79703
80345
|
init_approval_suggestions(),
|
|
79704
80346
|
init_interrupts(),
|
|
79705
80347
|
init_protocol_outbound(),
|
|
79706
|
-
init_queue()
|
|
80348
|
+
init_queue(),
|
|
80349
|
+
init_recoverable_notices()
|
|
79707
80350
|
]);
|
|
79708
80351
|
});
|
|
79709
80352
|
|
|
@@ -80004,8 +80647,8 @@ async function sendMessageStreamWithRetry(conversationId, messages, opts, socket
|
|
|
80004
80647
|
throw new Error("Cancelled by user");
|
|
80005
80648
|
}
|
|
80006
80649
|
}
|
|
80007
|
-
const
|
|
80008
|
-
throw new Error(detail || `Pre-stream approval conflict after ${preStreamRecoveryAttempts} recovery attempts`);
|
|
80650
|
+
const runErrorInfo = await fetchRunErrorInfo(runtime.activeRunId);
|
|
80651
|
+
throw Object.assign(new Error(runErrorInfo?.detail || runErrorInfo?.message || `Pre-stream approval conflict after ${preStreamRecoveryAttempts} recovery attempts`), { runErrorInfo });
|
|
80009
80652
|
}
|
|
80010
80653
|
if (action === "retry_transient") {
|
|
80011
80654
|
runtime.isRecoveringApprovals = true;
|
|
@@ -80138,8 +80781,8 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
80138
80781
|
}
|
|
80139
80782
|
continue;
|
|
80140
80783
|
}
|
|
80141
|
-
const
|
|
80142
|
-
throw new Error(detail || `Approval continuation conflict after ${preStreamRecoveryAttempts} recovery attempts`);
|
|
80784
|
+
const runErrorInfo = await fetchRunErrorInfo(runtime.activeRunId);
|
|
80785
|
+
throw Object.assign(new Error(runErrorInfo?.detail || runErrorInfo?.message || `Approval continuation conflict after ${preStreamRecoveryAttempts} recovery attempts`), { runErrorInfo });
|
|
80143
80786
|
}
|
|
80144
80787
|
if (action === "retry_transient") {
|
|
80145
80788
|
runtime.isRecoveringApprovals = true;
|
|
@@ -80265,7 +80908,7 @@ async function handleApprovalStop(params) {
|
|
|
80265
80908
|
agent_id: agentId,
|
|
80266
80909
|
conversation_id: conversationId
|
|
80267
80910
|
});
|
|
80268
|
-
|
|
80911
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
80269
80912
|
message: "requires_approval stop returned no approvals",
|
|
80270
80913
|
stopReason: "error",
|
|
80271
80914
|
isTerminal: true,
|
|
@@ -80568,6 +81211,7 @@ var init_turn_approval = __esm(async () => {
|
|
|
80568
81211
|
init_interrupts(),
|
|
80569
81212
|
init_protocol_outbound(),
|
|
80570
81213
|
init_queue(),
|
|
81214
|
+
init_recoverable_notices(),
|
|
80571
81215
|
init_recovery(),
|
|
80572
81216
|
init_send()
|
|
80573
81217
|
]);
|
|
@@ -80899,13 +81543,16 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80899
81543
|
}
|
|
80900
81544
|
if (errorInfo) {
|
|
80901
81545
|
latestErrorText = errorInfo.message || latestErrorText;
|
|
80902
|
-
|
|
81546
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
80903
81547
|
message: errorInfo.message || "Stream error",
|
|
80904
81548
|
stopReason: errorInfo.error_type || "error",
|
|
80905
81549
|
isTerminal: false,
|
|
80906
81550
|
runId: runId || errorInfo.run_id,
|
|
80907
81551
|
agentId,
|
|
80908
|
-
conversationId
|
|
81552
|
+
conversationId,
|
|
81553
|
+
errorInfo,
|
|
81554
|
+
cancelRequested: runtime.cancelRequested,
|
|
81555
|
+
abortSignal: turnAbortSignal
|
|
80909
81556
|
});
|
|
80910
81557
|
}
|
|
80911
81558
|
if (shouldOutput) {
|
|
@@ -80965,7 +81612,8 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80965
81612
|
}
|
|
80966
81613
|
if (stopReason !== "requires_approval") {
|
|
80967
81614
|
const lastRunId = runId || msgRunIds[msgRunIds.length - 1] || null;
|
|
80968
|
-
const
|
|
81615
|
+
const runErrorInfo = lastRunId ? await fetchRunErrorInfo(lastRunId) : null;
|
|
81616
|
+
const errorDetail = latestErrorText || runErrorInfo?.detail || runErrorInfo?.message || null;
|
|
80969
81617
|
if (shouldAttemptPostStopApprovalRecovery({
|
|
80970
81618
|
stopReason,
|
|
80971
81619
|
runIdsSeen: msgRunIds.length,
|
|
@@ -81127,13 +81775,16 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
81127
81775
|
conversation_id: conversationId
|
|
81128
81776
|
});
|
|
81129
81777
|
const errorMessage = errorDetail || `Unexpected stop reason: ${stopReason}`;
|
|
81130
|
-
|
|
81778
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
81131
81779
|
message: errorMessage,
|
|
81132
81780
|
stopReason: effectiveStopReason,
|
|
81133
81781
|
isTerminal: true,
|
|
81134
81782
|
runId,
|
|
81135
81783
|
agentId,
|
|
81136
|
-
conversationId
|
|
81784
|
+
conversationId,
|
|
81785
|
+
runErrorInfo: runErrorInfo ?? undefined,
|
|
81786
|
+
cancelRequested: runtime.cancelRequested,
|
|
81787
|
+
abortSignal: turnAbortSignal
|
|
81137
81788
|
});
|
|
81138
81789
|
break;
|
|
81139
81790
|
}
|
|
@@ -81217,12 +81868,15 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
81217
81868
|
conversation_id: conversationId
|
|
81218
81869
|
});
|
|
81219
81870
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
81220
|
-
|
|
81871
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
81221
81872
|
message: errorMessage,
|
|
81222
81873
|
stopReason: "error",
|
|
81223
81874
|
isTerminal: true,
|
|
81224
81875
|
agentId: agentId || undefined,
|
|
81225
|
-
conversationId
|
|
81876
|
+
conversationId,
|
|
81877
|
+
error,
|
|
81878
|
+
cancelRequested: runtime.cancelRequested,
|
|
81879
|
+
abortSignal: turnAbortSignal
|
|
81226
81880
|
});
|
|
81227
81881
|
if (isDebugEnabled()) {
|
|
81228
81882
|
console.error("[Listen] Error handling message:", error);
|
|
@@ -81588,18 +82242,24 @@ function buildDeviceStatus(runtime, params) {
|
|
|
81588
82242
|
function buildLoopStatus(runtime, params) {
|
|
81589
82243
|
const listener = getListenerRuntime(runtime);
|
|
81590
82244
|
if (!listener) {
|
|
81591
|
-
return {
|
|
82245
|
+
return {
|
|
82246
|
+
status: "WAITING_ON_INPUT",
|
|
82247
|
+
active_run_ids: [],
|
|
82248
|
+
plan_file_path: null
|
|
82249
|
+
};
|
|
81592
82250
|
}
|
|
81593
82251
|
const scope = getScopeForRuntime(runtime, params);
|
|
81594
82252
|
const scopedAgentId = resolveScopedAgentId(listener, scope);
|
|
81595
82253
|
const scopedConversationId = resolveScopedConversationId(listener, scope);
|
|
82254
|
+
const conversationPermissionModeState = getConversationPermissionModeState(listener, scopedAgentId, scopedConversationId);
|
|
81596
82255
|
const conversationRuntime = getConversationRuntime(listener, scopedAgentId, scopedConversationId);
|
|
81597
82256
|
const interruptedCacheActive = hasInterruptedCacheForScope(listener, scope);
|
|
81598
82257
|
const recovered = getRecoveredApprovalStateForScope(listener, scope);
|
|
81599
82258
|
const status = interruptedCacheActive ? !conversationRuntime?.isProcessing ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus === "WAITING_ON_APPROVAL" ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT" : recovered && recovered.pendingRequestIds.size > 0 && conversationRuntime?.loopStatus === "WAITING_ON_INPUT" ? "WAITING_ON_APPROVAL" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT";
|
|
81600
82259
|
return {
|
|
81601
82260
|
status,
|
|
81602
|
-
active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : []
|
|
82261
|
+
active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : [],
|
|
82262
|
+
plan_file_path: conversationPermissionModeState.mode === "plan" ? conversationPermissionModeState.planFilePath : null
|
|
81603
82263
|
};
|
|
81604
82264
|
}
|
|
81605
82265
|
function buildQueueSnapshot(runtime, params) {
|
|
@@ -81829,7 +82489,8 @@ function emitLoopErrorDelta(socket, runtime, params) {
|
|
|
81829
82489
|
...createLifecycleMessageBase("loop_error", params.runId),
|
|
81830
82490
|
message: params.message,
|
|
81831
82491
|
stop_reason: params.stopReason,
|
|
81832
|
-
is_terminal: params.isTerminal
|
|
82492
|
+
is_terminal: params.isTerminal,
|
|
82493
|
+
...params.apiError ? { api_error: params.apiError } : {}
|
|
81833
82494
|
}, {
|
|
81834
82495
|
agent_id: params.agentId,
|
|
81835
82496
|
conversation_id: params.conversationId
|
|
@@ -83072,12 +83733,13 @@ function handleModeChange(msg, socket, runtime, scope) {
|
|
|
83072
83733
|
}
|
|
83073
83734
|
} catch (error) {
|
|
83074
83735
|
trackListenerError("listener_mode_change_failed", error, "listener_mode_change");
|
|
83075
|
-
|
|
83736
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
83076
83737
|
message: error instanceof Error ? error.message : "Mode change failed",
|
|
83077
83738
|
stopReason: "error",
|
|
83078
83739
|
isTerminal: false,
|
|
83079
83740
|
agentId: scope?.agent_id,
|
|
83080
|
-
conversationId: scope?.conversation_id
|
|
83741
|
+
conversationId: scope?.conversation_id,
|
|
83742
|
+
error
|
|
83081
83743
|
});
|
|
83082
83744
|
if (isDebugEnabled()) {
|
|
83083
83745
|
console.error("[Listen] Mode change failed:", error);
|
|
@@ -83431,7 +84093,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
83431
84093
|
symlinkSync,
|
|
83432
84094
|
unlinkSync: unlinkSync8
|
|
83433
84095
|
} = await import("node:fs");
|
|
83434
|
-
const { basename:
|
|
84096
|
+
const { basename: basename5, join: join28 } = await import("node:path");
|
|
83435
84097
|
const lettaHome = process.env.LETTA_HOME || join28(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
|
|
83436
84098
|
const globalSkillsDir = join28(lettaHome, "skills");
|
|
83437
84099
|
if (parsed.type === "skill_enable") {
|
|
@@ -83455,7 +84117,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
83455
84117
|
}, "listener_skill_send_failed", "listener_skill_command");
|
|
83456
84118
|
return true;
|
|
83457
84119
|
}
|
|
83458
|
-
const linkName =
|
|
84120
|
+
const linkName = basename5(parsed.skill_path);
|
|
83459
84121
|
const linkPath = join28(globalSkillsDir, linkName);
|
|
83460
84122
|
mkdirSync15(globalSkillsDir, { recursive: true });
|
|
83461
84123
|
if (existsSync22(linkPath)) {
|
|
@@ -83827,6 +84489,7 @@ async function handleAbortMessageInput(listener, params, deps = {}) {
|
|
|
83827
84489
|
}
|
|
83828
84490
|
const interruptedRunId = scopedRuntime.activeRunId;
|
|
83829
84491
|
scopedRuntime.cancelRequested = true;
|
|
84492
|
+
const pendingRequestsSnapshot = hasPendingApprovals ? resolvedDeps.getPendingControlRequests(listener, scope) : [];
|
|
83830
84493
|
if (scopedRuntime.activeExecutingToolCallIds.length > 0 && (!scopedRuntime.pendingInterruptedResults || scopedRuntime.pendingInterruptedResults.length === 0)) {
|
|
83831
84494
|
scopedRuntime.pendingInterruptedResults = scopedRuntime.activeExecutingToolCallIds.map((toolCallId) => ({
|
|
83832
84495
|
type: "tool",
|
|
@@ -83872,9 +84535,8 @@ async function handleAbortMessageInput(listener, params, deps = {}) {
|
|
|
83872
84535
|
agentId: scope.agent_id,
|
|
83873
84536
|
conversationId: scope.conversation_id
|
|
83874
84537
|
});
|
|
83875
|
-
} else if (hasPendingApprovals) {
|
|
83876
|
-
|
|
83877
|
-
scopedRuntime.pendingInterruptedResults = pendingRequests.map((req) => ({
|
|
84538
|
+
} else if (hasPendingApprovals && (!scopedRuntime.pendingInterruptedResults || scopedRuntime.pendingInterruptedResults.length === 0) && pendingRequestsSnapshot.length > 0) {
|
|
84539
|
+
scopedRuntime.pendingInterruptedResults = pendingRequestsSnapshot.map((req) => ({
|
|
83878
84540
|
type: "approval",
|
|
83879
84541
|
tool_call_id: req.request.tool_call_id,
|
|
83880
84542
|
approve: false,
|
|
@@ -83885,6 +84547,7 @@ async function handleAbortMessageInput(listener, params, deps = {}) {
|
|
|
83885
84547
|
conversationId: scope.conversation_id,
|
|
83886
84548
|
continuationEpoch: scopedRuntime.continuationEpoch
|
|
83887
84549
|
};
|
|
84550
|
+
scopedRuntime.pendingInterruptedToolCallIds = null;
|
|
83888
84551
|
resolvedDeps.emitInterruptedStatusDelta(params.socket, scopedRuntime, {
|
|
83889
84552
|
runId: interruptedRunId,
|
|
83890
84553
|
agentId: scope.agent_id,
|
|
@@ -83929,12 +84592,13 @@ async function handleCwdChange(msg, socket, runtime) {
|
|
|
83929
84592
|
conversation_id: conversationId
|
|
83930
84593
|
});
|
|
83931
84594
|
} catch (error) {
|
|
83932
|
-
|
|
84595
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
83933
84596
|
message: error instanceof Error ? error.message : "Working directory change failed",
|
|
83934
84597
|
stopReason: "error",
|
|
83935
84598
|
isTerminal: false,
|
|
83936
84599
|
agentId,
|
|
83937
|
-
conversationId
|
|
84600
|
+
conversationId,
|
|
84601
|
+
error
|
|
83938
84602
|
});
|
|
83939
84603
|
}
|
|
83940
84604
|
}
|
|
@@ -84153,7 +84817,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84153
84817
|
return;
|
|
84154
84818
|
}
|
|
84155
84819
|
if (parsed.type === "__invalid_input") {
|
|
84156
|
-
|
|
84820
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84157
84821
|
message: parsed.reason,
|
|
84158
84822
|
stopReason: "error",
|
|
84159
84823
|
isTerminal: false,
|
|
@@ -84196,7 +84860,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84196
84860
|
}
|
|
84197
84861
|
const inputPayload = parsed.payload;
|
|
84198
84862
|
if (inputPayload.kind !== "create_message") {
|
|
84199
|
-
|
|
84863
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84200
84864
|
message: `Unsupported input payload kind: ${String(inputPayload.kind)}`,
|
|
84201
84865
|
stopReason: "error",
|
|
84202
84866
|
isTerminal: false,
|
|
@@ -84213,7 +84877,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84213
84877
|
};
|
|
84214
84878
|
const hasApprovalPayload = incoming.messages.some((payload) => ("type" in payload) && payload.type === "approval");
|
|
84215
84879
|
if (hasApprovalPayload) {
|
|
84216
|
-
|
|
84880
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84217
84881
|
message: "Protocol violation: approval payloads are not allowed in input.kind=create_message. Use input.kind=approval_response.",
|
|
84218
84882
|
stopReason: "error",
|
|
84219
84883
|
isTerminal: false,
|
|
@@ -84770,12 +85434,13 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84770
85434
|
if (!parsedScope) {
|
|
84771
85435
|
return;
|
|
84772
85436
|
}
|
|
84773
|
-
|
|
85437
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84774
85438
|
message: error instanceof Error ? error.message : "Failed to process listener message",
|
|
84775
85439
|
stopReason: "error",
|
|
84776
85440
|
isTerminal: false,
|
|
84777
85441
|
agentId: parsedScope.agent_id,
|
|
84778
|
-
conversationId: parsedScope.conversation_id
|
|
85442
|
+
conversationId: parsedScope.conversation_id,
|
|
85443
|
+
error
|
|
84779
85444
|
});
|
|
84780
85445
|
}
|
|
84781
85446
|
});
|
|
@@ -85073,6 +85738,7 @@ var init_client4 = __esm(async () => {
|
|
|
85073
85738
|
init_protocol_inbound(),
|
|
85074
85739
|
init_protocol_outbound(),
|
|
85075
85740
|
init_queue(),
|
|
85741
|
+
init_recoverable_notices(),
|
|
85076
85742
|
init_recovery(),
|
|
85077
85743
|
init_send(),
|
|
85078
85744
|
init_turn(),
|
|
@@ -85171,7 +85837,7 @@ import {
|
|
|
85171
85837
|
readFileSync as readFileSync14,
|
|
85172
85838
|
unlinkSync as unlinkSync8
|
|
85173
85839
|
} from "node:fs";
|
|
85174
|
-
import { homedir as
|
|
85840
|
+
import { homedir as homedir26 } from "node:os";
|
|
85175
85841
|
import { join as join31 } from "node:path";
|
|
85176
85842
|
import { format as format2 } from "node:util";
|
|
85177
85843
|
function isDebugEnabled2() {
|
|
@@ -85277,7 +85943,7 @@ function debugWarn2(prefix, message, ...args) {
|
|
|
85277
85943
|
}
|
|
85278
85944
|
var DEBUG_LOG_DIR2, MAX_SESSION_FILES3 = 5, DEFAULT_TAIL_LINES2 = 50, debugLogFile2;
|
|
85279
85945
|
var init_debug2 = __esm(() => {
|
|
85280
|
-
DEBUG_LOG_DIR2 = join31(
|
|
85946
|
+
DEBUG_LOG_DIR2 = join31(homedir26(), ".letta", "logs", "debug");
|
|
85281
85947
|
debugLogFile2 = new DebugLogFile2;
|
|
85282
85948
|
});
|
|
85283
85949
|
|
|
@@ -85306,10 +85972,10 @@ __export(exports_skills2, {
|
|
|
85306
85972
|
});
|
|
85307
85973
|
import { existsSync as existsSync24 } from "node:fs";
|
|
85308
85974
|
import { readdir as readdir7, readFile as readFile8, realpath as realpath4, stat as stat6 } from "node:fs/promises";
|
|
85309
|
-
import { dirname as
|
|
85975
|
+
import { dirname as dirname13, join as join32 } from "node:path";
|
|
85310
85976
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
85311
85977
|
function getBundledSkillsPath2() {
|
|
85312
|
-
const thisDir =
|
|
85978
|
+
const thisDir = dirname13(fileURLToPath8(import.meta.url));
|
|
85313
85979
|
if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
|
|
85314
85980
|
return join32(thisDir, "../skills/builtin");
|
|
85315
85981
|
}
|
|
@@ -85505,12 +86171,12 @@ import {
|
|
|
85505
86171
|
writeFileSync as fsWriteFileSync2,
|
|
85506
86172
|
mkdirSync as mkdirSync17
|
|
85507
86173
|
} from "node:fs";
|
|
85508
|
-
import { dirname as
|
|
86174
|
+
import { dirname as dirname14 } from "node:path";
|
|
85509
86175
|
async function readFile9(path23) {
|
|
85510
86176
|
return fsReadFileSync2(path23, { encoding: "utf-8" });
|
|
85511
86177
|
}
|
|
85512
86178
|
async function writeFile7(path23, content) {
|
|
85513
|
-
const dir =
|
|
86179
|
+
const dir = dirname14(path23);
|
|
85514
86180
|
if (!existsSync25(dir)) {
|
|
85515
86181
|
mkdirSync17(dir, { recursive: true });
|
|
85516
86182
|
}
|
|
@@ -85555,7 +86221,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85555
86221
|
}
|
|
85556
86222
|
const wasRaw = process.stdin.isRaw;
|
|
85557
86223
|
const wasFlowing = process.stdin.readableFlowing;
|
|
85558
|
-
return new Promise((
|
|
86224
|
+
return new Promise((resolve25) => {
|
|
85559
86225
|
let response = "";
|
|
85560
86226
|
let resolved = false;
|
|
85561
86227
|
const cleanup = () => {
|
|
@@ -85572,7 +86238,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85572
86238
|
};
|
|
85573
86239
|
const timeout = setTimeout(() => {
|
|
85574
86240
|
cleanup();
|
|
85575
|
-
|
|
86241
|
+
resolve25(null);
|
|
85576
86242
|
}, timeoutMs);
|
|
85577
86243
|
const onData = (data) => {
|
|
85578
86244
|
response += data.toString();
|
|
@@ -85582,7 +86248,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85582
86248
|
if (match3) {
|
|
85583
86249
|
clearTimeout(timeout);
|
|
85584
86250
|
cleanup();
|
|
85585
|
-
|
|
86251
|
+
resolve25({
|
|
85586
86252
|
r: parseHexComponent(match3[1] ?? "0"),
|
|
85587
86253
|
g: parseHexComponent(match3[2] ?? "0"),
|
|
85588
86254
|
b: parseHexComponent(match3[3] ?? "0")
|
|
@@ -85597,7 +86263,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85597
86263
|
} catch {
|
|
85598
86264
|
clearTimeout(timeout);
|
|
85599
86265
|
cleanup();
|
|
85600
|
-
|
|
86266
|
+
resolve25(null);
|
|
85601
86267
|
}
|
|
85602
86268
|
});
|
|
85603
86269
|
}
|
|
@@ -86806,10 +87472,10 @@ __export(exports_setup, {
|
|
|
86806
87472
|
runSetup: () => runSetup
|
|
86807
87473
|
});
|
|
86808
87474
|
async function runSetup() {
|
|
86809
|
-
return new Promise((
|
|
87475
|
+
return new Promise((resolve26) => {
|
|
86810
87476
|
const { waitUntilExit } = render_default(import_react32.default.createElement(SetupUI, {
|
|
86811
87477
|
onComplete: () => {
|
|
86812
|
-
|
|
87478
|
+
resolve26();
|
|
86813
87479
|
}
|
|
86814
87480
|
}));
|
|
86815
87481
|
waitUntilExit().catch((error) => {
|
|
@@ -87339,10 +88005,10 @@ __export(exports_import, {
|
|
|
87339
88005
|
});
|
|
87340
88006
|
import { createReadStream } from "node:fs";
|
|
87341
88007
|
import { chmod, mkdir as mkdir7, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
|
|
87342
|
-
import { dirname as
|
|
88008
|
+
import { dirname as dirname15, resolve as resolve26 } from "node:path";
|
|
87343
88009
|
async function importAgentFromFile(options) {
|
|
87344
88010
|
const client = await getClient();
|
|
87345
|
-
const resolvedPath =
|
|
88011
|
+
const resolvedPath = resolve26(options.filePath);
|
|
87346
88012
|
const file = createReadStream(resolvedPath);
|
|
87347
88013
|
const importResponse = await client.agents.importFile({
|
|
87348
88014
|
file,
|
|
@@ -87377,7 +88043,7 @@ async function extractSkillsFromAf(afPath, destDir) {
|
|
|
87377
88043
|
return [];
|
|
87378
88044
|
}
|
|
87379
88045
|
for (const skill2 of afData.skills) {
|
|
87380
|
-
const skillDir =
|
|
88046
|
+
const skillDir = resolve26(destDir, skill2.name);
|
|
87381
88047
|
await mkdir7(skillDir, { recursive: true });
|
|
87382
88048
|
if (skill2.files) {
|
|
87383
88049
|
await writeSkillFiles(skillDir, skill2.files);
|
|
@@ -87397,8 +88063,8 @@ async function writeSkillFiles(skillDir, files) {
|
|
|
87397
88063
|
}
|
|
87398
88064
|
}
|
|
87399
88065
|
async function writeSkillFile(skillDir, filePath, content) {
|
|
87400
|
-
const fullPath =
|
|
87401
|
-
await mkdir7(
|
|
88066
|
+
const fullPath = resolve26(skillDir, filePath);
|
|
88067
|
+
await mkdir7(dirname15(fullPath), { recursive: true });
|
|
87402
88068
|
await writeFile8(fullPath, content, "utf-8");
|
|
87403
88069
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
87404
88070
|
if (isScript) {
|
|
@@ -87704,12 +88370,12 @@ async function prepareHeadlessToolExecutionContext(params) {
|
|
|
87704
88370
|
};
|
|
87705
88371
|
}
|
|
87706
88372
|
async function flushAndExit(code) {
|
|
87707
|
-
const flushWritable = (stream2) => new Promise((
|
|
88373
|
+
const flushWritable = (stream2) => new Promise((resolve27) => {
|
|
87708
88374
|
if (stream2.destroyed || stream2.writableEnded) {
|
|
87709
|
-
|
|
88375
|
+
resolve27();
|
|
87710
88376
|
return;
|
|
87711
88377
|
}
|
|
87712
|
-
stream2.write("", () =>
|
|
88378
|
+
stream2.write("", () => resolve27());
|
|
87713
88379
|
});
|
|
87714
88380
|
await Promise.allSettled([
|
|
87715
88381
|
flushWritable(process.stdout),
|
|
@@ -87735,7 +88401,8 @@ async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride,
|
|
|
87735
88401
|
"default",
|
|
87736
88402
|
"acceptEdits",
|
|
87737
88403
|
"bypassPermissions",
|
|
87738
|
-
"plan"
|
|
88404
|
+
"plan",
|
|
88405
|
+
"memory"
|
|
87739
88406
|
];
|
|
87740
88407
|
if (validModes.includes(permissionModeValue)) {
|
|
87741
88408
|
permissionMode3.setMode(permissionModeValue);
|
|
@@ -88656,7 +89323,7 @@ ${loadedContents.join(`
|
|
|
88656
89323
|
} else {
|
|
88657
89324
|
console.error(`Conversation is busy, waiting ${Math.round(retryDelayMs / 1000)}s and retrying...`);
|
|
88658
89325
|
}
|
|
88659
|
-
await new Promise((
|
|
89326
|
+
await new Promise((resolve27) => setTimeout(resolve27, retryDelayMs));
|
|
88660
89327
|
continue;
|
|
88661
89328
|
}
|
|
88662
89329
|
}
|
|
@@ -88705,7 +89372,7 @@ ${loadedContents.join(`
|
|
|
88705
89372
|
const delaySeconds = Math.round(delayMs / 1000);
|
|
88706
89373
|
console.error(`Transient API error before streaming (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
|
|
88707
89374
|
}
|
|
88708
|
-
await new Promise((
|
|
89375
|
+
await new Promise((resolve27) => setTimeout(resolve27, delayMs));
|
|
88709
89376
|
conversationBusyRetries = 0;
|
|
88710
89377
|
continue;
|
|
88711
89378
|
}
|
|
@@ -88944,7 +89611,7 @@ ${loadedContents.join(`
|
|
|
88944
89611
|
const delaySeconds = Math.round(delayMs / 1000);
|
|
88945
89612
|
console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
|
|
88946
89613
|
}
|
|
88947
|
-
await new Promise((
|
|
89614
|
+
await new Promise((resolve27) => setTimeout(resolve27, delayMs));
|
|
88948
89615
|
refreshCurrentInputOtids();
|
|
88949
89616
|
continue;
|
|
88950
89617
|
}
|
|
@@ -89030,7 +89697,7 @@ ${loadedContents.join(`
|
|
|
89030
89697
|
} else {
|
|
89031
89698
|
console.error(`Empty LLM response, retrying (attempt ${attempt} of ${EMPTY_RESPONSE_MAX_RETRIES2})...`);
|
|
89032
89699
|
}
|
|
89033
|
-
await new Promise((
|
|
89700
|
+
await new Promise((resolve27) => setTimeout(resolve27, delayMs));
|
|
89034
89701
|
refreshCurrentInputOtids();
|
|
89035
89702
|
continue;
|
|
89036
89703
|
}
|
|
@@ -89058,7 +89725,7 @@ ${loadedContents.join(`
|
|
|
89058
89725
|
const delaySeconds = Math.round(delayMs / 1000);
|
|
89059
89726
|
console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
|
|
89060
89727
|
}
|
|
89061
|
-
await new Promise((
|
|
89728
|
+
await new Promise((resolve27) => setTimeout(resolve27, delayMs));
|
|
89062
89729
|
refreshCurrentInputOtids();
|
|
89063
89730
|
continue;
|
|
89064
89731
|
}
|
|
@@ -89392,9 +90059,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89392
90059
|
const syntheticUserLine = serializeQueuedMessageAsUserLine(queuedMessage);
|
|
89393
90060
|
maybeNotifyBlocked(syntheticUserLine);
|
|
89394
90061
|
if (lineResolver) {
|
|
89395
|
-
const
|
|
90062
|
+
const resolve27 = lineResolver;
|
|
89396
90063
|
lineResolver = null;
|
|
89397
|
-
|
|
90064
|
+
resolve27(syntheticUserLine);
|
|
89398
90065
|
return;
|
|
89399
90066
|
}
|
|
89400
90067
|
lineQueue.push(syntheticUserLine);
|
|
@@ -89402,9 +90069,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89402
90069
|
rl.on("line", (line) => {
|
|
89403
90070
|
maybeNotifyBlocked(line);
|
|
89404
90071
|
if (lineResolver) {
|
|
89405
|
-
const
|
|
90072
|
+
const resolve27 = lineResolver;
|
|
89406
90073
|
lineResolver = null;
|
|
89407
|
-
|
|
90074
|
+
resolve27(line);
|
|
89408
90075
|
} else {
|
|
89409
90076
|
lineQueue.push(line);
|
|
89410
90077
|
}
|
|
@@ -89413,17 +90080,17 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89413
90080
|
setMessageQueueAdder(null);
|
|
89414
90081
|
msgQueueRuntime.clear("shutdown");
|
|
89415
90082
|
if (lineResolver) {
|
|
89416
|
-
const
|
|
90083
|
+
const resolve27 = lineResolver;
|
|
89417
90084
|
lineResolver = null;
|
|
89418
|
-
|
|
90085
|
+
resolve27(null);
|
|
89419
90086
|
}
|
|
89420
90087
|
});
|
|
89421
90088
|
async function getNextLine() {
|
|
89422
90089
|
if (lineQueue.length > 0) {
|
|
89423
90090
|
return lineQueue.shift() ?? null;
|
|
89424
90091
|
}
|
|
89425
|
-
return new Promise((
|
|
89426
|
-
lineResolver =
|
|
90092
|
+
return new Promise((resolve27) => {
|
|
90093
|
+
lineResolver = resolve27;
|
|
89427
90094
|
});
|
|
89428
90095
|
}
|
|
89429
90096
|
async function requestPermission(toolCallId, toolName, toolInput) {
|
|
@@ -89927,7 +90594,7 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89927
90594
|
uuid: `retry-bidir-${randomUUID8()}`
|
|
89928
90595
|
};
|
|
89929
90596
|
console.log(JSON.stringify(retryMsg));
|
|
89930
|
-
await new Promise((
|
|
90597
|
+
await new Promise((resolve27) => setTimeout(resolve27, delayMs));
|
|
89931
90598
|
continue;
|
|
89932
90599
|
}
|
|
89933
90600
|
throw preStreamError;
|
|
@@ -90223,10 +90890,10 @@ async function detectAndEnableKittyProtocol() {
|
|
|
90223
90890
|
detectionComplete = true;
|
|
90224
90891
|
return;
|
|
90225
90892
|
}
|
|
90226
|
-
return new Promise((
|
|
90893
|
+
return new Promise((resolve27) => {
|
|
90227
90894
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
90228
90895
|
detectionComplete = true;
|
|
90229
|
-
|
|
90896
|
+
resolve27();
|
|
90230
90897
|
return;
|
|
90231
90898
|
}
|
|
90232
90899
|
const originalRawMode = process.stdin.isRaw;
|
|
@@ -90259,7 +90926,7 @@ async function detectAndEnableKittyProtocol() {
|
|
|
90259
90926
|
console.error("[kitty] protocol query unsupported; enabled anyway (best-effort)");
|
|
90260
90927
|
}
|
|
90261
90928
|
detectionComplete = true;
|
|
90262
|
-
|
|
90929
|
+
resolve27();
|
|
90263
90930
|
};
|
|
90264
90931
|
const handleData = (data) => {
|
|
90265
90932
|
if (timeoutId === undefined) {
|
|
@@ -90617,10 +91284,10 @@ __export(exports_settings, {
|
|
|
90617
91284
|
loadProjectSettings: () => loadProjectSettings,
|
|
90618
91285
|
getSetting: () => getSetting
|
|
90619
91286
|
});
|
|
90620
|
-
import { homedir as
|
|
91287
|
+
import { homedir as homedir29 } from "node:os";
|
|
90621
91288
|
import { join as join36 } from "node:path";
|
|
90622
91289
|
function getSettingsPath() {
|
|
90623
|
-
return join36(
|
|
91290
|
+
return join36(homedir29(), ".letta", "settings.json");
|
|
90624
91291
|
}
|
|
90625
91292
|
async function loadSettings() {
|
|
90626
91293
|
const settingsPath = getSettingsPath();
|
|
@@ -106126,16 +106793,16 @@ function clipStyledSpans(spans, maxColumns) {
|
|
|
106126
106793
|
return { spans: clipped, clipped: false };
|
|
106127
106794
|
}
|
|
106128
106795
|
function languageFromPath(filePath) {
|
|
106129
|
-
const
|
|
106130
|
-
const lower =
|
|
106796
|
+
const basename5 = filePath.split("/").pop() ?? filePath;
|
|
106797
|
+
const lower = basename5.toLowerCase();
|
|
106131
106798
|
if (lower === "makefile")
|
|
106132
106799
|
return "makefile";
|
|
106133
106800
|
if (lower === "dockerfile")
|
|
106134
106801
|
return "dockerfile";
|
|
106135
|
-
const dotIdx =
|
|
106802
|
+
const dotIdx = basename5.lastIndexOf(".");
|
|
106136
106803
|
if (dotIdx < 0)
|
|
106137
106804
|
return;
|
|
106138
|
-
const ext3 =
|
|
106805
|
+
const ext3 = basename5.slice(dotIdx + 1).toLowerCase();
|
|
106139
106806
|
return EXT_TO_LANG[ext3];
|
|
106140
106807
|
}
|
|
106141
106808
|
function colorForClassName(className, palette) {
|
|
@@ -110171,7 +110838,7 @@ var init_plan_viewer_template = () => {};
|
|
|
110171
110838
|
|
|
110172
110839
|
// src/web/generate-plan-viewer.ts
|
|
110173
110840
|
import { chmodSync as chmodSync2, existsSync as existsSync28, mkdirSync as mkdirSync20, writeFileSync as writeFileSync14 } from "node:fs";
|
|
110174
|
-
import { homedir as
|
|
110841
|
+
import { homedir as homedir30 } from "node:os";
|
|
110175
110842
|
import { join as join37 } from "node:path";
|
|
110176
110843
|
async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
110177
110844
|
const data = {
|
|
@@ -110205,7 +110872,7 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
|
110205
110872
|
var VIEWERS_DIR;
|
|
110206
110873
|
var init_generate_plan_viewer = __esm(() => {
|
|
110207
110874
|
init_plan_viewer_template();
|
|
110208
|
-
VIEWERS_DIR = join37(
|
|
110875
|
+
VIEWERS_DIR = join37(homedir30(), ".letta", "viewers");
|
|
110209
110876
|
});
|
|
110210
110877
|
|
|
110211
110878
|
// src/cli/components/StaticPlanApproval.tsx
|
|
@@ -112445,7 +113112,7 @@ var init_pasteRegistry = __esm(() => {
|
|
|
112445
113112
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
112446
113113
|
import { existsSync as existsSync29, readFileSync as readFileSync16, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
|
|
112447
113114
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
112448
|
-
import { basename as
|
|
113115
|
+
import { basename as basename5, extname as extname5, isAbsolute as isAbsolute19, join as join38, resolve as resolve27 } from "node:path";
|
|
112449
113116
|
function countLines2(text) {
|
|
112450
113117
|
return (text.match(/\r\n|\r|\n/g) || []).length + 1;
|
|
112451
113118
|
}
|
|
@@ -112492,8 +113159,8 @@ function translatePasteForImages(paste) {
|
|
|
112492
113159
|
}
|
|
112493
113160
|
} catch {}
|
|
112494
113161
|
}
|
|
112495
|
-
if (!
|
|
112496
|
-
filePath =
|
|
113162
|
+
if (!isAbsolute19(filePath))
|
|
113163
|
+
filePath = resolve27(process.cwd(), filePath);
|
|
112497
113164
|
const ext3 = extname5(filePath || "").toLowerCase();
|
|
112498
113165
|
if (IMAGE_EXTS.has(ext3) && existsSync29(filePath) && statSync10(filePath).isFile()) {
|
|
112499
113166
|
const buf = readFileSync16(filePath);
|
|
@@ -112502,7 +113169,7 @@ function translatePasteForImages(paste) {
|
|
|
112502
113169
|
const id = allocateImage({
|
|
112503
113170
|
data: b64,
|
|
112504
113171
|
mediaType: mt,
|
|
112505
|
-
filename:
|
|
113172
|
+
filename: basename5(filePath)
|
|
112506
113173
|
});
|
|
112507
113174
|
s = `[Image #${id}]`;
|
|
112508
113175
|
}
|
|
@@ -113268,8 +113935,8 @@ import {
|
|
|
113268
113935
|
readFileSync as readFileSync17,
|
|
113269
113936
|
writeFileSync as writeFileSync15
|
|
113270
113937
|
} from "node:fs";
|
|
113271
|
-
import { homedir as
|
|
113272
|
-
import { dirname as
|
|
113938
|
+
import { homedir as homedir31, platform as platform5 } from "node:os";
|
|
113939
|
+
import { dirname as dirname16, join as join39 } from "node:path";
|
|
113273
113940
|
function detectTerminalType() {
|
|
113274
113941
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
113275
113942
|
return "cursor";
|
|
@@ -113301,7 +113968,7 @@ function getKeybindingsPath(terminal) {
|
|
|
113301
113968
|
}[terminal];
|
|
113302
113969
|
const os7 = platform5();
|
|
113303
113970
|
if (os7 === "darwin") {
|
|
113304
|
-
return join39(
|
|
113971
|
+
return join39(homedir31(), "Library", "Application Support", appName, "User", "keybindings.json");
|
|
113305
113972
|
}
|
|
113306
113973
|
if (os7 === "win32") {
|
|
113307
113974
|
const appData = process.env.APPDATA;
|
|
@@ -113310,7 +113977,7 @@ function getKeybindingsPath(terminal) {
|
|
|
113310
113977
|
return join39(appData, appName, "User", "keybindings.json");
|
|
113311
113978
|
}
|
|
113312
113979
|
if (os7 === "linux") {
|
|
113313
|
-
return join39(
|
|
113980
|
+
return join39(homedir31(), ".config", appName, "User", "keybindings.json");
|
|
113314
113981
|
}
|
|
113315
113982
|
return null;
|
|
113316
113983
|
}
|
|
@@ -113360,7 +114027,7 @@ function installKeybinding(keybindingsPath) {
|
|
|
113360
114027
|
if (keybindingExists(keybindingsPath)) {
|
|
113361
114028
|
return { success: true, alreadyExists: true };
|
|
113362
114029
|
}
|
|
113363
|
-
const parentDir =
|
|
114030
|
+
const parentDir = dirname16(keybindingsPath);
|
|
113364
114031
|
if (!existsSync30(parentDir)) {
|
|
113365
114032
|
mkdirSync21(parentDir, { recursive: true });
|
|
113366
114033
|
}
|
|
@@ -113467,10 +114134,10 @@ function getWezTermConfigPath() {
|
|
|
113467
114134
|
if (existsSync30(xdgPath))
|
|
113468
114135
|
return xdgPath;
|
|
113469
114136
|
}
|
|
113470
|
-
const configPath = join39(
|
|
114137
|
+
const configPath = join39(homedir31(), ".config", "wezterm", "wezterm.lua");
|
|
113471
114138
|
if (existsSync30(configPath))
|
|
113472
114139
|
return configPath;
|
|
113473
|
-
return join39(
|
|
114140
|
+
return join39(homedir31(), ".wezterm.lua");
|
|
113474
114141
|
}
|
|
113475
114142
|
function wezTermDeleteFixExists(configPath) {
|
|
113476
114143
|
if (!existsSync30(configPath))
|
|
@@ -113519,7 +114186,7 @@ return config`);
|
|
|
113519
114186
|
${WEZTERM_DELETE_FIX}
|
|
113520
114187
|
`;
|
|
113521
114188
|
}
|
|
113522
|
-
const parentDir =
|
|
114189
|
+
const parentDir = dirname16(configPath);
|
|
113523
114190
|
if (!existsSync30(parentDir)) {
|
|
113524
114191
|
mkdirSync21(parentDir, { recursive: true });
|
|
113525
114192
|
}
|
|
@@ -114102,7 +114769,7 @@ __export(exports_custom, {
|
|
|
114102
114769
|
});
|
|
114103
114770
|
import { existsSync as existsSync31 } from "node:fs";
|
|
114104
114771
|
import { readdir as readdir9, readFile as readFile11 } from "node:fs/promises";
|
|
114105
|
-
import { basename as
|
|
114772
|
+
import { basename as basename6, dirname as dirname17, join as join40 } from "node:path";
|
|
114106
114773
|
async function getCustomCommands() {
|
|
114107
114774
|
if (cachedCommands !== null) {
|
|
114108
114775
|
return cachedCommands;
|
|
@@ -114162,8 +114829,8 @@ async function findCommandFiles(currentPath, rootPath, commands2, source2) {
|
|
|
114162
114829
|
async function parseCommandFile(filePath, rootPath, source2) {
|
|
114163
114830
|
const content = await readFile11(filePath, "utf-8");
|
|
114164
114831
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
114165
|
-
const id =
|
|
114166
|
-
const relativePath =
|
|
114832
|
+
const id = basename6(filePath, ".md");
|
|
114833
|
+
const relativePath = dirname17(filePath).slice(rootPath.length);
|
|
114167
114834
|
const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
|
|
114168
114835
|
let description = getStringField(frontmatter, "description");
|
|
114169
114836
|
if (!description) {
|
|
@@ -114511,12 +115178,12 @@ var init_HelpDialog = __esm(async () => {
|
|
|
114511
115178
|
});
|
|
114512
115179
|
|
|
114513
115180
|
// src/hooks/writer.ts
|
|
114514
|
-
import { homedir as
|
|
114515
|
-
import { resolve as
|
|
115181
|
+
import { homedir as homedir32 } from "node:os";
|
|
115182
|
+
import { resolve as resolve28 } from "node:path";
|
|
114516
115183
|
function isProjectSettingsPathCollidingWithGlobal2(workingDirectory) {
|
|
114517
|
-
const home = process.env.HOME ||
|
|
114518
|
-
const globalSettingsPath =
|
|
114519
|
-
const projectSettingsPath =
|
|
115184
|
+
const home = process.env.HOME || homedir32();
|
|
115185
|
+
const globalSettingsPath = resolve28(home, ".letta", "settings.json");
|
|
115186
|
+
const projectSettingsPath = resolve28(workingDirectory, ".letta", "settings.json");
|
|
114520
115187
|
return globalSettingsPath === projectSettingsPath;
|
|
114521
115188
|
}
|
|
114522
115189
|
function loadHooksFromLocation(location, workingDirectory = process.cwd()) {
|
|
@@ -117154,7 +117821,7 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
117154
117821
|
|
|
117155
117822
|
// src/cli/helpers/fileSearch.ts
|
|
117156
117823
|
import { readdirSync as readdirSync13, statSync as statSync11 } from "node:fs";
|
|
117157
|
-
import { join as join41, relative as relative15, resolve as
|
|
117824
|
+
import { join as join41, relative as relative15, resolve as resolve29 } from "node:path";
|
|
117158
117825
|
function searchDirectoryRecursive(dir, pattern, maxResults = 200, results = [], depth = 0, maxDepth = 10, lowerPattern = pattern.toLowerCase()) {
|
|
117159
117826
|
if (results.length >= maxResults || depth >= maxDepth) {
|
|
117160
117827
|
return results;
|
|
@@ -117197,7 +117864,7 @@ async function searchFiles(query, deep = false) {
|
|
|
117197
117864
|
const dirPart = query.slice(0, lastSlashIndex);
|
|
117198
117865
|
const pattern = query.slice(lastSlashIndex + 1);
|
|
117199
117866
|
try {
|
|
117200
|
-
const resolvedDir =
|
|
117867
|
+
const resolvedDir = resolve29(getIndexRoot(), dirPart);
|
|
117201
117868
|
try {
|
|
117202
117869
|
statSync11(resolvedDir);
|
|
117203
117870
|
searchDir = resolvedDir;
|
|
@@ -119325,7 +119992,7 @@ import {
|
|
|
119325
119992
|
writeFileSync as writeFileSync16
|
|
119326
119993
|
} from "node:fs";
|
|
119327
119994
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
119328
|
-
import { dirname as
|
|
119995
|
+
import { dirname as dirname18, join as join42 } from "node:path";
|
|
119329
119996
|
function runCommand(command, args, cwd2, input) {
|
|
119330
119997
|
try {
|
|
119331
119998
|
return execFileSync4(command, args, {
|
|
@@ -119572,8 +120239,8 @@ function runGit6(args, cwd2) {
|
|
|
119572
120239
|
}
|
|
119573
120240
|
function writeWorkflow(repoDir, workflowPath, content) {
|
|
119574
120241
|
const absolutePath = join42(repoDir, workflowPath);
|
|
119575
|
-
if (!existsSync32(
|
|
119576
|
-
mkdirSync22(
|
|
120242
|
+
if (!existsSync32(dirname18(absolutePath))) {
|
|
120243
|
+
mkdirSync22(dirname18(absolutePath), { recursive: true });
|
|
119577
120244
|
}
|
|
119578
120245
|
const next = `${content.trimEnd()}
|
|
119579
120246
|
`;
|
|
@@ -123479,7 +124146,7 @@ __export(exports_generate_memory_viewer, {
|
|
|
123479
124146
|
});
|
|
123480
124147
|
import { execFile as execFileCb5 } from "node:child_process";
|
|
123481
124148
|
import { chmodSync as chmodSync3, existsSync as existsSync33, mkdirSync as mkdirSync23, writeFileSync as writeFileSync17 } from "node:fs";
|
|
123482
|
-
import { homedir as
|
|
124149
|
+
import { homedir as homedir33 } from "node:os";
|
|
123483
124150
|
import { join as join43 } from "node:path";
|
|
123484
124151
|
import { promisify as promisify14 } from "node:util";
|
|
123485
124152
|
async function runGitSafe(cwd2, args) {
|
|
@@ -123793,7 +124460,7 @@ var init_generate_memory_viewer = __esm(async () => {
|
|
|
123793
124460
|
init_memoryGit()
|
|
123794
124461
|
]);
|
|
123795
124462
|
execFile14 = promisify14(execFileCb5);
|
|
123796
|
-
VIEWERS_DIR2 = join43(
|
|
124463
|
+
VIEWERS_DIR2 = join43(homedir33(), ".letta", "viewers");
|
|
123797
124464
|
REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
|
|
123798
124465
|
});
|
|
123799
124466
|
|
|
@@ -126511,11 +127178,11 @@ var init_PersonalitySelector = __esm(async () => {
|
|
|
126511
127178
|
|
|
126512
127179
|
// src/utils/aws-credentials.ts
|
|
126513
127180
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
126514
|
-
import { homedir as
|
|
127181
|
+
import { homedir as homedir34 } from "node:os";
|
|
126515
127182
|
import { join as join44 } from "node:path";
|
|
126516
127183
|
async function parseAwsCredentials() {
|
|
126517
|
-
const credentialsPath = join44(
|
|
126518
|
-
const configPath = join44(
|
|
127184
|
+
const credentialsPath = join44(homedir34(), ".aws", "credentials");
|
|
127185
|
+
const configPath = join44(homedir34(), ".aws", "config");
|
|
126519
127186
|
const profiles = new Map;
|
|
126520
127187
|
try {
|
|
126521
127188
|
const content = await readFile12(credentialsPath, "utf-8");
|
|
@@ -131996,7 +132663,7 @@ async function executeStatusLineCommand(command, payload, options) {
|
|
|
131996
132663
|
};
|
|
131997
132664
|
}
|
|
131998
132665
|
function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory, startTime) {
|
|
131999
|
-
return new Promise((
|
|
132666
|
+
return new Promise((resolve30, reject) => {
|
|
132000
132667
|
const [executable, ...args] = launcher;
|
|
132001
132668
|
if (!executable) {
|
|
132002
132669
|
reject(new Error("Empty launcher"));
|
|
@@ -132009,7 +132676,7 @@ function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory,
|
|
|
132009
132676
|
const safeResolve = (result) => {
|
|
132010
132677
|
if (!resolved) {
|
|
132011
132678
|
resolved = true;
|
|
132012
|
-
|
|
132679
|
+
resolve30(result);
|
|
132013
132680
|
}
|
|
132014
132681
|
};
|
|
132015
132682
|
let child;
|
|
@@ -132455,7 +133122,7 @@ __export(exports_shellAliases, {
|
|
|
132455
133122
|
clearAliasCache: () => clearAliasCache
|
|
132456
133123
|
});
|
|
132457
133124
|
import { existsSync as existsSync36, readFileSync as readFileSync20 } from "node:fs";
|
|
132458
|
-
import { homedir as
|
|
133125
|
+
import { homedir as homedir35 } from "node:os";
|
|
132459
133126
|
import { join as join46 } from "node:path";
|
|
132460
133127
|
function parseAliasesFromFile(filePath) {
|
|
132461
133128
|
const aliases = new Map;
|
|
@@ -132525,7 +133192,7 @@ function loadAliases(forceReload = false) {
|
|
|
132525
133192
|
if (aliasCache && !forceReload) {
|
|
132526
133193
|
return aliasCache;
|
|
132527
133194
|
}
|
|
132528
|
-
const home =
|
|
133195
|
+
const home = homedir35();
|
|
132529
133196
|
const allAliases = new Map;
|
|
132530
133197
|
for (const file of ALIAS_FILES) {
|
|
132531
133198
|
const filePath = join46(home, file);
|
|
@@ -133186,14 +133853,14 @@ __export(exports_export, {
|
|
|
133186
133853
|
packageSkills: () => packageSkills
|
|
133187
133854
|
});
|
|
133188
133855
|
import { readdir as readdir10, readFile as readFile13 } from "node:fs/promises";
|
|
133189
|
-
import { relative as relative16, resolve as
|
|
133856
|
+
import { relative as relative16, resolve as resolve30 } from "node:path";
|
|
133190
133857
|
async function packageSkills(agentId, skillsDir) {
|
|
133191
133858
|
const skills = [];
|
|
133192
133859
|
const skillNames = new Set;
|
|
133193
133860
|
const dirsToCheck = skillsDir ? [skillsDir] : [
|
|
133194
133861
|
agentId && getAgentSkillsDir(agentId),
|
|
133195
|
-
|
|
133196
|
-
|
|
133862
|
+
resolve30(process.cwd(), ".skills"),
|
|
133863
|
+
resolve30(process.env.HOME || "~", ".letta", "skills")
|
|
133197
133864
|
].filter((dir) => Boolean(dir));
|
|
133198
133865
|
for (const baseDir of dirsToCheck) {
|
|
133199
133866
|
try {
|
|
@@ -133203,8 +133870,8 @@ async function packageSkills(agentId, skillsDir) {
|
|
|
133203
133870
|
continue;
|
|
133204
133871
|
if (skillNames.has(entry.name))
|
|
133205
133872
|
continue;
|
|
133206
|
-
const skillDir =
|
|
133207
|
-
const skillMdPath =
|
|
133873
|
+
const skillDir = resolve30(baseDir, entry.name);
|
|
133874
|
+
const skillMdPath = resolve30(skillDir, "SKILL.md");
|
|
133208
133875
|
try {
|
|
133209
133876
|
await readFile13(skillMdPath, "utf-8");
|
|
133210
133877
|
} catch {
|
|
@@ -133234,7 +133901,7 @@ async function readSkillFiles(skillDir) {
|
|
|
133234
133901
|
async function walk(dir) {
|
|
133235
133902
|
const entries = await readdir10(dir, { withFileTypes: true });
|
|
133236
133903
|
for (const entry of entries) {
|
|
133237
|
-
const fullPath =
|
|
133904
|
+
const fullPath = resolve30(dir, entry.name);
|
|
133238
133905
|
if (entry.isDirectory()) {
|
|
133239
133906
|
await walk(fullPath);
|
|
133240
133907
|
} else {
|
|
@@ -133379,7 +134046,7 @@ __export(exports_App, {
|
|
|
133379
134046
|
});
|
|
133380
134047
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
133381
134048
|
import { existsSync as existsSync37, readFileSync as readFileSync21, renameSync as renameSync3, writeFileSync as writeFileSync18 } from "node:fs";
|
|
133382
|
-
import { homedir as
|
|
134049
|
+
import { homedir as homedir36, tmpdir as tmpdir6 } from "node:os";
|
|
133383
134050
|
import { join as join47, relative as relative17 } from "node:path";
|
|
133384
134051
|
function deriveReasoningEffort(modelSettings, llmConfig) {
|
|
133385
134052
|
if (modelSettings && "provider_type" in modelSettings) {
|
|
@@ -135718,7 +136385,7 @@ ${newState.originalPrompt}`,
|
|
|
135718
136385
|
cancelled = true;
|
|
135719
136386
|
break;
|
|
135720
136387
|
}
|
|
135721
|
-
await new Promise((
|
|
136388
|
+
await new Promise((resolve31) => setTimeout(resolve31, 100));
|
|
135722
136389
|
}
|
|
135723
136390
|
buffersRef.current.byId.delete(statusId);
|
|
135724
136391
|
buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
|
|
@@ -135782,7 +136449,7 @@ ${newState.originalPrompt}`,
|
|
|
135782
136449
|
cancelled = true;
|
|
135783
136450
|
break;
|
|
135784
136451
|
}
|
|
135785
|
-
await new Promise((
|
|
136452
|
+
await new Promise((resolve31) => setTimeout(resolve31, 100));
|
|
135786
136453
|
}
|
|
135787
136454
|
if (retryStatusId) {
|
|
135788
136455
|
buffersRef.current.byId.delete(retryStatusId);
|
|
@@ -136540,7 +137207,7 @@ ${feedback}
|
|
|
136540
137207
|
});
|
|
136541
137208
|
buffersRef.current.order.push(statusId);
|
|
136542
137209
|
refreshDerived();
|
|
136543
|
-
await new Promise((
|
|
137210
|
+
await new Promise((resolve31) => setTimeout(resolve31, delayMs));
|
|
136544
137211
|
buffersRef.current.byId.delete(statusId);
|
|
136545
137212
|
buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
|
|
136546
137213
|
refreshDerived();
|
|
@@ -136600,7 +137267,7 @@ ${feedback}
|
|
|
136600
137267
|
cancelled = true;
|
|
136601
137268
|
break;
|
|
136602
137269
|
}
|
|
136603
|
-
await new Promise((
|
|
137270
|
+
await new Promise((resolve31) => setTimeout(resolve31, 100));
|
|
136604
137271
|
}
|
|
136605
137272
|
if (retryStatusId) {
|
|
136606
137273
|
buffersRef.current.byId.delete(retryStatusId);
|
|
@@ -141543,7 +142210,7 @@ ${guidance}`);
|
|
|
141543
142210
|
}
|
|
141544
142211
|
if (mode === "bypassPermissions") {
|
|
141545
142212
|
const planFilePath = activePlanPath ?? fallbackPlanPath;
|
|
141546
|
-
const plansDir = join47(
|
|
142213
|
+
const plansDir = join47(homedir36(), ".letta", "plans");
|
|
141547
142214
|
handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
|
|
141548
142215
|
` + (planFilePath ? `Plan file path: ${planFilePath}
|
|
141549
142216
|
` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
|
|
@@ -141578,7 +142245,7 @@ ${guidance}`);
|
|
|
141578
142245
|
if (!hasUsablePlan) {
|
|
141579
142246
|
lastAutoHandledExitPlanToolCallIdRef.current = approval.toolCallId;
|
|
141580
142247
|
const planFilePath = activePlanPath ?? fallbackPlanPath;
|
|
141581
|
-
const plansDir = join47(
|
|
142248
|
+
const plansDir = join47(homedir36(), ".letta", "plans");
|
|
141582
142249
|
handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
|
|
141583
142250
|
` + (planFilePath ? `Plan file path: ${planFilePath}
|
|
141584
142251
|
` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
|
|
@@ -142990,8 +143657,8 @@ import {
|
|
|
142990
143657
|
readFileSync as readFileSync22,
|
|
142991
143658
|
writeFileSync as writeFileSync19
|
|
142992
143659
|
} from "node:fs";
|
|
142993
|
-
import { homedir as
|
|
142994
|
-
import { dirname as
|
|
143660
|
+
import { homedir as homedir37, platform as platform6 } from "node:os";
|
|
143661
|
+
import { dirname as dirname19, join as join48 } from "node:path";
|
|
142995
143662
|
function detectTerminalType2() {
|
|
142996
143663
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
142997
143664
|
return "cursor";
|
|
@@ -143023,7 +143690,7 @@ function getKeybindingsPath2(terminal) {
|
|
|
143023
143690
|
}[terminal];
|
|
143024
143691
|
const os8 = platform6();
|
|
143025
143692
|
if (os8 === "darwin") {
|
|
143026
|
-
return join48(
|
|
143693
|
+
return join48(homedir37(), "Library", "Application Support", appName, "User", "keybindings.json");
|
|
143027
143694
|
}
|
|
143028
143695
|
if (os8 === "win32") {
|
|
143029
143696
|
const appData = process.env.APPDATA;
|
|
@@ -143032,7 +143699,7 @@ function getKeybindingsPath2(terminal) {
|
|
|
143032
143699
|
return join48(appData, appName, "User", "keybindings.json");
|
|
143033
143700
|
}
|
|
143034
143701
|
if (os8 === "linux") {
|
|
143035
|
-
return join48(
|
|
143702
|
+
return join48(homedir37(), ".config", appName, "User", "keybindings.json");
|
|
143036
143703
|
}
|
|
143037
143704
|
return null;
|
|
143038
143705
|
}
|
|
@@ -143082,7 +143749,7 @@ function installKeybinding2(keybindingsPath) {
|
|
|
143082
143749
|
if (keybindingExists2(keybindingsPath)) {
|
|
143083
143750
|
return { success: true, alreadyExists: true };
|
|
143084
143751
|
}
|
|
143085
|
-
const parentDir =
|
|
143752
|
+
const parentDir = dirname19(keybindingsPath);
|
|
143086
143753
|
if (!existsSync38(parentDir)) {
|
|
143087
143754
|
mkdirSync24(parentDir, { recursive: true });
|
|
143088
143755
|
}
|
|
@@ -143189,10 +143856,10 @@ function getWezTermConfigPath2() {
|
|
|
143189
143856
|
if (existsSync38(xdgPath))
|
|
143190
143857
|
return xdgPath;
|
|
143191
143858
|
}
|
|
143192
|
-
const configPath = join48(
|
|
143859
|
+
const configPath = join48(homedir37(), ".config", "wezterm", "wezterm.lua");
|
|
143193
143860
|
if (existsSync38(configPath))
|
|
143194
143861
|
return configPath;
|
|
143195
|
-
return join48(
|
|
143862
|
+
return join48(homedir37(), ".wezterm.lua");
|
|
143196
143863
|
}
|
|
143197
143864
|
function wezTermDeleteFixExists2(configPath) {
|
|
143198
143865
|
if (!existsSync38(configPath))
|
|
@@ -143241,7 +143908,7 @@ return config`);
|
|
|
143241
143908
|
${WEZTERM_DELETE_FIX2}
|
|
143242
143909
|
`;
|
|
143243
143910
|
}
|
|
143244
|
-
const parentDir =
|
|
143911
|
+
const parentDir = dirname19(configPath);
|
|
143245
143912
|
if (!existsSync38(parentDir)) {
|
|
143246
143913
|
mkdirSync24(parentDir, { recursive: true });
|
|
143247
143914
|
}
|
|
@@ -143290,10 +143957,10 @@ __export(exports_settings2, {
|
|
|
143290
143957
|
loadProjectSettings: () => loadProjectSettings2,
|
|
143291
143958
|
getSetting: () => getSetting2
|
|
143292
143959
|
});
|
|
143293
|
-
import { homedir as
|
|
143960
|
+
import { homedir as homedir38 } from "node:os";
|
|
143294
143961
|
import { join as join49 } from "node:path";
|
|
143295
143962
|
function getSettingsPath2() {
|
|
143296
|
-
return join49(
|
|
143963
|
+
return join49(homedir38(), ".letta", "settings.json");
|
|
143297
143964
|
}
|
|
143298
143965
|
async function loadSettings2() {
|
|
143299
143966
|
const settingsPath = getSettingsPath2();
|
|
@@ -143815,10 +144482,10 @@ __export(exports_import2, {
|
|
|
143815
144482
|
});
|
|
143816
144483
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
143817
144484
|
import { chmod as chmod2, mkdir as mkdir8, readFile as readFile14, writeFile as writeFile9 } from "node:fs/promises";
|
|
143818
|
-
import { dirname as
|
|
144485
|
+
import { dirname as dirname20, resolve as resolve31 } from "node:path";
|
|
143819
144486
|
async function importAgentFromFile2(options) {
|
|
143820
144487
|
const client = await getClient();
|
|
143821
|
-
const resolvedPath =
|
|
144488
|
+
const resolvedPath = resolve31(options.filePath);
|
|
143822
144489
|
const file = createReadStream2(resolvedPath);
|
|
143823
144490
|
const importResponse = await client.agents.importFile({
|
|
143824
144491
|
file,
|
|
@@ -143853,7 +144520,7 @@ async function extractSkillsFromAf2(afPath, destDir) {
|
|
|
143853
144520
|
return [];
|
|
143854
144521
|
}
|
|
143855
144522
|
for (const skill2 of afData.skills) {
|
|
143856
|
-
const skillDir =
|
|
144523
|
+
const skillDir = resolve31(destDir, skill2.name);
|
|
143857
144524
|
await mkdir8(skillDir, { recursive: true });
|
|
143858
144525
|
if (skill2.files) {
|
|
143859
144526
|
await writeSkillFiles2(skillDir, skill2.files);
|
|
@@ -143873,8 +144540,8 @@ async function writeSkillFiles2(skillDir, files) {
|
|
|
143873
144540
|
}
|
|
143874
144541
|
}
|
|
143875
144542
|
async function writeSkillFile2(skillDir, filePath, content) {
|
|
143876
|
-
const fullPath =
|
|
143877
|
-
await mkdir8(
|
|
144543
|
+
const fullPath = resolve31(skillDir, filePath);
|
|
144544
|
+
await mkdir8(dirname20(fullPath), { recursive: true });
|
|
143878
144545
|
await writeFile9(fullPath, content, "utf-8");
|
|
143879
144546
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
143880
144547
|
if (isScript) {
|
|
@@ -143984,15 +144651,15 @@ __export(exports_memoryFilesystem2, {
|
|
|
143984
144651
|
MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
|
|
143985
144652
|
});
|
|
143986
144653
|
import { existsSync as existsSync39, mkdirSync as mkdirSync25 } from "node:fs";
|
|
143987
|
-
import { homedir as
|
|
144654
|
+
import { homedir as homedir39 } from "node:os";
|
|
143988
144655
|
import { join as join50 } from "node:path";
|
|
143989
|
-
function getMemoryFilesystemRoot2(agentId, homeDir =
|
|
144656
|
+
function getMemoryFilesystemRoot2(agentId, homeDir = homedir39()) {
|
|
143990
144657
|
return join50(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
|
|
143991
144658
|
}
|
|
143992
|
-
function getMemorySystemDir2(agentId, homeDir =
|
|
144659
|
+
function getMemorySystemDir2(agentId, homeDir = homedir39()) {
|
|
143993
144660
|
return join50(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
|
|
143994
144661
|
}
|
|
143995
|
-
function ensureMemoryFilesystemDirs2(agentId, homeDir =
|
|
144662
|
+
function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir39()) {
|
|
143996
144663
|
const root = getMemoryFilesystemRoot2(agentId, homeDir);
|
|
143997
144664
|
const systemDir = getMemorySystemDir2(agentId, homeDir);
|
|
143998
144665
|
if (!existsSync39(root)) {
|
|
@@ -148638,7 +149305,7 @@ async function runListenSubcommand(argv) {
|
|
|
148638
149305
|
await init_memoryGit();
|
|
148639
149306
|
import { cpSync, existsSync as existsSync22, mkdirSync as mkdirSync15, rmSync as rmSync2, statSync as statSync8 } from "node:fs";
|
|
148640
149307
|
import { readdir as readdir6 } from "node:fs/promises";
|
|
148641
|
-
import { homedir as
|
|
149308
|
+
import { homedir as homedir23 } from "node:os";
|
|
148642
149309
|
import { join as join28 } from "node:path";
|
|
148643
149310
|
import { parseArgs as parseArgs7 } from "node:util";
|
|
148644
149311
|
function printUsage4() {
|
|
@@ -148684,10 +149351,10 @@ function parseMemfsArgs(argv) {
|
|
|
148684
149351
|
});
|
|
148685
149352
|
}
|
|
148686
149353
|
function getMemoryRoot(agentId) {
|
|
148687
|
-
return join28(
|
|
149354
|
+
return join28(homedir23(), ".letta", "agents", agentId, "memory");
|
|
148688
149355
|
}
|
|
148689
149356
|
function getAgentRoot(agentId) {
|
|
148690
|
-
return join28(
|
|
149357
|
+
return join28(homedir23(), ".letta", "agents", agentId);
|
|
148691
149358
|
}
|
|
148692
149359
|
function formatBackupTimestamp(date = new Date) {
|
|
148693
149360
|
const pad = (value) => String(value).padStart(2, "0");
|
|
@@ -149236,13 +149903,20 @@ async function runSubcommand(argv) {
|
|
|
149236
149903
|
}
|
|
149237
149904
|
|
|
149238
149905
|
// src/permissions/mode.ts
|
|
149906
|
+
init_memoryScope();
|
|
149239
149907
|
init_readOnlyShell();
|
|
149240
149908
|
init_shell_command_normalization();
|
|
149241
|
-
import { homedir as
|
|
149242
|
-
import { isAbsolute as
|
|
149909
|
+
import { homedir as homedir24 } from "node:os";
|
|
149910
|
+
import { isAbsolute as isAbsolute17, join as join29, relative as relative12 } from "node:path";
|
|
149243
149911
|
var MODE_KEY2 = Symbol.for("@letta/permissionMode");
|
|
149244
149912
|
var PLAN_FILE_KEY2 = Symbol.for("@letta/planFilePath");
|
|
149245
149913
|
var MODE_BEFORE_PLAN_KEY2 = Symbol.for("@letta/permissionModeBeforePlan");
|
|
149914
|
+
function everyResolvedTargetIsWithinRoots2(candidatePaths, roots, workingDirectory) {
|
|
149915
|
+
return candidatePaths.length > 0 && candidatePaths.every((path23) => {
|
|
149916
|
+
const resolvedPath = resolveScopedTargetPath(path23, workingDirectory);
|
|
149917
|
+
return resolvedPath ? isPathWithinRoots(resolvedPath, roots) : false;
|
|
149918
|
+
});
|
|
149919
|
+
}
|
|
149246
149920
|
function getGlobalMode2() {
|
|
149247
149921
|
const global2 = globalThis;
|
|
149248
149922
|
if (!global2[MODE_KEY2]) {
|
|
@@ -149271,22 +149945,13 @@ function setGlobalModeBeforePlan2(value) {
|
|
|
149271
149945
|
global2[MODE_BEFORE_PLAN_KEY2] = value;
|
|
149272
149946
|
}
|
|
149273
149947
|
function resolvePlanTargetPath2(targetPath, workingDirectory) {
|
|
149274
|
-
|
|
149275
|
-
if (!trimmedPath)
|
|
149276
|
-
return null;
|
|
149277
|
-
if (trimmedPath.startsWith("~/")) {
|
|
149278
|
-
return resolve24(homedir23(), trimmedPath.slice(2));
|
|
149279
|
-
}
|
|
149280
|
-
if (isAbsolute16(trimmedPath)) {
|
|
149281
|
-
return resolve24(trimmedPath);
|
|
149282
|
-
}
|
|
149283
|
-
return resolve24(workingDirectory, trimmedPath);
|
|
149948
|
+
return resolveScopedTargetPath(targetPath, workingDirectory);
|
|
149284
149949
|
}
|
|
149285
149950
|
function isPathInPlansDir2(path23, plansDir) {
|
|
149286
149951
|
if (!path23.endsWith(".md"))
|
|
149287
149952
|
return false;
|
|
149288
149953
|
const rel = relative12(plansDir, path23);
|
|
149289
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
149954
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute17(rel);
|
|
149290
149955
|
}
|
|
149291
149956
|
function extractApplyPatchPaths2(input) {
|
|
149292
149957
|
const paths = [];
|
|
@@ -149473,7 +150138,7 @@ class PermissionModeManager2 {
|
|
|
149473
150138
|
return "allow";
|
|
149474
150139
|
}
|
|
149475
150140
|
if (writeTools.includes(toolName)) {
|
|
149476
|
-
const plansDir = join29(
|
|
150141
|
+
const plansDir = join29(homedir24(), ".letta", "plans");
|
|
149477
150142
|
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
149478
150143
|
let candidatePaths = [];
|
|
149479
150144
|
if ((toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") && toolArgs?.input) {
|
|
@@ -149524,7 +150189,7 @@ class PermissionModeManager2 {
|
|
|
149524
150189
|
}
|
|
149525
150190
|
const planWritePath = extractPlanFileWritePathFromShellCommand2(command);
|
|
149526
150191
|
if (planWritePath) {
|
|
149527
|
-
const plansDir = join29(
|
|
150192
|
+
const plansDir = join29(homedir24(), ".letta", "plans");
|
|
149528
150193
|
const resolvedPath = resolvePlanTargetPath2(planWritePath, workingDirectory);
|
|
149529
150194
|
if (resolvedPath && isPathInPlansDir2(resolvedPath, plansDir)) {
|
|
149530
150195
|
return "allow";
|
|
@@ -149533,6 +150198,94 @@ class PermissionModeManager2 {
|
|
|
149533
150198
|
}
|
|
149534
150199
|
return "deny";
|
|
149535
150200
|
}
|
|
150201
|
+
case "memory": {
|
|
150202
|
+
const allowedMemoryRoots = resolveAllowedMemoryRoots().roots;
|
|
150203
|
+
const allowedReadOnlyTools = [
|
|
150204
|
+
"Read",
|
|
150205
|
+
"Glob",
|
|
150206
|
+
"Grep",
|
|
150207
|
+
"NotebookRead",
|
|
150208
|
+
"ViewImage",
|
|
150209
|
+
"view_image",
|
|
150210
|
+
"TaskOutput",
|
|
150211
|
+
"task_output",
|
|
150212
|
+
"Skill",
|
|
150213
|
+
"skill",
|
|
150214
|
+
"read_file",
|
|
150215
|
+
"list_dir",
|
|
150216
|
+
"grep_files",
|
|
150217
|
+
"ReadFile",
|
|
150218
|
+
"ListDir",
|
|
150219
|
+
"GrepFiles",
|
|
150220
|
+
"read_file_gemini",
|
|
150221
|
+
"glob_gemini",
|
|
150222
|
+
"list_directory",
|
|
150223
|
+
"search_file_content",
|
|
150224
|
+
"read_many_files",
|
|
150225
|
+
"ReadFileGemini",
|
|
150226
|
+
"GlobGemini",
|
|
150227
|
+
"ListDirectory",
|
|
150228
|
+
"SearchFileContent",
|
|
150229
|
+
"ReadManyFiles"
|
|
150230
|
+
];
|
|
150231
|
+
const writeTools = [
|
|
150232
|
+
"Write",
|
|
150233
|
+
"Edit",
|
|
150234
|
+
"MultiEdit",
|
|
150235
|
+
"NotebookEdit",
|
|
150236
|
+
"apply_patch",
|
|
150237
|
+
"ApplyPatch",
|
|
150238
|
+
"replace",
|
|
150239
|
+
"Replace",
|
|
150240
|
+
"write_file",
|
|
150241
|
+
"WriteFile",
|
|
150242
|
+
"write_file_gemini",
|
|
150243
|
+
"WriteFileGemini"
|
|
150244
|
+
];
|
|
150245
|
+
const shellTools = [
|
|
150246
|
+
"Bash",
|
|
150247
|
+
"shell",
|
|
150248
|
+
"Shell",
|
|
150249
|
+
"shell_command",
|
|
150250
|
+
"ShellCommand",
|
|
150251
|
+
"run_shell_command",
|
|
150252
|
+
"RunShellCommand",
|
|
150253
|
+
"run_shell_command_gemini",
|
|
150254
|
+
"RunShellCommandGemini"
|
|
150255
|
+
];
|
|
150256
|
+
if (allowedReadOnlyTools.includes(toolName)) {
|
|
150257
|
+
return "allow";
|
|
150258
|
+
}
|
|
150259
|
+
if (toolName === "memory_apply_patch") {
|
|
150260
|
+
return allowedMemoryRoots.length > 0 ? "allow" : "deny";
|
|
150261
|
+
}
|
|
150262
|
+
if (writeTools.includes(toolName)) {
|
|
150263
|
+
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
150264
|
+
let candidatePaths = [];
|
|
150265
|
+
if ((toolName === "ApplyPatch" || toolName === "apply_patch") && toolArgs?.input) {
|
|
150266
|
+
candidatePaths = extractApplyPatchPaths2(toolArgs.input);
|
|
150267
|
+
} else if (typeof targetPath === "string") {
|
|
150268
|
+
candidatePaths = [targetPath];
|
|
150269
|
+
}
|
|
150270
|
+
if (allowedMemoryRoots.length > 0 && everyResolvedTargetIsWithinRoots2(candidatePaths, allowedMemoryRoots, workingDirectory)) {
|
|
150271
|
+
return "allow";
|
|
150272
|
+
}
|
|
150273
|
+
return "deny";
|
|
150274
|
+
}
|
|
150275
|
+
if (shellTools.includes(toolName)) {
|
|
150276
|
+
const command = toolArgs?.command;
|
|
150277
|
+
if (command && isReadOnlyShellCommand(command, { allowExternalPaths: true })) {
|
|
150278
|
+
return "allow";
|
|
150279
|
+
}
|
|
150280
|
+
if (command && allowedMemoryRoots.length > 0 && isScopedMemoryShellCommand(command, allowedMemoryRoots, {
|
|
150281
|
+
workingDirectory
|
|
150282
|
+
})) {
|
|
150283
|
+
return "allow";
|
|
150284
|
+
}
|
|
150285
|
+
return "deny";
|
|
150286
|
+
}
|
|
150287
|
+
return "deny";
|
|
150288
|
+
}
|
|
149536
150289
|
case "default":
|
|
149537
150290
|
return null;
|
|
149538
150291
|
default:
|
|
@@ -149555,8 +150308,8 @@ await __promiseAll([
|
|
|
149555
150308
|
init_secrets()
|
|
149556
150309
|
]);
|
|
149557
150310
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
149558
|
-
import { homedir as
|
|
149559
|
-
import { join as join30, resolve as
|
|
150311
|
+
import { homedir as homedir25 } from "node:os";
|
|
150312
|
+
import { join as join30, resolve as resolve24 } from "node:path";
|
|
149560
150313
|
var DEFAULT_SETTINGS3 = {
|
|
149561
150314
|
lastAgent: null,
|
|
149562
150315
|
tokenStreaming: false,
|
|
@@ -149942,7 +150695,7 @@ class SettingsManager2 {
|
|
|
149942
150695
|
if (!this.settings)
|
|
149943
150696
|
return;
|
|
149944
150697
|
const settingsPath = this.getSettingsPath();
|
|
149945
|
-
const home = process.env.HOME ||
|
|
150698
|
+
const home = process.env.HOME || homedir25();
|
|
149946
150699
|
const dirPath = join30(home, ".letta");
|
|
149947
150700
|
try {
|
|
149948
150701
|
if (!exists(dirPath)) {
|
|
@@ -150003,14 +150756,14 @@ class SettingsManager2 {
|
|
|
150003
150756
|
}
|
|
150004
150757
|
}
|
|
150005
150758
|
getSettingsPath() {
|
|
150006
|
-
const home = process.env.HOME ||
|
|
150759
|
+
const home = process.env.HOME || homedir25();
|
|
150007
150760
|
return join30(home, ".letta", "settings.json");
|
|
150008
150761
|
}
|
|
150009
150762
|
getProjectSettingsPath(workingDirectory) {
|
|
150010
150763
|
return join30(workingDirectory, ".letta", "settings.json");
|
|
150011
150764
|
}
|
|
150012
150765
|
isProjectSettingsPathCollidingWithGlobal(workingDirectory) {
|
|
150013
|
-
return
|
|
150766
|
+
return resolve24(this.getProjectSettingsPath(workingDirectory)) === resolve24(this.getSettingsPath());
|
|
150014
150767
|
}
|
|
150015
150768
|
getLocalProjectSettingsPath(workingDirectory) {
|
|
150016
150769
|
return join30(workingDirectory, ".letta", "settings.local.json");
|
|
@@ -150972,8 +151725,8 @@ function acquireSwitchLock2() {
|
|
|
150972
151725
|
const lock = getSwitchLock2();
|
|
150973
151726
|
lock.refCount++;
|
|
150974
151727
|
if (lock.refCount === 1) {
|
|
150975
|
-
lock.promise = new Promise((
|
|
150976
|
-
lock.resolve =
|
|
151728
|
+
lock.promise = new Promise((resolve25) => {
|
|
151729
|
+
lock.resolve = resolve25;
|
|
150977
151730
|
});
|
|
150978
151731
|
}
|
|
150979
151732
|
}
|
|
@@ -151458,7 +152211,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
151458
152211
|
printHelp();
|
|
151459
152212
|
const helpDelayMs = Number.parseInt(process.env.LETTA_TEST_HELP_EXIT_DELAY_MS ?? "", 10);
|
|
151460
152213
|
if (Number.isFinite(helpDelayMs) && helpDelayMs > 0) {
|
|
151461
|
-
await new Promise((
|
|
152214
|
+
await new Promise((resolve32) => setTimeout(resolve32, helpDelayMs));
|
|
151462
152215
|
}
|
|
151463
152216
|
process.exit(0);
|
|
151464
152217
|
}
|
|
@@ -151680,9 +152433,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
151680
152433
|
process.exit(1);
|
|
151681
152434
|
}
|
|
151682
152435
|
} else {
|
|
151683
|
-
const { resolve:
|
|
152436
|
+
const { resolve: resolve32 } = await import("path");
|
|
151684
152437
|
const { existsSync: existsSync40 } = await import("fs");
|
|
151685
|
-
const resolvedPath =
|
|
152438
|
+
const resolvedPath = resolve32(fromAfFile);
|
|
151686
152439
|
if (!existsSync40(resolvedPath)) {
|
|
151687
152440
|
console.error(`Error: AgentFile not found: ${resolvedPath}`);
|
|
151688
152441
|
process.exit(1);
|
|
@@ -151793,6 +152546,7 @@ Error: ${message}`);
|
|
|
151793
152546
|
"default",
|
|
151794
152547
|
"acceptEdits",
|
|
151795
152548
|
"plan",
|
|
152549
|
+
"memory",
|
|
151796
152550
|
"bypassPermissions"
|
|
151797
152551
|
];
|
|
151798
152552
|
if (validModes.includes(mode)) {
|
|
@@ -152557,4 +153311,4 @@ Error during initialization: ${message}`);
|
|
|
152557
153311
|
}
|
|
152558
153312
|
main();
|
|
152559
153313
|
|
|
152560
|
-
//# debugId=
|
|
153314
|
+
//# debugId=1C3BE0588811294864756E2164756E21
|