@letta-ai/letta-code 0.21.11 → 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 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.11",
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: bypassPermissions
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
- BRANCH_NAME="migration-$(date +%s)"
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: bypassPermissions
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: bypassPermissions
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
- BRANCH="defrag-$(date +%s)"
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: bypassPermissions
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/readOnlyShell.ts
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(resolve4(root));
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 = homedir11();
52697
+ const home = homedir12();
52550
52698
  const prefixes = [
52551
- normalizeSeparators(resolve4(home, ".letta", "agents", agentId, "memory")),
52552
- normalizeSeparators(resolve4(home, ".letta", "agents", agentId, "memory-worktrees"))
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(resolve4(home, ".letta", "agents", parentId, "memory")), normalizeSeparators(resolve4(home, ".letta", "agents", parentId, "memory-worktrees")));
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
- const home = homedir11();
52565
- if (p.startsWith("~/")) {
52566
- return normalizeSeparators(resolve4(home, p.slice(2)));
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;
52742
+ }
52743
+ if (expandedPath.startsWith("~/") || expandedPath.startsWith("$HOME/") || expandedPath.startsWith('"$HOME/') || expandedPath.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(expandedPath)) {
52744
+ return normalizeScopedPath(expandedPath);
52745
+ }
52746
+ if (cwd2) {
52747
+ return normalizeScopedPath(resolve5(cwd2, expandedPath));
52748
+ }
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;
52567
52764
  }
52568
- if (p.startsWith("$HOME/")) {
52569
- return normalizeSeparators(resolve4(home, p.slice(6)));
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
+ }
52570
52779
  }
52571
- if (p.startsWith('"$HOME/')) {
52572
- return normalizeSeparators(resolve4(home, p.slice(7).replace(/"$/, "")));
52780
+ return true;
52781
+ }
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;
52794
+ }
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 };
52573
52886
  }
52574
- return normalizeSeparators(resolve4(p));
52887
+ return {
52888
+ subcommand: null,
52889
+ worktreeSubcommand: null,
52890
+ resolvedCwd,
52891
+ isSafe: false
52892
+ };
52575
52893
  }
52576
- function isUnderMemoryDir(path4, prefixes) {
52577
- const resolved = expandPath(path4);
52578
- return prefixes.some((prefix) => resolved === prefix || resolved.startsWith(`${prefix}/`));
52894
+ function tokenLooksLikePath(token) {
52895
+ return token.includes("/") || token.includes("\\") || token === "." || token === ".." || token.startsWith("$") || token.startsWith("~") || token.startsWith("$HOME");
52579
52896
  }
52580
- function extractCdTarget(segment) {
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[0] === "cd" && tokens[1]) {
52583
- return tokens[1];
52912
+ if (tokens.length === 0) {
52913
+ return { nextCwd: cwd2, safe: false };
52584
52914
  }
52585
- return null;
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 isMemoryDirCommand(command, agentId) {
52588
- if (!command || !agentId) {
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 prefixes = getAllowedMemoryPrefixes(agentId);
52597
- const segments = trimmed.split(/&&|\|\||;/).map((s) => s.trim()).filter(Boolean);
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
- let cwd2 = null;
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 pipeParts = segment.split(/\|/).map((s) => s.trim()).filter(Boolean);
52604
- for (const part of pipeParts) {
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
- var MEMORY_DIR_APPROVE_ALL = true, SAFE_MEMORY_DIR_COMMANDS, ALWAYS_SAFE_COMMANDS, EXTERNAL_PATH_METADATA_COMMANDS, SAFE_GIT_SUBCOMMANDS, SAFE_LETTA_COMMANDS, SAFE_GH_COMMANDS;
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
- SAFE_MEMORY_DIR_COMMANDS = new Set([
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 homedir12 } from "node:os";
52966
- import { isAbsolute as isAbsolute2, join as join14, relative as relative3, resolve as resolve5 } from "node:path";
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
- const trimmedPath = targetPath.trim();
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("..") && !isAbsolute2(rel);
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(homedir12(), ".letta", "plans");
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(homedir12(), ".letta", "plans");
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 homedir14 } from "node:os";
57344
- import { dirname as dirname6, isAbsolute as isAbsolute8, relative as relative5, resolve as resolve12 } from "node:path";
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(dirname6(filePath), { recursive: true });
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(dirname6(newFilePath), { recursive: true });
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(homedir14(), ".letta", "agents", agentId, "memory");
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 (isAbsolute8(raw) || isWindowsAbsolute) {
57994
+ if (isAbsolute9(raw) || isWindowsAbsolute) {
57532
57995
  const absolutePath = resolve12(raw);
57533
57996
  const relToMemory = relative5(memoryDir, absolutePath);
57534
- if (relToMemory && !relToMemory.startsWith("..") && !isAbsolute8(relToMemory)) {
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("..") || isAbsolute8(rel)) {
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("..") || isAbsolute8(rel)) {
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 homedir15 } from "node:os";
57759
- import { dirname as dirname7, isAbsolute as isAbsolute9, relative as relative6, resolve as resolve13 } from "node:path";
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(dirname7(absPath), { recursive: true });
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(homedir15(), ".letta", "agents", agentId, "memory");
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 (isAbsolute9(raw) || isWindowsAbsolute) {
58530
+ if (isAbsolute10(raw) || isWindowsAbsolute) {
58068
58531
  const absolutePath = resolve13(raw);
58069
58532
  const relToMemory = relative6(memoryDir, absolutePath);
58070
- if (relToMemory && !relToMemory.startsWith("..") && !isAbsolute9(relToMemory)) {
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("..") || isAbsolute9(rel)) {
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("..") || isAbsolute9(rel)) {
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 dirname8, join as join19 } from "node:path";
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 = dirname8(fileURLToPath7(import.meta.url));
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 dirname9, join as join20 } from "node:path";
65829
+ import { dirname as dirname10, join as join20 } from "node:path";
65367
65830
  function hasAdditionalFiles(skillMdPath) {
65368
65831
  try {
65369
- const skillDir = dirname9(skillMdPath);
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 = dirname9(skillPath);
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 homedir16 = __require("node:os").homedir();
69710
- globPattern = globPattern.replace(/^~/, homedir16);
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 (READ_ONLY_SUBAGENT_TYPES.has(subagentType)) {
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, READ_ONLY_SUBAGENT_TYPES;
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
- READ_ONLY_SUBAGENT_TYPES = new Set([
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 homedir16 } from "node:os";
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 || homedir16();
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 homedir17 } from "node:os";
70465
- import { dirname as dirname11, relative as relative8, resolve as resolve22, win32 as win322 } from "node:path";
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) : dirname11(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(homedir17()), "~");
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 = dirname11(relativePath);
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(homedir17()).replace(/\/$/, "");
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 homedir18 } from "node:os";
72708
+ import { homedir as homedir19 } from "node:os";
72228
72709
  import { join as join22 } from "node:path";
72229
- function getMemoryFilesystemRoot(agentId, homeDir = homedir18()) {
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 = homedir18()) {
72713
+ function getMemorySystemDir(agentId, homeDir = homedir19()) {
72233
72714
  return join22(getMemoryFilesystemRoot(agentId, homeDir), MEMORY_SYSTEM_DIR);
72234
72715
  }
72235
- function ensureMemoryFilesystemDirs(agentId, homeDir = homedir18()) {
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)) {
@@ -75298,7 +75779,7 @@ import {
75298
75779
  readFile as readFile7,
75299
75780
  writeFile as writeFile4
75300
75781
  } from "node:fs/promises";
75301
- import { homedir as homedir19, tmpdir as tmpdir3 } from "node:os";
75782
+ import { homedir as homedir20, tmpdir as tmpdir3 } from "node:os";
75302
75783
  import { join as join25 } from "node:path";
75303
75784
  function buildReflectionSubagentPrompt(input) {
75304
75785
  const lines = [];
@@ -75492,7 +75973,7 @@ function getTranscriptRoot() {
75492
75973
  if (envRoot) {
75493
75974
  return envRoot;
75494
75975
  }
75495
- return join25(homedir19(), ".letta", DEFAULT_TRANSCRIPT_DIR);
75976
+ return join25(homedir20(), ".letta", DEFAULT_TRANSCRIPT_DIR);
75496
75977
  }
75497
75978
  function defaultState() {
75498
75979
  return { auto_cursor_line: 0 };
@@ -75681,7 +76162,7 @@ import {
75681
76162
  unlinkSync as unlinkSync7,
75682
76163
  writeFileSync as writeFileSync11
75683
76164
  } from "node:fs";
75684
- import { homedir as homedir20 } from "node:os";
76165
+ import { homedir as homedir21 } from "node:os";
75685
76166
  import { join as join26 } from "node:path";
75686
76167
  function truncateStr(value, maxLen) {
75687
76168
  if (value === null || value === undefined)
@@ -75822,7 +76303,7 @@ class ChunkLog {
75822
76303
  var MAX_ENTRIES = 100, CONTENT_TRUNCATE_LEN = 200, MAX_SESSION_FILES2 = 5, LOG_BASE_DIR, chunkLog;
75823
76304
  var init_chunkLog = __esm(() => {
75824
76305
  init_debug();
75825
- LOG_BASE_DIR = join26(homedir20(), ".letta", "logs", "chunk-logs");
76306
+ LOG_BASE_DIR = join26(homedir21(), ".letta", "logs", "chunk-logs");
75826
76307
  chunkLog = new ChunkLog;
75827
76308
  });
75828
76309
 
@@ -76839,6 +77320,7 @@ var init_engine = __esm(async () => {
76839
77320
  default: "Normal approval flow.",
76840
77321
  acceptEdits: "File edits auto-approved.",
76841
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.",
76842
77324
  bypassPermissions: "All tools auto-approved. Bias toward action."
76843
77325
  };
76844
77326
  sharedReminderProviders = {
@@ -76951,10 +77433,10 @@ var init_constants2 = __esm(() => {
76951
77433
  // src/websocket/listener/remote-settings.ts
76952
77434
  import { existsSync as existsSync21, readFileSync as readFileSync12 } from "node:fs";
76953
77435
  import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
76954
- import { homedir as homedir21 } from "node:os";
77436
+ import { homedir as homedir22 } from "node:os";
76955
77437
  import path20 from "node:path";
76956
77438
  function getRemoteSettingsPath() {
76957
- return path20.join(homedir21(), ".letta", "remote-settings.json");
77439
+ return path20.join(homedir22(), ".letta", "remote-settings.json");
76958
77440
  }
76959
77441
  function loadRemoteSettings() {
76960
77442
  if (_cache !== null) {
@@ -76998,7 +77480,7 @@ function saveRemoteSettings(updates) {
76998
77480
  }
76999
77481
  function loadLegacyCwdCache() {
77000
77482
  try {
77001
- const legacyPath = path20.join(homedir21(), ".letta", "cwd-cache.json");
77483
+ const legacyPath = path20.join(homedir22(), ".letta", "cwd-cache.json");
77002
77484
  if (!existsSync21(legacyPath))
77003
77485
  return {};
77004
77486
  const raw = readFileSync12(legacyPath, "utf-8");
@@ -78673,7 +79155,7 @@ __export(exports_diff, {
78673
79155
  ADV_DIFF_IGNORE_WHITESPACE: () => ADV_DIFF_IGNORE_WHITESPACE,
78674
79156
  ADV_DIFF_CONTEXT_LINES: () => ADV_DIFF_CONTEXT_LINES
78675
79157
  });
78676
- import { basename as basename2 } from "node:path";
79158
+ import { basename as basename3 } from "node:path";
78677
79159
  function readFileOrNull(p) {
78678
79160
  try {
78679
79161
  return __require("node:fs").readFileSync(p, "utf-8");
@@ -78697,7 +79179,7 @@ function applyAllOccurrences(content, oldStr, newStr) {
78697
79179
  return { ok: true, out: content.split(oldStr).join(newStr) };
78698
79180
  }
78699
79181
  function computeAdvancedDiff(input, opts) {
78700
- const fileName = basename2(input.filePath || "");
79182
+ const fileName = basename3(input.filePath || "");
78701
79183
  const fileContent = opts?.oldStrOverride !== undefined ? opts.oldStrOverride : readFileOrNull(input.filePath);
78702
79184
  if (fileContent === null && input.kind !== "write") {
78703
79185
  return { mode: "fallback", reason: "File not readable" };
@@ -78763,7 +79245,7 @@ function computeAdvancedDiff(input, opts) {
78763
79245
  return { mode: "advanced", fileName, oldStr, newStr, hunks };
78764
79246
  }
78765
79247
  function parsePatchToAdvancedDiff(patchLines, filePath) {
78766
- const fileName = basename2(filePath);
79248
+ const fileName = basename3(filePath);
78767
79249
  const hunks = [];
78768
79250
  let currentHunk = null;
78769
79251
  let oldLine = 1;
@@ -79090,7 +79572,7 @@ var init_formatArgsDisplay = __esm(async () => {
79090
79572
  });
79091
79573
 
79092
79574
  // src/helpers/diffPreview.ts
79093
- import path21, { basename as basename3 } from "node:path";
79575
+ import path21, { basename as basename4 } from "node:path";
79094
79576
  function parseHunkLinePrefix(raw) {
79095
79577
  if (raw.length === 0) {
79096
79578
  return { type: "context", content: "" };
@@ -79196,7 +79678,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
79196
79678
  filePath: resolvedFilePath,
79197
79679
  content: toolArgs.content || ""
79198
79680
  });
79199
- previews.push(toDiffPreview(result, basename3(filePath)));
79681
+ previews.push(toDiffPreview(result, basename4(filePath)));
79200
79682
  }
79201
79683
  } else if (isFileEditTool2(toolName)) {
79202
79684
  const filePath = toolArgs.file_path;
@@ -79208,7 +79690,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
79208
79690
  filePath: resolvedFilePath,
79209
79691
  edits: toolArgs.edits
79210
79692
  });
79211
- previews.push(toDiffPreview(result, basename3(filePath)));
79693
+ previews.push(toDiffPreview(result, basename4(filePath)));
79212
79694
  } else {
79213
79695
  const result = computeAdvancedDiff2({
79214
79696
  kind: "edit",
@@ -79217,7 +79699,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
79217
79699
  newString: toolArgs.new_string || "",
79218
79700
  replaceAll: toolArgs.replace_all
79219
79701
  });
79220
- previews.push(toDiffPreview(result, basename3(filePath)));
79702
+ previews.push(toDiffPreview(result, basename4(filePath)));
79221
79703
  }
79222
79704
  }
79223
79705
  } else if (isPatchTool2(toolName) && toolArgs.input) {
@@ -79226,7 +79708,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
79226
79708
  if (op.kind === "add" || op.kind === "update") {
79227
79709
  const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
79228
79710
  if (result) {
79229
- previews.push(toDiffPreview(result, basename3(op.path)));
79711
+ previews.push(toDiffPreview(result, basename4(op.path)));
79230
79712
  }
79231
79713
  }
79232
79714
  }
@@ -79236,7 +79718,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
79236
79718
  if (op.kind === "add" || op.kind === "update") {
79237
79719
  const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
79238
79720
  if (result) {
79239
- previews.push(toDiffPreview(result, basename3(op.path)));
79721
+ previews.push(toDiffPreview(result, basename4(op.path)));
79240
79722
  }
79241
79723
  }
79242
79724
  }
@@ -81760,18 +82242,24 @@ function buildDeviceStatus(runtime, params) {
81760
82242
  function buildLoopStatus(runtime, params) {
81761
82243
  const listener = getListenerRuntime(runtime);
81762
82244
  if (!listener) {
81763
- return { status: "WAITING_ON_INPUT", active_run_ids: [] };
82245
+ return {
82246
+ status: "WAITING_ON_INPUT",
82247
+ active_run_ids: [],
82248
+ plan_file_path: null
82249
+ };
81764
82250
  }
81765
82251
  const scope = getScopeForRuntime(runtime, params);
81766
82252
  const scopedAgentId = resolveScopedAgentId(listener, scope);
81767
82253
  const scopedConversationId = resolveScopedConversationId(listener, scope);
82254
+ const conversationPermissionModeState = getConversationPermissionModeState(listener, scopedAgentId, scopedConversationId);
81768
82255
  const conversationRuntime = getConversationRuntime(listener, scopedAgentId, scopedConversationId);
81769
82256
  const interruptedCacheActive = hasInterruptedCacheForScope(listener, scope);
81770
82257
  const recovered = getRecoveredApprovalStateForScope(listener, scope);
81771
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";
81772
82259
  return {
81773
82260
  status,
81774
- 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
81775
82263
  };
81776
82264
  }
81777
82265
  function buildQueueSnapshot(runtime, params) {
@@ -83605,7 +84093,7 @@ async function handleSkillCommand(parsed, socket) {
83605
84093
  symlinkSync,
83606
84094
  unlinkSync: unlinkSync8
83607
84095
  } = await import("node:fs");
83608
- const { basename: basename4, join: join28 } = await import("node:path");
84096
+ const { basename: basename5, join: join28 } = await import("node:path");
83609
84097
  const lettaHome = process.env.LETTA_HOME || join28(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
83610
84098
  const globalSkillsDir = join28(lettaHome, "skills");
83611
84099
  if (parsed.type === "skill_enable") {
@@ -83629,7 +84117,7 @@ async function handleSkillCommand(parsed, socket) {
83629
84117
  }, "listener_skill_send_failed", "listener_skill_command");
83630
84118
  return true;
83631
84119
  }
83632
- const linkName = basename4(parsed.skill_path);
84120
+ const linkName = basename5(parsed.skill_path);
83633
84121
  const linkPath = join28(globalSkillsDir, linkName);
83634
84122
  mkdirSync15(globalSkillsDir, { recursive: true });
83635
84123
  if (existsSync22(linkPath)) {
@@ -85349,7 +85837,7 @@ import {
85349
85837
  readFileSync as readFileSync14,
85350
85838
  unlinkSync as unlinkSync8
85351
85839
  } from "node:fs";
85352
- import { homedir as homedir25 } from "node:os";
85840
+ import { homedir as homedir26 } from "node:os";
85353
85841
  import { join as join31 } from "node:path";
85354
85842
  import { format as format2 } from "node:util";
85355
85843
  function isDebugEnabled2() {
@@ -85455,7 +85943,7 @@ function debugWarn2(prefix, message, ...args) {
85455
85943
  }
85456
85944
  var DEBUG_LOG_DIR2, MAX_SESSION_FILES3 = 5, DEFAULT_TAIL_LINES2 = 50, debugLogFile2;
85457
85945
  var init_debug2 = __esm(() => {
85458
- DEBUG_LOG_DIR2 = join31(homedir25(), ".letta", "logs", "debug");
85946
+ DEBUG_LOG_DIR2 = join31(homedir26(), ".letta", "logs", "debug");
85459
85947
  debugLogFile2 = new DebugLogFile2;
85460
85948
  });
85461
85949
 
@@ -85484,10 +85972,10 @@ __export(exports_skills2, {
85484
85972
  });
85485
85973
  import { existsSync as existsSync24 } from "node:fs";
85486
85974
  import { readdir as readdir7, readFile as readFile8, realpath as realpath4, stat as stat6 } from "node:fs/promises";
85487
- import { dirname as dirname12, join as join32 } from "node:path";
85975
+ import { dirname as dirname13, join as join32 } from "node:path";
85488
85976
  import { fileURLToPath as fileURLToPath8 } from "node:url";
85489
85977
  function getBundledSkillsPath2() {
85490
- const thisDir = dirname12(fileURLToPath8(import.meta.url));
85978
+ const thisDir = dirname13(fileURLToPath8(import.meta.url));
85491
85979
  if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
85492
85980
  return join32(thisDir, "../skills/builtin");
85493
85981
  }
@@ -85683,12 +86171,12 @@ import {
85683
86171
  writeFileSync as fsWriteFileSync2,
85684
86172
  mkdirSync as mkdirSync17
85685
86173
  } from "node:fs";
85686
- import { dirname as dirname13 } from "node:path";
86174
+ import { dirname as dirname14 } from "node:path";
85687
86175
  async function readFile9(path23) {
85688
86176
  return fsReadFileSync2(path23, { encoding: "utf-8" });
85689
86177
  }
85690
86178
  async function writeFile7(path23, content) {
85691
- const dir = dirname13(path23);
86179
+ const dir = dirname14(path23);
85692
86180
  if (!existsSync25(dir)) {
85693
86181
  mkdirSync17(dir, { recursive: true });
85694
86182
  }
@@ -85733,7 +86221,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
85733
86221
  }
85734
86222
  const wasRaw = process.stdin.isRaw;
85735
86223
  const wasFlowing = process.stdin.readableFlowing;
85736
- return new Promise((resolve26) => {
86224
+ return new Promise((resolve25) => {
85737
86225
  let response = "";
85738
86226
  let resolved = false;
85739
86227
  const cleanup = () => {
@@ -85750,7 +86238,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
85750
86238
  };
85751
86239
  const timeout = setTimeout(() => {
85752
86240
  cleanup();
85753
- resolve26(null);
86241
+ resolve25(null);
85754
86242
  }, timeoutMs);
85755
86243
  const onData = (data) => {
85756
86244
  response += data.toString();
@@ -85760,7 +86248,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
85760
86248
  if (match3) {
85761
86249
  clearTimeout(timeout);
85762
86250
  cleanup();
85763
- resolve26({
86251
+ resolve25({
85764
86252
  r: parseHexComponent(match3[1] ?? "0"),
85765
86253
  g: parseHexComponent(match3[2] ?? "0"),
85766
86254
  b: parseHexComponent(match3[3] ?? "0")
@@ -85775,7 +86263,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
85775
86263
  } catch {
85776
86264
  clearTimeout(timeout);
85777
86265
  cleanup();
85778
- resolve26(null);
86266
+ resolve25(null);
85779
86267
  }
85780
86268
  });
85781
86269
  }
@@ -86984,10 +87472,10 @@ __export(exports_setup, {
86984
87472
  runSetup: () => runSetup
86985
87473
  });
86986
87474
  async function runSetup() {
86987
- return new Promise((resolve27) => {
87475
+ return new Promise((resolve26) => {
86988
87476
  const { waitUntilExit } = render_default(import_react32.default.createElement(SetupUI, {
86989
87477
  onComplete: () => {
86990
- resolve27();
87478
+ resolve26();
86991
87479
  }
86992
87480
  }));
86993
87481
  waitUntilExit().catch((error) => {
@@ -87517,10 +88005,10 @@ __export(exports_import, {
87517
88005
  });
87518
88006
  import { createReadStream } from "node:fs";
87519
88007
  import { chmod, mkdir as mkdir7, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
87520
- import { dirname as dirname14, resolve as resolve27 } from "node:path";
88008
+ import { dirname as dirname15, resolve as resolve26 } from "node:path";
87521
88009
  async function importAgentFromFile(options) {
87522
88010
  const client = await getClient();
87523
- const resolvedPath = resolve27(options.filePath);
88011
+ const resolvedPath = resolve26(options.filePath);
87524
88012
  const file = createReadStream(resolvedPath);
87525
88013
  const importResponse = await client.agents.importFile({
87526
88014
  file,
@@ -87555,7 +88043,7 @@ async function extractSkillsFromAf(afPath, destDir) {
87555
88043
  return [];
87556
88044
  }
87557
88045
  for (const skill2 of afData.skills) {
87558
- const skillDir = resolve27(destDir, skill2.name);
88046
+ const skillDir = resolve26(destDir, skill2.name);
87559
88047
  await mkdir7(skillDir, { recursive: true });
87560
88048
  if (skill2.files) {
87561
88049
  await writeSkillFiles(skillDir, skill2.files);
@@ -87575,8 +88063,8 @@ async function writeSkillFiles(skillDir, files) {
87575
88063
  }
87576
88064
  }
87577
88065
  async function writeSkillFile(skillDir, filePath, content) {
87578
- const fullPath = resolve27(skillDir, filePath);
87579
- await mkdir7(dirname14(fullPath), { recursive: true });
88066
+ const fullPath = resolve26(skillDir, filePath);
88067
+ await mkdir7(dirname15(fullPath), { recursive: true });
87580
88068
  await writeFile8(fullPath, content, "utf-8");
87581
88069
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
87582
88070
  if (isScript) {
@@ -87882,12 +88370,12 @@ async function prepareHeadlessToolExecutionContext(params) {
87882
88370
  };
87883
88371
  }
87884
88372
  async function flushAndExit(code) {
87885
- const flushWritable = (stream2) => new Promise((resolve28) => {
88373
+ const flushWritable = (stream2) => new Promise((resolve27) => {
87886
88374
  if (stream2.destroyed || stream2.writableEnded) {
87887
- resolve28();
88375
+ resolve27();
87888
88376
  return;
87889
88377
  }
87890
- stream2.write("", () => resolve28());
88378
+ stream2.write("", () => resolve27());
87891
88379
  });
87892
88380
  await Promise.allSettled([
87893
88381
  flushWritable(process.stdout),
@@ -87913,7 +88401,8 @@ async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride,
87913
88401
  "default",
87914
88402
  "acceptEdits",
87915
88403
  "bypassPermissions",
87916
- "plan"
88404
+ "plan",
88405
+ "memory"
87917
88406
  ];
87918
88407
  if (validModes.includes(permissionModeValue)) {
87919
88408
  permissionMode3.setMode(permissionModeValue);
@@ -88834,7 +89323,7 @@ ${loadedContents.join(`
88834
89323
  } else {
88835
89324
  console.error(`Conversation is busy, waiting ${Math.round(retryDelayMs / 1000)}s and retrying...`);
88836
89325
  }
88837
- await new Promise((resolve28) => setTimeout(resolve28, retryDelayMs));
89326
+ await new Promise((resolve27) => setTimeout(resolve27, retryDelayMs));
88838
89327
  continue;
88839
89328
  }
88840
89329
  }
@@ -88883,7 +89372,7 @@ ${loadedContents.join(`
88883
89372
  const delaySeconds = Math.round(delayMs / 1000);
88884
89373
  console.error(`Transient API error before streaming (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
88885
89374
  }
88886
- await new Promise((resolve28) => setTimeout(resolve28, delayMs));
89375
+ await new Promise((resolve27) => setTimeout(resolve27, delayMs));
88887
89376
  conversationBusyRetries = 0;
88888
89377
  continue;
88889
89378
  }
@@ -89122,7 +89611,7 @@ ${loadedContents.join(`
89122
89611
  const delaySeconds = Math.round(delayMs / 1000);
89123
89612
  console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
89124
89613
  }
89125
- await new Promise((resolve28) => setTimeout(resolve28, delayMs));
89614
+ await new Promise((resolve27) => setTimeout(resolve27, delayMs));
89126
89615
  refreshCurrentInputOtids();
89127
89616
  continue;
89128
89617
  }
@@ -89208,7 +89697,7 @@ ${loadedContents.join(`
89208
89697
  } else {
89209
89698
  console.error(`Empty LLM response, retrying (attempt ${attempt} of ${EMPTY_RESPONSE_MAX_RETRIES2})...`);
89210
89699
  }
89211
- await new Promise((resolve28) => setTimeout(resolve28, delayMs));
89700
+ await new Promise((resolve27) => setTimeout(resolve27, delayMs));
89212
89701
  refreshCurrentInputOtids();
89213
89702
  continue;
89214
89703
  }
@@ -89236,7 +89725,7 @@ ${loadedContents.join(`
89236
89725
  const delaySeconds = Math.round(delayMs / 1000);
89237
89726
  console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
89238
89727
  }
89239
- await new Promise((resolve28) => setTimeout(resolve28, delayMs));
89728
+ await new Promise((resolve27) => setTimeout(resolve27, delayMs));
89240
89729
  refreshCurrentInputOtids();
89241
89730
  continue;
89242
89731
  }
@@ -89570,9 +90059,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
89570
90059
  const syntheticUserLine = serializeQueuedMessageAsUserLine(queuedMessage);
89571
90060
  maybeNotifyBlocked(syntheticUserLine);
89572
90061
  if (lineResolver) {
89573
- const resolve28 = lineResolver;
90062
+ const resolve27 = lineResolver;
89574
90063
  lineResolver = null;
89575
- resolve28(syntheticUserLine);
90064
+ resolve27(syntheticUserLine);
89576
90065
  return;
89577
90066
  }
89578
90067
  lineQueue.push(syntheticUserLine);
@@ -89580,9 +90069,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
89580
90069
  rl.on("line", (line) => {
89581
90070
  maybeNotifyBlocked(line);
89582
90071
  if (lineResolver) {
89583
- const resolve28 = lineResolver;
90072
+ const resolve27 = lineResolver;
89584
90073
  lineResolver = null;
89585
- resolve28(line);
90074
+ resolve27(line);
89586
90075
  } else {
89587
90076
  lineQueue.push(line);
89588
90077
  }
@@ -89591,17 +90080,17 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
89591
90080
  setMessageQueueAdder(null);
89592
90081
  msgQueueRuntime.clear("shutdown");
89593
90082
  if (lineResolver) {
89594
- const resolve28 = lineResolver;
90083
+ const resolve27 = lineResolver;
89595
90084
  lineResolver = null;
89596
- resolve28(null);
90085
+ resolve27(null);
89597
90086
  }
89598
90087
  });
89599
90088
  async function getNextLine() {
89600
90089
  if (lineQueue.length > 0) {
89601
90090
  return lineQueue.shift() ?? null;
89602
90091
  }
89603
- return new Promise((resolve28) => {
89604
- lineResolver = resolve28;
90092
+ return new Promise((resolve27) => {
90093
+ lineResolver = resolve27;
89605
90094
  });
89606
90095
  }
89607
90096
  async function requestPermission(toolCallId, toolName, toolInput) {
@@ -90105,7 +90594,7 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
90105
90594
  uuid: `retry-bidir-${randomUUID8()}`
90106
90595
  };
90107
90596
  console.log(JSON.stringify(retryMsg));
90108
- await new Promise((resolve28) => setTimeout(resolve28, delayMs));
90597
+ await new Promise((resolve27) => setTimeout(resolve27, delayMs));
90109
90598
  continue;
90110
90599
  }
90111
90600
  throw preStreamError;
@@ -90401,10 +90890,10 @@ async function detectAndEnableKittyProtocol() {
90401
90890
  detectionComplete = true;
90402
90891
  return;
90403
90892
  }
90404
- return new Promise((resolve28) => {
90893
+ return new Promise((resolve27) => {
90405
90894
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
90406
90895
  detectionComplete = true;
90407
- resolve28();
90896
+ resolve27();
90408
90897
  return;
90409
90898
  }
90410
90899
  const originalRawMode = process.stdin.isRaw;
@@ -90437,7 +90926,7 @@ async function detectAndEnableKittyProtocol() {
90437
90926
  console.error("[kitty] protocol query unsupported; enabled anyway (best-effort)");
90438
90927
  }
90439
90928
  detectionComplete = true;
90440
- resolve28();
90929
+ resolve27();
90441
90930
  };
90442
90931
  const handleData = (data) => {
90443
90932
  if (timeoutId === undefined) {
@@ -90795,10 +91284,10 @@ __export(exports_settings, {
90795
91284
  loadProjectSettings: () => loadProjectSettings,
90796
91285
  getSetting: () => getSetting
90797
91286
  });
90798
- import { homedir as homedir28 } from "node:os";
91287
+ import { homedir as homedir29 } from "node:os";
90799
91288
  import { join as join36 } from "node:path";
90800
91289
  function getSettingsPath() {
90801
- return join36(homedir28(), ".letta", "settings.json");
91290
+ return join36(homedir29(), ".letta", "settings.json");
90802
91291
  }
90803
91292
  async function loadSettings() {
90804
91293
  const settingsPath = getSettingsPath();
@@ -106304,16 +106793,16 @@ function clipStyledSpans(spans, maxColumns) {
106304
106793
  return { spans: clipped, clipped: false };
106305
106794
  }
106306
106795
  function languageFromPath(filePath) {
106307
- const basename4 = filePath.split("/").pop() ?? filePath;
106308
- const lower = basename4.toLowerCase();
106796
+ const basename5 = filePath.split("/").pop() ?? filePath;
106797
+ const lower = basename5.toLowerCase();
106309
106798
  if (lower === "makefile")
106310
106799
  return "makefile";
106311
106800
  if (lower === "dockerfile")
106312
106801
  return "dockerfile";
106313
- const dotIdx = basename4.lastIndexOf(".");
106802
+ const dotIdx = basename5.lastIndexOf(".");
106314
106803
  if (dotIdx < 0)
106315
106804
  return;
106316
- const ext3 = basename4.slice(dotIdx + 1).toLowerCase();
106805
+ const ext3 = basename5.slice(dotIdx + 1).toLowerCase();
106317
106806
  return EXT_TO_LANG[ext3];
106318
106807
  }
106319
106808
  function colorForClassName(className, palette) {
@@ -110349,7 +110838,7 @@ var init_plan_viewer_template = () => {};
110349
110838
 
110350
110839
  // src/web/generate-plan-viewer.ts
110351
110840
  import { chmodSync as chmodSync2, existsSync as existsSync28, mkdirSync as mkdirSync20, writeFileSync as writeFileSync14 } from "node:fs";
110352
- import { homedir as homedir29 } from "node:os";
110841
+ import { homedir as homedir30 } from "node:os";
110353
110842
  import { join as join37 } from "node:path";
110354
110843
  async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
110355
110844
  const data = {
@@ -110383,7 +110872,7 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
110383
110872
  var VIEWERS_DIR;
110384
110873
  var init_generate_plan_viewer = __esm(() => {
110385
110874
  init_plan_viewer_template();
110386
- VIEWERS_DIR = join37(homedir29(), ".letta", "viewers");
110875
+ VIEWERS_DIR = join37(homedir30(), ".letta", "viewers");
110387
110876
  });
110388
110877
 
110389
110878
  // src/cli/components/StaticPlanApproval.tsx
@@ -112623,7 +113112,7 @@ var init_pasteRegistry = __esm(() => {
112623
113112
  import { execFileSync as execFileSync3 } from "node:child_process";
112624
113113
  import { existsSync as existsSync29, readFileSync as readFileSync16, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
112625
113114
  import { tmpdir as tmpdir4 } from "node:os";
112626
- import { basename as basename4, extname as extname5, isAbsolute as isAbsolute18, join as join38, resolve as resolve28 } from "node:path";
113115
+ import { basename as basename5, extname as extname5, isAbsolute as isAbsolute19, join as join38, resolve as resolve27 } from "node:path";
112627
113116
  function countLines2(text) {
112628
113117
  return (text.match(/\r\n|\r|\n/g) || []).length + 1;
112629
113118
  }
@@ -112670,8 +113159,8 @@ function translatePasteForImages(paste) {
112670
113159
  }
112671
113160
  } catch {}
112672
113161
  }
112673
- if (!isAbsolute18(filePath))
112674
- filePath = resolve28(process.cwd(), filePath);
113162
+ if (!isAbsolute19(filePath))
113163
+ filePath = resolve27(process.cwd(), filePath);
112675
113164
  const ext3 = extname5(filePath || "").toLowerCase();
112676
113165
  if (IMAGE_EXTS.has(ext3) && existsSync29(filePath) && statSync10(filePath).isFile()) {
112677
113166
  const buf = readFileSync16(filePath);
@@ -112680,7 +113169,7 @@ function translatePasteForImages(paste) {
112680
113169
  const id = allocateImage({
112681
113170
  data: b64,
112682
113171
  mediaType: mt,
112683
- filename: basename4(filePath)
113172
+ filename: basename5(filePath)
112684
113173
  });
112685
113174
  s = `[Image #${id}]`;
112686
113175
  }
@@ -113446,8 +113935,8 @@ import {
113446
113935
  readFileSync as readFileSync17,
113447
113936
  writeFileSync as writeFileSync15
113448
113937
  } from "node:fs";
113449
- import { homedir as homedir30, platform as platform5 } from "node:os";
113450
- import { dirname as dirname15, join as join39 } from "node:path";
113938
+ import { homedir as homedir31, platform as platform5 } from "node:os";
113939
+ import { dirname as dirname16, join as join39 } from "node:path";
113451
113940
  function detectTerminalType() {
113452
113941
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
113453
113942
  return "cursor";
@@ -113479,7 +113968,7 @@ function getKeybindingsPath(terminal) {
113479
113968
  }[terminal];
113480
113969
  const os7 = platform5();
113481
113970
  if (os7 === "darwin") {
113482
- return join39(homedir30(), "Library", "Application Support", appName, "User", "keybindings.json");
113971
+ return join39(homedir31(), "Library", "Application Support", appName, "User", "keybindings.json");
113483
113972
  }
113484
113973
  if (os7 === "win32") {
113485
113974
  const appData = process.env.APPDATA;
@@ -113488,7 +113977,7 @@ function getKeybindingsPath(terminal) {
113488
113977
  return join39(appData, appName, "User", "keybindings.json");
113489
113978
  }
113490
113979
  if (os7 === "linux") {
113491
- return join39(homedir30(), ".config", appName, "User", "keybindings.json");
113980
+ return join39(homedir31(), ".config", appName, "User", "keybindings.json");
113492
113981
  }
113493
113982
  return null;
113494
113983
  }
@@ -113538,7 +114027,7 @@ function installKeybinding(keybindingsPath) {
113538
114027
  if (keybindingExists(keybindingsPath)) {
113539
114028
  return { success: true, alreadyExists: true };
113540
114029
  }
113541
- const parentDir = dirname15(keybindingsPath);
114030
+ const parentDir = dirname16(keybindingsPath);
113542
114031
  if (!existsSync30(parentDir)) {
113543
114032
  mkdirSync21(parentDir, { recursive: true });
113544
114033
  }
@@ -113645,10 +114134,10 @@ function getWezTermConfigPath() {
113645
114134
  if (existsSync30(xdgPath))
113646
114135
  return xdgPath;
113647
114136
  }
113648
- const configPath = join39(homedir30(), ".config", "wezterm", "wezterm.lua");
114137
+ const configPath = join39(homedir31(), ".config", "wezterm", "wezterm.lua");
113649
114138
  if (existsSync30(configPath))
113650
114139
  return configPath;
113651
- return join39(homedir30(), ".wezterm.lua");
114140
+ return join39(homedir31(), ".wezterm.lua");
113652
114141
  }
113653
114142
  function wezTermDeleteFixExists(configPath) {
113654
114143
  if (!existsSync30(configPath))
@@ -113697,7 +114186,7 @@ return config`);
113697
114186
  ${WEZTERM_DELETE_FIX}
113698
114187
  `;
113699
114188
  }
113700
- const parentDir = dirname15(configPath);
114189
+ const parentDir = dirname16(configPath);
113701
114190
  if (!existsSync30(parentDir)) {
113702
114191
  mkdirSync21(parentDir, { recursive: true });
113703
114192
  }
@@ -114280,7 +114769,7 @@ __export(exports_custom, {
114280
114769
  });
114281
114770
  import { existsSync as existsSync31 } from "node:fs";
114282
114771
  import { readdir as readdir9, readFile as readFile11 } from "node:fs/promises";
114283
- import { basename as basename5, dirname as dirname16, join as join40 } from "node:path";
114772
+ import { basename as basename6, dirname as dirname17, join as join40 } from "node:path";
114284
114773
  async function getCustomCommands() {
114285
114774
  if (cachedCommands !== null) {
114286
114775
  return cachedCommands;
@@ -114340,8 +114829,8 @@ async function findCommandFiles(currentPath, rootPath, commands2, source2) {
114340
114829
  async function parseCommandFile(filePath, rootPath, source2) {
114341
114830
  const content = await readFile11(filePath, "utf-8");
114342
114831
  const { frontmatter, body } = parseFrontmatter(content);
114343
- const id = basename5(filePath, ".md");
114344
- const relativePath = dirname16(filePath).slice(rootPath.length);
114832
+ const id = basename6(filePath, ".md");
114833
+ const relativePath = dirname17(filePath).slice(rootPath.length);
114345
114834
  const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
114346
114835
  let description = getStringField(frontmatter, "description");
114347
114836
  if (!description) {
@@ -114689,12 +115178,12 @@ var init_HelpDialog = __esm(async () => {
114689
115178
  });
114690
115179
 
114691
115180
  // src/hooks/writer.ts
114692
- import { homedir as homedir31 } from "node:os";
114693
- import { resolve as resolve29 } from "node:path";
115181
+ import { homedir as homedir32 } from "node:os";
115182
+ import { resolve as resolve28 } from "node:path";
114694
115183
  function isProjectSettingsPathCollidingWithGlobal2(workingDirectory) {
114695
- const home = process.env.HOME || homedir31();
114696
- const globalSettingsPath = resolve29(home, ".letta", "settings.json");
114697
- const projectSettingsPath = resolve29(workingDirectory, ".letta", "settings.json");
115184
+ const home = process.env.HOME || homedir32();
115185
+ const globalSettingsPath = resolve28(home, ".letta", "settings.json");
115186
+ const projectSettingsPath = resolve28(workingDirectory, ".letta", "settings.json");
114698
115187
  return globalSettingsPath === projectSettingsPath;
114699
115188
  }
114700
115189
  function loadHooksFromLocation(location, workingDirectory = process.cwd()) {
@@ -117332,7 +117821,7 @@ var init_AgentInfoBar = __esm(async () => {
117332
117821
 
117333
117822
  // src/cli/helpers/fileSearch.ts
117334
117823
  import { readdirSync as readdirSync13, statSync as statSync11 } from "node:fs";
117335
- import { join as join41, relative as relative15, resolve as resolve30 } from "node:path";
117824
+ import { join as join41, relative as relative15, resolve as resolve29 } from "node:path";
117336
117825
  function searchDirectoryRecursive(dir, pattern, maxResults = 200, results = [], depth = 0, maxDepth = 10, lowerPattern = pattern.toLowerCase()) {
117337
117826
  if (results.length >= maxResults || depth >= maxDepth) {
117338
117827
  return results;
@@ -117375,7 +117864,7 @@ async function searchFiles(query, deep = false) {
117375
117864
  const dirPart = query.slice(0, lastSlashIndex);
117376
117865
  const pattern = query.slice(lastSlashIndex + 1);
117377
117866
  try {
117378
- const resolvedDir = resolve30(getIndexRoot(), dirPart);
117867
+ const resolvedDir = resolve29(getIndexRoot(), dirPart);
117379
117868
  try {
117380
117869
  statSync11(resolvedDir);
117381
117870
  searchDir = resolvedDir;
@@ -119503,7 +119992,7 @@ import {
119503
119992
  writeFileSync as writeFileSync16
119504
119993
  } from "node:fs";
119505
119994
  import { tmpdir as tmpdir5 } from "node:os";
119506
- import { dirname as dirname17, join as join42 } from "node:path";
119995
+ import { dirname as dirname18, join as join42 } from "node:path";
119507
119996
  function runCommand(command, args, cwd2, input) {
119508
119997
  try {
119509
119998
  return execFileSync4(command, args, {
@@ -119750,8 +120239,8 @@ function runGit6(args, cwd2) {
119750
120239
  }
119751
120240
  function writeWorkflow(repoDir, workflowPath, content) {
119752
120241
  const absolutePath = join42(repoDir, workflowPath);
119753
- if (!existsSync32(dirname17(absolutePath))) {
119754
- mkdirSync22(dirname17(absolutePath), { recursive: true });
120242
+ if (!existsSync32(dirname18(absolutePath))) {
120243
+ mkdirSync22(dirname18(absolutePath), { recursive: true });
119755
120244
  }
119756
120245
  const next = `${content.trimEnd()}
119757
120246
  `;
@@ -123657,7 +124146,7 @@ __export(exports_generate_memory_viewer, {
123657
124146
  });
123658
124147
  import { execFile as execFileCb5 } from "node:child_process";
123659
124148
  import { chmodSync as chmodSync3, existsSync as existsSync33, mkdirSync as mkdirSync23, writeFileSync as writeFileSync17 } from "node:fs";
123660
- import { homedir as homedir32 } from "node:os";
124149
+ import { homedir as homedir33 } from "node:os";
123661
124150
  import { join as join43 } from "node:path";
123662
124151
  import { promisify as promisify14 } from "node:util";
123663
124152
  async function runGitSafe(cwd2, args) {
@@ -123971,7 +124460,7 @@ var init_generate_memory_viewer = __esm(async () => {
123971
124460
  init_memoryGit()
123972
124461
  ]);
123973
124462
  execFile14 = promisify14(execFileCb5);
123974
- VIEWERS_DIR2 = join43(homedir32(), ".letta", "viewers");
124463
+ VIEWERS_DIR2 = join43(homedir33(), ".letta", "viewers");
123975
124464
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
123976
124465
  });
123977
124466
 
@@ -126689,11 +127178,11 @@ var init_PersonalitySelector = __esm(async () => {
126689
127178
 
126690
127179
  // src/utils/aws-credentials.ts
126691
127180
  import { readFile as readFile12 } from "node:fs/promises";
126692
- import { homedir as homedir33 } from "node:os";
127181
+ import { homedir as homedir34 } from "node:os";
126693
127182
  import { join as join44 } from "node:path";
126694
127183
  async function parseAwsCredentials() {
126695
- const credentialsPath = join44(homedir33(), ".aws", "credentials");
126696
- const configPath = join44(homedir33(), ".aws", "config");
127184
+ const credentialsPath = join44(homedir34(), ".aws", "credentials");
127185
+ const configPath = join44(homedir34(), ".aws", "config");
126697
127186
  const profiles = new Map;
126698
127187
  try {
126699
127188
  const content = await readFile12(credentialsPath, "utf-8");
@@ -132174,7 +132663,7 @@ async function executeStatusLineCommand(command, payload, options) {
132174
132663
  };
132175
132664
  }
132176
132665
  function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory, startTime) {
132177
- return new Promise((resolve31, reject) => {
132666
+ return new Promise((resolve30, reject) => {
132178
132667
  const [executable, ...args] = launcher;
132179
132668
  if (!executable) {
132180
132669
  reject(new Error("Empty launcher"));
@@ -132187,7 +132676,7 @@ function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory,
132187
132676
  const safeResolve = (result) => {
132188
132677
  if (!resolved) {
132189
132678
  resolved = true;
132190
- resolve31(result);
132679
+ resolve30(result);
132191
132680
  }
132192
132681
  };
132193
132682
  let child;
@@ -132633,7 +133122,7 @@ __export(exports_shellAliases, {
132633
133122
  clearAliasCache: () => clearAliasCache
132634
133123
  });
132635
133124
  import { existsSync as existsSync36, readFileSync as readFileSync20 } from "node:fs";
132636
- import { homedir as homedir34 } from "node:os";
133125
+ import { homedir as homedir35 } from "node:os";
132637
133126
  import { join as join46 } from "node:path";
132638
133127
  function parseAliasesFromFile(filePath) {
132639
133128
  const aliases = new Map;
@@ -132703,7 +133192,7 @@ function loadAliases(forceReload = false) {
132703
133192
  if (aliasCache && !forceReload) {
132704
133193
  return aliasCache;
132705
133194
  }
132706
- const home = homedir34();
133195
+ const home = homedir35();
132707
133196
  const allAliases = new Map;
132708
133197
  for (const file of ALIAS_FILES) {
132709
133198
  const filePath = join46(home, file);
@@ -133364,14 +133853,14 @@ __export(exports_export, {
133364
133853
  packageSkills: () => packageSkills
133365
133854
  });
133366
133855
  import { readdir as readdir10, readFile as readFile13 } from "node:fs/promises";
133367
- import { relative as relative16, resolve as resolve31 } from "node:path";
133856
+ import { relative as relative16, resolve as resolve30 } from "node:path";
133368
133857
  async function packageSkills(agentId, skillsDir) {
133369
133858
  const skills = [];
133370
133859
  const skillNames = new Set;
133371
133860
  const dirsToCheck = skillsDir ? [skillsDir] : [
133372
133861
  agentId && getAgentSkillsDir(agentId),
133373
- resolve31(process.cwd(), ".skills"),
133374
- resolve31(process.env.HOME || "~", ".letta", "skills")
133862
+ resolve30(process.cwd(), ".skills"),
133863
+ resolve30(process.env.HOME || "~", ".letta", "skills")
133375
133864
  ].filter((dir) => Boolean(dir));
133376
133865
  for (const baseDir of dirsToCheck) {
133377
133866
  try {
@@ -133381,8 +133870,8 @@ async function packageSkills(agentId, skillsDir) {
133381
133870
  continue;
133382
133871
  if (skillNames.has(entry.name))
133383
133872
  continue;
133384
- const skillDir = resolve31(baseDir, entry.name);
133385
- const skillMdPath = resolve31(skillDir, "SKILL.md");
133873
+ const skillDir = resolve30(baseDir, entry.name);
133874
+ const skillMdPath = resolve30(skillDir, "SKILL.md");
133386
133875
  try {
133387
133876
  await readFile13(skillMdPath, "utf-8");
133388
133877
  } catch {
@@ -133412,7 +133901,7 @@ async function readSkillFiles(skillDir) {
133412
133901
  async function walk(dir) {
133413
133902
  const entries = await readdir10(dir, { withFileTypes: true });
133414
133903
  for (const entry of entries) {
133415
- const fullPath = resolve31(dir, entry.name);
133904
+ const fullPath = resolve30(dir, entry.name);
133416
133905
  if (entry.isDirectory()) {
133417
133906
  await walk(fullPath);
133418
133907
  } else {
@@ -133557,7 +134046,7 @@ __export(exports_App, {
133557
134046
  });
133558
134047
  import { randomUUID as randomUUID9 } from "node:crypto";
133559
134048
  import { existsSync as existsSync37, readFileSync as readFileSync21, renameSync as renameSync3, writeFileSync as writeFileSync18 } from "node:fs";
133560
- import { homedir as homedir35, tmpdir as tmpdir6 } from "node:os";
134049
+ import { homedir as homedir36, tmpdir as tmpdir6 } from "node:os";
133561
134050
  import { join as join47, relative as relative17 } from "node:path";
133562
134051
  function deriveReasoningEffort(modelSettings, llmConfig) {
133563
134052
  if (modelSettings && "provider_type" in modelSettings) {
@@ -135896,7 +136385,7 @@ ${newState.originalPrompt}`,
135896
136385
  cancelled = true;
135897
136386
  break;
135898
136387
  }
135899
- await new Promise((resolve32) => setTimeout(resolve32, 100));
136388
+ await new Promise((resolve31) => setTimeout(resolve31, 100));
135900
136389
  }
135901
136390
  buffersRef.current.byId.delete(statusId);
135902
136391
  buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
@@ -135960,7 +136449,7 @@ ${newState.originalPrompt}`,
135960
136449
  cancelled = true;
135961
136450
  break;
135962
136451
  }
135963
- await new Promise((resolve32) => setTimeout(resolve32, 100));
136452
+ await new Promise((resolve31) => setTimeout(resolve31, 100));
135964
136453
  }
135965
136454
  if (retryStatusId) {
135966
136455
  buffersRef.current.byId.delete(retryStatusId);
@@ -136718,7 +137207,7 @@ ${feedback}
136718
137207
  });
136719
137208
  buffersRef.current.order.push(statusId);
136720
137209
  refreshDerived();
136721
- await new Promise((resolve32) => setTimeout(resolve32, delayMs));
137210
+ await new Promise((resolve31) => setTimeout(resolve31, delayMs));
136722
137211
  buffersRef.current.byId.delete(statusId);
136723
137212
  buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
136724
137213
  refreshDerived();
@@ -136778,7 +137267,7 @@ ${feedback}
136778
137267
  cancelled = true;
136779
137268
  break;
136780
137269
  }
136781
- await new Promise((resolve32) => setTimeout(resolve32, 100));
137270
+ await new Promise((resolve31) => setTimeout(resolve31, 100));
136782
137271
  }
136783
137272
  if (retryStatusId) {
136784
137273
  buffersRef.current.byId.delete(retryStatusId);
@@ -141721,7 +142210,7 @@ ${guidance}`);
141721
142210
  }
141722
142211
  if (mode === "bypassPermissions") {
141723
142212
  const planFilePath = activePlanPath ?? fallbackPlanPath;
141724
- const plansDir = join47(homedir35(), ".letta", "plans");
142213
+ const plansDir = join47(homedir36(), ".letta", "plans");
141725
142214
  handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
141726
142215
  ` + (planFilePath ? `Plan file path: ${planFilePath}
141727
142216
  ` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
@@ -141756,7 +142245,7 @@ ${guidance}`);
141756
142245
  if (!hasUsablePlan) {
141757
142246
  lastAutoHandledExitPlanToolCallIdRef.current = approval.toolCallId;
141758
142247
  const planFilePath = activePlanPath ?? fallbackPlanPath;
141759
- const plansDir = join47(homedir35(), ".letta", "plans");
142248
+ const plansDir = join47(homedir36(), ".letta", "plans");
141760
142249
  handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
141761
142250
  ` + (planFilePath ? `Plan file path: ${planFilePath}
141762
142251
  ` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
@@ -143168,8 +143657,8 @@ import {
143168
143657
  readFileSync as readFileSync22,
143169
143658
  writeFileSync as writeFileSync19
143170
143659
  } from "node:fs";
143171
- import { homedir as homedir36, platform as platform6 } from "node:os";
143172
- import { dirname as dirname18, join as join48 } from "node:path";
143660
+ import { homedir as homedir37, platform as platform6 } from "node:os";
143661
+ import { dirname as dirname19, join as join48 } from "node:path";
143173
143662
  function detectTerminalType2() {
143174
143663
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
143175
143664
  return "cursor";
@@ -143201,7 +143690,7 @@ function getKeybindingsPath2(terminal) {
143201
143690
  }[terminal];
143202
143691
  const os8 = platform6();
143203
143692
  if (os8 === "darwin") {
143204
- return join48(homedir36(), "Library", "Application Support", appName, "User", "keybindings.json");
143693
+ return join48(homedir37(), "Library", "Application Support", appName, "User", "keybindings.json");
143205
143694
  }
143206
143695
  if (os8 === "win32") {
143207
143696
  const appData = process.env.APPDATA;
@@ -143210,7 +143699,7 @@ function getKeybindingsPath2(terminal) {
143210
143699
  return join48(appData, appName, "User", "keybindings.json");
143211
143700
  }
143212
143701
  if (os8 === "linux") {
143213
- return join48(homedir36(), ".config", appName, "User", "keybindings.json");
143702
+ return join48(homedir37(), ".config", appName, "User", "keybindings.json");
143214
143703
  }
143215
143704
  return null;
143216
143705
  }
@@ -143260,7 +143749,7 @@ function installKeybinding2(keybindingsPath) {
143260
143749
  if (keybindingExists2(keybindingsPath)) {
143261
143750
  return { success: true, alreadyExists: true };
143262
143751
  }
143263
- const parentDir = dirname18(keybindingsPath);
143752
+ const parentDir = dirname19(keybindingsPath);
143264
143753
  if (!existsSync38(parentDir)) {
143265
143754
  mkdirSync24(parentDir, { recursive: true });
143266
143755
  }
@@ -143367,10 +143856,10 @@ function getWezTermConfigPath2() {
143367
143856
  if (existsSync38(xdgPath))
143368
143857
  return xdgPath;
143369
143858
  }
143370
- const configPath = join48(homedir36(), ".config", "wezterm", "wezterm.lua");
143859
+ const configPath = join48(homedir37(), ".config", "wezterm", "wezterm.lua");
143371
143860
  if (existsSync38(configPath))
143372
143861
  return configPath;
143373
- return join48(homedir36(), ".wezterm.lua");
143862
+ return join48(homedir37(), ".wezterm.lua");
143374
143863
  }
143375
143864
  function wezTermDeleteFixExists2(configPath) {
143376
143865
  if (!existsSync38(configPath))
@@ -143419,7 +143908,7 @@ return config`);
143419
143908
  ${WEZTERM_DELETE_FIX2}
143420
143909
  `;
143421
143910
  }
143422
- const parentDir = dirname18(configPath);
143911
+ const parentDir = dirname19(configPath);
143423
143912
  if (!existsSync38(parentDir)) {
143424
143913
  mkdirSync24(parentDir, { recursive: true });
143425
143914
  }
@@ -143468,10 +143957,10 @@ __export(exports_settings2, {
143468
143957
  loadProjectSettings: () => loadProjectSettings2,
143469
143958
  getSetting: () => getSetting2
143470
143959
  });
143471
- import { homedir as homedir37 } from "node:os";
143960
+ import { homedir as homedir38 } from "node:os";
143472
143961
  import { join as join49 } from "node:path";
143473
143962
  function getSettingsPath2() {
143474
- return join49(homedir37(), ".letta", "settings.json");
143963
+ return join49(homedir38(), ".letta", "settings.json");
143475
143964
  }
143476
143965
  async function loadSettings2() {
143477
143966
  const settingsPath = getSettingsPath2();
@@ -143993,10 +144482,10 @@ __export(exports_import2, {
143993
144482
  });
143994
144483
  import { createReadStream as createReadStream2 } from "node:fs";
143995
144484
  import { chmod as chmod2, mkdir as mkdir8, readFile as readFile14, writeFile as writeFile9 } from "node:fs/promises";
143996
- import { dirname as dirname19, resolve as resolve32 } from "node:path";
144485
+ import { dirname as dirname20, resolve as resolve31 } from "node:path";
143997
144486
  async function importAgentFromFile2(options) {
143998
144487
  const client = await getClient();
143999
- const resolvedPath = resolve32(options.filePath);
144488
+ const resolvedPath = resolve31(options.filePath);
144000
144489
  const file = createReadStream2(resolvedPath);
144001
144490
  const importResponse = await client.agents.importFile({
144002
144491
  file,
@@ -144031,7 +144520,7 @@ async function extractSkillsFromAf2(afPath, destDir) {
144031
144520
  return [];
144032
144521
  }
144033
144522
  for (const skill2 of afData.skills) {
144034
- const skillDir = resolve32(destDir, skill2.name);
144523
+ const skillDir = resolve31(destDir, skill2.name);
144035
144524
  await mkdir8(skillDir, { recursive: true });
144036
144525
  if (skill2.files) {
144037
144526
  await writeSkillFiles2(skillDir, skill2.files);
@@ -144051,8 +144540,8 @@ async function writeSkillFiles2(skillDir, files) {
144051
144540
  }
144052
144541
  }
144053
144542
  async function writeSkillFile2(skillDir, filePath, content) {
144054
- const fullPath = resolve32(skillDir, filePath);
144055
- await mkdir8(dirname19(fullPath), { recursive: true });
144543
+ const fullPath = resolve31(skillDir, filePath);
144544
+ await mkdir8(dirname20(fullPath), { recursive: true });
144056
144545
  await writeFile9(fullPath, content, "utf-8");
144057
144546
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
144058
144547
  if (isScript) {
@@ -144162,15 +144651,15 @@ __export(exports_memoryFilesystem2, {
144162
144651
  MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
144163
144652
  });
144164
144653
  import { existsSync as existsSync39, mkdirSync as mkdirSync25 } from "node:fs";
144165
- import { homedir as homedir38 } from "node:os";
144654
+ import { homedir as homedir39 } from "node:os";
144166
144655
  import { join as join50 } from "node:path";
144167
- function getMemoryFilesystemRoot2(agentId, homeDir = homedir38()) {
144656
+ function getMemoryFilesystemRoot2(agentId, homeDir = homedir39()) {
144168
144657
  return join50(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
144169
144658
  }
144170
- function getMemorySystemDir2(agentId, homeDir = homedir38()) {
144659
+ function getMemorySystemDir2(agentId, homeDir = homedir39()) {
144171
144660
  return join50(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
144172
144661
  }
144173
- function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir38()) {
144662
+ function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir39()) {
144174
144663
  const root = getMemoryFilesystemRoot2(agentId, homeDir);
144175
144664
  const systemDir = getMemorySystemDir2(agentId, homeDir);
144176
144665
  if (!existsSync39(root)) {
@@ -148816,7 +149305,7 @@ async function runListenSubcommand(argv) {
148816
149305
  await init_memoryGit();
148817
149306
  import { cpSync, existsSync as existsSync22, mkdirSync as mkdirSync15, rmSync as rmSync2, statSync as statSync8 } from "node:fs";
148818
149307
  import { readdir as readdir6 } from "node:fs/promises";
148819
- import { homedir as homedir22 } from "node:os";
149308
+ import { homedir as homedir23 } from "node:os";
148820
149309
  import { join as join28 } from "node:path";
148821
149310
  import { parseArgs as parseArgs7 } from "node:util";
148822
149311
  function printUsage4() {
@@ -148862,10 +149351,10 @@ function parseMemfsArgs(argv) {
148862
149351
  });
148863
149352
  }
148864
149353
  function getMemoryRoot(agentId) {
148865
- return join28(homedir22(), ".letta", "agents", agentId, "memory");
149354
+ return join28(homedir23(), ".letta", "agents", agentId, "memory");
148866
149355
  }
148867
149356
  function getAgentRoot(agentId) {
148868
- return join28(homedir22(), ".letta", "agents", agentId);
149357
+ return join28(homedir23(), ".letta", "agents", agentId);
148869
149358
  }
148870
149359
  function formatBackupTimestamp(date = new Date) {
148871
149360
  const pad = (value) => String(value).padStart(2, "0");
@@ -149414,13 +149903,20 @@ async function runSubcommand(argv) {
149414
149903
  }
149415
149904
 
149416
149905
  // src/permissions/mode.ts
149906
+ init_memoryScope();
149417
149907
  init_readOnlyShell();
149418
149908
  init_shell_command_normalization();
149419
- import { homedir as homedir23 } from "node:os";
149420
- import { isAbsolute as isAbsolute16, join as join29, relative as relative12, resolve as resolve24 } from "node:path";
149909
+ import { homedir as homedir24 } from "node:os";
149910
+ import { isAbsolute as isAbsolute17, join as join29, relative as relative12 } from "node:path";
149421
149911
  var MODE_KEY2 = Symbol.for("@letta/permissionMode");
149422
149912
  var PLAN_FILE_KEY2 = Symbol.for("@letta/planFilePath");
149423
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
+ }
149424
149920
  function getGlobalMode2() {
149425
149921
  const global2 = globalThis;
149426
149922
  if (!global2[MODE_KEY2]) {
@@ -149449,22 +149945,13 @@ function setGlobalModeBeforePlan2(value) {
149449
149945
  global2[MODE_BEFORE_PLAN_KEY2] = value;
149450
149946
  }
149451
149947
  function resolvePlanTargetPath2(targetPath, workingDirectory) {
149452
- const trimmedPath = targetPath.trim();
149453
- if (!trimmedPath)
149454
- return null;
149455
- if (trimmedPath.startsWith("~/")) {
149456
- return resolve24(homedir23(), trimmedPath.slice(2));
149457
- }
149458
- if (isAbsolute16(trimmedPath)) {
149459
- return resolve24(trimmedPath);
149460
- }
149461
- return resolve24(workingDirectory, trimmedPath);
149948
+ return resolveScopedTargetPath(targetPath, workingDirectory);
149462
149949
  }
149463
149950
  function isPathInPlansDir2(path23, plansDir) {
149464
149951
  if (!path23.endsWith(".md"))
149465
149952
  return false;
149466
149953
  const rel = relative12(plansDir, path23);
149467
- return rel !== "" && !rel.startsWith("..") && !isAbsolute16(rel);
149954
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute17(rel);
149468
149955
  }
149469
149956
  function extractApplyPatchPaths2(input) {
149470
149957
  const paths = [];
@@ -149651,7 +150138,7 @@ class PermissionModeManager2 {
149651
150138
  return "allow";
149652
150139
  }
149653
150140
  if (writeTools.includes(toolName)) {
149654
- const plansDir = join29(homedir23(), ".letta", "plans");
150141
+ const plansDir = join29(homedir24(), ".letta", "plans");
149655
150142
  const targetPath = toolArgs?.file_path || toolArgs?.path;
149656
150143
  let candidatePaths = [];
149657
150144
  if ((toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") && toolArgs?.input) {
@@ -149702,7 +150189,7 @@ class PermissionModeManager2 {
149702
150189
  }
149703
150190
  const planWritePath = extractPlanFileWritePathFromShellCommand2(command);
149704
150191
  if (planWritePath) {
149705
- const plansDir = join29(homedir23(), ".letta", "plans");
150192
+ const plansDir = join29(homedir24(), ".letta", "plans");
149706
150193
  const resolvedPath = resolvePlanTargetPath2(planWritePath, workingDirectory);
149707
150194
  if (resolvedPath && isPathInPlansDir2(resolvedPath, plansDir)) {
149708
150195
  return "allow";
@@ -149711,6 +150198,94 @@ class PermissionModeManager2 {
149711
150198
  }
149712
150199
  return "deny";
149713
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
+ }
149714
150289
  case "default":
149715
150290
  return null;
149716
150291
  default:
@@ -149733,8 +150308,8 @@ await __promiseAll([
149733
150308
  init_secrets()
149734
150309
  ]);
149735
150310
  import { randomUUID as randomUUID4 } from "node:crypto";
149736
- import { homedir as homedir24 } from "node:os";
149737
- import { join as join30, resolve as resolve25 } from "node:path";
150311
+ import { homedir as homedir25 } from "node:os";
150312
+ import { join as join30, resolve as resolve24 } from "node:path";
149738
150313
  var DEFAULT_SETTINGS3 = {
149739
150314
  lastAgent: null,
149740
150315
  tokenStreaming: false,
@@ -150120,7 +150695,7 @@ class SettingsManager2 {
150120
150695
  if (!this.settings)
150121
150696
  return;
150122
150697
  const settingsPath = this.getSettingsPath();
150123
- const home = process.env.HOME || homedir24();
150698
+ const home = process.env.HOME || homedir25();
150124
150699
  const dirPath = join30(home, ".letta");
150125
150700
  try {
150126
150701
  if (!exists(dirPath)) {
@@ -150181,14 +150756,14 @@ class SettingsManager2 {
150181
150756
  }
150182
150757
  }
150183
150758
  getSettingsPath() {
150184
- const home = process.env.HOME || homedir24();
150759
+ const home = process.env.HOME || homedir25();
150185
150760
  return join30(home, ".letta", "settings.json");
150186
150761
  }
150187
150762
  getProjectSettingsPath(workingDirectory) {
150188
150763
  return join30(workingDirectory, ".letta", "settings.json");
150189
150764
  }
150190
150765
  isProjectSettingsPathCollidingWithGlobal(workingDirectory) {
150191
- return resolve25(this.getProjectSettingsPath(workingDirectory)) === resolve25(this.getSettingsPath());
150766
+ return resolve24(this.getProjectSettingsPath(workingDirectory)) === resolve24(this.getSettingsPath());
150192
150767
  }
150193
150768
  getLocalProjectSettingsPath(workingDirectory) {
150194
150769
  return join30(workingDirectory, ".letta", "settings.local.json");
@@ -151150,8 +151725,8 @@ function acquireSwitchLock2() {
151150
151725
  const lock = getSwitchLock2();
151151
151726
  lock.refCount++;
151152
151727
  if (lock.refCount === 1) {
151153
- lock.promise = new Promise((resolve26) => {
151154
- lock.resolve = resolve26;
151728
+ lock.promise = new Promise((resolve25) => {
151729
+ lock.resolve = resolve25;
151155
151730
  });
151156
151731
  }
151157
151732
  }
@@ -151636,7 +152211,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
151636
152211
  printHelp();
151637
152212
  const helpDelayMs = Number.parseInt(process.env.LETTA_TEST_HELP_EXIT_DELAY_MS ?? "", 10);
151638
152213
  if (Number.isFinite(helpDelayMs) && helpDelayMs > 0) {
151639
- await new Promise((resolve33) => setTimeout(resolve33, helpDelayMs));
152214
+ await new Promise((resolve32) => setTimeout(resolve32, helpDelayMs));
151640
152215
  }
151641
152216
  process.exit(0);
151642
152217
  }
@@ -151858,9 +152433,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
151858
152433
  process.exit(1);
151859
152434
  }
151860
152435
  } else {
151861
- const { resolve: resolve33 } = await import("path");
152436
+ const { resolve: resolve32 } = await import("path");
151862
152437
  const { existsSync: existsSync40 } = await import("fs");
151863
- const resolvedPath = resolve33(fromAfFile);
152438
+ const resolvedPath = resolve32(fromAfFile);
151864
152439
  if (!existsSync40(resolvedPath)) {
151865
152440
  console.error(`Error: AgentFile not found: ${resolvedPath}`);
151866
152441
  process.exit(1);
@@ -151971,6 +152546,7 @@ Error: ${message}`);
151971
152546
  "default",
151972
152547
  "acceptEdits",
151973
152548
  "plan",
152549
+ "memory",
151974
152550
  "bypassPermissions"
151975
152551
  ];
151976
152552
  if (validModes.includes(mode)) {
@@ -152735,4 +153311,4 @@ Error during initialization: ${message}`);
152735
153311
  }
152736
153312
  main();
152737
153313
 
152738
- //# debugId=AA1793542E1A081B64756E2164756E21
153314
+ //# debugId=1C3BE0588811294864756E2164756E21