@letta-ai/letta-code 0.31.12 → 0.31.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/channels-slack.js +20 -1
  3. package/dist/channels-slack.js.map +3 -3
  4. package/dist/gateway-core.js +2 -1
  5. package/dist/gateway-core.js.map +3 -3
  6. package/dist/mcp-client.js +4 -4
  7. package/dist/mcp-client.js.map +2 -2
  8. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  9. package/dist/types/backend/api/client.d.ts.map +1 -1
  10. package/dist/types/backend/backend.d.ts +1 -0
  11. package/dist/types/backend/backend.d.ts.map +1 -1
  12. package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
  13. package/dist/types/channels/plugin-types.d.ts +1 -1
  14. package/dist/types/channels/plugin-types.d.ts.map +1 -1
  15. package/dist/types/channels/slack/internal-types.d.ts +5 -0
  16. package/dist/types/channels/slack/internal-types.d.ts.map +1 -1
  17. package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
  18. package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
  19. package/dist/types/channels/types.d.ts +1 -0
  20. package/dist/types/channels/types.d.ts.map +1 -1
  21. package/dist/types/cli/helpers/git-context.d.ts +1 -1
  22. package/dist/types/cli/helpers/git-context.d.ts.map +1 -1
  23. package/dist/types/tools/impl/bash.d.ts +2 -0
  24. package/dist/types/tools/impl/bash.d.ts.map +1 -1
  25. package/dist/types/tools/impl/exec-command.d.ts +8 -0
  26. package/dist/types/tools/impl/exec-command.d.ts.map +1 -1
  27. package/dist/types/websocket/listener/cwd-change.d.ts.map +1 -1
  28. package/dist/types/websocket/listener/device-git-context.d.ts +17 -0
  29. package/dist/types/websocket/listener/device-git-context.d.ts.map +1 -0
  30. package/dist/types/websocket/listener/listener-constants.d.ts.map +1 -1
  31. package/dist/types/websocket/listener/protocol-outbound.d.ts +1 -0
  32. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  33. package/dist/types/websocket/listener/stream-observers.d.ts.map +1 -1
  34. package/dist/types/websocket/listener/worktree-watcher.d.ts.map +1 -1
  35. package/letta.js +846 -703
  36. package/package.json +3 -2
  37. package/scripts/codex-watch/release-analysis.test.ts +87 -0
  38. package/scripts/codex-watch/release-analysis.ts +57 -7
  39. package/scripts/postinstall-patches.js +37 -14
  40. package/scripts/source-file-size-baseline.json +2 -2
  41. package/skills/dispatching-coding-agents/SKILL.md +6 -6
  42. package/skills/messaging-agents/SKILL.md +18 -5
  43. package/dist/types/tools/impl/foreground-sleep.d.ts +0 -13
  44. package/dist/types/tools/impl/foreground-sleep.d.ts.map +0 -1
package/letta.js CHANGED
@@ -5400,10 +5400,10 @@ var package_default;
5400
5400
  var init_package = __esm(() => {
5401
5401
  package_default = {
5402
5402
  name: "@letta-ai/letta-code",
5403
- version: "0.31.12",
5403
+ version: "0.31.13",
5404
5404
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5405
5405
  type: "module",
5406
- packageManager: "bun@1.3.10",
5406
+ packageManager: "bun@1.3.14",
5407
5407
  bin: {
5408
5408
  letta: "letta.js"
5409
5409
  },
@@ -5522,6 +5522,7 @@ var init_package = __esm(() => {
5522
5522
  },
5523
5523
  license: "Apache-2.0",
5524
5524
  engines: {
5525
+ bun: ">=1.3.2",
5525
5526
  node: ">=22.19.0"
5526
5527
  },
5527
5528
  publishConfig: {
@@ -6670,14 +6671,6 @@ function consumeLastSDKDiagnostic() {
6670
6671
  function clearLastSDKDiagnostic() {
6671
6672
  lastSDKDiagnostic = null;
6672
6673
  }
6673
- function getNodeRoutingHeader() {
6674
- const raw = process.env.LETTA_NODE;
6675
- if (raw === undefined || raw.trim() === "") {
6676
- return {};
6677
- }
6678
- const enabled = NODE_HEADER_ENABLED_VALUES.has(raw.trim().toLowerCase());
6679
- return { "x-letta-node": enabled ? "1" : "0" };
6680
- }
6681
6674
  function getRuntimeEnvironmentDeviceId() {
6682
6675
  return process.env[RUNTIME_ENVIRONMENT_DEVICE_ID_ENV]?.trim() || settingsManager.getOrCreateDeviceId();
6683
6676
  }
@@ -6686,7 +6679,6 @@ function getClientDefaultHeaders() {
6686
6679
  "X-Letta-Source": "letta-code",
6687
6680
  "User-Agent": `letta-code/${package_default.version}`,
6688
6681
  "X-Letta-Environment-Device-Id": getRuntimeEnvironmentDeviceId(),
6689
- ...getNodeRoutingHeader(),
6690
6682
  ...process.env.LETTA_MEMFS_BACKEND === "hosted" ? { "x-letta-memfs-backend": "hosted" } : {}
6691
6683
  };
6692
6684
  }
@@ -6779,7 +6771,7 @@ If you experience this issue multiple times, move ~/.letta to ~/.letta_backup, a
6779
6771
  };
6780
6772
  return client;
6781
6773
  }
6782
- var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnostic = null, _cachedApiKey, _testClientOverride = null, sdkLogger, NODE_HEADER_ENABLED_VALUES, RUNTIME_ENVIRONMENT_DEVICE_ID_ENV = "LETTA_RUNTIME_ENVIRONMENT_DEVICE_ID";
6774
+ var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnostic = null, _cachedApiKey, _testClientOverride = null, sdkLogger, RUNTIME_ENVIRONMENT_DEVICE_ID_ENV = "LETTA_RUNTIME_ENVIRONMENT_DEVICE_ID";
6783
6775
  var init_client2 = __esm(() => {
6784
6776
  init_letta_client();
6785
6777
  init_oauth();
@@ -6809,7 +6801,6 @@ var init_client2 = __esm(() => {
6809
6801
  console.debug(...args);
6810
6802
  }
6811
6803
  };
6812
- NODE_HEADER_ENABLED_VALUES = new Set(["1", "true", "yes"]);
6813
6804
  });
6814
6805
 
6815
6806
  // src/utils/text-files.ts
@@ -88360,8 +88351,9 @@ Usage notes:
88360
88351
  - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 120000ms (2 minutes).
88361
88352
  - Write a clear, concise user-facing description of what this command does. This description may be shown directly in chat as part of a status row like \`Running command: <description>\` or \`Ran command: <description>\`. Describe the command's purpose, not its shell syntax. For simple commands, keep it brief (5-10 words). For complex commands (piped commands, obscure flags, or anything hard to understand at a glance), add enough context to clarify what it does.
88362
88353
  - If the output exceeds 30000 characters, output will be truncated before being returned to you.
88363
- - You can use the \`run_in_background\` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes. You do not need to use '&' at the end of the command when using this parameter.
88364
- - Pick between \`run_in_background\` and the Monitor tool by how many notifications you need. **One** ("tell me when the server is ready / the build finishes") → Bash with \`run_in_background\` and a command that exits when the condition is true, e.g. \`until grep -q "Ready in" dev.log; do sleep 0.5; done\`. You get a single completion notification when it exits. **One per occurrence** ("tell me every time an ERROR line appears") → use Monitor: each stdout line is an event — you keep working and notifications arrive in the chat. Foreground \`sleep\` is blocked; background the wait (\`run_in_background\` or Monitor) instead of polling BashOutput, and keep working.
88354
+ - Ordinary commands wait briefly for a result, then automatically continue in the background if they are still running. You will receive a task ID and one completion notification, so do not predict command duration, set \`run_in_background\` merely because a command may be slow, or poll for completion.
88355
+ - Set \`run_in_background\` only when you want the command to return a task ID immediately. You do not need to use '&' at the end of the command.
88356
+ - Pick between Bash and the Monitor tool by how many notifications you need. **One** ("tell me when the server is ready / the build finishes") → Bash with a command that exits when the condition is true, e.g. \`until grep -q "Ready in" dev.log; do sleep 0.5; done\`. Bash automatically yields and sends one completion notification. **One per occurrence** ("tell me every time an ERROR line appears") → use Monitor: each stdout line is an event while you keep working.
88365
88357
 
88366
88358
  - Avoid using Bash with the \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:
88367
88359
  - File search: Use Glob (NOT find or ls)
@@ -88487,61 +88479,7 @@ var EnterWorktree_default = "# EnterWorktree\n\nCreate a fresh isolated git work
88487
88479
  var init_EnterWorktree = () => {};
88488
88480
 
88489
88481
  // src/tools/descriptions/ExecCommand.md
88490
- var ExecCommand_default = `Runs a command in a PTY, returning output or a session ID for ongoing interaction.
88491
-
88492
- For ordinary one-shot commands, omit \`yield_time_ms\` and let the default wait for completion; set \`yield_time_ms\` only when intentionally returning early from a long-running or interactive command.
88493
-
88494
- Provide the required \`description\` field as a clear, concise user-facing status label for what the command does. It may be shown directly in chat with no prefix, so make it grammatical by itself and avoid tense-dependent wording. Use an imperative or purpose phrase like \`Find debug log entries\` or \`Search recent logs for errors\`. Describe the command's purpose, not its shell syntax. Keep it brief for simple commands; add only enough context to clarify commands that are hard to parse at a glance.
88495
-
88496
- # Committing changes with git
88497
-
88498
- Only create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:
88499
-
88500
- Git Safety Protocol:
88501
- - NEVER update the git config
88502
- - NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them
88503
- - NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
88504
- - NEVER run force push to main/master, warn the user if they request it
88505
- - CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen -- so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit
88506
- - When staging files, prefer adding specific files by name rather than using "git add -A" or "git add .", which can accidentally include sensitive files (.env, credentials) or large binaries
88507
- - NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive.
88508
-
88509
- 1. Run the following shell commands in parallel:
88510
- - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.
88511
- - Run a git diff command to see both staged and unstaged changes that will be committed.
88512
- - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.
88513
- 2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:
88514
- - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. "add" means a wholly new feature, "update" means an enhancement to an existing feature, "fix" means a bug fix, etc.).
88515
- - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files
88516
- - Draft a concise (1-2 sentences) commit message that focuses on the "why" rather than the "what"
88517
- - Ensure it accurately reflects the changes and their purpose
88518
- 3. Run the following commands:
88519
- - Add relevant untracked files to the staging area.
88520
- - Create the commit with a message ending with:
88521
- 👾 Generated with [Letta Code](https://letta.com)
88522
-
88523
- Co-Authored-By: Letta Code <noreply@letta.com>
88524
- - Run git status after the commit completes to verify success.
88525
- Note: git status depends on the commit completing, so run it sequentially after the commit.
88526
- 4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit
88527
-
88528
- Important notes:
88529
- - NEVER run additional commands to read or explore code, besides git commands
88530
- - DO NOT push to the remote repository unless the user explicitly asks you to do so
88531
- - IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.
88532
- - IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.
88533
- - If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit
88534
- - In order to ensure good formatting, ALWAYS pass the commit message as a single-quoted string with embedded newlines, a la this example:
88535
- <example>
88536
- git commit -m 'Commit message here.
88537
-
88538
- 👾 Generated with [Letta Code](https://letta.com)
88539
-
88540
- Co-Authored-By: Letta Code <noreply@letta.com>'
88541
- </example>
88542
-
88543
- Use single quotes (not double quotes) and do NOT wrap the message in \`$(...)\` or backticks — single-quoting preserves the message verbatim (including \`$VAR\`, backticks, and other special characters) without needing escapes.
88544
- `;
88482
+ var ExecCommand_default = "Runs a command in a PTY, returning output or a session ID for ongoing interaction.\n\nFor ordinary one-shot commands, omit `yield_time_ms` and let the default wait for completion; set `yield_time_ms` only when intentionally returning early from a long-running or interactive command.\n\nIf a command is still running when this tool yields, you will receive a notification when it completes. Do not poll the session just to check whether it has finished. Use `write_stdin` only when you need to send input, interrupt the process, or obtain output before you can continue.\n\nProvide the required `description` field as a clear, concise user-facing status label for what the command does. It may be shown directly in chat with no prefix, so make it grammatical by itself and avoid tense-dependent wording. Use an imperative or purpose phrase like `Find debug log entries` or `Search recent logs for errors`. Describe the command's purpose, not its shell syntax. Keep it brief for simple commands; add only enough context to clarify commands that are hard to parse at a glance.\n\n# Committing changes with git\n\nOnly create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:\n\nGit Safety Protocol:\n- NEVER update the git config\n- NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them \n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it\n- NEVER run force push to main/master, warn the user if they request it\n- CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen -- so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit\n- When staging files, prefer adding specific files by name rather than using \"git add -A\" or \"git add .\", which can accidentally include sensitive files (.env, credentials) or large binaries\n- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive.\n\n1. Run the following shell commands in parallel:\n - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.\n - Run a git diff command to see both staged and unstaged changes that will be committed.\n - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.\n2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:\n - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. \"add\" means a wholly new feature, \"update\" means an enhancement to an existing feature, \"fix\" means a bug fix, etc.).\n - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files\n - Draft a concise (1-2 sentences) commit message that focuses on the \"why\" rather than the \"what\"\n - Ensure it accurately reflects the changes and their purpose\n3. Run the following commands:\n - Add relevant untracked files to the staging area.\n - Create the commit with a message ending with:\n 👾 Generated with [Letta Code](https://letta.com)\n\n Co-Authored-By: Letta Code <noreply@letta.com>\n - Run git status after the commit completes to verify success.\n Note: git status depends on the commit completing, so run it sequentially after the commit.\n4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit\n\nImportant notes:\n- NEVER run additional commands to read or explore code, besides git commands\n- DO NOT push to the remote repository unless the user explicitly asks you to do so\n- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.\n- IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.\n- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit\n- In order to ensure good formatting, ALWAYS pass the commit message as a single-quoted string with embedded newlines, a la this example:\n<example>\ngit commit -m 'Commit message here.\n\n👾 Generated with [Letta Code](https://letta.com)\n\nCo-Authored-By: Letta Code <noreply@letta.com>'\n</example>\n\nUse single quotes (not double quotes) and do NOT wrap the message in `$(...)` or backticks — single-quoting preserves the message verbatim (including `$VAR`, backticks, and other special characters) without needing escapes.\n";
88545
88483
  var init_ExecCommand = () => {};
88546
88484
 
88547
88485
  // src/tools/descriptions/ExitWorktree.md
@@ -89615,8 +89553,7 @@ The user has the ability to modify \`content\`. If modified, this will be stated
89615
89553
  var init_WriteFileGemini = () => {};
89616
89554
 
89617
89555
  // src/tools/descriptions/WriteStdin.md
89618
- var WriteStdin_default = `Writes characters to an existing unified exec session and returns recent output.
89619
- `;
89556
+ var WriteStdin_default = "Writes characters to an existing unified exec session and returns recent output.\n\nUse this tool to send input, interrupt a process, or inspect new output from a long-lived interactive process such as a dev server or REPL. Do not call it with empty `chars` merely to wait for completion; `exec_command` sends a notification when a yielded process completes. If the process needs a completion deadline, create a one-shot scheduled check instead of blocking or polling.\n";
89620
89557
  var init_WriteStdin = () => {};
89621
89558
 
89622
89559
  // src/tools/descriptions/WriteTodosGemini.md
@@ -92790,53 +92727,6 @@ var init_worktree_ownership = __esm(() => {
92790
92727
  ]);
92791
92728
  });
92792
92729
 
92793
- // src/tools/impl/foreground-sleep.ts
92794
- function commandRunsForegroundSleep(command) {
92795
- const segments = splitShellSegmentsAllowCommandSubstitution(command) ?? splitShellSegments(command);
92796
- if (!segments) {
92797
- return false;
92798
- }
92799
- for (const segment of segments) {
92800
- for (const word of tokenizeShellWords(segment)) {
92801
- if (SHELL_KEYWORDS.has(word)) {
92802
- continue;
92803
- }
92804
- if (ASSIGNMENT_PREFIX.test(word)) {
92805
- continue;
92806
- }
92807
- if (word.split("/").pop() === "sleep") {
92808
- return true;
92809
- }
92810
- break;
92811
- }
92812
- }
92813
- return false;
92814
- }
92815
- var FOREGROUND_SLEEP_BLOCKED_MESSAGE = 'Foreground `sleep` is blocked — it stalls the session while nothing happens. Run the wait in the background and keep working: use Bash with `run_in_background` and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits. For one notification per occurrence ("tell me every time an ERROR line appears"), use the Monitor tool instead. `sleep` inside `run_in_background` commands and Monitor scripts is fine.', SHELL_KEYWORDS, ASSIGNMENT_PREFIX;
92816
- var init_foreground_sleep = __esm(() => {
92817
- SHELL_KEYWORDS = new Set([
92818
- "if",
92819
- "then",
92820
- "elif",
92821
- "else",
92822
- "fi",
92823
- "while",
92824
- "until",
92825
- "do",
92826
- "done",
92827
- "for",
92828
- "case",
92829
- "esac",
92830
- "{",
92831
- "}",
92832
- "(",
92833
- ")",
92834
- "!",
92835
- "time"
92836
- ]);
92837
- ASSIGNMENT_PREFIX = /^[A-Za-z_][A-Za-z0-9_]*=/;
92838
- });
92839
-
92840
92730
  // src/tools/impl/process_manager.ts
92841
92731
  var exports_process_manager = {};
92842
92732
  __export(exports_process_manager, {
@@ -95651,6 +95541,7 @@ __export(exports_bash, {
95651
95541
  getBackgroundLauncher: () => getBackgroundLauncher,
95652
95542
  bash: () => bash
95653
95543
  });
95544
+ import { rmSync as rmSync4 } from "node:fs";
95654
95545
  function rebuildCachedLauncher(command, secretEnv) {
95655
95546
  if (!cachedWorkingLauncher)
95656
95547
  return null;
@@ -95799,7 +95690,8 @@ async function bash(args) {
95799
95690
  signal,
95800
95691
  onOutput,
95801
95692
  secretEnv,
95802
- parentScope
95693
+ parentScope,
95694
+ foregroundYieldMs = DEFAULT_FOREGROUND_YIELD_MS
95803
95695
  } = args;
95804
95696
  const userCwd = getCurrentWorkingDirectory();
95805
95697
  const sanitizeOutput = (text) => scrubSecretsFromString(text, secretEnv ?? {});
@@ -95825,194 +95717,184 @@ async function bash(args) {
95825
95717
  const recoveredFrom = consumeWorkingDirectoryRecovery();
95826
95718
  const recoveryNote = recoveredFrom ? `Note: working directory ${recoveredFrom} no longer exists; running in ${userCwd} instead.
95827
95719
  ` : "";
95828
- if (run_in_background) {
95829
- try {
95830
- assertBackgroundProcessCapacity();
95831
- } catch (error4) {
95832
- return {
95833
- content: [
95834
- {
95835
- type: "text",
95836
- text: error4 instanceof Error ? error4.message : String(error4)
95837
- }
95838
- ],
95839
- status: "error"
95840
- };
95841
- }
95842
- const bgEnv = secretEnv ? { ...getShellEnv(), ...secretEnv } : getShellEnv();
95843
- const bgCommand = withStrictShellPrelude(command, bgEnv);
95844
- const bashId = getNextBashId();
95845
- const outputFile = createBackgroundOutputFile(bashId);
95846
- const launcher = getBackgroundLauncher(bgCommand, bgEnv, secretEnv);
95847
- const [executable] = launcher;
95848
- if (!executable) {
95849
- return {
95850
- content: [{ type: "text", text: "No shell available" }],
95851
- status: "error"
95852
- };
95853
- }
95854
- noteExpectedWorktreeForLauncher(launcher, userCwd);
95855
- const sandboxed = applyShellSandbox(launcher, userCwd, bgEnv);
95856
- let bgProcess;
95857
- let outputWriteFailed = false;
95858
- const runningProcess = startShellProcess(sandboxed.launcher, {
95859
- cwd: userCwd,
95860
- env: sandboxed.env,
95861
- timeoutMs: timeout > 0 ? timeout : 0,
95862
- sourceCommand: command,
95863
- captureOutput: false,
95864
- onOutput(text, stream10) {
95865
- const sanitizedText = sanitizeOutput(text);
95866
- appendBackgroundProcessOutput(bgProcess, stream10, sanitizedText);
95867
- const wrote = appendToOutputFile(outputFile, stream10 === "stderr" ? `[stderr] ${sanitizedText}` : sanitizedText);
95868
- if (!wrote && bgProcess.status === "running") {
95869
- outputWriteFailed = true;
95870
- appendBackgroundProcessOutput(bgProcess, "stderr", "[output file write failed; output may be incomplete]");
95871
- bgProcess.status = "failed";
95872
- try {
95873
- runningProcess.process.kill("SIGTERM");
95874
- } catch {}
95720
+ try {
95721
+ assertBackgroundProcessCapacity();
95722
+ } catch (error4) {
95723
+ return {
95724
+ content: [
95725
+ {
95726
+ type: "text",
95727
+ text: error4 instanceof Error ? error4.message : String(error4)
95875
95728
  }
95876
- }
95877
- });
95878
- bgProcess = {
95879
- process: runningProcess.process,
95880
- command,
95881
- stdout: [],
95882
- stderr: [],
95883
- status: "running",
95884
- exitCode: null,
95885
- lastReadIndex: { stdout: 0, stderr: 0 },
95886
- startTime: new Date,
95887
- outputFile,
95888
- totalStdoutLines: 0,
95889
- totalStderrLines: 0,
95890
- runtimeScope: parentScope,
95891
- secrets: secretEnv
95729
+ ],
95730
+ status: "error"
95892
95731
  };
95893
- backgroundProcesses.set(bashId, bgProcess);
95894
- const notificationScope = resolveNotificationScope(parentScope);
95895
- runningProcess.completion.then(({ exitCode }) => {
95896
- bgProcess.status = exitCode === 0 && !outputWriteFailed ? "completed" : "failed";
95897
- bgProcess.exitCode = exitCode;
95898
- appendToOutputFile(outputFile, `
95732
+ }
95733
+ const bgEnv = secretEnv ? { ...getShellEnv(), ...secretEnv } : getShellEnv();
95734
+ const bgCommand = withStrictShellPrelude(command, bgEnv);
95735
+ const bashId = getNextBashId();
95736
+ const outputFile = createBackgroundOutputFile(bashId);
95737
+ const launcher = getBackgroundLauncher(bgCommand, bgEnv, secretEnv);
95738
+ const [executable] = launcher;
95739
+ if (!executable) {
95740
+ return {
95741
+ content: [{ type: "text", text: "No shell available" }],
95742
+ status: "error"
95743
+ };
95744
+ }
95745
+ noteExpectedWorktreeForLauncher(launcher, userCwd);
95746
+ const sandboxed = applyShellSandbox(launcher, userCwd, bgEnv);
95747
+ let bgProcess;
95748
+ let outputWriteFailed = false;
95749
+ const foregroundOutput = { stdout: "", stderr: "" };
95750
+ const effectiveTimeout = run_in_background ? timeout > 0 ? timeout : 0 : Math.min(Math.max(timeout, 1), 600000);
95751
+ const runningProcess = startShellProcess(sandboxed.launcher, {
95752
+ cwd: userCwd,
95753
+ env: sandboxed.env,
95754
+ timeoutMs: effectiveTimeout,
95755
+ sourceCommand: command,
95756
+ signal: run_in_background ? undefined : signal,
95757
+ captureOutput: false,
95758
+ onOutput(text, stream10) {
95759
+ const sanitizedText = sanitizeOutput(text);
95760
+ if (!run_in_background) {
95761
+ foregroundOutput[stream10] += text;
95762
+ onOutput?.(text, stream10);
95763
+ }
95764
+ appendBackgroundProcessOutput(bgProcess, stream10, sanitizedText);
95765
+ const wrote = appendToOutputFile(outputFile, stream10 === "stderr" ? `[stderr] ${sanitizedText}` : sanitizedText);
95766
+ if (!wrote && bgProcess.status === "running") {
95767
+ outputWriteFailed = true;
95768
+ appendBackgroundProcessOutput(bgProcess, "stderr", "[output file write failed; output may be incomplete]");
95769
+ bgProcess.status = "failed";
95770
+ try {
95771
+ runningProcess.process.kill("SIGTERM");
95772
+ } catch {}
95773
+ }
95774
+ }
95775
+ });
95776
+ bgProcess = {
95777
+ process: runningProcess.process,
95778
+ command,
95779
+ stdout: [],
95780
+ stderr: [],
95781
+ status: "running",
95782
+ exitCode: null,
95783
+ lastReadIndex: { stdout: 0, stderr: 0 },
95784
+ startTime: new Date,
95785
+ outputFile,
95786
+ totalStdoutLines: 0,
95787
+ totalStderrLines: 0,
95788
+ runtimeScope: parentScope,
95789
+ secrets: secretEnv
95790
+ };
95791
+ backgroundProcesses.set(bashId, bgProcess);
95792
+ const notificationScope = resolveNotificationScope(parentScope);
95793
+ const settled = runningProcess.completion.then(({ exitCode }) => {
95794
+ bgProcess.status = exitCode === 0 && !outputWriteFailed ? "completed" : "failed";
95795
+ bgProcess.exitCode = exitCode;
95796
+ appendToOutputFile(outputFile, `
95899
95797
  [exit code: ${exitCode}]
95900
95798
  `);
95901
- scrubCompletedBackgroundOutput(bgProcess);
95902
- notifyBackgroundCompletion({
95903
- bashId,
95904
- description,
95905
- outputFile,
95906
- bgProcess,
95907
- scope: notificationScope,
95908
- status: exitCode === 0 && !outputWriteFailed ? "completed" : "failed",
95909
- detail: outputWriteFailed ? "Output file write failed; output may be incomplete" : exitCode === null ? "Terminated by signal before exiting" : `Exit code: ${exitCode}`
95910
- });
95911
- scheduleBackgroundProcessCleanup(bashId);
95912
- }, (error4) => {
95913
- const err = error4;
95914
- const message = sanitizeOutput(err.killed ? `Command timed out after ${timeout}ms` : err.message);
95915
- bgProcess.status = "failed";
95916
- appendBackgroundProcessOutput(bgProcess, "stderr", message);
95917
- appendToOutputFile(outputFile, err.killed ? `
95799
+ scrubCompletedBackgroundOutput(bgProcess);
95800
+ return {
95801
+ status: exitCode === 0 && !outputWriteFailed ? "completed" : "failed",
95802
+ detail: outputWriteFailed ? "Output file write failed; output may be incomplete" : exitCode === null ? "Terminated by signal before exiting" : `Exit code: ${exitCode}`,
95803
+ exitCode
95804
+ };
95805
+ }, (error4) => {
95806
+ const err = error4;
95807
+ const message = sanitizeOutput(err.killed ? `Command timed out after ${timeout}ms` : err.message);
95808
+ bgProcess.status = "failed";
95809
+ appendBackgroundProcessOutput(bgProcess, "stderr", message);
95810
+ appendToOutputFile(outputFile, err.killed ? `
95918
95811
  [timeout after ${timeout}ms]
95919
95812
  ` : `
95920
95813
  [error] ${message}
95921
95814
  `);
95922
- scrubCompletedBackgroundOutput(bgProcess);
95815
+ scrubCompletedBackgroundOutput(bgProcess);
95816
+ return {
95817
+ status: "failed",
95818
+ detail: err.killed ? message : `Error: ${message}`,
95819
+ error: err
95820
+ };
95821
+ });
95822
+ const notifyWhenSettled = () => {
95823
+ settled.then(({ status, detail }) => {
95923
95824
  notifyBackgroundCompletion({
95924
95825
  bashId,
95925
95826
  description,
95926
95827
  outputFile,
95927
95828
  bgProcess,
95928
95829
  scope: notificationScope,
95929
- status: "failed",
95930
- detail: err.killed ? message : `Error: ${message}`
95830
+ status,
95831
+ detail
95931
95832
  });
95932
95833
  scheduleBackgroundProcessCleanup(bashId);
95933
95834
  });
95934
- return {
95935
- content: [
95936
- {
95937
- type: "text",
95938
- text: `${recoveryNote}Command running in background with ID: ${bashId}
95939
- Output file: ${outputFile}`
95835
+ };
95836
+ if (!run_in_background) {
95837
+ const outcome = await Promise.race([
95838
+ settled.then((result) => ({ type: "settled", result })),
95839
+ new Promise((resolve11) => {
95840
+ const timer = setTimeout(() => resolve11({ type: "yield" }), Math.max(0, foregroundYieldMs));
95841
+ if (typeof timer === "object" && timer !== null && "unref" in timer) {
95842
+ timer.unref();
95940
95843
  }
95941
- ],
95942
- status: "success"
95943
- };
95944
- }
95945
- if (commandRunsForegroundSleep(command)) {
95946
- return {
95947
- content: [{ type: "text", text: FOREGROUND_SLEEP_BLOCKED_MESSAGE }],
95948
- status: "error"
95949
- };
95950
- }
95951
- const effectiveTimeout = Math.min(Math.max(timeout, 1), 600000);
95952
- try {
95953
- const { stdout, stderr, exitCode } = await spawnCommand(command, {
95954
- cwd: userCwd,
95955
- env: getShellEnv(),
95956
- timeout: effectiveTimeout,
95957
- signal,
95958
- onOutput,
95959
- secretEnv
95960
- });
95961
- let output = stdout;
95962
- if (stderr)
95963
- output = output ? `${output}
95964
- ${stderr}` : stderr;
95965
- const { content: truncatedOutput } = truncateByChars(output || "(Command completed with no output)", LIMITS.BASH_OUTPUT_CHARS, "Bash", { workingDirectory: userCwd, toolName: "Bash", secrets: secretEnv });
95966
- if (exitCode !== 0 && exitCode !== null) {
95967
- return {
95968
- content: [
95969
- {
95970
- type: "text",
95971
- text: `${recoveryNote}Exit code: ${exitCode}
95844
+ })
95845
+ ]);
95846
+ if (outcome.type === "settled") {
95847
+ backgroundProcesses.delete(bashId);
95848
+ rmSync4(outputFile, { force: true });
95849
+ const { result } = outcome;
95850
+ const output = [foregroundOutput.stdout, foregroundOutput.stderr].filter(Boolean).join(`
95851
+ `);
95852
+ const { content: truncatedOutput } = truncateByChars(output || "(Command completed with no output)", LIMITS.BASH_OUTPUT_CHARS, "Bash", { workingDirectory: userCwd, toolName: "Bash", secrets: secretEnv });
95853
+ if (result.status === "failed") {
95854
+ const isAbort = signal?.aborted || "error" in result && (result.error.name === "AbortError" || result.error.code === "ABORT_ERR");
95855
+ return {
95856
+ content: [
95857
+ {
95858
+ type: "text",
95859
+ text: isAbort ? INTERRUPTED_BY_USER : `${recoveryNote}${result.detail}
95972
95860
  ${truncatedOutput}`
95973
- }
95974
- ],
95975
- status: "error"
95861
+ }
95862
+ ],
95863
+ status: "error"
95864
+ };
95865
+ }
95866
+ return {
95867
+ content: [{ type: "text", text: `${recoveryNote}${truncatedOutput}` }],
95868
+ status: "success"
95976
95869
  };
95977
95870
  }
95978
- return {
95979
- content: [{ type: "text", text: `${recoveryNote}${truncatedOutput}` }],
95980
- status: "success"
95981
- };
95982
- } catch (error4) {
95983
- const err = error4;
95984
- const isAbort = signal?.aborted || err.code === "ABORT_ERR" || err.name === "AbortError" || err.message === "The operation was aborted";
95985
- let errorMessage = "";
95986
- if (isAbort) {
95987
- errorMessage = INTERRUPTED_BY_USER;
95988
- } else {
95989
- if (err.killed && err.signal === "SIGTERM")
95990
- errorMessage = `Command timed out after ${effectiveTimeout}ms
95991
- `;
95992
- if (err.code && typeof err.code === "number")
95993
- errorMessage += `Exit code: ${err.code}
95994
- `;
95995
- if (err.stderr)
95996
- errorMessage += err.stderr;
95997
- else if (err.message)
95998
- errorMessage += err.message;
95999
- if (err.stdout)
96000
- errorMessage = `${err.stdout}
96001
- ${errorMessage}`;
96002
- }
96003
- const { content: truncatedError } = truncateByChars(errorMessage.trim() || "Command failed with unknown error", LIMITS.BASH_OUTPUT_CHARS, "Bash", { workingDirectory: userCwd, toolName: "Bash", secrets: secretEnv });
95871
+ backgroundProcesses.set(bashId, bgProcess);
95872
+ notifyWhenSettled();
96004
95873
  return {
96005
95874
  content: [
96006
95875
  {
96007
95876
  type: "text",
96008
- text: isAbort ? truncatedError : `${recoveryNote}${truncatedError}`
95877
+ text: `${recoveryNote}Command is still running with task ID: ${bashId}
95878
+ Output file: ${outputFile}
95879
+ You will be notified when it completes. Do not poll unless you need intermediate output.`
96009
95880
  }
96010
95881
  ],
96011
- status: "error"
95882
+ status: "success"
96012
95883
  };
96013
95884
  }
95885
+ notifyWhenSettled();
95886
+ return {
95887
+ content: [
95888
+ {
95889
+ type: "text",
95890
+ text: `${recoveryNote}Command running in background with ID: ${bashId}
95891
+ Output file: ${outputFile}`
95892
+ }
95893
+ ],
95894
+ status: "success"
95895
+ };
96014
95896
  }
96015
- var cachedWorkingLauncher = null, NOTIFICATION_TAIL_LINES = 50;
95897
+ var cachedWorkingLauncher = null, DEFAULT_FOREGROUND_YIELD_MS = 1e4, NOTIFICATION_TAIL_LINES = 50;
96016
95898
  var init_bash = __esm(() => {
96017
95899
  init_constants2();
96018
95900
  init_runtime_context();
@@ -96020,7 +95902,6 @@ var init_bash = __esm(() => {
96020
95902
  init_message_queue_bridge();
96021
95903
  init_task_notifications();
96022
95904
  init_worktree_ownership();
96023
- init_foreground_sleep();
96024
95905
  init_process_manager();
96025
95906
  init_shell_env();
96026
95907
  init_shell_launchers();
@@ -96883,98 +96764,6 @@ var init_connection = __esm(() => {
96883
96764
  resumeStateByRuntime = new WeakMap;
96884
96765
  });
96885
96766
 
96886
- // src/cli/helpers/git-context.ts
96887
- import { execFileSync } from "node:child_process";
96888
- function runGit(args, cwd) {
96889
- try {
96890
- return execFileSync("git", args, {
96891
- cwd,
96892
- encoding: "utf-8",
96893
- stdio: ["ignore", "pipe", "ignore"],
96894
- windowsHide: true
96895
- }).trim();
96896
- } catch {
96897
- return null;
96898
- }
96899
- }
96900
- function truncateLines(value, maxLines) {
96901
- const lines = value.split(`
96902
- `);
96903
- if (lines.length <= maxLines) {
96904
- return value;
96905
- }
96906
- return lines.slice(0, maxLines).join(`
96907
- `) + `
96908
- ... and ${lines.length - maxLines} more changes`;
96909
- }
96910
- function formatGitUser(name, email) {
96911
- if (!name && !email) {
96912
- return null;
96913
- }
96914
- if (name && email) {
96915
- return `${name} <${email}>`;
96916
- }
96917
- return name || email;
96918
- }
96919
- function gatherGitContextSnapshot(options = {}) {
96920
- const cwd = options.cwd ?? process.cwd();
96921
- const recentCommitLimit = options.recentCommitLimit ?? 3;
96922
- if (!runGit(["rev-parse", "--git-dir"], cwd)) {
96923
- return {
96924
- isGitRepo: false,
96925
- branch: null,
96926
- status: null,
96927
- recentCommits: null,
96928
- gitUser: null
96929
- };
96930
- }
96931
- const branch = runGit(["branch", "--show-current"], cwd);
96932
- const fullStatus = runGit(["status", "--short"], cwd);
96933
- const status = typeof fullStatus === "string" && options.statusLineLimit ? truncateLines(fullStatus, options.statusLineLimit) : fullStatus;
96934
- const recentCommits = options.recentCommitFormat ? runGit([
96935
- "log",
96936
- `--format=${options.recentCommitFormat}`,
96937
- "-n",
96938
- String(recentCommitLimit)
96939
- ], cwd) : runGit(["log", "--oneline", "-n", String(recentCommitLimit)], cwd);
96940
- const userConfig = runGit(["config", "--get-regexp", "^user\\.(name|email)$"], cwd);
96941
- let userName = null;
96942
- let userEmail = null;
96943
- if (userConfig) {
96944
- for (const line of userConfig.split(`
96945
- `)) {
96946
- if (line.startsWith("user.name "))
96947
- userName = line.slice("user.name ".length);
96948
- else if (line.startsWith("user.email "))
96949
- userEmail = line.slice("user.email ".length);
96950
- }
96951
- }
96952
- const gitUser = formatGitUser(userName, userEmail);
96953
- return {
96954
- isGitRepo: true,
96955
- branch,
96956
- status,
96957
- recentCommits,
96958
- gitUser
96959
- };
96960
- }
96961
- function getGitContext(cwd) {
96962
- if (!runGit(["rev-parse", "--git-dir"], cwd)) {
96963
- return null;
96964
- }
96965
- const branch = runGit(["branch", "--show-current"], cwd);
96966
- const branchList = runGit([
96967
- "branch",
96968
- "--sort=-committerdate",
96969
- "--format=%(refname:short)",
96970
- "--no-color"
96971
- ], cwd);
96972
- const recentBranches = branchList ? branchList.split(`
96973
- `).map((b) => b.trim()).filter((b) => b.length > 0 && b !== branch).slice(0, 10) : [];
96974
- return { branch, recent_branches: recentBranches };
96975
- }
96976
- var init_git_context = () => {};
96977
-
96978
96767
  // src/cli/helpers/memory-reminder.ts
96979
96768
  function isValidStepCount(value) {
96980
96769
  return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0;
@@ -97415,6 +97204,169 @@ var init_constants3 = __esm(() => {
97415
97204
  SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
97416
97205
  });
97417
97206
 
97207
+ // src/cli/helpers/git-context.ts
97208
+ import { execFile as execFile2, execFileSync } from "node:child_process";
97209
+ import { promisify as promisify3 } from "node:util";
97210
+ function runGit(args, cwd) {
97211
+ try {
97212
+ return execFileSync("git", args, {
97213
+ cwd,
97214
+ encoding: "utf-8",
97215
+ stdio: ["ignore", "pipe", "ignore"],
97216
+ windowsHide: true
97217
+ }).trim();
97218
+ } catch {
97219
+ return null;
97220
+ }
97221
+ }
97222
+ async function runGitAsync(args, cwd) {
97223
+ try {
97224
+ const { stdout } = await execFileAsync("git", args, {
97225
+ cwd,
97226
+ encoding: "utf-8",
97227
+ windowsHide: true
97228
+ });
97229
+ return stdout.trim();
97230
+ } catch {
97231
+ return null;
97232
+ }
97233
+ }
97234
+ function truncateLines(value, maxLines) {
97235
+ const lines = value.split(`
97236
+ `);
97237
+ if (lines.length <= maxLines) {
97238
+ return value;
97239
+ }
97240
+ return lines.slice(0, maxLines).join(`
97241
+ `) + `
97242
+ ... and ${lines.length - maxLines} more changes`;
97243
+ }
97244
+ function formatGitUser(name, email) {
97245
+ if (!name && !email) {
97246
+ return null;
97247
+ }
97248
+ if (name && email) {
97249
+ return `${name} <${email}>`;
97250
+ }
97251
+ return name || email;
97252
+ }
97253
+ function gatherGitContextSnapshot(options = {}) {
97254
+ const cwd = options.cwd ?? process.cwd();
97255
+ const recentCommitLimit = options.recentCommitLimit ?? 3;
97256
+ if (!runGit(["rev-parse", "--git-dir"], cwd)) {
97257
+ return {
97258
+ isGitRepo: false,
97259
+ branch: null,
97260
+ status: null,
97261
+ recentCommits: null,
97262
+ gitUser: null
97263
+ };
97264
+ }
97265
+ const branch = runGit(["branch", "--show-current"], cwd);
97266
+ const fullStatus = runGit(["status", "--short"], cwd);
97267
+ const status = typeof fullStatus === "string" && options.statusLineLimit ? truncateLines(fullStatus, options.statusLineLimit) : fullStatus;
97268
+ const recentCommits = options.recentCommitFormat ? runGit([
97269
+ "log",
97270
+ `--format=${options.recentCommitFormat}`,
97271
+ "-n",
97272
+ String(recentCommitLimit)
97273
+ ], cwd) : runGit(["log", "--oneline", "-n", String(recentCommitLimit)], cwd);
97274
+ const userConfig = runGit(["config", "--get-regexp", "^user\\.(name|email)$"], cwd);
97275
+ let userName = null;
97276
+ let userEmail = null;
97277
+ if (userConfig) {
97278
+ for (const line of userConfig.split(`
97279
+ `)) {
97280
+ if (line.startsWith("user.name "))
97281
+ userName = line.slice("user.name ".length);
97282
+ else if (line.startsWith("user.email "))
97283
+ userEmail = line.slice("user.email ".length);
97284
+ }
97285
+ }
97286
+ const gitUser = formatGitUser(userName, userEmail);
97287
+ return {
97288
+ isGitRepo: true,
97289
+ branch,
97290
+ status,
97291
+ recentCommits,
97292
+ gitUser
97293
+ };
97294
+ }
97295
+ async function getGitContextAsync(cwd) {
97296
+ if (!await runGitAsync(["rev-parse", "--git-dir"], cwd)) {
97297
+ return null;
97298
+ }
97299
+ const branch = await runGitAsync(["branch", "--show-current"], cwd);
97300
+ const branchList = await runGitAsync([
97301
+ "branch",
97302
+ "--sort=-committerdate",
97303
+ "--format=%(refname:short)",
97304
+ "--no-color"
97305
+ ], cwd);
97306
+ const recentBranches = branchList ? branchList.split(`
97307
+ `).map((b) => b.trim()).filter((b) => b.length > 0 && b !== branch).slice(0, 10) : [];
97308
+ return { branch, recent_branches: recentBranches };
97309
+ }
97310
+ var execFileAsync;
97311
+ var init_git_context = __esm(() => {
97312
+ execFileAsync = promisify3(execFile2);
97313
+ });
97314
+
97315
+ // src/websocket/listener/device-git-context.ts
97316
+ class DeviceGitContextCache {
97317
+ load;
97318
+ now;
97319
+ entries = new Map;
97320
+ pending = new Map;
97321
+ constructor(load = getGitContextAsync, now = Date.now) {
97322
+ this.load = load;
97323
+ this.now = now;
97324
+ }
97325
+ read(cwd) {
97326
+ const cached2 = this.entries.get(cwd);
97327
+ if (cached2 && cached2.expiresAt > this.now()) {
97328
+ return cached2.value;
97329
+ }
97330
+ return cached2?.value ?? null;
97331
+ }
97332
+ async refresh(cwd, options = {}) {
97333
+ const cached2 = this.entries.get(cwd);
97334
+ if (!options.force && cached2 && cached2.expiresAt > this.now()) {
97335
+ return cached2.value;
97336
+ }
97337
+ const pending = this.pending.get(cwd);
97338
+ if (pending) {
97339
+ return pending;
97340
+ }
97341
+ const load = this.load(cwd).then((value) => {
97342
+ this.entries.set(cwd, {
97343
+ expiresAt: this.now() + GIT_CONTEXT_CACHE_TTL_MS,
97344
+ value
97345
+ });
97346
+ this.prune();
97347
+ return value;
97348
+ }).finally(() => {
97349
+ this.pending.delete(cwd);
97350
+ });
97351
+ this.pending.set(cwd, load);
97352
+ return load;
97353
+ }
97354
+ prune() {
97355
+ if (this.entries.size <= MAX_GIT_CONTEXT_CACHE_ENTRIES) {
97356
+ return;
97357
+ }
97358
+ const oldestKey = this.entries.keys().next().value;
97359
+ if (oldestKey) {
97360
+ this.entries.delete(oldestKey);
97361
+ }
97362
+ }
97363
+ }
97364
+ var GIT_CONTEXT_CACHE_TTL_MS = 15000, MAX_GIT_CONTEXT_CACHE_ENTRIES = 64, deviceGitContextCache;
97365
+ var init_device_git_context = __esm(() => {
97366
+ init_git_context();
97367
+ deviceGitContextCache = new DeviceGitContextCache;
97368
+ });
97369
+
97418
97370
  // src/websocket/listener/device-status-cache.ts
97419
97371
  function recordDeviceStatus(transport, scope, status) {
97420
97372
  shouldEmitDeviceStatus(transport, scope, status, true);
@@ -97443,6 +97395,7 @@ var SUPPORTED_REMOTE_COMMANDS;
97443
97395
  var init_listener_constants = __esm(() => {
97444
97396
  SUPPORTED_REMOTE_COMMANDS = [
97445
97397
  "clear",
97398
+ "clear-messages",
97446
97399
  "doctor",
97447
97400
  "init",
97448
97401
  "remember",
@@ -97505,7 +97458,7 @@ function terminateStalledTransport(transport, state, reason) {
97505
97458
  state.pollTimer = null;
97506
97459
  }
97507
97460
  recordOutboundQueuePerf("queue:killed", 1);
97508
- console.error(`[Listen Wire] Terminating stalled transport (${reason})`);
97461
+ debugWarn("Listen Wire", `Terminating stalled transport (${reason})`);
97509
97462
  if (getListenerTransportKind(transport) === "websocket") {
97510
97463
  const ws = transport;
97511
97464
  try {
@@ -97886,7 +97839,7 @@ function notifyStreamObservers(listener, message, runtimeScope) {
97886
97839
  try {
97887
97840
  observer(observed);
97888
97841
  } catch (error4) {
97889
- console.error("[Listen V2] Stream observer failed", error4);
97842
+ debugWarn("Listen V2", "Stream observer failed", error4);
97890
97843
  }
97891
97844
  }
97892
97845
  }
@@ -97901,11 +97854,14 @@ function notifyStreamObserversRuntimeStopped(listener) {
97901
97854
  try {
97902
97855
  observer(observed);
97903
97856
  } catch (error4) {
97904
- console.error("[Listen V2] Stream observer failed on stop", error4);
97857
+ debugWarn("Listen V2", "Stream observer failed on stop", error4);
97905
97858
  }
97906
97859
  }
97907
97860
  listener.streamObservers.clear();
97908
97861
  }
97862
+ var init_stream_observers = __esm(() => {
97863
+ init_debug();
97864
+ });
97909
97865
 
97910
97866
  // src/websocket/listener/inbound-queue.ts
97911
97867
  function getInboundClientMessageId(incoming) {
@@ -98010,6 +97966,7 @@ var init_turn_correlation = __esm(() => {
98010
97966
  // src/websocket/listener/protocol-outbound.ts
98011
97967
  var exports_protocol_outbound = {};
98012
97968
  __export(exports_protocol_outbound, {
97969
+ refreshDeviceGitContext: () => refreshDeviceGitContext,
98013
97970
  isSystemReminderPart: () => isSystemReminderPart,
98014
97971
  emitSubagentStateUpdate: () => emitSubagentStateUpdate,
98015
97972
  emitSubagentStateIfOpen: () => emitSubagentStateIfOpen,
@@ -98048,25 +98005,6 @@ function getProtocolPerfKey(message) {
98048
98005
  }
98049
98006
  return message.type;
98050
98007
  }
98051
- function getCachedDeviceGitContext(cwd) {
98052
- const now = Date.now();
98053
- const cached2 = gitContextCache.get(cwd);
98054
- if (cached2 && cached2.expiresAt > now) {
98055
- return cached2.value;
98056
- }
98057
- const value = getGitContext(cwd);
98058
- gitContextCache.set(cwd, {
98059
- expiresAt: now + GIT_CONTEXT_CACHE_TTL_MS,
98060
- value
98061
- });
98062
- if (gitContextCache.size > MAX_GIT_CONTEXT_CACHE_ENTRIES) {
98063
- const oldestKey = gitContextCache.keys().next().value;
98064
- if (oldestKey) {
98065
- gitContextCache.delete(oldestKey);
98066
- }
98067
- }
98068
- return value;
98069
- }
98070
98008
  function getListenerRuntime(runtime) {
98071
98009
  if (!runtime)
98072
98010
  return null;
@@ -98081,6 +98019,18 @@ function getScopeForRuntime(runtime, scope) {
98081
98019
  }
98082
98020
  return scope ?? {};
98083
98021
  }
98022
+ function getDeviceStatusWorkingDirectory(runtime, params) {
98023
+ const listener = getListenerRuntime(runtime);
98024
+ if (!listener) {
98025
+ return process.cwd();
98026
+ }
98027
+ const scope = getScopeForRuntime(runtime, params);
98028
+ const conversationRuntime = getConversationRuntime(listener, resolveScopedAgentId(listener, scope), resolveScopedConversationId(listener, scope));
98029
+ return conversationRuntime?.activeWorkingDirectory ?? getConversationWorkingDirectory(listener, resolveScopedAgentId(listener, scope), resolveScopedConversationId(listener, scope));
98030
+ }
98031
+ async function refreshDeviceGitContext(runtime, params) {
98032
+ await deviceGitContextCache.refresh(getDeviceStatusWorkingDirectory(runtime, params));
98033
+ }
98084
98034
  function emitRuntimeStateUpdates(runtime, scope) {
98085
98035
  emitLoopStatusIfOpen(runtime, scope);
98086
98036
  emitDeviceStatusIfOpen(runtime, scope);
@@ -98096,7 +98046,7 @@ function buildDeviceStatus(runtime, params) {
98096
98046
  is_processing: false,
98097
98047
  current_permission_mode: permissionMode.getMode(),
98098
98048
  current_working_directory: fallbackCwd,
98099
- git_context: getCachedDeviceGitContext(fallbackCwd),
98049
+ git_context: deviceGitContextCache.read(fallbackCwd),
98100
98050
  letta_code_version: process.env.npm_package_version || null,
98101
98051
  current_toolset: null,
98102
98052
  current_toolset_preference: "auto",
@@ -98149,7 +98099,7 @@ function buildDeviceStatus(runtime, params) {
98149
98099
  is_processing: !!conversationRuntime?.isProcessing,
98150
98100
  current_permission_mode: conversationPermissionModeState.mode,
98151
98101
  current_working_directory: resolvedCwd,
98152
- git_context: getCachedDeviceGitContext(resolvedCwd),
98102
+ git_context: deviceGitContextCache.read(resolvedCwd),
98153
98103
  letta_code_version: process.env.npm_package_version || null,
98154
98104
  current_toolset: conversationRuntime?.currentToolset ?? (toolsetPreference === "auto" ? null : toolsetPreference),
98155
98105
  current_toolset_preference: conversationRuntime?.currentToolset === null ? toolsetPreference : conversationRuntime?.currentToolsetPreference ?? toolsetPreference,
@@ -98253,7 +98203,7 @@ function emitProtocolV2Message(socket, runtime, message, scope, routing) {
98253
98203
  try {
98254
98204
  payload = JSON.stringify(outbound);
98255
98205
  } catch (error4) {
98256
- console.error(`[Listen V2] Failed to emit ${message.type} (seq=${eventSeq})`, error4);
98206
+ debugWarn("Listen V2", `Failed to emit ${message.type} (seq=${eventSeq})`, error4);
98257
98207
  safeEmitWsEvent("send", "lifecycle", {
98258
98208
  type: "_ws_send_error",
98259
98209
  message_type: message.type,
@@ -98266,15 +98216,13 @@ function emitProtocolV2Message(socket, runtime, message, scope, routing) {
98266
98216
  payload,
98267
98217
  perfKey: getProtocolPerfKey(message),
98268
98218
  onSent: () => {
98269
- if (isDebugEnabled()) {
98270
- console.log(`[Listen V2] Emitting ${message.type} (seq=${eventSeq})`);
98271
- }
98219
+ debugLog("Listen V2", `Emitting ${message.type} (seq=${eventSeq})`);
98272
98220
  safeEmitWsEvent("send", "protocol", outbound);
98273
98221
  }
98274
98222
  };
98275
98223
  },
98276
98224
  onSendError: (error4) => {
98277
- console.error(`[Listen V2] Failed to emit ${message.type}`, error4);
98225
+ debugWarn("Listen V2", `Failed to emit ${message.type}`, error4);
98278
98226
  safeEmitWsEvent("send", "lifecycle", {
98279
98227
  type: "_ws_send_error",
98280
98228
  message_type: message.type,
@@ -98580,11 +98528,10 @@ function emitStreamDelta(socket, runtime, delta2, scope, subagentId) {
98580
98528
  };
98581
98529
  emitProtocolV2Message(socket, runtime, message, scope, TO_SUBSCRIBERS);
98582
98530
  }
98583
- var GIT_CONTEXT_CACHE_TTL_MS = 15000, MAX_GIT_CONTEXT_CACHE_ENTRIES = 64, FROZEN_SUPPORTED_COMMANDS, gitContextCache;
98531
+ var FROZEN_SUPPORTED_COMMANDS;
98584
98532
  var init_protocol_outbound = __esm(() => {
98585
98533
  init_memory_filesystem2();
98586
98534
  init_subagent_state();
98587
- init_git_context();
98588
98535
  init_memory_reminder();
98589
98536
  init_system_prompt_warning();
98590
98537
  init_constants2();
@@ -98597,16 +98544,17 @@ var init_protocol_outbound = __esm(() => {
98597
98544
  init_connection();
98598
98545
  init_constants3();
98599
98546
  init_cwd();
98547
+ init_device_git_context();
98600
98548
  init_device_status_cache();
98601
98549
  init_listener_constants();
98602
98550
  init_outbound_wire();
98603
98551
  init_permission_mode();
98604
98552
  init_protocol_outbound_routing();
98605
98553
  init_runtime();
98554
+ init_stream_observers();
98606
98555
  init_transport();
98607
98556
  init_turn_correlation();
98608
98557
  FROZEN_SUPPORTED_COMMANDS = [...SUPPORTED_REMOTE_COMMANDS];
98609
- gitContextCache = new Map;
98610
98558
  });
98611
98559
 
98612
98560
  // src/websocket/listener/cwd-change.ts
@@ -98651,10 +98599,13 @@ async function switchConversationWorkingDirectory(params) {
98651
98599
  }
98652
98600
  if (params.emitStatus !== false) {
98653
98601
  const statusTransport = params.statusSocket ?? getOrCreateProcessTransport(runtime);
98654
- emitDeviceStatusUpdate(statusTransport, params.statusRuntime ?? conversationRuntime ?? runtime, {
98602
+ const statusRuntime = params.statusRuntime ?? conversationRuntime ?? runtime;
98603
+ const statusScope = {
98655
98604
  agent_id: agentId,
98656
98605
  conversation_id: conversationId
98657
- });
98606
+ };
98607
+ await refreshDeviceGitContext(statusRuntime, statusScope);
98608
+ emitDeviceStatusUpdate(statusTransport, statusRuntime, statusScope);
98658
98609
  }
98659
98610
  }
98660
98611
  var init_cwd_change = __esm(() => {
@@ -98685,7 +98636,7 @@ function startWorktreeWatcher(params) {
98685
98636
  }).catch((err) => {
98686
98637
  if (err.name === "AbortError")
98687
98638
  return;
98688
- console.error("[WorktreeWatcher] watch loop error:", err);
98639
+ debugWarn("WorktreeWatcher", "watch loop error:", err);
98689
98640
  });
98690
98641
  return state;
98691
98642
  }
@@ -98741,7 +98692,7 @@ async function runWatchLoop(params) {
98741
98692
  agentId,
98742
98693
  conversationId
98743
98694
  }).catch((err) => {
98744
- console.error("[WorktreeWatcher] failed to handle new worktree:", err);
98695
+ debugWarn("WorktreeWatcher", "failed to handle new worktree:", err);
98745
98696
  });
98746
98697
  }, DEBOUNCE_MS);
98747
98698
  }
@@ -98761,7 +98712,7 @@ async function handleNewWorktree(params) {
98761
98712
  return;
98762
98713
  }
98763
98714
  clearExpectedWorktreePath(conversationRuntime);
98764
- console.log(`[WorktreeWatcher] New worktree detected: ${newWorktreePath} — switching CWD`);
98715
+ debugLog("WorktreeWatcher", `New worktree detected: ${newWorktreePath} — switching CWD`);
98765
98716
  await switchConversationWorkingDirectory({
98766
98717
  runtime,
98767
98718
  agentId,
@@ -98794,6 +98745,7 @@ async function safeReaddir(dir) {
98794
98745
  }
98795
98746
  var WORKTREES_DIR = ".letta/worktrees", DEBOUNCE_MS = 500;
98796
98747
  var init_worktree_watcher = __esm(() => {
98748
+ init_debug();
98797
98749
  init_cwd();
98798
98750
  init_cwd_change();
98799
98751
  init_runtime();
@@ -99839,6 +99791,7 @@ function formatExecOutput(params) {
99839
99791
  }
99840
99792
  if (params.sessionId !== null) {
99841
99793
  sections.push(`Process running with session ID ${params.sessionId}`);
99794
+ sections.push("You will be notified when the process completes. Do not poll unless you need the output before continuing.");
99842
99795
  }
99843
99796
  sections.push(`Original token count: ${params.originalTokenCount}`);
99844
99797
  sections.push("Output:");
@@ -99909,7 +99862,7 @@ function createSessionOutputAppender(params) {
99909
99862
  appendSessionOutput(params.session, `
99910
99863
  [output file write failed; output may be incomplete]
99911
99864
  `, "stderr");
99912
- markSessionFailed(params.session);
99865
+ markSessionFailed(params.session, "Output file write failed; output may be incomplete");
99913
99866
  const bgProc = backgroundProcesses.get(params.session.id);
99914
99867
  if (bgProc) {
99915
99868
  try {
@@ -99919,19 +99872,61 @@ function createSessionOutputAppender(params) {
99919
99872
  }
99920
99873
  };
99921
99874
  }
99922
- function markSessionFailed(session) {
99875
+ function notifyExecCompletion(session) {
99876
+ if (!session.notificationArmed || session.completionDelivered || session.activeWriteStdinCalls > 0) {
99877
+ return;
99878
+ }
99879
+ const backgroundProcess = backgroundProcesses.get(session.id);
99880
+ if (backgroundProcess?.completionNotificationSuppressed) {
99881
+ session.completionDelivered = true;
99882
+ return;
99883
+ }
99884
+ session.completionDelivered = true;
99885
+ const status = session.status === "completed" ? "completed" : "failed";
99886
+ const unreadOutput = session.output.slice(session.readOffset) || "(no new output)";
99887
+ const { content: result } = truncateByChars(scrubSecretsFromString([
99888
+ `$ ${session.command}`,
99889
+ `Session ID: ${session.id}`,
99890
+ session.completionDetail,
99891
+ unreadOutput
99892
+ ].filter(Boolean).join(`
99893
+
99894
+ `), session.secrets), LIMITS.BASH_NOTIFICATION_CHARS, "exec_command", { useMiddleTruncation: true });
99895
+ const durationMs = backgroundProcess?.startTime ? Math.max(0, Date.now() - backgroundProcess.startTime.getTime()) : undefined;
99896
+ addToMessageQueue({
99897
+ kind: "task_notification",
99898
+ text: formatTaskNotification({
99899
+ taskId: `exec_${session.id}`,
99900
+ status,
99901
+ summary: `Exec command "${session.description?.trim() || session.command}" ${status}`,
99902
+ result,
99903
+ outputFile: session.outputFile,
99904
+ usage: durationMs === undefined ? undefined : { durationMs }
99905
+ }),
99906
+ agentId: session.notificationScope?.agentId,
99907
+ conversationId: session.notificationScope?.conversationId
99908
+ });
99909
+ }
99910
+ function markSessionFailed(session, detail) {
99911
+ if (session.status !== "running")
99912
+ return;
99923
99913
  session.status = "failed";
99914
+ session.completionDetail = detail;
99924
99915
  const bgProcess = backgroundProcesses.get(session.id);
99925
99916
  if (bgProcess) {
99926
99917
  bgProcess.status = "failed";
99927
99918
  scrubCompletedBackgroundOutput(bgProcess);
99928
99919
  scheduleBackgroundProcessCleanup(session.id);
99929
99920
  }
99921
+ notifyExecCompletion(session);
99930
99922
  scheduleExecSessionCleanup(session.id);
99931
99923
  }
99932
99924
  function markSessionClosed(session, code2) {
99925
+ if (session.status !== "running")
99926
+ return;
99933
99927
  session.status = code2 === 0 && !session.outputWriteFailed ? "completed" : "failed";
99934
99928
  session.exitCode = code2;
99929
+ session.completionDetail = code2 === null ? "Terminated by signal before exiting" : `Exit code: ${code2}`;
99935
99930
  const bgProcess = backgroundProcesses.get(session.id);
99936
99931
  if (bgProcess) {
99937
99932
  bgProcess.status = session.status;
@@ -99939,6 +99934,7 @@ function markSessionClosed(session, code2) {
99939
99934
  scrubCompletedBackgroundOutput(bgProcess);
99940
99935
  scheduleBackgroundProcessCleanup(session.id);
99941
99936
  }
99937
+ notifyExecCompletion(session);
99942
99938
  scheduleExecSessionCleanup(session.id);
99943
99939
  }
99944
99940
  async function waitForSessionOutput(params) {
@@ -99986,13 +99982,19 @@ async function startExecSession(args) {
99986
99982
  const session = {
99987
99983
  id: id2,
99988
99984
  command: args.cmd,
99985
+ description: args.description,
99989
99986
  output: "",
99987
+ outputFile,
99990
99988
  chunks: [],
99991
99989
  readOffset: 0,
99992
99990
  status: "running",
99993
99991
  exitCode: null,
99994
99992
  tty: args.tty ?? false,
99995
- secrets: args.secretEnv ?? {}
99993
+ secrets: args.secretEnv ?? {},
99994
+ notificationScope: resolveNotificationScope(args.parentScope),
99995
+ notificationArmed: false,
99996
+ completionDelivered: false,
99997
+ activeWriteStdinCalls: 0
99996
99998
  };
99997
99999
  execSessions.set(id2, session);
99998
100000
  const appendOutput = createSessionOutputAppender({
@@ -100041,7 +100043,7 @@ async function startExecSession(args) {
100041
100043
  if (error4 instanceof ShellExecutionError) {
100042
100044
  appendOutput(error4.message, "stderr");
100043
100045
  }
100044
- markSessionFailed(session);
100046
+ markSessionFailed(session, `Error: ${error4 instanceof Error ? error4.message : String(error4)}`);
100045
100047
  });
100046
100048
  return session;
100047
100049
  }
@@ -100060,6 +100062,9 @@ async function exec_command(args) {
100060
100062
  onOutput: args.onOutput
100061
100063
  });
100062
100064
  const sessionId = session.status === "running" ? session.id : null;
100065
+ if (sessionId !== null) {
100066
+ session.notificationArmed = true;
100067
+ }
100063
100068
  const formattedOutput = formatExecOutput({
100064
100069
  chunkId: generateChunkId(),
100065
100070
  wallTimeMs,
@@ -100093,19 +100098,35 @@ async function write_stdin(args) {
100093
100098
  throw new Error("stdin is closed for this session; rerun exec_command with tty=true to keep stdin open");
100094
100099
  }
100095
100100
  }
100096
- if (chars && session.tty) {
100097
- backgroundProcess.process.write(chars);
100098
- await sleep9(100, args.signal);
100101
+ session.activeWriteStdinCalls++;
100102
+ let output;
100103
+ let wallTimeMs;
100104
+ let waitCompleted = false;
100105
+ try {
100106
+ if (chars && session.tty) {
100107
+ backgroundProcess.process.write(chars);
100108
+ await sleep9(100, args.signal);
100109
+ }
100110
+ const startOffset = session.readOffset;
100111
+ const yieldTimeMs = clampWriteStdinYieldTime(args.yield_time_ms, chars);
100112
+ ({ output, wallTimeMs } = await waitForSessionOutput({
100113
+ session,
100114
+ startOffset,
100115
+ yieldTimeMs,
100116
+ signal: args.signal,
100117
+ onOutput: args.onOutput
100118
+ }));
100119
+ waitCompleted = true;
100120
+ } finally {
100121
+ session.activeWriteStdinCalls--;
100122
+ if (session.status !== "running") {
100123
+ if (waitCompleted) {
100124
+ session.completionDelivered = true;
100125
+ } else {
100126
+ notifyExecCompletion(session);
100127
+ }
100128
+ }
100099
100129
  }
100100
- const startOffset = session.readOffset;
100101
- const yieldTimeMs = clampWriteStdinYieldTime(args.yield_time_ms, chars);
100102
- const { output, wallTimeMs } = await waitForSessionOutput({
100103
- session,
100104
- startOffset,
100105
- yieldTimeMs,
100106
- signal: args.signal,
100107
- onOutput: args.onOutput
100108
- });
100109
100130
  const nextSessionId = session.status === "running" ? session.id : null;
100110
100131
  const formattedOutput = formatExecOutput({
100111
100132
  chunkId: generateChunkId(),
@@ -100128,6 +100149,8 @@ var DEFAULT_EXEC_YIELD_TIME_MS = 1e4, DEFAULT_WRITE_STDIN_YIELD_TIME_MS = 250, M
100128
100149
  var init_exec_command = __esm(() => {
100129
100150
  init_runtime_context();
100130
100151
  init_secret_substitution();
100152
+ init_message_queue_bridge();
100153
+ init_task_notifications();
100131
100154
  init_worktree_ownership();
100132
100155
  init_process_manager();
100133
100156
  init_shell();
@@ -100302,9 +100325,9 @@ var init_exit_worktree = __esm(() => {
100302
100325
  });
100303
100326
 
100304
100327
  // src/tools/impl/glob.ts
100305
- import { execFile as execFile2 } from "node:child_process";
100328
+ import { execFile as execFile3 } from "node:child_process";
100306
100329
  import * as path20 from "node:path";
100307
- import { promisify as promisify3 } from "node:util";
100330
+ import { promisify as promisify4 } from "node:util";
100308
100331
  function applyFileLimit(files, workingDirectory) {
100309
100332
  const totalFiles = files.length;
100310
100333
  if (totalFiles <= LIMITS.GLOB_MAX_FILES) {
@@ -100342,7 +100365,7 @@ async function glob(args) {
100342
100365
  baseDir
100343
100366
  ];
100344
100367
  try {
100345
- const { stdout } = await execFileAsync(rgPath, rgArgs, {
100368
+ const { stdout } = await execFileAsync2(rgPath, rgArgs, {
100346
100369
  maxBuffer: 50 * 1024 * 1024,
100347
100370
  cwd: userCwd,
100348
100371
  signal
@@ -100366,12 +100389,12 @@ async function glob(args) {
100366
100389
  throw new Error(`Glob failed: ${err.message || "Unknown error"}`);
100367
100390
  }
100368
100391
  }
100369
- var execFileAsync;
100392
+ var execFileAsync2;
100370
100393
  var init_glob = __esm(() => {
100371
100394
  init_runtime_context();
100372
100395
  init_ripgrep_manager();
100373
100396
  init_truncation();
100374
- execFileAsync = promisify3(execFile2);
100397
+ execFileAsync2 = promisify4(execFile3);
100375
100398
  });
100376
100399
 
100377
100400
  // src/tools/impl/glob-gemini.ts
@@ -100390,9 +100413,9 @@ var init_glob_gemini = __esm(() => {
100390
100413
  });
100391
100414
 
100392
100415
  // src/tools/impl/grep.ts
100393
- import { execFile as execFile3 } from "node:child_process";
100416
+ import { execFile as execFile4 } from "node:child_process";
100394
100417
  import * as path21 from "node:path";
100395
- import { promisify as promisify4 } from "node:util";
100418
+ import { promisify as promisify5 } from "node:util";
100396
100419
  function applyOffsetAndLimit(items3, offset, limit3) {
100397
100420
  const sliced = items3.slice(offset);
100398
100421
  if (limit3 > 0) {
@@ -100454,7 +100477,7 @@ async function grep(args) {
100454
100477
  else
100455
100478
  rgArgs.push(userCwd);
100456
100479
  try {
100457
- const { stdout } = await execFileAsync2(rgPath, rgArgs, {
100480
+ const { stdout } = await execFileAsync3(rgPath, rgArgs, {
100458
100481
  maxBuffer: 10 * 1024 * 1024,
100459
100482
  cwd: userCwd,
100460
100483
  signal
@@ -100549,12 +100572,12 @@ Found 0 total occurrences across 0 files.`,
100549
100572
  throw new Error(`Grep failed: ${message}`);
100550
100573
  }
100551
100574
  }
100552
- var execFileAsync2;
100575
+ var execFileAsync3;
100553
100576
  var init_grep = __esm(() => {
100554
100577
  init_runtime_context();
100555
100578
  init_ripgrep_manager();
100556
100579
  init_truncation();
100557
- execFileAsync2 = promisify4(execFile3);
100580
+ execFileAsync3 = promisify5(execFile4);
100558
100581
  });
100559
100582
 
100560
100583
  // src/tools/impl/grep-files.ts
@@ -104406,13 +104429,13 @@ var exports_image_resize_sips = {};
104406
104429
  __export(exports_image_resize_sips, {
104407
104430
  convertHeicToJpegWithSips: () => convertHeicToJpegWithSips
104408
104431
  });
104409
- import { execFile as execFile4 } from "node:child_process";
104432
+ import { execFile as execFile5 } from "node:child_process";
104410
104433
  import { mkdtemp, readFile as readFile10, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
104411
104434
  import { tmpdir as tmpdir5 } from "node:os";
104412
104435
  import { join as join23 } from "node:path";
104413
- function execFileAsync3(file, args) {
104436
+ function execFileAsync4(file, args) {
104414
104437
  return new Promise((resolve19, reject) => {
104415
- execFile4(file, args, (error4) => {
104438
+ execFile5(file, args, (error4) => {
104416
104439
  if (error4) {
104417
104440
  reject(error4);
104418
104441
  return;
@@ -104427,7 +104450,7 @@ async function convertHeicToJpegWithSips(buffer) {
104427
104450
  const outputPath = join23(workDir, "output.jpg");
104428
104451
  try {
104429
104452
  await writeFile8(inputPath, buffer);
104430
- await execFileAsync3("/usr/bin/sips", [
104453
+ await execFileAsync4("/usr/bin/sips", [
104431
104454
  "-s",
104432
104455
  "format",
104433
104456
  "jpeg",
@@ -114805,6 +114828,9 @@ function buildSubagentArgs(type3, config, model, userPrompt, existingAgentId, ex
114805
114828
  }
114806
114829
  if (isDeployingExisting) {
114807
114830
  if (existingConversationId) {
114831
+ if (existingConversationId === "default" && existingAgentId) {
114832
+ args.push("--agent", existingAgentId);
114833
+ }
114808
114834
  args.push("--conv", existingConversationId);
114809
114835
  } else if (existingAgentId) {
114810
114836
  args.push("--agent", existingAgentId, "--new");
@@ -116176,7 +116202,7 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
116176
116202
  },
116177
116203
  run_in_background: {
116178
116204
  type: "boolean",
116179
- description: "Set to true to run this command in the background. Use TaskOutput to read the output later."
116205
+ description: "Set to true only when the command should return a task ID immediately. Ordinary commands already yield automatically if they are still running after a brief wait, and completion is delivered without polling."
116180
116206
  }
116181
116207
  },
116182
116208
  required: ["command", "description"],
@@ -116747,7 +116773,7 @@ var init_Monitor2 = __esm(() => {
116747
116773
  properties: {
116748
116774
  description: {
116749
116775
  type: "string",
116750
- description: "Short human-readable description of what you are monitoring (shown in notifications)."
116776
+ description: "Clear, concise user-facing description of the update you are waiting for. This may be shown directly in chat, so make it grammatical by itself. Describe the expected event, not the polling command or monitor implementation. Prefer `CI results and review comments for the auth fix`, `Deployment completion or failure`, or `New errors in the API logs` over internal labels like `PR checks and state transitions`."
116751
116777
  },
116752
116778
  timeout_ms: {
116753
116779
  type: "number",
@@ -126691,12 +126717,12 @@ import {
126691
126717
  mkdirSync as mkdirSync15,
126692
126718
  readFileSync as readFileSync13,
126693
126719
  renameSync as renameSync3,
126694
- rmSync as rmSync4,
126720
+ rmSync as rmSync5,
126695
126721
  writeFileSync as writeFileSync11
126696
126722
  } from "node:fs";
126697
126723
  import { homedir as homedir21, platform as platform3 } from "node:os";
126698
126724
  import { dirname as dirname21, isAbsolute as isAbsolute21, join as join32 } from "node:path";
126699
- import { promisify as promisify5 } from "node:util";
126725
+ import { promisify as promisify6 } from "node:util";
126700
126726
  function getAgentRootDir(agentId) {
126701
126727
  return join32(homedir21(), ".letta", "agents", agentId);
126702
126728
  }
@@ -126836,7 +126862,7 @@ async function syncRepoMount(args) {
126836
126862
  timeoutMs: GIT_CLONE_TIMEOUT_MS
126837
126863
  });
126838
126864
  } catch (err) {
126839
- rmSync4(args.directory, { recursive: true, force: true });
126865
+ rmSync5(args.directory, { recursive: true, force: true });
126840
126866
  throw err;
126841
126867
  }
126842
126868
  } else if (!existsSync25(join32(args.directory, ".git"))) {
@@ -126974,7 +127000,7 @@ async function runGit3(cwd, args, token, options) {
126974
127000
  const timeoutMs = options?.timeoutMs ?? GIT_DEFAULT_TIMEOUT_MS;
126975
127001
  let result;
126976
127002
  try {
126977
- result = await execFile5("git", allArgs, {
127003
+ result = await execFile6("git", allArgs, {
126978
127004
  cwd,
126979
127005
  env: buildNonInteractiveGitEnv2(),
126980
127006
  maxBuffer: 10485760,
@@ -127572,7 +127598,7 @@ async function cloneMemoryRepo(agentId) {
127572
127598
  const tmpDir = `${dir}-git-clone-tmp`;
127573
127599
  try {
127574
127600
  if (existsSync25(tmpDir)) {
127575
- rmSync4(tmpDir, { recursive: true, force: true });
127601
+ rmSync5(tmpDir, { recursive: true, force: true });
127576
127602
  }
127577
127603
  mkdirSync15(tmpDir, { recursive: true });
127578
127604
  await runGitWithRetry(tmpDir, ["clone", url, "."], token, {
@@ -127590,7 +127616,7 @@ async function cloneMemoryRepo(agentId) {
127590
127616
  debugLog("memfs-git", "Migrated existing memory directory to git repo");
127591
127617
  } finally {
127592
127618
  if (existsSync25(tmpDir)) {
127593
- rmSync4(tmpDir, { recursive: true, force: true });
127619
+ rmSync5(tmpDir, { recursive: true, force: true });
127594
127620
  }
127595
127621
  }
127596
127622
  }
@@ -127885,7 +127911,7 @@ async function addGitMemoryTag(agentId, prefetchedAgent) {
127885
127911
  debugWarn("memfs-git", `Failed to add git-memory tag: ${err instanceof Error ? err.message : String(err)}`);
127886
127912
  }
127887
127913
  }
127888
- var execFile5, RETRYABLE_GIT_HTTP_ERROR_RE, RETRYABLE_GIT_NETWORK_ERROR_RE, MISSING_CWD_GIT_ERROR_RE, NON_FAST_FORWARD_PUSH_ERROR_RE, UNRELATED_HISTORY_PULL_ERROR_RE, NO_UPSTREAM_PULL_ERROR_RE, AGENT_DISPLAY_NAME_TIMEOUT_MS = 3000, HOSTED_BACKEND_HEADER2 = "x-letta-memfs-backend", HOSTED_BACKEND_VALUE2 = "hosted", GIT_DEFAULT_TIMEOUT_MS = 60000, GIT_CLONE_TIMEOUT_MS = 180000, gitConfig = (dir, args) => withSerializedGitConfigMutation(dir, () => runGit3(dir, args)), MEMORY_REPOSITORY_CONFIG_KEY = "letta.memoryRepository.url", MEMORY_REPOSITORY_PUSH_LOG = "memory-repository-push.log";
127914
+ var execFile6, RETRYABLE_GIT_HTTP_ERROR_RE, RETRYABLE_GIT_NETWORK_ERROR_RE, MISSING_CWD_GIT_ERROR_RE, NON_FAST_FORWARD_PUSH_ERROR_RE, UNRELATED_HISTORY_PULL_ERROR_RE, NO_UPSTREAM_PULL_ERROR_RE, AGENT_DISPLAY_NAME_TIMEOUT_MS = 3000, HOSTED_BACKEND_HEADER2 = "x-letta-memfs-backend", HOSTED_BACKEND_VALUE2 = "hosted", GIT_DEFAULT_TIMEOUT_MS = 60000, GIT_CLONE_TIMEOUT_MS = 180000, gitConfig = (dir, args) => withSerializedGitConfigMutation(dir, () => runGit3(dir, args)), MEMORY_REPOSITORY_CONFIG_KEY = "letta.memoryRepository.url", MEMORY_REPOSITORY_PUSH_LOG = "memory-repository-push.log";
127889
127915
  var init_memory_git = __esm(() => {
127890
127916
  init_client2();
127891
127917
  init_memfs_git_proxy();
@@ -127896,7 +127922,7 @@ var init_memory_git = __esm(() => {
127896
127922
  init_memory_git_config_lock();
127897
127923
  init_memory_git_hooks();
127898
127924
  init_memory_git_signing();
127899
- execFile5 = promisify5(execFileCb2);
127925
+ execFile6 = promisify6(execFileCb2);
127900
127926
  RETRYABLE_GIT_HTTP_ERROR_RE = /(?:\bHTTP\s+(?:520|521|522|523|524)\b|The requested URL returned error:\s*(?:520|521|522|523|524))/i;
127901
127927
  RETRYABLE_GIT_NETWORK_ERROR_RE = /(remote end hung up unexpectedly|connection reset by peer|operation timed out|timed out|SIGTERM|ETIMEDOUT)/i;
127902
127928
  MISSING_CWD_GIT_ERROR_RE = /(Unable to read current working directory: No such file or directory|\buv_cwd\b|\bcwd\b.*\bENOENT\b)/i;
@@ -128573,7 +128599,7 @@ import {
128573
128599
  readdirSync as readdirSync9,
128574
128600
  readFileSync as readFileSync14,
128575
128601
  readSync,
128576
- rmSync as rmSync5,
128602
+ rmSync as rmSync6,
128577
128603
  statSync as statSync8,
128578
128604
  writeFileSync as writeFileSync12
128579
128605
  } from "node:fs";
@@ -129121,7 +129147,7 @@ class LocalStore {
129121
129147
  this.persistedMessageByMessageIdByConversationKey.delete(key);
129122
129148
  this.lastSessionEntryIdByConversationKey.delete(key);
129123
129149
  if (this.storageDir) {
129124
- rmSync5(join33(this.storageDir, "conversations", encodePathSegment(key)), {
129150
+ rmSync6(join33(this.storageDir, "conversations", encodePathSegment(key)), {
129125
129151
  recursive: true,
129126
129152
  force: true
129127
129153
  });
@@ -129129,7 +129155,7 @@ class LocalStore {
129129
129155
  }
129130
129156
  }
129131
129157
  if (this.storageDir) {
129132
- rmSync5(join33(this.storageDir, "agents", `${encodePathSegment(agentId)}.json`), { force: true });
129158
+ rmSync6(join33(this.storageDir, "agents", `${encodePathSegment(agentId)}.json`), { force: true });
129133
129159
  }
129134
129160
  }
129135
129161
  retrieveAgentRecord(agentId) {
@@ -129440,7 +129466,7 @@ class LocalStore {
129440
129466
  continue;
129441
129467
  this.compiledSystemPromptByConversationKey.delete(key);
129442
129468
  if (this.storageDir) {
129443
- rmSync5(join33(this.storageDir, "conversations", encodePathSegment(key), "system-prompt.json"), { force: true });
129469
+ rmSync6(join33(this.storageDir, "conversations", encodePathSegment(key), "system-prompt.json"), { force: true });
129444
129470
  }
129445
129471
  }
129446
129472
  }
@@ -135626,7 +135652,7 @@ var init_local_backend = __esm(() => {
135626
135652
  });
135627
135653
 
135628
135654
  // src/backend/backend.ts
135629
- import { mkdtempSync as mkdtempSync2, rmSync as rmSync6 } from "node:fs";
135655
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync7 } from "node:fs";
135630
135656
  import { homedir as homedir22, tmpdir as tmpdir6 } from "node:os";
135631
135657
  import { join as join34 } from "node:path";
135632
135658
  function toApiConversationMessageListBody(body) {
@@ -135657,6 +135683,7 @@ class APIBackend {
135657
135683
  }
135658
135684
  getApiClientOverride;
135659
135685
  forkConversationOverride;
135686
+ retrieveAgentInflightByKey = new Map;
135660
135687
  constructor(deps = {}) {
135661
135688
  this.getApiClientOverride = deps.getClient;
135662
135689
  this.forkConversationOverride = deps.forkConversation;
@@ -135670,7 +135697,24 @@ class APIBackend {
135670
135697
  }
135671
135698
  async retrieveAgent(agentId, options) {
135672
135699
  const client = await this.getClient();
135673
- return client.agents.retrieve(agentId, options);
135700
+ if (options !== undefined) {
135701
+ return client.agents.retrieve(agentId, options);
135702
+ }
135703
+ const inflight2 = this.retrieveAgentInflightByKey.get(agentId);
135704
+ if (inflight2)
135705
+ return inflight2;
135706
+ const request = client.agents.retrieve(agentId, undefined);
135707
+ this.retrieveAgentInflightByKey.set(agentId, request);
135708
+ request.then(() => {
135709
+ if (this.retrieveAgentInflightByKey.get(agentId) === request) {
135710
+ this.retrieveAgentInflightByKey.delete(agentId);
135711
+ }
135712
+ }, () => {
135713
+ if (this.retrieveAgentInflightByKey.get(agentId) === request) {
135714
+ this.retrieveAgentInflightByKey.delete(agentId);
135715
+ }
135716
+ });
135717
+ return request;
135674
135718
  }
135675
135719
  async listAgentSecrets(agentId) {
135676
135720
  const client = await this.getClient();
@@ -135829,7 +135873,7 @@ function configureEphemeralLocalBackend() {
135829
135873
  executionMode: localBackendExecutionMode()
135830
135874
  });
135831
135875
  process.once("exit", () => {
135832
- rmSync6(stateStorageDir, { recursive: true, force: true });
135876
+ rmSync7(stateStorageDir, { recursive: true, force: true });
135833
135877
  });
135834
135878
  }
135835
135879
  function isLocalBackendEnabled() {
@@ -136554,7 +136598,7 @@ __export(exports_personality, {
136554
136598
  import { execFile as execFileCb3 } from "node:child_process";
136555
136599
  import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "node:fs";
136556
136600
  import { dirname as dirname22, join as join35 } from "node:path";
136557
- import { promisify as promisify6 } from "node:util";
136601
+ import { promisify as promisify7 } from "node:util";
136558
136602
  function ensureTrailingNewline2(content) {
136559
136603
  return `${content.trimEnd()}
136560
136604
  `;
@@ -136704,7 +136748,7 @@ async function applyPersonalityToMemory(params) {
136704
136748
  const isLocalMemfs = getBackend().capabilities.localMemfs;
136705
136749
  const blockDefinitions = getPersonalityBlockDefinitions(params.personalityId, isLocalMemfs ? "local" : "cloud");
136706
136750
  const repoDir = isLocalMemfs ? getScopedMemoryFilesystemRoot(params.agentId) : getMemoryRepoDir(params.agentId);
136707
- const statusResult = await execFile6("git", ["status", "--porcelain"], {
136751
+ const statusResult = await execFile7("git", ["status", "--porcelain"], {
136708
136752
  cwd: repoDir,
136709
136753
  timeout: 1e4
136710
136754
  });
@@ -136768,7 +136812,7 @@ async function applyPersonalityToMemory(params) {
136768
136812
  commitMessage
136769
136813
  };
136770
136814
  }
136771
- var execFile6, PRIMARY_PERSONA_RELATIVE_PATH = "system/persona.md", LEGACY_PERSONA_RELATIVE_PATH = "memory/system/persona.md", PRIMARY_HUMAN_RELATIVE_PATH = "system/human.md", LEGACY_HUMAN_RELATIVE_PATH = "memory/system/human.md";
136815
+ var execFile7, PRIMARY_PERSONA_RELATIVE_PATH = "system/persona.md", LEGACY_PERSONA_RELATIVE_PATH = "memory/system/persona.md", PRIMARY_HUMAN_RELATIVE_PATH = "system/human.md", LEGACY_HUMAN_RELATIVE_PATH = "memory/system/human.md";
136772
136816
  var init_personality = __esm(() => {
136773
136817
  init_backend2();
136774
136818
  init_settings_manager();
@@ -136776,7 +136820,7 @@ var init_personality = __esm(() => {
136776
136820
  init_memory_filesystem2();
136777
136821
  init_memory_git();
136778
136822
  init_personality_presets();
136779
- execFile6 = promisify6(execFileCb3);
136823
+ execFile7 = promisify7(execFileCb3);
136780
136824
  });
136781
136825
 
136782
136826
  // src/cli/args.ts
@@ -148670,7 +148714,7 @@ Learn more about this warning here: https://reactjs.org/link/legacy-context`, so
148670
148714
 
148671
148715
  ` + ("" + errorBoundaryMessage);
148672
148716
  console["error"](combinedMessage);
148673
- } else {}
148717
+ }
148674
148718
  } catch (e2) {
148675
148719
  setTimeout(function() {
148676
148720
  throw e2;
@@ -164543,7 +164587,7 @@ var CAPTURING_REGEX_SOURCE, RegexSource = class {
164543
164587
  let localIncludedRule = repository[reference.ruleName];
164544
164588
  if (localIncludedRule) {
164545
164589
  ruleId = _RuleFactory.getCompiledRuleId(localIncludedRule, helper, repository);
164546
- } else {}
164590
+ }
164547
164591
  break;
164548
164592
  case 3:
164549
164593
  case 4:
@@ -164555,11 +164599,11 @@ var CAPTURING_REGEX_SOURCE, RegexSource = class {
164555
164599
  let externalIncludedRule = externalGrammar.repository[externalGrammarInclude];
164556
164600
  if (externalIncludedRule) {
164557
164601
  ruleId = _RuleFactory.getCompiledRuleId(externalIncludedRule, helper, externalGrammar.repository);
164558
- } else {}
164602
+ }
164559
164603
  } else {
164560
164604
  ruleId = _RuleFactory.getCompiledRuleId(externalGrammar.repository.$self, helper, externalGrammar.repository);
164561
164605
  }
164562
- } else {}
164606
+ }
164563
164607
  break;
164564
164608
  }
164565
164609
  } else {
@@ -175258,7 +175302,7 @@ import {
175258
175302
  mkdirSync as mkdirSync18,
175259
175303
  readdirSync as readdirSync10,
175260
175304
  renameSync as renameSync4,
175261
- rmSync as rmSync7,
175305
+ rmSync as rmSync8,
175262
175306
  statSync as statSync10
175263
175307
  } from "node:fs";
175264
175308
  import { arch as arch2, homedir as homedir23, platform as platform5 } from "node:os";
@@ -175635,8 +175679,8 @@ async function downloadFd() {
175635
175679
  chmodSync5(FD_LOCAL_PATH, 493);
175636
175680
  }
175637
175681
  } finally {
175638
- rmSync7(archivePath, { force: true });
175639
- rmSync7(extractDir, { recursive: true, force: true });
175682
+ rmSync8(archivePath, { force: true });
175683
+ rmSync8(extractDir, { recursive: true, force: true });
175640
175684
  }
175641
175685
  return FD_LOCAL_PATH;
175642
175686
  }
@@ -179446,12 +179490,12 @@ __export(exports_auto_update, {
179446
179490
  buildInstallArgs: () => buildInstallArgs
179447
179491
  });
179448
179492
  import {
179449
- execFile as execFile7
179493
+ execFile as execFile8
179450
179494
  } from "node:child_process";
179451
179495
  import { accessSync, constants as constants4, realpathSync as realpathSync4 } from "node:fs";
179452
179496
  import { readdir as readdir7, rm as rm6 } from "node:fs/promises";
179453
179497
  import { dirname as dirname23, join as join41 } from "node:path";
179454
- import { promisify as promisify7 } from "node:util";
179498
+ import { promisify as promisify8 } from "node:util";
179455
179499
  function debugLog2(...args) {
179456
179500
  if (DEBUG) {
179457
179501
  console.error("[auto-update]", ...args);
@@ -179514,7 +179558,7 @@ function buildUpdateExecOptions(timeout, platform6 = process.platform) {
179514
179558
  };
179515
179559
  }
179516
179560
  async function runUpdateCommand(command, args, timeout) {
179517
- return execFileAsync4(command, args, buildUpdateExecOptions(timeout));
179561
+ return execFileAsync5(command, args, buildUpdateExecOptions(timeout));
179518
179562
  }
179519
179563
  function getResolvedEntrypoint() {
179520
179564
  const argv = process.argv[1] || "";
@@ -179837,11 +179881,11 @@ async function manualUpdate(options) {
179837
179881
  To update manually: ${installCmd}`
179838
179882
  };
179839
179883
  }
179840
- var execFileAsync4, DEBUG, DEFAULT_UPDATE_PACKAGE_NAME = "@letta-ai/letta-code", DEFAULT_UPDATE_REGISTRY_BASE_URL = "https://registry.npmjs.org", UPDATE_PACKAGE_NAME_ENV = "LETTA_UPDATE_PACKAGE_NAME", UPDATE_REGISTRY_BASE_URL_ENV = "LETTA_UPDATE_REGISTRY_BASE_URL", UPDATE_INSTALL_REGISTRY_URL_ENV = "LETTA_UPDATE_INSTALL_REGISTRY_URL", DESKTOP_MANAGED_ENV = "LETTA_CODE_DESKTOP_MANAGED", INSTALL_ARG_PREFIX, VALID_PACKAGE_MANAGERS, NPM_PREFIX_TIMEOUT_MS = 5000, UPDATE_INSTALL_TIMEOUT_MS = 60000;
179884
+ var execFileAsync5, DEBUG, DEFAULT_UPDATE_PACKAGE_NAME = "@letta-ai/letta-code", DEFAULT_UPDATE_REGISTRY_BASE_URL = "https://registry.npmjs.org", UPDATE_PACKAGE_NAME_ENV = "LETTA_UPDATE_PACKAGE_NAME", UPDATE_REGISTRY_BASE_URL_ENV = "LETTA_UPDATE_REGISTRY_BASE_URL", UPDATE_INSTALL_REGISTRY_URL_ENV = "LETTA_UPDATE_INSTALL_REGISTRY_URL", DESKTOP_MANAGED_ENV = "LETTA_CODE_DESKTOP_MANAGED", INSTALL_ARG_PREFIX, VALID_PACKAGE_MANAGERS, NPM_PREFIX_TIMEOUT_MS = 5000, UPDATE_INSTALL_TIMEOUT_MS = 60000;
179841
179885
  var init_auto_update = __esm(() => {
179842
179886
  init_error_reporting();
179843
179887
  init_version();
179844
- execFileAsync4 = promisify7(execFile7);
179888
+ execFileAsync5 = promisify8(execFile8);
179845
179889
  DEBUG = process.env.LETTA_DEBUG_AUTOUPDATE === "1";
179846
179890
  INSTALL_ARG_PREFIX = {
179847
179891
  npm: ["install", "-g"],
@@ -181216,7 +181260,7 @@ __export(exports_transcription, {
181216
181260
  isTranscriptionConfigured: () => isTranscriptionConfigured
181217
181261
  });
181218
181262
  import { execFileSync as execFileSync4 } from "node:child_process";
181219
- import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync22, rmSync as rmSync8 } from "node:fs";
181263
+ import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync22, rmSync as rmSync9 } from "node:fs";
181220
181264
  import { tmpdir as tmpdir8 } from "node:os";
181221
181265
  import { basename as basename12, extname as extname5, join as join43 } from "node:path";
181222
181266
  function audioMimeTypeForPath(localPath) {
@@ -181261,12 +181305,12 @@ function prepareOpenAiTranscriptionFile(localPath) {
181261
181305
  convertedPath
181262
181306
  ], { stdio: "ignore", timeout: TRANSCRIPTION_TIMEOUT_MS });
181263
181307
  } catch (error4) {
181264
- rmSync8(tempDir, { recursive: true, force: true });
181308
+ rmSync9(tempDir, { recursive: true, force: true });
181265
181309
  throw new Error(`Unsupported audio format ${extname5(localPath).replace(/^\./, "") || "unknown"}; ffmpeg conversion failed. ffmpeg is required to transcribe this audio format; install ffmpeg on the channel listener machine. ${error4 instanceof Error ? error4.message : String(error4)}`);
181266
181310
  }
181267
181311
  return {
181268
181312
  localPath: convertedPath,
181269
- cleanup: () => rmSync8(tempDir, { recursive: true, force: true })
181313
+ cleanup: () => rmSync9(tempDir, { recursive: true, force: true })
181270
181314
  };
181271
181315
  }
181272
181316
  function isTranscriptionConfigured() {
@@ -187270,6 +187314,11 @@ function createSlackAdapter(config) {
187270
187314
  throw error4;
187271
187315
  }
187272
187316
  }
187317
+ async function listCustomEmojis() {
187318
+ const client = await ensureWriteClient();
187319
+ const response = await client.emoji.list();
187320
+ return Object.keys(response.emoji ?? {}).sort((left, right) => left.localeCompare(right));
187321
+ }
187273
187322
  async function downloadAttachment(params) {
187274
187323
  const slackApp = await ensureApp();
187275
187324
  return await downloadSlackAttachmentById({
@@ -187485,6 +187534,7 @@ function createSlackAdapter(config) {
187485
187534
  await Promise.all(status.getUniqueSources(event.sources).map((source) => status.activate(source, SLACK_ASSISTANT_WORKING_STATUS, activity)));
187486
187535
  },
187487
187536
  sendMessage,
187537
+ listCustomEmojis,
187488
187538
  downloadAttachment,
187489
187539
  sendDirectReply,
187490
187540
  handleControlRequestEvent,
@@ -187632,10 +187682,27 @@ async function reactInSlack(context3) {
187632
187682
  });
187633
187683
  return request.remove ? `Reaction removed on slack (message_id: ${result2.messageId})` : `Reaction added on slack (message_id: ${result2.messageId})`;
187634
187684
  }
187685
+ async function listSlackCustomEmojis(context3) {
187686
+ const listCustomEmojis = context3.adapter.listCustomEmojis;
187687
+ if (typeof listCustomEmojis !== "function") {
187688
+ return "Error: Running Slack adapter does not support custom emoji discovery.";
187689
+ }
187690
+ try {
187691
+ const names2 = await listCustomEmojis.call(context3.adapter);
187692
+ if (names2.length === 0) {
187693
+ return "This Slack workspace has no custom emoji available to the app.";
187694
+ }
187695
+ return `Available custom Slack emoji (${names2.length}): ${names2.map((name) => `:${name}:`).join(", ")}`;
187696
+ } catch (error4) {
187697
+ const message = error4 instanceof Error ? error4.message : String(error4);
187698
+ return `Error: Could not list custom Slack emoji. ${message}`;
187699
+ }
187700
+ }
187635
187701
  function createSlackMessageActionAdapter(options = {}) {
187636
187702
  const actions = [
187637
187703
  "send",
187638
187704
  ...options.react ? ["react"] : [],
187705
+ ...options.listCustomEmojis ? ["list-custom-emojis"] : [],
187639
187706
  ...options.uploadFile ? ["upload-file"] : [],
187640
187707
  ...options.downloadFile ? ["download-file"] : []
187641
187708
  ];
@@ -187674,6 +187741,8 @@ function createSlackMessageActionAdapter(options = {}) {
187674
187741
  return await sendSlackMessage(context3);
187675
187742
  case "react":
187676
187743
  return options.react ? await reactInSlack(context3) : 'Error: Action "react" is not supported on slack.';
187744
+ case "list-custom-emojis":
187745
+ return options.listCustomEmojis ? await listSlackCustomEmojis(context3) : 'Error: Action "list-custom-emojis" is not supported on slack.';
187677
187746
  case "download-file":
187678
187747
  return options.downloadFile ? await options.downloadFile(context3) : 'Error: Action "download-file" is not supported on slack.';
187679
187748
  default:
@@ -188064,6 +188133,7 @@ var init_message_actions2 = __esm(() => {
188064
188133
  init_target_resolution();
188065
188134
  slackMessageActions = createSlackMessageActionAdapter({
188066
188135
  react: true,
188136
+ listCustomEmojis: true,
188067
188137
  uploadFile: true,
188068
188138
  downloadFile: downloadSlackFile,
188069
188139
  resolveMessageTarget: async (params) => await resolveSlackMessageTarget({
@@ -188101,7 +188171,7 @@ async function runSlackSetup() {
188101
188171
  console.log(` 5. Add the /cancel slash command if you want Slack-native cancellation
188102
188172
  `);
188103
188173
  console.log("Recommended bot token scopes:");
188104
- console.log(" app_mentions:read, channels:history, chat:write, commands, groups:history, im:history, users:read");
188174
+ console.log(" app_mentions:read, channels:history, chat:write, commands, emoji:read, groups:history, im:history, users:read");
188105
188175
  console.log(` reactions:read, reactions:write, files:read, files:write
188106
188176
  `);
188107
188177
  await ensureSlackRuntimeInstalled();
@@ -190872,7 +190942,7 @@ var init_state = __esm(() => {
190872
190942
  });
190873
190943
 
190874
190944
  // src/channels/whatsapp/session.ts
190875
- import { mkdirSync as mkdirSync24, readFileSync as readFileSync25, rmSync as rmSync9, writeFileSync as writeFileSync18 } from "node:fs";
190945
+ import { mkdirSync as mkdirSync24, readFileSync as readFileSync25, rmSync as rmSync10, writeFileSync as writeFileSync18 } from "node:fs";
190876
190946
  import { homedir as homedir26 } from "node:os";
190877
190947
  import { join as join48 } from "node:path";
190878
190948
  function shouldDropLine(line) {
@@ -190984,7 +191054,7 @@ function acquireWhatsAppSessionLease(accountId, options = {}) {
190984
191054
  if (activeSessionLeases.get(accountId) === lockDir) {
190985
191055
  activeSessionLeases.delete(accountId);
190986
191056
  }
190987
- rmSync9(lockDir, { recursive: true, force: true });
191057
+ rmSync10(lockDir, { recursive: true, force: true });
190988
191058
  }
190989
191059
  };
190990
191060
  } catch (error4) {
@@ -190993,7 +191063,7 @@ function acquireWhatsAppSessionLease(accountId, options = {}) {
190993
191063
  }
190994
191064
  const owner = readLeaseOwner(lockDir);
190995
191065
  if (owner.pid && !isProcessAlive(owner.pid)) {
190996
- rmSync9(lockDir, { recursive: true, force: true });
191066
+ rmSync10(lockDir, { recursive: true, force: true });
190997
191067
  continue;
190998
191068
  }
190999
191069
  const ownerLabel = owner.pid ? `PID ${owner.pid}${owner.command ? ` (${owner.command})` : ""}` : "an unknown live process";
@@ -199871,26 +199941,26 @@ function defineLazyProperty(object3, propertyName, valueGetter) {
199871
199941
  }
199872
199942
 
199873
199943
  // node_modules/default-browser-id/index.js
199874
- import { promisify as promisify8 } from "node:util";
199944
+ import { promisify as promisify9 } from "node:util";
199875
199945
  import process15 from "node:process";
199876
- import { execFile as execFile8 } from "node:child_process";
199946
+ import { execFile as execFile9 } from "node:child_process";
199877
199947
  async function defaultBrowserId() {
199878
199948
  if (process15.platform !== "darwin") {
199879
199949
  throw new Error("macOS only");
199880
199950
  }
199881
- const { stdout } = await execFileAsync5("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
199951
+ const { stdout } = await execFileAsync6("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
199882
199952
  const match3 = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
199883
199953
  return match3?.groups.id ?? "com.apple.Safari";
199884
199954
  }
199885
- var execFileAsync5;
199955
+ var execFileAsync6;
199886
199956
  var init_default_browser_id = __esm(() => {
199887
- execFileAsync5 = promisify8(execFile8);
199957
+ execFileAsync6 = promisify9(execFile9);
199888
199958
  });
199889
199959
 
199890
199960
  // node_modules/run-applescript/index.js
199891
199961
  import process16 from "node:process";
199892
- import { promisify as promisify9 } from "node:util";
199893
- import { execFile as execFile9, execFileSync as execFileSync6 } from "node:child_process";
199962
+ import { promisify as promisify10 } from "node:util";
199963
+ import { execFile as execFile10, execFileSync as execFileSync6 } from "node:child_process";
199894
199964
  async function runAppleScript(script4, { humanReadableOutput = true, signal } = {}) {
199895
199965
  if (process16.platform !== "darwin") {
199896
199966
  throw new Error("macOS only");
@@ -199900,12 +199970,12 @@ async function runAppleScript(script4, { humanReadableOutput = true, signal } =
199900
199970
  if (signal) {
199901
199971
  execOptions.signal = signal;
199902
199972
  }
199903
- const { stdout } = await execFileAsync6("osascript", ["-e", script4, outputArguments], execOptions);
199973
+ const { stdout } = await execFileAsync7("osascript", ["-e", script4, outputArguments], execOptions);
199904
199974
  return stdout.trim();
199905
199975
  }
199906
- var execFileAsync6;
199976
+ var execFileAsync7;
199907
199977
  var init_run_applescript = __esm(() => {
199908
- execFileAsync6 = promisify9(execFile9);
199978
+ execFileAsync7 = promisify10(execFile10);
199909
199979
  });
199910
199980
 
199911
199981
  // node_modules/bundle-name/index.js
@@ -199918,9 +199988,9 @@ var init_bundle_name = __esm(() => {
199918
199988
  });
199919
199989
 
199920
199990
  // node_modules/default-browser/windows.js
199921
- import { promisify as promisify10 } from "node:util";
199922
- import { execFile as execFile10 } from "node:child_process";
199923
- async function defaultBrowser(_execFileAsync = execFileAsync7) {
199991
+ import { promisify as promisify11 } from "node:util";
199992
+ import { execFile as execFile11 } from "node:child_process";
199993
+ async function defaultBrowser(_execFileAsync = execFileAsync8) {
199924
199994
  const { stdout } = await _execFileAsync("reg", [
199925
199995
  "QUERY",
199926
199996
  " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
@@ -199938,9 +200008,9 @@ async function defaultBrowser(_execFileAsync = execFileAsync7) {
199938
200008
  }
199939
200009
  return browser;
199940
200010
  }
199941
- var execFileAsync7, windowsBrowserProgIds, UnknownBrowserError;
200011
+ var execFileAsync8, windowsBrowserProgIds, UnknownBrowserError;
199942
200012
  var init_windows = __esm(() => {
199943
- execFileAsync7 = promisify10(execFile10);
200013
+ execFileAsync8 = promisify11(execFile11);
199944
200014
  windowsBrowserProgIds = {
199945
200015
  AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
199946
200016
  MSEdgeDHTML: { name: "Edge", id: "com.microsoft.edge" },
@@ -199957,9 +200027,9 @@ var init_windows = __esm(() => {
199957
200027
  });
199958
200028
 
199959
200029
  // node_modules/default-browser/index.js
199960
- import { promisify as promisify11 } from "node:util";
200030
+ import { promisify as promisify12 } from "node:util";
199961
200031
  import process17 from "node:process";
199962
- import { execFile as execFile11 } from "node:child_process";
200032
+ import { execFile as execFile12 } from "node:child_process";
199963
200033
  async function defaultBrowser2() {
199964
200034
  if (process17.platform === "darwin") {
199965
200035
  const id2 = await defaultBrowserId();
@@ -199967,7 +200037,7 @@ async function defaultBrowser2() {
199967
200037
  return { name, id: id2 };
199968
200038
  }
199969
200039
  if (process17.platform === "linux") {
199970
- const { stdout } = await execFileAsync8("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
200040
+ const { stdout } = await execFileAsync9("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
199971
200041
  const id2 = stdout.trim();
199972
200042
  const name = titleize(id2.replace(/.desktop$/, "").replace("-", " "));
199973
200043
  return { name, id: id2 };
@@ -199977,12 +200047,12 @@ async function defaultBrowser2() {
199977
200047
  }
199978
200048
  throw new Error("Only macOS, Linux, and Windows are supported");
199979
200049
  }
199980
- var execFileAsync8, titleize = (string3) => string3.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x4) => x4.toUpperCase());
200050
+ var execFileAsync9, titleize = (string3) => string3.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x4) => x4.toUpperCase());
199981
200051
  var init_default_browser = __esm(() => {
199982
200052
  init_default_browser_id();
199983
200053
  init_bundle_name();
199984
200054
  init_windows();
199985
- execFileAsync8 = promisify11(execFile11);
200055
+ execFileAsync9 = promisify12(execFile12);
199986
200056
  });
199987
200057
 
199988
200058
  // node_modules/open/index.js
@@ -199996,14 +200066,14 @@ import process18 from "node:process";
199996
200066
  import { Buffer as Buffer6 } from "node:buffer";
199997
200067
  import path31 from "node:path";
199998
200068
  import { fileURLToPath as fileURLToPath8 } from "node:url";
199999
- import { promisify as promisify12 } from "node:util";
200069
+ import { promisify as promisify13 } from "node:util";
200000
200070
  import childProcess from "node:child_process";
200001
200071
  import fs13, { constants as fsConstants2 } from "node:fs/promises";
200002
200072
  async function getWindowsDefaultBrowserFromWsl() {
200003
200073
  const powershellPath = await powerShellPath();
200004
200074
  const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
200005
200075
  const encodedCommand = Buffer6.from(rawCommand, "utf16le").toString("base64");
200006
- const { stdout } = await execFile12(powershellPath, [
200076
+ const { stdout } = await execFile13(powershellPath, [
200007
200077
  "-NoProfile",
200008
200078
  "-NonInteractive",
200009
200079
  "-ExecutionPolicy",
@@ -200039,7 +200109,7 @@ function detectPlatformBinary({ [platform6]: platformBinary }, { wsl }) {
200039
200109
  }
200040
200110
  return detectArchBinary(platformBinary);
200041
200111
  }
200042
- var execFile12, __dirname2, localXdgOpenPath, platform6, arch3, pTryEach = async (array2, mapper) => {
200112
+ var execFile13, __dirname2, localXdgOpenPath, platform6, arch3, pTryEach = async (array2, mapper) => {
200043
200113
  let latestError;
200044
200114
  for (const item of array2) {
200045
200115
  try {
@@ -200218,7 +200288,7 @@ var init_open = __esm(() => {
200218
200288
  init_wsl_utils();
200219
200289
  init_default_browser();
200220
200290
  init_is_inside_container();
200221
- execFile12 = promisify12(childProcess.execFile);
200291
+ execFile13 = promisify13(childProcess.execFile);
200222
200292
  __dirname2 = path31.dirname(fileURLToPath8(import.meta.url));
200223
200293
  localXdgOpenPath = path31.join(__dirname2, "xdg-open");
200224
200294
  ({ platform: platform6, arch: arch3 } = process18);
@@ -207663,7 +207733,7 @@ import {
207663
207733
  mkdirSync as mkdirSync28,
207664
207734
  readFileSync as readFileSync30,
207665
207735
  renameSync as renameSync6,
207666
- rmSync as rmSync10,
207736
+ rmSync as rmSync11,
207667
207737
  statSync as statSync14,
207668
207738
  writeFileSync as writeFileSync21
207669
207739
  } from "node:fs";
@@ -207809,7 +207879,7 @@ function isLockStale(lockDir) {
207809
207879
  }
207810
207880
  function stealLock(lockDir) {
207811
207881
  try {
207812
- rmSync10(lockDir, { recursive: true, force: true });
207882
+ rmSync11(lockDir, { recursive: true, force: true });
207813
207883
  } catch {}
207814
207884
  }
207815
207885
  function acquireLock() {
@@ -207831,7 +207901,7 @@ function acquireLock() {
207831
207901
  try {
207832
207902
  const current = readLockOwner(lockDir);
207833
207903
  if (current && current.token === token2) {
207834
- rmSync10(lockDir, { recursive: true, force: true });
207904
+ rmSync11(lockDir, { recursive: true, force: true });
207835
207905
  }
207836
207906
  } catch {}
207837
207907
  }
@@ -208336,11 +208406,12 @@ function safeAppendCronRunLogForTask(task2, entry) {
208336
208406
  try {
208337
208407
  appendCronRunLogForTask(task2, entry);
208338
208408
  } catch (err) {
208339
- console.error(`[Cron] Error writing run log for task ${task2.id}:`, err instanceof Error ? err.message : err);
208409
+ debugWarn("Cron", `Error writing run log for task ${task2.id}:`, err instanceof Error ? err.message : err);
208340
208410
  }
208341
208411
  }
208342
208412
  var DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2000000, DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2000;
208343
208413
  var init_run_log = __esm(() => {
208414
+ init_debug();
208344
208415
  init_cron_file();
208345
208416
  });
208346
208417
 
@@ -208877,7 +208948,7 @@ function scheduleQueuePump(runtime, socket, opts, processQueuedTurn) {
208877
208948
  error: error4,
208878
208949
  context: "listener_queue_pump"
208879
208950
  });
208880
- console.error("[Listen] Error in queue pump:", error4);
208951
+ debugWarn("Listen", "Error in queue pump:", error4);
208881
208952
  emitListenerStatus(runtime.listener, opts.onStatusChange, opts.connectionId);
208882
208953
  evictConversationRuntimeIfIdle(runtime);
208883
208954
  });
@@ -208885,6 +208956,7 @@ function scheduleQueuePump(runtime, socket, opts, processQueuedTurn) {
208885
208956
  var init_queue = __esm(async () => {
208886
208957
  init_queue_runtime();
208887
208958
  init_error_reporting();
208959
+ init_debug();
208888
208960
  init_protocol_outbound();
208889
208961
  init_runtime();
208890
208962
  init_transport();
@@ -209139,6 +209211,13 @@ function formatCronPrompt(task2, timing2) {
209139
209211
  var init_prompt = () => {};
209140
209212
 
209141
209213
  // src/cron/scheduler.ts
209214
+ function logScheduler(opts, message) {
209215
+ if (opts.onLog) {
209216
+ opts.onLog(`[Cron] ${message}`);
209217
+ return;
209218
+ }
209219
+ debugWarn("Cron", message);
209220
+ }
209142
209221
  function minuteKey(date) {
209143
209222
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}T${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
209144
209223
  }
@@ -209403,7 +209482,7 @@ async function runCronTaskNow(taskId) {
209403
209482
  }
209404
209483
  function tick2(state, socket, opts, processQueuedTurn) {
209405
209484
  if (!verifySchedulerLease(state.token)) {
209406
- console.error("[Cron] Scheduler lease lost. Stopping.");
209485
+ logScheduler(opts, "Scheduler lease lost. Stopping.");
209407
209486
  stopScheduler();
209408
209487
  return;
209409
209488
  }
@@ -209440,7 +209519,7 @@ function tick2(state, socket, opts, processQueuedTurn) {
209440
209519
  return;
209441
209520
  const schedulerNow = new Date;
209442
209521
  fireCronTask(freshTask, { intendedOccurrence, schedulerNow }, socket, opts, processQueuedTurn, "automatic").catch((err) => {
209443
- console.error(`[Cron] Error firing task ${taskId}:`, err);
209522
+ logScheduler(opts, `Error firing task ${taskId}: ${err instanceof Error ? err.message : String(err)}`);
209444
209523
  setLastRunOutcome(freshTask.id, {
209445
209524
  outcome: "failed",
209446
209525
  reason: "scheduler_error",
@@ -209478,12 +209557,12 @@ function startScheduler(socket, opts, processQueuedTurn, _retryCount = 0) {
209478
209557
  token2 = claimSchedulerLease();
209479
209558
  } catch (err) {
209480
209559
  if (_retryCount < MAX_LEASE_RETRIES) {
209481
- console.warn(`[Cron] Could not claim scheduler lease (attempt ${_retryCount + 1}/${MAX_LEASE_RETRIES + 1}): ${err instanceof Error ? err.message : err}`);
209482
- console.warn("[Cron] Cron tasks will not fire until the scheduler starts. Retrying...");
209560
+ logScheduler(opts, `Could not claim scheduler lease (attempt ${_retryCount + 1}/${MAX_LEASE_RETRIES + 1}): ${err instanceof Error ? err.message : err}`);
209561
+ logScheduler(opts, "Cron tasks will not fire until the scheduler starts. Retrying...");
209483
209562
  setTimeout(() => startScheduler(socket, opts, processQueuedTurn, _retryCount + 1), LEASE_RETRY_MS);
209484
209563
  } else {
209485
- console.error(`[Cron] Failed to claim scheduler lease after ${MAX_LEASE_RETRIES + 1} attempts. Cron tasks will not fire.`);
209486
- console.error("[Cron] Another process may hold the lease. Restart Letta Code to retry.");
209564
+ logScheduler(opts, `Failed to claim scheduler lease after ${MAX_LEASE_RETRIES + 1} attempts. Cron tasks will not fire.`);
209565
+ logScheduler(opts, "Another process may hold the lease. Restart Letta Code to retry.");
209487
209566
  }
209488
209567
  return;
209489
209568
  }
@@ -209512,7 +209591,7 @@ function startScheduler(socket, opts, processQueuedTurn, _retryCount = 0) {
209512
209591
  state.lastMtime = 0;
209513
209592
  }
209514
209593
  } catch (err) {
209515
- console.error("[Cron] GC error:", err);
209594
+ logScheduler(opts, `GC error: ${err instanceof Error ? err.message : String(err)}`);
209516
209595
  }
209517
209596
  }, GC_INTERVAL_MS);
209518
209597
  schedulerState = state;
@@ -209535,6 +209614,7 @@ function stopScheduler() {
209535
209614
  var schedulerState = null, listenerFireContext = null, TICK_INTERVAL_MS = 60000, GC_INTERVAL_MS, LEASE_RETRY_MS = 30000, MAX_LEASE_RETRIES = 3, NEW_CONVERSATION_TARGET = "new";
209536
209615
  var init_scheduler = __esm(async () => {
209537
209616
  init_backend2();
209617
+ init_debug();
209538
209618
  init_connection();
209539
209619
  init_protocol_outbound();
209540
209620
  init_runtime();
@@ -215283,7 +215363,7 @@ async function awaitMemoryPushBounded(commandName, agentId, memoryRoot) {
215283
215363
  });
215284
215364
  const warnOnFailure = (result2) => {
215285
215365
  if (result2.status === "push_failed" || result2.status === "conflict") {
215286
- console.warn(`[${commandName}] push failed for ${agentId}: ${result2.summary}`);
215366
+ warnMemoryCommand(`[${commandName}] push failed for ${agentId}: ${result2.summary}`);
215287
215367
  }
215288
215368
  };
215289
215369
  let timer;
@@ -215293,15 +215373,15 @@ async function awaitMemoryPushBounded(commandName, agentId, memoryRoot) {
215293
215373
  try {
215294
215374
  const result2 = await Promise.race([syncPromise, capPromise]);
215295
215375
  if (result2 === "timed_out") {
215296
- console.warn(`[${commandName}] push still in flight after ${MEMORY_PUSH_AWAIT_CAP_MS}ms for ${agentId}; responding now, push continues in background`);
215376
+ warnMemoryCommand(`[${commandName}] push still in flight after ${MEMORY_PUSH_AWAIT_CAP_MS}ms for ${agentId}; responding now, push continues in background`);
215297
215377
  syncPromise.then(warnOnFailure).catch((err) => {
215298
- console.warn(`[${commandName}] background push failed for ${agentId}:`, err instanceof Error ? err.message : err);
215378
+ warnMemoryCommand(`[${commandName}] background push failed for ${agentId}:`, err instanceof Error ? err.message : err);
215299
215379
  });
215300
215380
  return;
215301
215381
  }
215302
215382
  warnOnFailure(result2);
215303
215383
  } catch (err) {
215304
- console.warn(`[${commandName}] push failed for ${agentId}:`, err instanceof Error ? err.message : err);
215384
+ warnMemoryCommand(`[${commandName}] push failed for ${agentId}:`, err instanceof Error ? err.message : err);
215305
215385
  } finally {
215306
215386
  if (timer)
215307
215387
  clearTimeout(timer);
@@ -215526,15 +215606,15 @@ function handleMemoryProtocolCommand(parsed, context3) {
215526
215606
  runDetachedListenerTask("memory_history", async () => {
215527
215607
  const { getScopedMemoryFilesystemRoot: getScopedMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
215528
215608
  const { execFile: execFileCb4 } = await import("node:child_process");
215529
- const { promisify: promisify13 } = await import("node:util");
215530
- const execFileAsync9 = promisify13(execFileCb4);
215609
+ const { promisify: promisify14 } = await import("node:util");
215610
+ const execFileAsync10 = promisify14(execFileCb4);
215531
215611
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
215532
215612
  const limit3 = parsed.limit ?? 50;
215533
215613
  const gitArgs = ["log", `--max-count=${limit3}`, "--format=%H|%s|%aI|%an"];
215534
215614
  if (parsed.file_path) {
215535
215615
  gitArgs.push("--", parsed.file_path);
215536
215616
  }
215537
- const { stdout } = await execFileAsync9("git", gitArgs, {
215617
+ const { stdout } = await execFileAsync10("git", gitArgs, {
215538
215618
  cwd: memoryRoot,
215539
215619
  timeout: 1e4
215540
215620
  });
@@ -215562,11 +215642,11 @@ function handleMemoryProtocolCommand(parsed, context3) {
215562
215642
  runDetachedListenerTask("memory_file_at_ref", async () => {
215563
215643
  const { getScopedMemoryFilesystemRoot: getScopedMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
215564
215644
  const { execFile: execFileCb4 } = await import("node:child_process");
215565
- const { promisify: promisify13 } = await import("node:util");
215566
- const execFileAsync9 = promisify13(execFileCb4);
215645
+ const { promisify: promisify14 } = await import("node:util");
215646
+ const execFileAsync10 = promisify14(execFileCb4);
215567
215647
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
215568
215648
  try {
215569
- const { stdout } = await execFileAsync9("git", ["show", `${parsed.ref}:${parsed.file_path}`], { cwd: memoryRoot, timeout: 1e4 });
215649
+ const { stdout } = await execFileAsync10("git", ["show", `${parsed.ref}:${parsed.file_path}`], { cwd: memoryRoot, timeout: 1e4 });
215570
215650
  safeSocketSend(socket, {
215571
215651
  type: "memory_file_at_ref_response",
215572
215652
  request_id: parsed.request_id,
@@ -215593,11 +215673,11 @@ function handleMemoryProtocolCommand(parsed, context3) {
215593
215673
  runDetachedListenerTask("memory_commit_diff", async () => {
215594
215674
  const { getScopedMemoryFilesystemRoot: getScopedMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
215595
215675
  const { execFile: execFileCb4 } = await import("node:child_process");
215596
- const { promisify: promisify13 } = await import("node:util");
215597
- const execFileAsync9 = promisify13(execFileCb4);
215676
+ const { promisify: promisify14 } = await import("node:util");
215677
+ const execFileAsync10 = promisify14(execFileCb4);
215598
215678
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
215599
215679
  try {
215600
- const { stdout } = await execFileAsync9("git", ["show", parsed.sha, "--format=", "--no-color"], { cwd: memoryRoot, timeout: 1e4 });
215680
+ const { stdout } = await execFileAsync10("git", ["show", parsed.sha, "--format=", "--no-color"], { cwd: memoryRoot, timeout: 1e4 });
215601
215681
  safeSocketSend(socket, {
215602
215682
  type: "memory_commit_diff_response",
215603
215683
  request_id: parsed.request_id,
@@ -215679,7 +215759,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
215679
215759
  }, "listener_read_memory_file_send_failed", "listener_read_memory_file");
215680
215760
  } catch (err) {
215681
215761
  trackListenerError("listener_read_memory_file_failed", err, "listener_memory_read");
215682
- console.error(`[Listen] read_memory_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
215762
+ warnMemoryCommand(`[Listen] read_memory_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
215683
215763
  sendFailure(err instanceof Error ? err.message : "Failed to read memory file");
215684
215764
  }
215685
215765
  });
@@ -215778,7 +215858,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
215778
215858
  }, "listener_write_memory_file_send_failed", "listener_write_memory_file");
215779
215859
  } catch (err) {
215780
215860
  trackListenerError("listener_write_memory_file_failed", err, "listener_memory_write");
215781
- console.error(`[Listen] write_memory_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
215861
+ warnMemoryCommand(`[Listen] write_memory_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
215782
215862
  sendFailure(err instanceof Error ? err.message : "Failed to write memory file");
215783
215863
  }
215784
215864
  });
@@ -215891,7 +215971,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
215891
215971
  }, "listener_delete_memory_file_send_failed", "listener_delete_memory_file");
215892
215972
  } catch (err) {
215893
215973
  trackListenerError("listener_delete_memory_file_failed", err, "listener_memory_delete");
215894
- console.error(`[Listen] delete_memory_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
215974
+ warnMemoryCommand(`[Listen] delete_memory_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
215895
215975
  sendFailure(err instanceof Error ? err.message : "Failed to delete memory file");
215896
215976
  }
215897
215977
  });
@@ -215899,10 +215979,12 @@ function handleMemoryProtocolCommand(parsed, context3) {
215899
215979
  }
215900
215980
  return false;
215901
215981
  }
215902
- var WIKI_LINK_REGEX, IMAGE_MIME_BY_EXTENSION, MEMORY_PUSH_AWAIT_CAP_MS = 8000;
215982
+ var warnMemoryCommand, WIKI_LINK_REGEX, IMAGE_MIME_BY_EXTENSION, MEMORY_PUSH_AWAIT_CAP_MS = 8000;
215903
215983
  var init_memory6 = __esm(() => {
215904
215984
  init_error_reporting();
215985
+ init_debug();
215905
215986
  init_protocol_inbound();
215987
+ warnMemoryCommand = debugWarn.bind(null, "memory-commands");
215906
215988
  WIKI_LINK_REGEX = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
215907
215989
  IMAGE_MIME_BY_EXTENSION = {
215908
215990
  ".gif": "image/gif",
@@ -300571,7 +300653,7 @@ ${lanes.join(`
300571
300653
  if (!links2.hasReportedStatementInAmbientContext) {
300572
300654
  return links2.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
300573
300655
  }
300574
- } else {}
300656
+ }
300575
300657
  }
300576
300658
  return false;
300577
300659
  }
@@ -310035,7 +310117,7 @@ ${lanes.join(`
310035
310117
  ], 2));
310036
310118
  setParentRecursive(requireStatement, false);
310037
310119
  statements = insertStatementAfterCustomPrologue(statements.slice(), requireStatement);
310038
- } else {}
310120
+ }
310039
310121
  }
310040
310122
  }
310041
310123
  if (statements !== visited2.statements) {
@@ -385584,7 +385666,7 @@ import {
385584
385666
  existsSync as existsSync47,
385585
385667
  mkdirSync as mkdirSync33,
385586
385668
  readFileSync as readFileSync35,
385587
- rmSync as rmSync11,
385669
+ rmSync as rmSync12,
385588
385670
  writeFileSync as writeFileSync25
385589
385671
  } from "node:fs";
385590
385672
  import path37 from "node:path";
@@ -386187,7 +386269,7 @@ function removeManagedModPackage(params) {
386187
386269
  assertSafePackageRemovalRoot(match3.metadata);
386188
386270
  registry.packagesValue.splice(match3.index, 1);
386189
386271
  writePackageRegistry(registry.registryPath, registry.registry);
386190
- rmSync11(match3.metadata.packageRoot, { force: true, recursive: true });
386272
+ rmSync12(match3.metadata.packageRoot, { force: true, recursive: true });
386191
386273
  return {
386192
386274
  package: mutationItem(match3.metadata, match3.index, match3.metadata.enabled),
386193
386275
  registryPath: registry.registryPath,
@@ -387701,7 +387783,7 @@ async function syncMemfsForAgent(agentId) {
387701
387783
  debugLog("memfs-sync", `Agent ${agentId} does not have memfs tag (self-hosted), skipping`);
387702
387784
  return;
387703
387785
  }
387704
- console.warn(`[memfs-sync] Agent ${agentId} is missing the memfs tag on Letta Cloud — repairing (auto-enabling memfs).`);
387786
+ debugWarn("memfs-sync", `Agent ${agentId} is missing the memfs tag on Letta Cloud — repairing (auto-enabling memfs).`);
387705
387787
  await applyMemfsFlags2(agentId, true, {
387706
387788
  pullOnExistingRepo: true,
387707
387789
  agentTags: agent.tags ?? []
@@ -390486,7 +390568,7 @@ function markAsFinished(b3, id2) {
390486
390568
  if (updatedLine.kind === "assistant" && "text" in updatedLine && updatedLine.text) {
390487
390569
  b3.lastAssistantMessage = updatedLine.text;
390488
390570
  }
390489
- } else {}
390571
+ }
390490
390572
  }
390491
390573
  function handleOtidTransition(b3, newOtid) {
390492
390574
  if (b3.lastOtid && b3.lastOtid !== newOtid) {
@@ -390504,7 +390586,7 @@ function markCurrentLineAsFinished(b3) {
390504
390586
  const prev = b3.byId.get(b3.lastOtid);
390505
390587
  if (prev && (prev.kind === "assistant" || prev.kind === "reasoning")) {
390506
390588
  markAsFinished(b3, b3.lastOtid);
390507
- } else {}
390589
+ }
390508
390590
  }
390509
390591
  function markIncompleteToolsAsCancelled(b3, setInterruptedFlag = true, reason = "internal_cancel", skipMarkCurrentLine = false) {
390510
390592
  if (setInterruptedFlag) {
@@ -397886,12 +397968,12 @@ function rowToolCalls(row, index, diagnostics2) {
397886
397968
  }
397887
397969
  return calls;
397888
397970
  }
397889
- function contentText2(content) {
397971
+ function contentText(content) {
397890
397972
  if (typeof content === "string") {
397891
397973
  if (content.startsWith(CONTENT_JSON_PREFIX)) {
397892
397974
  const encoded = content.slice(CONTENT_JSON_PREFIX.length);
397893
397975
  try {
397894
- return contentText2(JSON.parse(encoded));
397976
+ return contentText(JSON.parse(encoded));
397895
397977
  } catch {
397896
397978
  return encoded;
397897
397979
  }
@@ -397977,7 +398059,7 @@ var init_hermes = __esm(() => {
397977
398059
  });
397978
398060
  };
397979
398061
  if (row.role === "user") {
397980
- const content = contentText2(row.content);
398062
+ const content = contentText(row.content);
397981
398063
  if (content) {
397982
398064
  emit({
397983
398065
  type: "message",
@@ -397997,7 +398079,7 @@ var init_hermes = __esm(() => {
397997
398079
  ...timestamp ? { timestamp } : {}
397998
398080
  });
397999
398081
  }
398000
- const content = contentText2(row.content);
398082
+ const content = contentText(row.content);
398001
398083
  if (content) {
398002
398084
  emit({
398003
398085
  type: "message",
@@ -398020,7 +398102,7 @@ var init_hermes = __esm(() => {
398020
398102
  if (row.role === "tool") {
398021
398103
  emit({
398022
398104
  type: "tool_result",
398023
- content: contentText2(row.content),
398105
+ content: contentText(row.content),
398024
398106
  ...typeof row.tool_call_id === "string" && row.tool_call_id ? { callId: row.tool_call_id } : {},
398025
398107
  ...timestamp ? { timestamp } : {}
398026
398108
  });
@@ -401381,11 +401463,11 @@ import { randomUUID as randomUUID27 } from "node:crypto";
401381
401463
  import { existsSync as existsSync53 } from "node:fs";
401382
401464
  import { mkdir as mkdir13 } from "node:fs/promises";
401383
401465
  import { dirname as dirname28, isAbsolute as isAbsolute26, join as join68, resolve as resolve34 } from "node:path";
401384
- import { promisify as promisify13 } from "node:util";
401466
+ import { promisify as promisify14 } from "node:util";
401385
401467
  async function runGit4(cwd2, args) {
401386
401468
  try {
401387
401469
  const allArgs = [...GIT_DISABLE_COMMIT_SIGNING_ARGS, ...args];
401388
- const { stdout, stderr } = await execFile13("git", allArgs, {
401470
+ const { stdout, stderr } = await execFile14("git", allArgs, {
401389
401471
  cwd: cwd2,
401390
401472
  env: {
401391
401473
  ...process.env,
@@ -401749,11 +401831,11 @@ async function finalizeReflectionMemoryWorktreeImpl(worktree, options) {
401749
401831
  async function finalizeReflectionMemoryWorktree(worktree, options) {
401750
401832
  return await finalizeReflectionMemoryWorktreeImpl(worktree, options);
401751
401833
  }
401752
- var execFile13, GIT_TIMEOUT_MS = 30000, HARNESS_GIT_ENV;
401834
+ var execFile14, GIT_TIMEOUT_MS = 30000, HARNESS_GIT_ENV;
401753
401835
  var init_memory_worktree = __esm(() => {
401754
401836
  init_memory_git_signing();
401755
401837
  init_debug();
401756
- execFile13 = promisify13(execFileCb4);
401838
+ execFile14 = promisify14(execFileCb4);
401757
401839
  HARNESS_GIT_ENV = {
401758
401840
  GIT_AUTHOR_NAME: "Letta Code",
401759
401841
  GIT_AUTHOR_EMAIL: "noreply@letta.com",
@@ -402850,7 +402932,7 @@ function notifyTurnStarted(msg) {
402850
402932
  try {
402851
402933
  hooksByOtid.get(otid)?.onStarted?.();
402852
402934
  } catch (error4) {
402853
- console.error("[Listen V2] Turn observer onStarted failed", error4);
402935
+ debugWarn("Listen V2", "Turn observer onStarted failed", error4);
402854
402936
  }
402855
402937
  }
402856
402938
  }
@@ -402859,12 +402941,13 @@ function notifyTurnFinished(msg) {
402859
402941
  try {
402860
402942
  hooksByOtid.get(otid)?.onFinished();
402861
402943
  } catch (error4) {
402862
- console.error("[Listen V2] Turn observer onFinished failed", error4);
402944
+ debugWarn("Listen V2", "Turn observer onFinished failed", error4);
402863
402945
  }
402864
402946
  }
402865
402947
  }
402866
402948
  var hooksByOtid;
402867
402949
  var init_turn_observers = __esm(() => {
402950
+ init_debug();
402868
402951
  hooksByOtid = new Map;
402869
402952
  });
402870
402953
 
@@ -405504,7 +405587,7 @@ function handleTerminalSpawn(msg, socket, cwd2, connectionId = "legacy") {
405504
405587
  alive = false;
405505
405588
  }
405506
405589
  if (alive) {
405507
- console.log(`[Terminal] Reusing session (age=${Date.now() - existing.spawnedAt}ms), pid=${existing.pid}`);
405590
+ debugLog("Terminal", `Reusing session (age=${Date.now() - existing.spawnedAt}ms), pid=${existing.pid}`);
405508
405591
  sendTerminalMessage(socket, {
405509
405592
  type: "terminal_spawned",
405510
405593
  terminal_id,
@@ -405516,18 +405599,18 @@ function handleTerminalSpawn(msg, socket, cwd2, connectionId = "legacy") {
405516
405599
  }
405517
405600
  killTerminal(terminal_id, connectionId);
405518
405601
  const shell2 = getDefaultShell();
405519
- console.log(`[Terminal] Spawning PTY (${IS_BUN ? "bun" : "node-pty"}): shell=${shell2}, cwd=${cwd2}, cols=${cols}, rows=${rows}`);
405602
+ debugLog("Terminal", `Spawning PTY (${IS_BUN ? "bun" : "node-pty"}): shell=${shell2}, cwd=${cwd2}, cols=${cols}, rows=${rows}`);
405520
405603
  try {
405521
405604
  const session = IS_BUN ? spawnBun(shell2, cwd2, cols, rows, terminal_id, connectionId, socket) : spawnNodePty(shell2, cwd2, cols, rows, terminal_id, connectionId, socket);
405522
405605
  terminals.set(terminalKey, session);
405523
- console.log(`[Terminal] Session stored for terminal_id=${terminal_id}, pid=${session.pid}`);
405606
+ debugLog("Terminal", `Session stored for terminal_id=${terminal_id}, pid=${session.pid}`);
405524
405607
  sendTerminalMessage(socket, {
405525
405608
  type: "terminal_spawned",
405526
405609
  terminal_id,
405527
405610
  pid: session.pid
405528
405611
  });
405529
405612
  } catch (error4) {
405530
- console.error("[Terminal] Failed to spawn PTY:", error4);
405613
+ debugWarn("Terminal", "Failed to spawn PTY:", error4);
405531
405614
  sendTerminalMessage(socket, {
405532
405615
  type: "terminal_exited",
405533
405616
  terminal_id,
@@ -405545,7 +405628,7 @@ function handleTerminalResize(msg, connectionId = "legacy") {
405545
405628
  function handleTerminalKill(msg, connectionId = "legacy") {
405546
405629
  const session = terminals.get(getTerminalKey(connectionId, msg.terminal_id));
405547
405630
  if (session && Date.now() - session.spawnedAt < 2000) {
405548
- console.log(`[Terminal] Ignoring kill for recently spawned session (age=${Date.now() - session.spawnedAt}ms)`);
405631
+ debugLog("Terminal", `Ignoring kill for recently spawned session (age=${Date.now() - session.spawnedAt}ms)`);
405549
405632
  return;
405550
405633
  }
405551
405634
  killTerminal(msg.terminal_id, connectionId);
@@ -405554,7 +405637,7 @@ function killTerminal(terminalId, connectionId) {
405554
405637
  const terminalKey = getTerminalKey(connectionId, terminalId);
405555
405638
  const session = terminals.get(terminalKey);
405556
405639
  if (session) {
405557
- console.log(`[Terminal] killTerminal: terminalId=${terminalId}, pid=${session.pid}`);
405640
+ debugLog("Terminal", `killTerminal: terminalId=${terminalId}, pid=${session.pid}`);
405558
405641
  session.kill();
405559
405642
  terminals.delete(terminalKey);
405560
405643
  }
@@ -405573,6 +405656,7 @@ function killAllTerminals() {
405573
405656
  }
405574
405657
  var IS_BUN, FLUSH_INTERVAL_MS = 16, MAX_BUFFER_BYTES, terminals;
405575
405658
  var init_terminal_handler = __esm(() => {
405659
+ init_debug();
405576
405660
  IS_BUN = typeof Bun !== "undefined";
405577
405661
  MAX_BUFFER_BYTES = 64 * 1024;
405578
405662
  terminals = new Map;
@@ -405682,7 +405766,7 @@ var init_connection_lifecycle = __esm(async () => {
405682
405766
  });
405683
405767
 
405684
405768
  // src/websocket/listener/connection-state-sync.ts
405685
- function emitInitialConnectionState(runtime, transport, connectionId, options = {}) {
405769
+ async function emitInitialConnectionState(runtime, transport, connectionId, options = {}) {
405686
405770
  if (options.emitInitialState === false)
405687
405771
  return;
405688
405772
  const routing = toListenerConnection(connectionId);
@@ -405695,17 +405779,19 @@ function emitInitialConnectionState(runtime, transport, connectionId, options =
405695
405779
  agent_id: conversationRuntime.agentId,
405696
405780
  conversation_id: conversationRuntime.conversationId
405697
405781
  };
405782
+ await refreshDeviceGitContext(conversationRuntime, scope);
405698
405783
  emitDeviceStatusUpdate(transport, conversationRuntime, scope, routing);
405699
405784
  emitLoopStatusUpdate(transport, conversationRuntime, scope, routing);
405700
405785
  }
405701
405786
  }
405702
- function replaySubscribedConnectionState(listener, transport, runtime, scope, forceDeviceStatus) {
405787
+ async function replaySubscribedConnectionState(listener, transport, runtime, scope, options = {}) {
405788
+ await (options.refreshGitContext ?? refreshDeviceGitContext)(listener, scope);
405703
405789
  const connection = findListenerConnectionByTransport(listener, transport);
405704
405790
  if (connection) {
405705
405791
  replayPendingApprovalRequestsToConnection(runtime, connection.id);
405706
405792
  }
405707
405793
  emitStateSync(transport, listener, scope, {
405708
- forceDeviceStatus,
405794
+ forceDeviceStatus: options.forceDeviceStatus,
405709
405795
  ...connection ? { routing: toListenerConnection(connection.id) } : {}
405710
405796
  });
405711
405797
  }
@@ -405716,7 +405802,7 @@ var init_connection_state_sync = __esm(() => {
405716
405802
  });
405717
405803
 
405718
405804
  // src/websocket/listener/grep-in-files.ts
405719
- import { execFile as execFile14 } from "node:child_process";
405805
+ import { execFile as execFile15 } from "node:child_process";
405720
405806
  import { createRequire as createRequire6 } from "node:module";
405721
405807
  import * as path43 from "node:path";
405722
405808
  import { fileURLToPath as fileURLToPath10 } from "node:url";
@@ -405772,7 +405858,7 @@ async function runGrepInFiles(args) {
405772
405858
  }
405773
405859
  function runRipgrep(rgArgs) {
405774
405860
  return new Promise((resolve35, reject2) => {
405775
- const child = execFile14(rgPath, rgArgs, {
405861
+ const child = execFile15(rgPath, rgArgs, {
405776
405862
  maxBuffer: 50 * 1024 * 1024
405777
405863
  }, (error4, stdout, _stderr) => {
405778
405864
  if (error4 && error4.code !== 1) {
@@ -406240,10 +406326,10 @@ function createFileCommandSession(params) {
406240
406326
  return true;
406241
406327
  }
406242
406328
  if (isListInDirectoryCommand(parsed)) {
406243
- console.log(`[Listen] Received list_in_directory command: path=${parsed.path}`);
406329
+ logFileCommand(`[Listen] Received list_in_directory command: path=${parsed.path}`);
406244
406330
  runDetachedListenerTask("list_in_directory", async () => {
406245
406331
  try {
406246
- console.log(`[Listen] Reading directory: ${parsed.path}`);
406332
+ logFileCommand(`[Listen] Reading directory: ${parsed.path}`);
406247
406333
  const { folders: allFolders, files: allFiles } = await listDirectoryDirect(parsed.path, parsed.path, !!parsed.include_files);
406248
406334
  const total = allFolders.length + allFiles.length;
406249
406335
  const offset = parsed.offset ?? 0;
@@ -406265,11 +406351,11 @@ function createFileCommandSession(params) {
406265
406351
  if (parsed.include_files) {
406266
406352
  response.files = files;
406267
406353
  }
406268
- console.log(`[Listen] Sending list_in_directory_response: ${folders.length} folders, ${files?.length ?? 0} files`);
406354
+ logFileCommand(`[Listen] Sending list_in_directory_response: ${folders.length} folders, ${files?.length ?? 0} files`);
406269
406355
  safeSocketSend(socket, response, "listener_list_directory_send_failed", "listener_list_in_directory");
406270
406356
  } catch (err) {
406271
406357
  trackListenerError3("listener_list_directory_failed", err, "listener_file_browser");
406272
- console.error(`[Listen] list_in_directory error: ${err instanceof Error ? err.message : "Unknown error"}`);
406358
+ warnFileCommand(`[Listen] list_in_directory error: ${err instanceof Error ? err.message : "Unknown error"}`);
406273
406359
  safeSocketSend(socket, {
406274
406360
  type: "list_in_directory_response",
406275
406361
  path: parsed.path,
@@ -406284,14 +406370,14 @@ function createFileCommandSession(params) {
406284
406370
  return true;
406285
406371
  }
406286
406372
  if (isGetTreeCommand(parsed)) {
406287
- console.log(`[Listen] Received get_tree command: path=${parsed.path}, depth=${parsed.depth}`);
406373
+ logFileCommand(`[Listen] Received get_tree command: path=${parsed.path}, depth=${parsed.depth}`);
406288
406374
  runDetachedListenerTask("get_tree", async () => {
406289
406375
  try {
406290
406376
  const { entries: results, hasMoreDepth } = await getTreeDirect({
406291
406377
  root: parsed.path,
406292
406378
  depth: parsed.depth
406293
406379
  });
406294
- console.log(`[Listen] Sending get_tree_response: ${results.length} entries, has_more_depth=${hasMoreDepth}`);
406380
+ logFileCommand(`[Listen] Sending get_tree_response: ${results.length} entries, has_more_depth=${hasMoreDepth}`);
406295
406381
  safeSocketSend(socket, {
406296
406382
  type: "get_tree_response",
406297
406383
  path: parsed.path,
@@ -406302,7 +406388,7 @@ function createFileCommandSession(params) {
406302
406388
  }, "listener_get_tree_send_failed", "listener_get_tree");
406303
406389
  } catch (err) {
406304
406390
  trackListenerError3("listener_get_tree_failed", err, "listener_file_browser");
406305
- console.error(`[Listen] get_tree error: ${err instanceof Error ? err.message : "Unknown error"}`);
406391
+ warnFileCommand(`[Listen] get_tree error: ${err instanceof Error ? err.message : "Unknown error"}`);
406306
406392
  safeSocketSend(socket, {
406307
406393
  type: "get_tree_response",
406308
406394
  path: parsed.path,
@@ -406318,7 +406404,7 @@ function createFileCommandSession(params) {
406318
406404
  }
406319
406405
  if (isReadFileCommand(parsed)) {
406320
406406
  const encoding = parsed.encoding ?? "utf8";
406321
- console.log(`[Listen] Received read_file command: path=${parsed.path}, encoding=${encoding}, request_id=${parsed.request_id}`);
406407
+ logFileCommand(`[Listen] Received read_file command: path=${parsed.path}, encoding=${encoding}, request_id=${parsed.request_id}`);
406322
406408
  runDetachedListenerTask("read_file", async () => {
406323
406409
  try {
406324
406410
  let content;
@@ -406333,7 +406419,7 @@ function createFileCommandSession(params) {
406333
406419
  } else {
406334
406420
  content = await readUtf8TextStrict(parsed.path);
406335
406421
  }
406336
- console.log(`[Listen] read_file success: ${parsed.path} (${content.length} bytes, ${encoding})`);
406422
+ logFileCommand(`[Listen] read_file success: ${parsed.path} (${content.length} bytes, ${encoding})`);
406337
406423
  safeSocketSend(socket, {
406338
406424
  type: "read_file_response",
406339
406425
  request_id: parsed.request_id,
@@ -406344,7 +406430,7 @@ function createFileCommandSession(params) {
406344
406430
  }, "listener_read_file_send_failed", "listener_read_file");
406345
406431
  } catch (err) {
406346
406432
  trackListenerError3("listener_read_file_failed", err, "listener_file_read");
406347
- console.error(`[Listen] read_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
406433
+ warnFileCommand(`[Listen] read_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
406348
406434
  safeSocketSend(socket, {
406349
406435
  type: "read_file_response",
406350
406436
  request_id: parsed.request_id,
@@ -406359,7 +406445,7 @@ function createFileCommandSession(params) {
406359
406445
  return true;
406360
406446
  }
406361
406447
  if (isWriteFileCommand(parsed)) {
406362
- console.log(`[Listen] Received write_file command: path=${parsed.path}, request_id=${parsed.request_id}`);
406448
+ logFileCommand(`[Listen] Received write_file command: path=${parsed.path}, request_id=${parsed.request_id}`);
406363
406449
  runDetachedListenerTask("write_file", async () => {
406364
406450
  try {
406365
406451
  const { edit: edit3 } = await Promise.resolve().then(() => (init_edit2(), exports_edit));
@@ -406387,7 +406473,7 @@ function createFileCommandSession(params) {
406387
406473
  });
406388
406474
  }
406389
406475
  }
406390
- console.log(`[Listen] write_file success: ${parsed.path} (${parsed.content.length} bytes)`);
406476
+ logFileCommand(`[Listen] write_file success: ${parsed.path} (${parsed.content.length} bytes)`);
406391
406477
  safeSocketSend(socket, {
406392
406478
  type: "write_file_response",
406393
406479
  request_id: parsed.request_id,
@@ -406395,7 +406481,7 @@ function createFileCommandSession(params) {
406395
406481
  success: true
406396
406482
  }, "listener_write_file_send_failed", "listener_write_file");
406397
406483
  } catch (err) {
406398
- console.error(`[Listen] write_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
406484
+ warnFileCommand(`[Listen] write_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
406399
406485
  safeSocketSend(socket, {
406400
406486
  type: "write_file_response",
406401
406487
  request_id: parsed.request_id,
@@ -406470,11 +406556,11 @@ function createFileCommandSession(params) {
406470
406556
  return true;
406471
406557
  }
406472
406558
  if (isEditFileCommand(parsed)) {
406473
- console.log(`[Listen] Received edit_file command: file_path=${parsed.file_path}, request_id=${parsed.request_id}`);
406559
+ logFileCommand(`[Listen] Received edit_file command: file_path=${parsed.file_path}, request_id=${parsed.request_id}`);
406474
406560
  runDetachedListenerTask("edit_file", async () => {
406475
406561
  try {
406476
406562
  const { edit: edit3 } = await Promise.resolve().then(() => (init_edit2(), exports_edit));
406477
- console.log(`[Listen] Executing edit: old_string="${parsed.old_string.slice(0, 50)}${parsed.old_string.length > 50 ? "..." : ""}"`);
406563
+ logFileCommand(`[Listen] Executing edit: old_string="${parsed.old_string.slice(0, 50)}${parsed.old_string.length > 50 ? "..." : ""}"`);
406478
406564
  const result2 = await edit3({
406479
406565
  file_path: parsed.file_path,
406480
406566
  old_string: parsed.old_string,
@@ -406482,7 +406568,7 @@ function createFileCommandSession(params) {
406482
406568
  replace_all: parsed.replace_all,
406483
406569
  expected_replacements: parsed.expected_replacements
406484
406570
  });
406485
- console.log(`[Listen] edit_file success: ${result2.replacements} replacement(s) at line ${result2.startLine}`);
406571
+ logFileCommand(`[Listen] edit_file success: ${result2.replacements} replacement(s) at line ${result2.startLine}`);
406486
406572
  if (result2.replacements > 0) {
406487
406573
  try {
406488
406574
  const contentAfter = await readUtf8TextStrict(parsed.file_path);
@@ -406507,7 +406593,7 @@ function createFileCommandSession(params) {
406507
406593
  }, "listener_edit_file_send_failed", "listener_edit_file");
406508
406594
  } catch (err) {
406509
406595
  trackListenerError3("listener_edit_file_failed", err, "listener_file_edit");
406510
- console.error(`[Listen] edit_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
406596
+ warnFileCommand(`[Listen] edit_file error: ${err instanceof Error ? err.message : "Unknown error"}`);
406511
406597
  safeSocketSend(socket, {
406512
406598
  type: "edit_file_response",
406513
406599
  request_id: parsed.request_id,
@@ -406527,9 +406613,9 @@ function createFileCommandSession(params) {
406527
406613
  try {
406528
406614
  const content = parsed.document_content;
406529
406615
  await writeUtf8Text(parsed.path, content);
406530
- console.log(`[Listen] file_ops: wrote ${content.length} bytes to ${parsed.path}`);
406616
+ logFileCommand(`[Listen] file_ops: wrote ${content.length} bytes to ${parsed.path}`);
406531
406617
  } catch (err) {
406532
- console.error(`[Listen] file_ops error: ${err instanceof Error ? err.message : "Unknown error"}`);
406618
+ warnFileCommand(`[Listen] file_ops error: ${err instanceof Error ? err.message : "Unknown error"}`);
406533
406619
  }
406534
406620
  });
406535
406621
  }
@@ -406539,13 +406625,16 @@ function createFileCommandSession(params) {
406539
406625
  };
406540
406626
  return { handle: handle2, dispose };
406541
406627
  }
406542
- var import_picomatch2, DIR_LISTING_IGNORED_NAMES, RECURSIVE_IGNORED_NAMES, PROTECTED_HOME_NAMES, MAX_SEARCH_VISITED_ENTRIES = 50000, MAX_TREE_ENTRIES = 5000, MAX_SEARCH_RESULTS = 200, MAX_BASE64_READ_BYTES, ignoreConfigCache;
406628
+ var import_picomatch2, logFileCommand, warnFileCommand, DIR_LISTING_IGNORED_NAMES, RECURSIVE_IGNORED_NAMES, PROTECTED_HOME_NAMES, MAX_SEARCH_VISITED_ENTRIES = 50000, MAX_TREE_ENTRIES = 5000, MAX_SEARCH_RESULTS = 200, MAX_BASE64_READ_BYTES, ignoreConfigCache;
406543
406629
  var init_file_commands = __esm(() => {
406544
406630
  init_error_reporting();
406631
+ init_debug();
406545
406632
  init_text_files();
406546
406633
  init_grep_in_files();
406547
406634
  init_protocol_inbound();
406548
406635
  import_picomatch2 = __toESM(require_picomatch(), 1);
406636
+ logFileCommand = debugLog.bind(null, "file-commands");
406637
+ warnFileCommand = debugWarn.bind(null, "file-commands");
406549
406638
  DIR_LISTING_IGNORED_NAMES = new Set([".DS_Store", ".git", "Thumbs.db"]);
406550
406639
  RECURSIVE_IGNORED_NAMES = new Set([
406551
406640
  ...DIR_LISTING_IGNORED_NAMES,
@@ -407489,6 +407578,13 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
407489
407578
  actingUserId: command.runtime.acting_user_id
407490
407579
  });
407491
407580
  break;
407581
+ case "clear-messages":
407582
+ output = await handleClearCommand(socket, conversationRuntime, {
407583
+ ...opts,
407584
+ actingUserId: command.runtime.acting_user_id,
407585
+ resetAllAgentMessages: true
407586
+ });
407587
+ break;
407492
407588
  case "doctor":
407493
407589
  output = await handleDoctorCommand(socket, conversationRuntime, opts);
407494
407590
  break;
@@ -407643,7 +407739,7 @@ async function handleUpgradeLettaCodeCommand(opts) {
407643
407739
  if (opts.onLog) {
407644
407740
  opts.onLog(line);
407645
407741
  } else {
407646
- console.log(line);
407742
+ debugLog("upgrade-letta-code", message);
407647
407743
  }
407648
407744
  };
407649
407745
  log2(`command received (connectionName=${opts.connectionName ?? "unknown"}, execPath=${process.execPath}, entrypoint=${process.argv[1] ?? "unknown"})`);
@@ -407787,7 +407883,10 @@ async function handleClearCommand(_socket, conversationRuntime, opts) {
407787
407883
  if (!agentId) {
407788
407884
  throw new Error("No agent ID available for /clear command");
407789
407885
  }
407790
- if (conversationRuntime.conversationId === "default" && !backend3.capabilities.localModelCatalog) {
407886
+ if (opts.resetAllAgentMessages && backend3.capabilities.localModelCatalog) {
407887
+ throw new Error("/clear-messages is not supported by the local backend.");
407888
+ }
407889
+ if (!backend3.capabilities.localModelCatalog && (opts.resetAllAgentMessages || conversationRuntime.conversationId === "default")) {
407791
407890
  const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
407792
407891
  const client = await getClient2();
407793
407892
  await client.agents.messages.reset(agentId, {
@@ -407800,7 +407899,7 @@ async function handleClearCommand(_socket, conversationRuntime, opts) {
407800
407899
  clearConversationRuntimeState(conversationRuntime);
407801
407900
  conversationRuntime.conversationId = conversation.id;
407802
407901
  emitListenerStatus(conversationRuntime.listener, opts.onStatusChange, opts.connectionId);
407803
- return "Agent's in-context messages cleared & moved to conversation history";
407902
+ return opts.resetAllAgentMessages ? "All agent messages reset" : "Agent's in-context messages cleared & moved to conversation history";
407804
407903
  }
407805
407904
  async function handleDoctorCommand(socket, conversationRuntime, opts) {
407806
407905
  const agentId = conversationRuntime.agentId;
@@ -408070,7 +408169,7 @@ function getCwdScopeKeyFromRuntimeKey(runtimeKey) {
408070
408169
  const conversationId = runtimeKey.slice(markerIndex + marker.length);
408071
408170
  return conversationId === "default" ? runtimeKey : `conversation:${conversationId}`;
408072
408171
  }
408073
- function applyScopeUpdates(socket, runtime) {
408172
+ async function applyScopeUpdates(socket, runtime) {
408074
408173
  for (const [runtimeKey, state] of runtime.reminderStateByConversation) {
408075
408174
  const scopeKey = getCwdScopeKeyFromRuntimeKey(runtimeKey);
408076
408175
  if (!scopeKey || runtime.workingDirectoryByConversation.has(scopeKey)) {
@@ -408084,10 +408183,12 @@ function applyScopeUpdates(socket, runtime) {
408084
408183
  if (runtime.workingDirectoryByConversation.has(scopeKey) || conversationRuntime.activeWorkingDirectory) {
408085
408184
  continue;
408086
408185
  }
408087
- emitDeviceStatusUpdate(socket, conversationRuntime, {
408186
+ const scope = {
408088
408187
  agent_id: conversationRuntime.agentId,
408089
408188
  conversation_id: conversationRuntime.conversationId
408090
- });
408189
+ };
408190
+ await refreshDeviceGitContext(conversationRuntime, scope);
408191
+ emitDeviceStatusUpdate(socket, conversationRuntime, scope);
408091
408192
  }
408092
408193
  }
408093
408194
  async function handleSetBootWorkingDirectoryCommand(command, context3) {
@@ -408100,7 +408201,7 @@ async function handleSetBootWorkingDirectoryCommand(command, context3) {
408100
408201
  settingsManager.loadLocalProjectSettings(normalizedPath)
408101
408202
  ]);
408102
408203
  if (setBootWorkingDirectory(runtime, normalizedPath)) {
408103
- applyScopeUpdates(socket, runtime);
408204
+ await applyScopeUpdates(socket, runtime);
408104
408205
  }
408105
408206
  safeSocketSend(socket, {
408106
408207
  type: "set_boot_working_directory_response",
@@ -409179,8 +409280,8 @@ var init_connect_providers = __esm(() => {
409179
409280
  });
409180
409281
 
409181
409282
  // src/websocket/listener/commands/git-branches.ts
409182
- import { execFile as execFile15 } from "node:child_process";
409183
- import { promisify as promisify14 } from "node:util";
409283
+ import { execFile as execFile16 } from "node:child_process";
409284
+ import { promisify as promisify15 } from "node:util";
409184
409285
  function handleGitBranchCommand(parsed, context3) {
409185
409286
  const { socket, runtime, safeSocketSend, runDetachedListenerTask } = context3;
409186
409287
  if (isSearchBranchesCommand(parsed)) {
@@ -409188,8 +409289,8 @@ function handleGitBranchCommand(parsed, context3) {
409188
409289
  try {
409189
409290
  const cwd2 = parsed.cwd ?? getBootWorkingDirectory(runtime);
409190
409291
  const maxResults = parsed.max_results ?? 20;
409191
- const execFileAsync9 = promisify14(execFile15);
409192
- const { stdout } = await execFileAsync9("git", ["branch", "-a", "--format=%(refname:short)\t%(HEAD)"], {
409292
+ const execFileAsync10 = promisify15(execFile16);
409293
+ const { stdout } = await execFileAsync10("git", ["branch", "-a", "--format=%(refname:short)\t%(HEAD)"], {
409193
409294
  cwd: cwd2,
409194
409295
  encoding: "utf-8",
409195
409296
  timeout: 5000
@@ -409228,14 +409329,16 @@ function handleGitBranchCommand(parsed, context3) {
409228
409329
  runDetachedListenerTask("checkout_branch", async () => {
409229
409330
  try {
409230
409331
  const cwd2 = parsed.cwd ?? getBootWorkingDirectory(runtime);
409231
- const execFileAsync9 = promisify14(execFile15);
409332
+ const execFileAsync10 = promisify15(execFile16);
409232
409333
  const args = parsed.create ? ["checkout", "-b", parsed.branch] : ["checkout", parsed.branch];
409233
- await execFileAsync9("git", args, {
409334
+ await execFileAsync10("git", args, {
409234
409335
  cwd: cwd2,
409235
409336
  encoding: "utf-8",
409236
409337
  timeout: 1e4
409237
409338
  });
409238
- const gitCtx = getGitContext(cwd2);
409339
+ const gitCtx = await deviceGitContextCache.refresh(cwd2, {
409340
+ force: true
409341
+ });
409239
409342
  safeSocketSend(socket, {
409240
409343
  type: "checkout_branch_response",
409241
409344
  request_id: parsed.request_id,
@@ -409258,8 +409361,8 @@ function handleGitBranchCommand(parsed, context3) {
409258
409361
  return false;
409259
409362
  }
409260
409363
  var init_git_branches = __esm(() => {
409261
- init_git_context();
409262
409364
  init_cwd();
409365
+ init_device_git_context();
409263
409366
  init_protocol_inbound();
409264
409367
  init_protocol_outbound();
409265
409368
  });
@@ -409804,6 +409907,13 @@ var init_split_stream_lifecycle = __esm(() => {
409804
409907
  });
409805
409908
 
409806
409909
  // src/websocket/listener/message-router.ts
409910
+ function logV2Command(opts, message) {
409911
+ if (opts.onLog) {
409912
+ opts.onLog(`[Listen V2] ${message}`);
409913
+ return;
409914
+ }
409915
+ debugLog("Listen V2", message);
409916
+ }
409807
409917
  function createListenerMessageHandler(params) {
409808
409918
  const {
409809
409919
  runtime,
@@ -409853,7 +409963,7 @@ function createListenerMessageHandler(params) {
409853
409963
  if (!parsed) {
409854
409964
  return;
409855
409965
  }
409856
- console.log(`[Listen V2] Received ${summarizeV2Command(parsed)}`);
409966
+ logV2Command(opts, `Received ${summarizeV2Command(parsed)}`);
409857
409967
  if (parsedScope) {
409858
409968
  subscribeListenerConnection(runtime, connectionId, parsedScope);
409859
409969
  }
@@ -409929,7 +410039,7 @@ function createListenerMessageHandler(params) {
409929
410039
  }
409930
410040
  if (parsed.type === "sync") {
409931
410041
  if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
409932
- console.log(`[Listen V2] Dropping sync: runtime mismatch or closed`);
410042
+ logV2Command(opts, "Dropping sync: runtime mismatch or closed");
409933
410043
  if (parsed.request_id) {
409934
410044
  safeSocketSend(socket, {
409935
410045
  type: "sync_response",
@@ -409983,7 +410093,7 @@ function createListenerMessageHandler(params) {
409983
410093
  }, "input_accepted_response", "input");
409984
410094
  };
409985
410095
  if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
409986
- console.log(`[Listen V2] Dropping input: runtime mismatch or closed`);
410096
+ logV2Command(opts, "Dropping input: runtime mismatch or closed");
409987
410097
  acknowledgeInput(false, "Runtime is no longer active");
409988
410098
  return;
409989
410099
  }
@@ -410702,7 +410812,7 @@ async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
410702
410812
  }
410703
410813
  }
410704
410814
  }
410705
- replaySubscribedConnectionState(listenerRuntime, socket, syncScopedRuntime, scope, opts?.forceDeviceStatus);
410815
+ await replaySubscribedConnectionState(listenerRuntime, socket, syncScopedRuntime, scope, opts);
410706
410816
  (opts?.scheduleWarmupsAfterSync ?? scheduleListenerWarmupsAfterSync)(listenerRuntime, scope);
410707
410817
  }
410708
410818
  function getParsedRuntimeScope(parsed) {
@@ -410826,7 +410936,7 @@ async function startConnectedListenerRuntime(runtime, transport, opts, processQu
410826
410936
  runtime.hasSuccessfulConnection = true;
410827
410937
  runtime.everConnected = true;
410828
410938
  await opts.onConnected(opts.connectionId);
410829
- emitInitialConnectionState(runtime, transport, opts.connectionId, options);
410939
+ await emitInitialConnectionState(runtime, transport, opts.connectionId, options);
410830
410940
  for (const conversationRuntime of runtime.conversationRuntimes.values()) {
410831
410941
  replayPendingApprovalRequestsToConnection(conversationRuntime, opts.connectionId);
410832
410942
  }
@@ -411284,6 +411394,7 @@ var init_lifecycle = __esm(async () => {
411284
411394
  init_recovery_sync();
411285
411395
  init_runtime();
411286
411396
  init_split_stream_lifecycle();
411397
+ init_stream_observers();
411287
411398
  init_transport();
411288
411399
  init_worktree_watcher();
411289
411400
  await __promiseAll([
@@ -414170,6 +414281,8 @@ async function runListenSubcommand(argv) {
414170
414281
  return 1;
414171
414282
  }
414172
414283
  const debugMode = !!values3.debug;
414284
+ if (debugMode)
414285
+ process.env.LETTA_DEBUG = "1";
414173
414286
  const skillsDirectory = values3.skills ?? process.env.LETTA_SKILLS_DIRECTORY;
414174
414287
  if (values3.help) {
414175
414288
  printListenUsage();
@@ -414265,6 +414378,11 @@ async function runListenSubcommand(argv) {
414265
414378
  const sessionLog = new RemoteSessionLog;
414266
414379
  sessionLog.init();
414267
414380
  console.log(`Log file: ${sessionLog.path}`);
414381
+ const logListenerMessage = (message) => {
414382
+ sessionLog.log(message);
414383
+ if (debugMode)
414384
+ console.log(`[${formatTimestamp3()}] ${message}`);
414385
+ };
414268
414386
  try {
414269
414387
  const deviceId = settingsManager.getOrCreateDeviceId();
414270
414388
  const startupMode = await resolveListenerStartupMode(channelNames, channelNames.length > 0 || restoreEnabledChannels);
@@ -414401,6 +414519,7 @@ async function runListenSubcommand(argv) {
414401
414519
  connectionId: connectionId2,
414402
414520
  deviceId,
414403
414521
  connectionName,
414522
+ onLog: logListenerMessage,
414404
414523
  onWsEvent: process.env.LETTA_LOG_WS_EVENTS === "1" ? (direction, label, event) => {
414405
414524
  sessionLog.wsEvent(direction, label, event);
414406
414525
  } : undefined,
@@ -414501,10 +414620,7 @@ async function runListenSubcommand(argv) {
414501
414620
  sessionLog.log(`status: ${status}`);
414502
414621
  console.log(`[${formatTimestamp3()}] status: ${status}`);
414503
414622
  },
414504
- onLog: (message) => {
414505
- sessionLog.log(message);
414506
- console.log(`[${formatTimestamp3()}] ${message}`);
414507
- },
414623
+ onLog: logListenerMessage,
414508
414624
  onConnected: async () => {
414509
414625
  sessionLog.log("Connected. Awaiting instructions.");
414510
414626
  await startChannelGateway();
@@ -414569,10 +414685,7 @@ async function runListenSubcommand(argv) {
414569
414685
  clearRetryStatusCallback?.();
414570
414686
  updateStatusCallback?.(status);
414571
414687
  },
414572
- onLog: (message) => {
414573
- sessionLog.log(message);
414574
- console.log(`[${formatTimestamp3()}] ${message}`);
414575
- },
414688
+ onLog: logListenerMessage,
414576
414689
  onConnected: async () => {
414577
414690
  sessionLog.log("Connected. Awaiting instructions.");
414578
414691
  await startChannelGateway();
@@ -419041,7 +419154,7 @@ function finalize(ctx, schema5) {
419041
419154
  result2.$schema = "http://json-schema.org/draft-07/schema#";
419042
419155
  } else if (ctx.target === "draft-04") {
419043
419156
  result2.$schema = "http://json-schema.org/draft-04/schema#";
419044
- } else if (ctx.target === "openapi-3.0") {} else {}
419157
+ } else if (ctx.target === "openapi-3.0") {}
419045
419158
  if (ctx.external?.uri) {
419046
419159
  const id2 = ctx.external.registry.get(schema5)?.id;
419047
419160
  if (!id2)
@@ -419256,7 +419369,7 @@ var formatMap2, stringProcessor = (schema5, ctx, _json, _params) => {
419256
419369
  if (val === undefined) {
419257
419370
  if (ctx.unrepresentable === "throw") {
419258
419371
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
419259
- } else {}
419372
+ }
419260
419373
  } else if (typeof val === "bigint") {
419261
419374
  if (ctx.unrepresentable === "throw") {
419262
419375
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -431970,7 +432083,7 @@ var init_mcp_client = __esm(() => {
431970
432083
  init_streamableHttp();
431971
432084
  DEFAULT_CLIENT_INFO = {
431972
432085
  name: "letta-code",
431973
- version: "0.31.12"
432086
+ version: "0.31.13"
431974
432087
  };
431975
432088
  });
431976
432089
 
@@ -433204,7 +433317,7 @@ var init_memory_tokens = __esm(() => {
433204
433317
  });
433205
433318
 
433206
433319
  // src/cli/subcommands/memory.ts
433207
- import { cpSync, existsSync as existsSync57, mkdirSync as mkdirSync39, rmSync as rmSync12, statSync as statSync19 } from "node:fs";
433320
+ import { cpSync, existsSync as existsSync57, mkdirSync as mkdirSync39, rmSync as rmSync13, statSync as statSync19 } from "node:fs";
433208
433321
  import { readdir as readdir12 } from "node:fs/promises";
433209
433322
  import { dirname as dirname31, join as join72 } from "node:path";
433210
433323
  import { parseArgs as parseArgs11 } from "node:util";
@@ -433341,10 +433454,10 @@ async function runMemorySubcommand(argv) {
433341
433454
  return 1;
433342
433455
  }
433343
433456
  const { execFile: execFileCb5 } = await import("node:child_process");
433344
- const { promisify: promisify15 } = await import("node:util");
433345
- const execFile16 = promisify15(execFileCb5);
433457
+ const { promisify: promisify16 } = await import("node:util");
433458
+ const execFile17 = promisify16(execFileCb5);
433346
433459
  const dir = getScopedMemoryFilesystemRoot(agentId);
433347
- const { stdout } = await execFile16("git", ["diff"], { cwd: dir });
433460
+ const { stdout } = await execFile17("git", ["diff"], { cwd: dir });
433348
433461
  if (stdout.trim()) {
433349
433462
  console.log(stdout);
433350
433463
  return 2;
@@ -433411,7 +433524,7 @@ async function runMemorySubcommand(argv) {
433411
433524
  return 1;
433412
433525
  }
433413
433526
  const root2 = getMemoryRoot(agentId);
433414
- rmSync12(root2, { recursive: true, force: true });
433527
+ rmSync13(root2, { recursive: true, force: true });
433415
433528
  cpSync(backupPath, root2, { recursive: true });
433416
433529
  console.log(JSON.stringify({ restoredFrom: backupPath }, null, 2));
433417
433530
  return 0;
@@ -434197,7 +434310,7 @@ import {
434197
434310
  readdirSync as readdirSync22,
434198
434311
  readFileSync as readFileSync39,
434199
434312
  renameSync as renameSync7,
434200
- rmSync as rmSync13,
434313
+ rmSync as rmSync14,
434201
434314
  writeFileSync as writeFileSync29
434202
434315
  } from "node:fs";
434203
434316
  import { tmpdir as tmpdir10 } from "node:os";
@@ -434418,7 +434531,7 @@ function copyPackageInternalNodeModules(params) {
434418
434531
  }
434419
434532
  function restoreRegistry(registryPath, previousContents) {
434420
434533
  if (previousContents === null) {
434421
- rmSync13(registryPath, { force: true });
434534
+ rmSync14(registryPath, { force: true });
434422
434535
  return;
434423
434536
  }
434424
434537
  mkdirSync40(path46.dirname(registryPath), { recursive: true });
@@ -434427,17 +434540,17 @@ function restoreRegistry(registryPath, previousContents) {
434427
434540
  function removeIfExists(targetPath) {
434428
434541
  if (!targetPath)
434429
434542
  return;
434430
- rmSync13(targetPath, { force: true, recursive: true });
434543
+ rmSync14(targetPath, { force: true, recursive: true });
434431
434544
  }
434432
434545
  function restoreDestination(params) {
434433
- rmSync13(params.destinationRoot, { force: true, recursive: true });
434546
+ rmSync14(params.destinationRoot, { force: true, recursive: true });
434434
434547
  if (params.backupRoot && existsSync59(params.backupRoot)) {
434435
434548
  renameSync7(params.backupRoot, params.destinationRoot);
434436
434549
  }
434437
434550
  }
434438
434551
  function restoreDestinationIfNeeded(params) {
434439
434552
  if (!params.backupRoot || !existsSync59(params.backupRoot)) {
434440
- rmSync13(params.destinationRoot, { force: true, recursive: true });
434553
+ rmSync14(params.destinationRoot, { force: true, recursive: true });
434441
434554
  return;
434442
434555
  }
434443
434556
  restoreDestination(params);
@@ -434479,7 +434592,7 @@ function installPreparedManagedModPackage(params) {
434479
434592
  }
434480
434593
  if (existsSync59(destinationRoot)) {
434481
434594
  backupRoot = makeSiblingTempDirectory(destinationRoot, "backup");
434482
- rmSync13(backupRoot, { force: true, recursive: true });
434595
+ rmSync14(backupRoot, { force: true, recursive: true });
434483
434596
  renameSync7(destinationRoot, backupRoot);
434484
434597
  destinationNeedsRollback = true;
434485
434598
  }
@@ -434930,7 +435043,7 @@ async function installNpmManagedModPackage(params) {
434930
435043
  packageDirectory
434931
435044
  });
434932
435045
  } finally {
434933
- rmSync13(tempRoot, { force: true, recursive: true });
435046
+ rmSync14(tempRoot, { force: true, recursive: true });
434934
435047
  }
434935
435048
  }
434936
435049
  async function installGitManagedModPackage(params) {
@@ -434962,7 +435075,7 @@ async function installGitManagedModPackage(params) {
434962
435075
  packageInfo
434963
435076
  });
434964
435077
  } finally {
434965
- rmSync13(tempRoot, { force: true, recursive: true });
435078
+ rmSync14(tempRoot, { force: true, recursive: true });
434966
435079
  }
434967
435080
  }
434968
435081
  async function updateNpmManagedModPackage(params) {
@@ -434993,7 +435106,7 @@ async function updateNpmManagedModPackage(params) {
434993
435106
  previousVersion: existing.version
434994
435107
  };
434995
435108
  } finally {
434996
- rmSync13(tempRoot, { force: true, recursive: true });
435109
+ rmSync14(tempRoot, { force: true, recursive: true });
434997
435110
  }
434998
435111
  }
434999
435112
  async function updateGitManagedModPackage(params) {
@@ -435035,7 +435148,7 @@ async function updateGitManagedModPackage(params) {
435035
435148
  previousVersion: existing.version
435036
435149
  };
435037
435150
  } finally {
435038
- rmSync13(tempRoot, { force: true, recursive: true });
435151
+ rmSync14(tempRoot, { force: true, recursive: true });
435039
435152
  }
435040
435153
  }
435041
435154
  var SKIPPED_PACKAGE_COPY_NAMES, spawnNpmInstallProcessOverride = null, spawnGitInstallProcess, platformOverride2 = null;
@@ -435054,7 +435167,7 @@ import {
435054
435167
  existsSync as existsSync60,
435055
435168
  lstatSync as lstatSync4,
435056
435169
  mkdirSync as mkdirSync41,
435057
- rmSync as rmSync14,
435170
+ rmSync as rmSync15,
435058
435171
  writeFileSync as writeFileSync30
435059
435172
  } from "node:fs";
435060
435173
  import path47 from "node:path";
@@ -435163,7 +435276,7 @@ function scaffoldLocalModPackage(options) {
435163
435276
  writeFileSync30(readmePath, createReadme(packageName));
435164
435277
  writeFileSync30(modGuidePath, createModGuide(packageName, manifestEntry));
435165
435278
  } catch (error5) {
435166
- rmSync14(outputDirectory, { force: true, recursive: true });
435279
+ rmSync15(outputDirectory, { force: true, recursive: true });
435167
435280
  throw error5;
435168
435281
  }
435169
435282
  return {
@@ -438266,7 +438379,7 @@ import {
438266
438379
  existsSync as existsSync62,
438267
438380
  mkdtempSync as mkdtempSync5,
438268
438381
  readFileSync as readFileSync40,
438269
- rmSync as rmSync15,
438382
+ rmSync as rmSync16,
438270
438383
  statSync as statSync21,
438271
438384
  writeFileSync as writeFileSync31
438272
438385
  } from "node:fs";
@@ -438535,15 +438648,15 @@ function resolveSkillSourceSpecifier(input) {
438535
438648
  }
438536
438649
  return null;
438537
438650
  }
438538
- async function execFile16(command, args, options = {}) {
438651
+ async function execFile17(command, args, options = {}) {
438539
438652
  const { execFile: execFileCb5 } = await import("node:child_process");
438540
- const { promisify: promisify15 } = await import("node:util");
438541
- return promisify15(execFileCb5)(command, args, options);
438653
+ const { promisify: promisify16 } = await import("node:util");
438654
+ return promisify16(execFileCb5)(command, args, options);
438542
438655
  }
438543
438656
  async function resolveBranchAndSubdir(location) {
438544
438657
  if (!location.subdir)
438545
438658
  return location;
438546
- const { stdout } = await execFile16("git", ["ls-remote", "--heads", location.repoUrl], {
438659
+ const { stdout } = await execFile17("git", ["ls-remote", "--heads", location.repoUrl], {
438547
438660
  timeout: 60000
438548
438661
  });
438549
438662
  const branches = stdout.split(`
@@ -438570,7 +438683,7 @@ async function cloneSkillSource(location) {
438570
438683
  args.push("--branch", resolvedLocation.branch);
438571
438684
  }
438572
438685
  args.push(resolvedLocation.repoUrl, tmpDir);
438573
- await execFile16("git", args, { timeout: 120000 });
438686
+ await execFile17("git", args, { timeout: 120000 });
438574
438687
  const sourceDir = resolvedLocation.subdir ? join76(tmpDir, resolvedLocation.subdir) : tmpDir;
438575
438688
  return { tmpDir, sourceDir };
438576
438689
  }
@@ -438633,7 +438746,7 @@ async function downloadDirectSkillFileSource(location, options = {}) {
438633
438746
  writeFileSync31(join76(sourceDir, "SKILL.md"), skillText, "utf8");
438634
438747
  return { tmpDir, sourceDir };
438635
438748
  } catch (error5) {
438636
- rmSync15(tmpDir, { recursive: true, force: true });
438749
+ rmSync16(tmpDir, { recursive: true, force: true });
438637
438750
  throw error5;
438638
438751
  }
438639
438752
  }
@@ -438683,7 +438796,7 @@ async function downloadClawHubSkillSource(location) {
438683
438796
  throw new Error(`ClawHub download failed for ${location.slug}@${version2}: ${response.status}`);
438684
438797
  }
438685
438798
  writeFileSync31(zipPath, Buffer.from(await response.arrayBuffer()));
438686
- const { stdout } = await execFile16("unzip", ["-Z1", zipPath], {
438799
+ const { stdout } = await execFile17("unzip", ["-Z1", zipPath], {
438687
438800
  timeout: 30000
438688
438801
  });
438689
438802
  const members = stdout.split(`
@@ -438692,7 +438805,7 @@ async function downloadClawHubSkillSource(location) {
438692
438805
  throw new Error(`ClawHub download was empty for ${location.slug}@${version2}`);
438693
438806
  }
438694
438807
  members.forEach(assertSafeZipMember);
438695
- await execFile16("unzip", ["-q", zipPath, "-d", sourceDir], {
438808
+ await execFile17("unzip", ["-q", zipPath, "-d", sourceDir], {
438696
438809
  timeout: 30000
438697
438810
  });
438698
438811
  return { tmpDir, sourceDir };
@@ -438736,7 +438849,7 @@ async function installSkillDirectory(params) {
438736
438849
  if (!params.force) {
438737
438850
  throw new Error(`Skill "${name}" already exists at ${targetPath}. Re-run with --force to replace it.`);
438738
438851
  }
438739
- rmSync15(targetPath, { recursive: true, force: true });
438852
+ rmSync16(targetPath, { recursive: true, force: true });
438740
438853
  }
438741
438854
  await mkdir14(skillsDir, { recursive: true });
438742
438855
  cpSync2(sourceDir, targetPath, {
@@ -438787,7 +438900,7 @@ async function deleteSkillDirectory(params) {
438787
438900
  if (!statSync21(targetPath).isDirectory()) {
438788
438901
  throw new Error(`Skill path is not a directory: ${targetPath}`);
438789
438902
  }
438790
- rmSync15(targetPath, { recursive: true, force: true });
438903
+ rmSync16(targetPath, { recursive: true, force: true });
438791
438904
  return { name, path: normalize5(targetPath) };
438792
438905
  }
438793
438906
  async function loadSkillMemorySyncFn() {
@@ -438851,7 +438964,7 @@ async function installSkill(specifier, agentId, force) {
438851
438964
  };
438852
438965
  } finally {
438853
438966
  if (tmpDir)
438854
- rmSync15(tmpDir, { recursive: true, force: true });
438967
+ rmSync16(tmpDir, { recursive: true, force: true });
438855
438968
  }
438856
438969
  }
438857
438970
  async function getAgentMemoryDir(agentId) {
@@ -441244,7 +441357,9 @@ function bindProactiveSlackThreadRoute(params) {
441244
441357
  }
441245
441358
  }
441246
441359
  function createProactiveSlackTransport(params) {
441360
+ const listCustomEmojis = params.adapter.listCustomEmojis?.bind(params.adapter);
441247
441361
  return {
441362
+ ...listCustomEmojis ? { listCustomEmojis } : {},
441248
441363
  sendMessage: async (message) => {
441249
441364
  const result2 = await params.adapter.sendMessage(message);
441250
441365
  const isRootChannelPost = params.target.chatType === "channel" && !message.threadId?.trim() && !message.replyToMessageId?.trim() && !message.reaction;
@@ -443088,6 +443203,7 @@ Replies to routed Slack threads stay in the current thread automatically.` : "";
443088
443203
  Replies to routed Telegram topics stay in the current topic automatically.` : "";
443089
443204
  const slackCapabilities = discovery.activeChannels.includes("slack") ? [
443090
443205
  hasAction("react") ? 'action="react" with emoji + messageId' : "",
443206
+ hasAction("list-custom-emojis") ? 'action="list-custom-emojis" to discover the workspace custom emoji names available for reactions' : "",
443091
443207
  hasAction("upload-file") ? 'action="upload-file" with media' : "",
443092
443208
  hasAction("download-file") ? 'action="download-file" with attachmentId + messageId' : ""
443093
443209
  ].filter(Boolean) : [];
@@ -443217,7 +443333,7 @@ var init_message_channel_gateway_tool = __esm(() => {
443217
443333
  });
443218
443334
 
443219
443335
  // src/channels/custom/scaffolding.ts
443220
- import { existsSync as existsSync63, mkdirSync as mkdirSync42, rmSync as rmSync16, writeFileSync as writeFileSync32 } from "node:fs";
443336
+ import { existsSync as existsSync63, mkdirSync as mkdirSync42, rmSync as rmSync17, writeFileSync as writeFileSync32 } from "node:fs";
443221
443337
  function removeUserPlugin(channelId) {
443222
443338
  if (FIRST_PARTY_SET.has(channelId)) {
443223
443339
  return;
@@ -443230,7 +443346,7 @@ function removeUserPlugin(channelId) {
443230
443346
  return;
443231
443347
  }
443232
443348
  try {
443233
- rmSync16(channelDir, { recursive: true, force: true });
443349
+ rmSync17(channelDir, { recursive: true, force: true });
443234
443350
  } catch (err) {
443235
443351
  console.error(`[channels] Failed to remove plugin folder ${channelDir}:`, err);
443236
443352
  }
@@ -444971,6 +445087,51 @@ var init_router = __esm(async () => {
444971
445087
  ]);
444972
445088
  });
444973
445089
 
445090
+ // src/utils/version.ts
445091
+ function parseSemver(version2) {
445092
+ const match3 = version2.match(/^(\d+)\.(\d+)\.(\d+)/);
445093
+ if (!match3)
445094
+ return null;
445095
+ const [, major, minor, patch2] = match3;
445096
+ return [
445097
+ parseInt(major ?? "0", 10),
445098
+ parseInt(minor ?? "0", 10),
445099
+ parseInt(patch2 ?? "0", 10)
445100
+ ];
445101
+ }
445102
+ function compareSemver(a2, b3) {
445103
+ const aParts = parseSemver(a2);
445104
+ const bParts = parseSemver(b3);
445105
+ if (!aParts || !bParts)
445106
+ return null;
445107
+ for (let i4 = 0;i4 < 3; i4++) {
445108
+ const a3 = aParts[i4] ?? 0;
445109
+ const b4 = bParts[i4] ?? 0;
445110
+ if (a3 < b4)
445111
+ return -1;
445112
+ if (a3 > b4)
445113
+ return 1;
445114
+ }
445115
+ return 0;
445116
+ }
445117
+ function isVersionBelow(version2, minimum3) {
445118
+ const result2 = compareSemver(version2, minimum3);
445119
+ return result2 === -1;
445120
+ }
445121
+
445122
+ // src/runtime-version.ts
445123
+ function assertSupportedBunRuntime(bunVersion = process.versions.bun) {
445124
+ if (!bunVersion || !isVersionBelow(bunVersion, MINIMUM_BUN_VERSION)) {
445125
+ return;
445126
+ }
445127
+ throw new Error(`Letta Code cannot run on Bun ${bunVersion}. Bun ${MINIMUM_BUN_VERSION} or newer is required because older versions can stop reading child-process output. Upgrade Bun, or install Letta Code from npm to run it with Node.`);
445128
+ }
445129
+ var MINIMUM_BUN_VERSION;
445130
+ var init_runtime_version = __esm(() => {
445131
+ init_package();
445132
+ MINIMUM_BUN_VERSION = package_default.engines.bun.replace(/^>=/, "");
445133
+ });
445134
+
444974
445135
  // src/startup-auto-update.ts
444975
445136
  function startStartupAutoUpdateCheck(checkAndAutoUpdate2, logError = console.error) {
444976
445137
  return checkAndAutoUpdate2().then((result2) => {
@@ -445124,38 +445285,6 @@ var init_kitty_protocol_detector = __esm(() => {
445124
445285
  DISABLED = process.env.LETTA_DISABLE_KITTY === "1";
445125
445286
  });
445126
445287
 
445127
- // src/utils/version.ts
445128
- function parseSemver(version2) {
445129
- const match3 = version2.match(/^(\d+)\.(\d+)\.(\d+)/);
445130
- if (!match3)
445131
- return null;
445132
- const [, major, minor, patch2] = match3;
445133
- return [
445134
- parseInt(major ?? "0", 10),
445135
- parseInt(minor ?? "0", 10),
445136
- parseInt(patch2 ?? "0", 10)
445137
- ];
445138
- }
445139
- function compareSemver(a2, b3) {
445140
- const aParts = parseSemver(a2);
445141
- const bParts = parseSemver(b3);
445142
- if (!aParts || !bParts)
445143
- return null;
445144
- for (let i4 = 0;i4 < 3; i4++) {
445145
- const a3 = aParts[i4] ?? 0;
445146
- const b4 = bParts[i4] ?? 0;
445147
- if (a3 < b4)
445148
- return -1;
445149
- if (a3 > b4)
445150
- return 1;
445151
- }
445152
- return 0;
445153
- }
445154
- function isVersionBelow(version2, minimum3) {
445155
- const result2 = compareSemver(version2, minimum3);
445156
- return result2 === -1;
445157
- }
445158
-
445159
445288
  // src/startup-docker-check.ts
445160
445289
  var exports_startup_docker_check = {};
445161
445290
  __export(exports_startup_docker_check, {
@@ -451323,7 +451452,7 @@ import { existsSync as existsSync67 } from "node:fs";
451323
451452
  import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir17, writeFile as writeFile20 } from "node:fs/promises";
451324
451453
  import { homedir as homedir46 } from "node:os";
451325
451454
  import { join as join84 } from "node:path";
451326
- import { promisify as promisify15 } from "node:util";
451455
+ import { promisify as promisify16 } from "node:util";
451327
451456
  function buildGitEnv(token2, askpassPath) {
451328
451457
  return {
451329
451458
  ...process.env,
@@ -451346,7 +451475,7 @@ function formatTokenStatus(token2) {
451346
451475
  }
451347
451476
  async function runGit6(cwd2, args, env4) {
451348
451477
  try {
451349
- await execFile17("git", args, {
451478
+ await execFile18("git", args, {
451350
451479
  cwd: cwd2,
451351
451480
  env: env4,
451352
451481
  encoding: "utf-8",
@@ -451431,11 +451560,11 @@ async function maybeUploadReflectionArenaChoiceToHf(row) {
451431
451560
  };
451432
451561
  }
451433
451562
  }
451434
- var execFile17, HF_REPO_ID = "letta-ai/reflection-arena", HF_REPO_URL, GIT_TIMEOUT_MS2 = 60000, HF_CACHE_ROOT, HF_REPO_DIR, HF_DATASET_PATH = "data/choices.jsonl";
451563
+ var execFile18, HF_REPO_ID = "letta-ai/reflection-arena", HF_REPO_URL, GIT_TIMEOUT_MS2 = 60000, HF_CACHE_ROOT, HF_REPO_DIR, HF_DATASET_PATH = "data/choices.jsonl";
451435
451564
  var init_reflection_arena_hf_upload = __esm(() => {
451436
451565
  init_secrets_store();
451437
451566
  init_version();
451438
- execFile17 = promisify15(execFileCb5);
451567
+ execFile18 = promisify16(execFileCb5);
451439
451568
  HF_REPO_URL = `https://huggingface.co/datasets/${HF_REPO_ID}`;
451440
451569
  HF_CACHE_ROOT = join84(homedir46(), ".letta", "reflection-arena", "hf-upload");
451441
451570
  HF_REPO_DIR = join84(HF_CACHE_ROOT, "repo");
@@ -451447,7 +451576,7 @@ import { randomInt as randomInt2, randomUUID as randomUUID37 } from "node:crypto
451447
451576
  import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile30, writeFile as writeFile21 } from "node:fs/promises";
451448
451577
  import { homedir as homedir47 } from "node:os";
451449
451578
  import { join as join85 } from "node:path";
451450
- import { promisify as promisify16 } from "node:util";
451579
+ import { promisify as promisify17 } from "node:util";
451451
451580
  function sampleReflectionArenaComparisonModel(excludedModels = []) {
451452
451581
  const excluded = new Set(excludedModels);
451453
451582
  const candidates2 = REFLECTION_ARENA_COMPARISON_MODEL_POOL.filter((entry) => !excluded.has(entry.model));
@@ -451464,7 +451593,7 @@ function sampleReflectionArenaComparisonModel(excludedModels = []) {
451464
451593
  }
451465
451594
  async function getGitOutput(cwd2, args) {
451466
451595
  try {
451467
- const { stdout } = await execFile18("git", args, {
451596
+ const { stdout } = await execFile19("git", args, {
451468
451597
  cwd: cwd2,
451469
451598
  encoding: "utf-8",
451470
451599
  timeout: 30000,
@@ -452039,7 +452168,7 @@ async function finalizeReflectionArenaChoice(options) {
452039
452168
  run: completedRun
452040
452169
  };
452041
452170
  }
452042
- var execFile18, REFLECTION_ARENA_TELEMETRY_TRANSCRIPT_MAX_CHARS = 1e6, REFLECTION_ARENA_MODEL_A_DEFAULT = "letta/auto-memory", REFLECTION_ARENA_COMPARISON_MODEL_POOL, ANSI_BOLD = "\x1B[1m", ANSI_CYAN = "\x1B[36m", ANSI_MAGENTA = "\x1B[35m", ANSI_RESET_BOLD = "\x1B[22m", ANSI_RESET_FOREGROUND = "\x1B[39m", REFLECTION_ARENA_CANDIDATE_COUNT = 2, REFLECTION_ARENA_CHOICE_QUESTION = "Which reflection should be merged?", REFLECTION_ARENA_NOTES_QUESTION = "Optional feedback for this choice?", updateLocks;
452171
+ var execFile19, REFLECTION_ARENA_TELEMETRY_TRANSCRIPT_MAX_CHARS = 1e6, REFLECTION_ARENA_MODEL_A_DEFAULT = "letta/auto-memory", REFLECTION_ARENA_COMPARISON_MODEL_POOL, ANSI_BOLD = "\x1B[1m", ANSI_CYAN = "\x1B[36m", ANSI_MAGENTA = "\x1B[35m", ANSI_RESET_BOLD = "\x1B[22m", ANSI_RESET_FOREGROUND = "\x1B[39m", REFLECTION_ARENA_CANDIDATE_COUNT = 2, REFLECTION_ARENA_CHOICE_QUESTION = "Which reflection should be merged?", REFLECTION_ARENA_NOTES_QUESTION = "Optional feedback for this choice?", updateLocks;
452043
452172
  var init_reflection_arena = __esm(() => {
452044
452173
  init_memory_filesystem2();
452045
452174
  init_memory_worktree();
@@ -452051,7 +452180,7 @@ var init_reflection_arena = __esm(() => {
452051
452180
  init_reflection_transcript();
452052
452181
  init_telemetry();
452053
452182
  init_debug();
452054
- execFile18 = promisify16(execFileCb6);
452183
+ execFile19 = promisify17(execFileCb6);
452055
452184
  REFLECTION_ARENA_COMPARISON_MODEL_POOL = [
452056
452185
  { model: "lc-anthropic/claude-sonnet-5", weight: 1 },
452057
452186
  { model: "lc-anthropic/claude-opus-4-8", weight: 3 },
@@ -453283,6 +453412,14 @@ var init_registry2 = __esm(() => {
453283
453412
  return "Clearing in-context messages...";
453284
453413
  }
453285
453414
  },
453415
+ "/clear-messages": {
453416
+ desc: "Reset all agent messages (destructive)",
453417
+ hidden: true,
453418
+ noArgs: true,
453419
+ handler: () => {
453420
+ return "Resetting agent messages...";
453421
+ }
453422
+ },
453286
453423
  "/chdir": {
453287
453424
  desc: "Change working directory for this TUI session (/chdir <path>)",
453288
453425
  args: "<path>",
@@ -464441,7 +464578,7 @@ import {
464441
464578
  mkdirSync as mkdirSync46,
464442
464579
  mkdtempSync as mkdtempSync6,
464443
464580
  readFileSync as readFileSync44,
464444
- rmSync as rmSync17,
464581
+ rmSync as rmSync18,
464445
464582
  writeFileSync as writeFileSync36
464446
464583
  } from "node:fs";
464447
464584
  import { tmpdir as tmpdir12 } from "node:os";
@@ -464811,7 +464948,7 @@ async function installGithubApp(options) {
464811
464948
  agentUrl: resolvedAgentId ? buildAgentReference(resolvedAgentId) : null
464812
464949
  };
464813
464950
  } finally {
464814
- rmSync17(tempDir, { recursive: true, force: true });
464951
+ rmSync18(tempDir, { recursive: true, force: true });
464815
464952
  }
464816
464953
  }
464817
464954
  var DEFAULT_WORKFLOW_PATH = ".github/workflows/letta.yml", ALTERNATE_WORKFLOW_PATH = ".github/workflows/letta-code.yml";
@@ -468577,7 +468714,7 @@ import { execFile as execFileCb7 } from "node:child_process";
468577
468714
  import { chmodSync as chmodSync7, existsSync as existsSync70, mkdirSync as mkdirSync47, writeFileSync as writeFileSync37 } from "node:fs";
468578
468715
  import { homedir as homedir51 } from "node:os";
468579
468716
  import { join as join89 } from "node:path";
468580
- import { promisify as promisify17 } from "node:util";
468717
+ import { promisify as promisify18 } from "node:util";
468581
468718
  function messagesFromOverview(overview) {
468582
468719
  return overview.messages?.map((message) => ({
468583
468720
  id: message.id,
@@ -468604,7 +468741,7 @@ function contextFromOverview(overview, model, contextWindow) {
468604
468741
  }
468605
468742
  async function runGitSafe(cwd2, args) {
468606
468743
  try {
468607
- const { stdout } = await execFile19("git", args, {
468744
+ const { stdout } = await execFile20("git", args, {
468608
468745
  cwd: cwd2,
468609
468746
  maxBuffer: 10 * 1024 * 1024,
468610
468747
  timeout: 60000
@@ -468915,7 +469052,7 @@ async function generateAndOpenMemoryViewer(agentId, options) {
468915
469052
  }
468916
469053
  return { filePath, opened: !skipOpen };
468917
469054
  }
468918
- var execFile19, VIEWERS_DIR, MAX_COMMITS = 500, RECENT_DIFF_COUNT = 50, PER_DIFF_CAP = 1e5, TOTAL_PAYLOAD_CAP = 5000000, RECORD_SEP = "\x1E", REFLECTION_PATTERN;
469055
+ var execFile20, VIEWERS_DIR, MAX_COMMITS = 500, RECENT_DIFF_COUNT = 50, PER_DIFF_CAP = 1e5, TOTAL_PAYLOAD_CAP = 5000000, RECORD_SEP = "\x1E", REFLECTION_PATTERN;
468919
469056
  var init_generate_memory_viewer = __esm(() => {
468920
469057
  init_memory_filesystem2();
468921
469058
  init_memory_scanner();
@@ -468926,7 +469063,7 @@ var init_generate_memory_viewer = __esm(() => {
468926
469063
  init_context_usage();
468927
469064
  init_local_memory_context();
468928
469065
  init_memory_viewer_template();
468929
- execFile19 = promisify17(execFileCb7);
469066
+ execFile20 = promisify18(execFileCb7);
468930
469067
  VIEWERS_DIR = join89(homedir51(), ".letta", "viewers");
468931
469068
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
468932
469069
  });
@@ -492346,10 +492483,10 @@ import { execFile as execFileCb8 } from "node:child_process";
492346
492483
  import { chmodSync as chmodSync8, existsSync as existsSync72, mkdirSync as mkdirSync48, writeFileSync as writeFileSync38 } from "node:fs";
492347
492484
  import { homedir as homedir53 } from "node:os";
492348
492485
  import { isAbsolute as isAbsolute30, join as join92, resolve as resolve42 } from "node:path";
492349
- import { promisify as promisify18 } from "node:util";
492486
+ import { promisify as promisify19 } from "node:util";
492350
492487
  async function runGit8(cwd2, args) {
492351
492488
  try {
492352
- const { stdout } = await execFile20("git", args, {
492489
+ const { stdout } = await execFile21("git", args, {
492353
492490
  cwd: cwd2,
492354
492491
  maxBuffer: GIT_MAX_BUFFER,
492355
492492
  timeout: GIT_TIMEOUT_MS3
@@ -492584,7 +492721,7 @@ async function generateAndOpenDiffViewer(targetPath) {
492584
492721
  }
492585
492722
  return { filePath, opened: !skipOpen, fileCount: rendered.files.length };
492586
492723
  }
492587
- var execFile20, VIEWERS_DIR2, GIT_TIMEOUT_MS3 = 60000, GIT_MAX_BUFFER, MAX_RENDERED_FILES = 100, DIFF_UNSAFE_CSS = `
492724
+ var execFile21, VIEWERS_DIR2, GIT_TIMEOUT_MS3 = 60000, GIT_MAX_BUFFER, MAX_RENDERED_FILES = 100, DIFF_UNSAFE_CSS = `
492588
492725
  :host {
492589
492726
  --diffs-addition-color-override: #15803d;
492590
492727
  --diffs-deletion-color-override: #b91c1c;
@@ -492640,7 +492777,7 @@ var init_generate_diff_viewer = __esm(() => {
492640
492777
  init_dist15();
492641
492778
  init_ssr();
492642
492779
  init_diff_viewer_template();
492643
- execFile20 = promisify18(execFileCb8);
492780
+ execFile21 = promisify19(execFileCb8);
492644
492781
  VIEWERS_DIR2 = join92(homedir53(), ".letta", "viewers");
492645
492782
  GIT_MAX_BUFFER = 50 * 1024 * 1024;
492646
492783
  });
@@ -495030,7 +495167,7 @@ function useConfigurationHandlers(ctx) {
495030
495167
  registryHandle,
495031
495168
  contextWindow: selectedContextWindow,
495032
495169
  reasoningCapabilities
495033
- }) : getReasoningTierOptionsForHandle2(modelHandle, selectedContextWindow, reasoningCapabilities);
495170
+ }) : getReasoningTierOptionsForHandle2(registryHandle, selectedContextWindow, reasoningCapabilities);
495034
495171
  const reasoningTierOptions = baseReasoningTierOptions.map((option2) => {
495035
495172
  const optionModel = models3.find((entry) => entry.id === option2.modelId);
495036
495173
  const serviceTier = modelUpdateArgs?.service_tier;
@@ -502627,10 +502764,10 @@ __export(exports_worktree_diff_list, {
502627
502764
  });
502628
502765
  import { execFile as execFileCb9 } from "node:child_process";
502629
502766
  import { basename as basename31 } from "node:path";
502630
- import { promisify as promisify19 } from "node:util";
502767
+ import { promisify as promisify20 } from "node:util";
502631
502768
  async function runGit9(cwd2, args) {
502632
502769
  try {
502633
- const { stdout } = await execFile21("git", args, {
502770
+ const { stdout } = await execFile22("git", args, {
502634
502771
  cwd: cwd2,
502635
502772
  maxBuffer: GIT_MAX_BUFFER2,
502636
502773
  timeout: GIT_TIMEOUT_MS4
@@ -502759,9 +502896,9 @@ async function listWorktreeDiffOptions(cwd2 = process.cwd()) {
502759
502896
  const worktrees = parseWorktreeList(output, currentPath);
502760
502897
  return Promise.all(worktrees.map((worktree) => summarizeWorktree(worktree)));
502761
502898
  }
502762
- var execFile21, GIT_TIMEOUT_MS4 = 60000, GIT_MAX_BUFFER2;
502899
+ var execFile22, GIT_TIMEOUT_MS4 = 60000, GIT_MAX_BUFFER2;
502763
502900
  var init_worktree_diff_list = __esm(() => {
502764
- execFile21 = promisify19(execFileCb9);
502901
+ execFile22 = promisify20(execFileCb9);
502765
502902
  GIT_MAX_BUFFER2 = 10 * 1024 * 1024;
502766
502903
  });
502767
502904
 
@@ -504039,15 +504176,19 @@ Tip: Use /clear instead to clear the current message buffer.`;
504039
504176
  });
504040
504177
  return { submitted: true };
504041
504178
  }
504042
- if (msg.trim() === "/clear") {
504043
- const cmd = commandRunner.start(msg.trim(), "Clearing in-context messages...");
504179
+ const resetAllAgentMessages = trimmed === "/clear-messages";
504180
+ if (trimmed === "/clear" || resetAllAgentMessages) {
504181
+ const cmd = commandRunner.start(trimmed, resetAllAgentMessages ? "Resetting agent messages..." : "Clearing in-context messages...");
504044
504182
  resetPendingReasoningCycle();
504045
504183
  setCommandRunning(true);
504046
504184
  const clearPrevConversationId = conversationIdRef.current;
504047
- await runEndHooks("new");
504048
504185
  try {
504049
504186
  const backend3 = getBackend();
504050
- if (conversationIdRef.current === "default" && !backend3.capabilities.localModelCatalog) {
504187
+ if (resetAllAgentMessages && backend3.capabilities.localModelCatalog) {
504188
+ throw new Error("/clear-messages is unsupported by local backend.");
504189
+ }
504190
+ await runEndHooks("new");
504191
+ if (!backend3.capabilities.localModelCatalog && (resetAllAgentMessages || conversationIdRef.current === "default")) {
504051
504192
  const client = await getClient();
504052
504193
  await client.agents.messages.reset(agentId, {
504053
504194
  add_default_initial_messages: false
@@ -504081,7 +504222,7 @@ Tip: Use /clear instead to clear the current message buffer.`;
504081
504222
  previousConversationId: clearPrevConversationId ?? null,
504082
504223
  reason: "new"
504083
504224
  }, modAdapter.context);
504084
- cmd.finish("Agent's in-context messages cleared & moved to conversation history", true);
504225
+ cmd.finish(resetAllAgentMessages ? "All agent messages reset" : "Agent's in-context messages cleared & moved to conversation history", true);
504085
504226
  } catch (error5) {
504086
504227
  const errorDetails = formatErrorDetails2(error5, agentId);
504087
504228
  cmd.fail(`Failed: ${errorDetails}`);
@@ -510717,6 +510858,7 @@ var init_src5 = __esm(async () => {
510717
510858
  init_terminal_theme();
510718
510859
  init_startup_backend_mode();
510719
510860
  init_startup();
510861
+ init_runtime_version();
510720
510862
  init_settings_manager();
510721
510863
  init_startup_auto_update();
510722
510864
  init_debug();
@@ -510730,6 +510872,7 @@ var init_src5 = __esm(async () => {
510730
510872
  ]);
510731
510873
  EMPTY_APPROVAL_ARRAY = [];
510732
510874
  EMPTY_MESSAGE_ARRAY = [];
510875
+ assertSupportedBunRuntime();
510733
510876
  main2();
510734
510877
  });
510735
510878
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js
@@ -512927,4 +513070,4 @@ function registerBunOAuthFlows() {
512927
513070
  registerBunOAuthFlows();
512928
513071
  await init_src5().then(() => exports_src2);
512929
513072
 
512930
- //# debugId=D6C12B8170F7A1C664756E2164756E21
513073
+ //# debugId=67341FA9FF6344CE64756E2164756E21