@letta-ai/letta-code 0.31.11 → 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 (52) hide show
  1. package/README.md +16 -14
  2. package/dist/agent-presets.js +3 -3
  3. package/dist/agent-presets.js.map +1 -1
  4. package/dist/channels-slack.js +20 -1
  5. package/dist/channels-slack.js.map +3 -3
  6. package/dist/gateway-core.js +2 -1
  7. package/dist/gateway-core.js.map +3 -3
  8. package/dist/mcp-client.js +4 -4
  9. package/dist/mcp-client.js.map +2 -2
  10. package/dist/types/agent/subagents/manager.d.ts +1 -1
  11. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  12. package/dist/types/backend/api/client.d.ts.map +1 -1
  13. package/dist/types/backend/backend.d.ts +1 -0
  14. package/dist/types/backend/backend.d.ts.map +1 -1
  15. package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
  16. package/dist/types/channels/plugin-types.d.ts +1 -1
  17. package/dist/types/channels/plugin-types.d.ts.map +1 -1
  18. package/dist/types/channels/slack/internal-types.d.ts +5 -0
  19. package/dist/types/channels/slack/internal-types.d.ts.map +1 -1
  20. package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
  21. package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
  22. package/dist/types/channels/types.d.ts +1 -0
  23. package/dist/types/channels/types.d.ts.map +1 -1
  24. package/dist/types/cli/helpers/git-context.d.ts +1 -1
  25. package/dist/types/cli/helpers/git-context.d.ts.map +1 -1
  26. package/dist/types/tools/impl/bash.d.ts +2 -0
  27. package/dist/types/tools/impl/bash.d.ts.map +1 -1
  28. package/dist/types/tools/impl/exec-command.d.ts +8 -0
  29. package/dist/types/tools/impl/exec-command.d.ts.map +1 -1
  30. package/dist/types/tools/impl/task.d.ts +2 -2
  31. package/dist/types/websocket/listener/cwd-change.d.ts.map +1 -1
  32. package/dist/types/websocket/listener/device-git-context.d.ts +17 -0
  33. package/dist/types/websocket/listener/device-git-context.d.ts.map +1 -0
  34. package/dist/types/websocket/listener/listener-constants.d.ts.map +1 -1
  35. package/dist/types/websocket/listener/protocol-outbound.d.ts +1 -0
  36. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  37. package/dist/types/websocket/listener/stream-observers.d.ts.map +1 -1
  38. package/dist/types/websocket/listener/worktree-watcher.d.ts.map +1 -1
  39. package/letta.js +1008 -888
  40. package/package.json +3 -2
  41. package/scripts/codex-watch/release-analysis.test.ts +87 -0
  42. package/scripts/codex-watch/release-analysis.ts +57 -7
  43. package/scripts/postinstall-patches.js +37 -14
  44. package/scripts/source-file-size-baseline.json +3 -3
  45. package/skills/browser-use/SKILL.md +22 -61
  46. package/skills/dispatching-coding-agents/SKILL.md +6 -6
  47. package/skills/messaging-agents/SKILL.md +34 -21
  48. package/skills/scheduling-tasks/SKILL.md +1 -1
  49. package/skills/submitting-feedback/SKILL.md +4 -2
  50. package/skills/teleporting-between-environments/SKILL.md +12 -12
  51. package/dist/types/tools/impl/foreground-sleep.d.ts +0 -13
  52. 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.11",
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
@@ -7968,7 +7959,7 @@ Other
7968
7959
  - [ ] Make a permissions edit: let the user know that you can modify permissions (what commands are automatically approved/denied). Ask them if there are certain actions they would like you to avoid.
7969
7960
  - [ ] Create a local mod: let the user know you can customize Letta Code with trusted local mods for new tools, slash commands, provider integrations, UI panels/status, events, or permission overlays. Explain that mods are for executable harness behavior, while memory and skills are for retained knowledge and reusable procedures.
7970
7961
  - [ ] Worktrees: let the user know that you can help them orchestrate many agents in parallel, and also work in parallel to other agents. Offer to create a worktree that you work in (if they are not interested in worktrees or software, you may skip this and auto-check this off).
7971
- - [ ] Moving machines: ask the user to add another remote environment (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
7962
+ - [ ] Moving machines: ask the user to connect another computer (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
7972
7963
  `;
7973
7964
  var init_onboarding = () => {};
7974
7965
 
@@ -8021,7 +8012,7 @@ Other
8021
8012
  - [ ] Make a permissions edit: let the user know that you can modify permissions (what commands are automatically approved/denied). Ask them if there are certain actions they would like you to avoid.
8022
8013
  - [ ] Create a local mod: let the user know you can customize Letta Code with trusted local mods for new tools, slash commands, provider integrations, UI panels/status, events, or permission overlays. Explain that mods are for executable harness behavior, while memory and skills are for retained knowledge and reusable procedures.
8023
8014
  - [ ] Worktrees: let the user know that you can help them orchestrate many agents in parallel, and also work in parallel to other agents. Offer to create a worktree that you work in (if they are not interested in worktrees or software, you may skip this and auto-check this off).
8024
- - [ ] Moving machines: ask the user to add another remote environment (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
8015
+ - [ ] Moving machines: ask the user to connect another computer (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
8025
8016
  `;
8026
8017
  var init_onboarding_local = () => {};
8027
8018
 
@@ -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",
@@ -114801,10 +114824,13 @@ function buildSubagentArgs(type3, config, model, userPrompt, existingAgentId, ex
114801
114824
  args.push("--backend", options.backendMode);
114802
114825
  }
114803
114826
  if (options.environment) {
114804
- args.push("--environment", options.environment);
114827
+ args.push("--computer", options.environment);
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
@@ -137024,14 +137068,15 @@ var init_args = __esm(() => {
137024
137068
  description: "Inject agent-to-agent system reminder (headless mode)"
137025
137069
  }
137026
137070
  },
137027
- environment: {
137071
+ computer: {
137028
137072
  parser: { type: "string" },
137029
137073
  mode: "headless",
137030
137074
  help: {
137031
137075
  argLabel: "<selector>",
137032
- description: "Route headless message through 'cloud' sandbox or an environment by name, device ID, or connection ID"
137076
+ description: "Route headless message through 'cloud' or a computer by name, device ID, or connection ID"
137033
137077
  }
137034
137078
  },
137079
+ environment: { parser: { type: "string" }, mode: "headless" },
137035
137080
  env: { parser: { type: "string" }, mode: "headless" },
137036
137081
  skills: {
137037
137082
  parser: { type: "string" },
@@ -148669,7 +148714,7 @@ Learn more about this warning here: https://reactjs.org/link/legacy-context`, so
148669
148714
 
148670
148715
  ` + ("" + errorBoundaryMessage);
148671
148716
  console["error"](combinedMessage);
148672
- } else {}
148717
+ }
148673
148718
  } catch (e2) {
148674
148719
  setTimeout(function() {
148675
148720
  throw e2;
@@ -164542,7 +164587,7 @@ var CAPTURING_REGEX_SOURCE, RegexSource = class {
164542
164587
  let localIncludedRule = repository[reference.ruleName];
164543
164588
  if (localIncludedRule) {
164544
164589
  ruleId = _RuleFactory.getCompiledRuleId(localIncludedRule, helper, repository);
164545
- } else {}
164590
+ }
164546
164591
  break;
164547
164592
  case 3:
164548
164593
  case 4:
@@ -164554,11 +164599,11 @@ var CAPTURING_REGEX_SOURCE, RegexSource = class {
164554
164599
  let externalIncludedRule = externalGrammar.repository[externalGrammarInclude];
164555
164600
  if (externalIncludedRule) {
164556
164601
  ruleId = _RuleFactory.getCompiledRuleId(externalIncludedRule, helper, externalGrammar.repository);
164557
- } else {}
164602
+ }
164558
164603
  } else {
164559
164604
  ruleId = _RuleFactory.getCompiledRuleId(externalGrammar.repository.$self, helper, externalGrammar.repository);
164560
164605
  }
164561
- } else {}
164606
+ }
164562
164607
  break;
164563
164608
  }
164564
164609
  } else {
@@ -175257,7 +175302,7 @@ import {
175257
175302
  mkdirSync as mkdirSync18,
175258
175303
  readdirSync as readdirSync10,
175259
175304
  renameSync as renameSync4,
175260
- rmSync as rmSync7,
175305
+ rmSync as rmSync8,
175261
175306
  statSync as statSync10
175262
175307
  } from "node:fs";
175263
175308
  import { arch as arch2, homedir as homedir23, platform as platform5 } from "node:os";
@@ -175634,8 +175679,8 @@ async function downloadFd() {
175634
175679
  chmodSync5(FD_LOCAL_PATH, 493);
175635
175680
  }
175636
175681
  } finally {
175637
- rmSync7(archivePath, { force: true });
175638
- rmSync7(extractDir, { recursive: true, force: true });
175682
+ rmSync8(archivePath, { force: true });
175683
+ rmSync8(extractDir, { recursive: true, force: true });
175639
175684
  }
175640
175685
  return FD_LOCAL_PATH;
175641
175686
  }
@@ -179445,12 +179490,12 @@ __export(exports_auto_update, {
179445
179490
  buildInstallArgs: () => buildInstallArgs
179446
179491
  });
179447
179492
  import {
179448
- execFile as execFile7
179493
+ execFile as execFile8
179449
179494
  } from "node:child_process";
179450
179495
  import { accessSync, constants as constants4, realpathSync as realpathSync4 } from "node:fs";
179451
179496
  import { readdir as readdir7, rm as rm6 } from "node:fs/promises";
179452
179497
  import { dirname as dirname23, join as join41 } from "node:path";
179453
- import { promisify as promisify7 } from "node:util";
179498
+ import { promisify as promisify8 } from "node:util";
179454
179499
  function debugLog2(...args) {
179455
179500
  if (DEBUG) {
179456
179501
  console.error("[auto-update]", ...args);
@@ -179513,7 +179558,7 @@ function buildUpdateExecOptions(timeout, platform6 = process.platform) {
179513
179558
  };
179514
179559
  }
179515
179560
  async function runUpdateCommand(command, args, timeout) {
179516
- return execFileAsync4(command, args, buildUpdateExecOptions(timeout));
179561
+ return execFileAsync5(command, args, buildUpdateExecOptions(timeout));
179517
179562
  }
179518
179563
  function getResolvedEntrypoint() {
179519
179564
  const argv = process.argv[1] || "";
@@ -179836,11 +179881,11 @@ async function manualUpdate(options) {
179836
179881
  To update manually: ${installCmd}`
179837
179882
  };
179838
179883
  }
179839
- 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;
179840
179885
  var init_auto_update = __esm(() => {
179841
179886
  init_error_reporting();
179842
179887
  init_version();
179843
- execFileAsync4 = promisify7(execFile7);
179888
+ execFileAsync5 = promisify8(execFile8);
179844
179889
  DEBUG = process.env.LETTA_DEBUG_AUTOUPDATE === "1";
179845
179890
  INSTALL_ARG_PREFIX = {
179846
179891
  npm: ["install", "-g"],
@@ -181215,7 +181260,7 @@ __export(exports_transcription, {
181215
181260
  isTranscriptionConfigured: () => isTranscriptionConfigured
181216
181261
  });
181217
181262
  import { execFileSync as execFileSync4 } from "node:child_process";
181218
- 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";
181219
181264
  import { tmpdir as tmpdir8 } from "node:os";
181220
181265
  import { basename as basename12, extname as extname5, join as join43 } from "node:path";
181221
181266
  function audioMimeTypeForPath(localPath) {
@@ -181260,12 +181305,12 @@ function prepareOpenAiTranscriptionFile(localPath) {
181260
181305
  convertedPath
181261
181306
  ], { stdio: "ignore", timeout: TRANSCRIPTION_TIMEOUT_MS });
181262
181307
  } catch (error4) {
181263
- rmSync8(tempDir, { recursive: true, force: true });
181308
+ rmSync9(tempDir, { recursive: true, force: true });
181264
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)}`);
181265
181310
  }
181266
181311
  return {
181267
181312
  localPath: convertedPath,
181268
- cleanup: () => rmSync8(tempDir, { recursive: true, force: true })
181313
+ cleanup: () => rmSync9(tempDir, { recursive: true, force: true })
181269
181314
  };
181270
181315
  }
181271
181316
  function isTranscriptionConfigured() {
@@ -187269,6 +187314,11 @@ function createSlackAdapter(config) {
187269
187314
  throw error4;
187270
187315
  }
187271
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
+ }
187272
187322
  async function downloadAttachment(params) {
187273
187323
  const slackApp = await ensureApp();
187274
187324
  return await downloadSlackAttachmentById({
@@ -187484,6 +187534,7 @@ function createSlackAdapter(config) {
187484
187534
  await Promise.all(status.getUniqueSources(event.sources).map((source) => status.activate(source, SLACK_ASSISTANT_WORKING_STATUS, activity)));
187485
187535
  },
187486
187536
  sendMessage,
187537
+ listCustomEmojis,
187487
187538
  downloadAttachment,
187488
187539
  sendDirectReply,
187489
187540
  handleControlRequestEvent,
@@ -187631,10 +187682,27 @@ async function reactInSlack(context3) {
187631
187682
  });
187632
187683
  return request.remove ? `Reaction removed on slack (message_id: ${result2.messageId})` : `Reaction added on slack (message_id: ${result2.messageId})`;
187633
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
+ }
187634
187701
  function createSlackMessageActionAdapter(options = {}) {
187635
187702
  const actions = [
187636
187703
  "send",
187637
187704
  ...options.react ? ["react"] : [],
187705
+ ...options.listCustomEmojis ? ["list-custom-emojis"] : [],
187638
187706
  ...options.uploadFile ? ["upload-file"] : [],
187639
187707
  ...options.downloadFile ? ["download-file"] : []
187640
187708
  ];
@@ -187673,6 +187741,8 @@ function createSlackMessageActionAdapter(options = {}) {
187673
187741
  return await sendSlackMessage(context3);
187674
187742
  case "react":
187675
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.';
187676
187746
  case "download-file":
187677
187747
  return options.downloadFile ? await options.downloadFile(context3) : 'Error: Action "download-file" is not supported on slack.';
187678
187748
  default:
@@ -188063,6 +188133,7 @@ var init_message_actions2 = __esm(() => {
188063
188133
  init_target_resolution();
188064
188134
  slackMessageActions = createSlackMessageActionAdapter({
188065
188135
  react: true,
188136
+ listCustomEmojis: true,
188066
188137
  uploadFile: true,
188067
188138
  downloadFile: downloadSlackFile,
188068
188139
  resolveMessageTarget: async (params) => await resolveSlackMessageTarget({
@@ -188100,7 +188171,7 @@ async function runSlackSetup() {
188100
188171
  console.log(` 5. Add the /cancel slash command if you want Slack-native cancellation
188101
188172
  `);
188102
188173
  console.log("Recommended bot token scopes:");
188103
- 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");
188104
188175
  console.log(` reactions:read, reactions:write, files:read, files:write
188105
188176
  `);
188106
188177
  await ensureSlackRuntimeInstalled();
@@ -190871,7 +190942,7 @@ var init_state = __esm(() => {
190871
190942
  });
190872
190943
 
190873
190944
  // src/channels/whatsapp/session.ts
190874
- 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";
190875
190946
  import { homedir as homedir26 } from "node:os";
190876
190947
  import { join as join48 } from "node:path";
190877
190948
  function shouldDropLine(line) {
@@ -190983,7 +191054,7 @@ function acquireWhatsAppSessionLease(accountId, options = {}) {
190983
191054
  if (activeSessionLeases.get(accountId) === lockDir) {
190984
191055
  activeSessionLeases.delete(accountId);
190985
191056
  }
190986
- rmSync9(lockDir, { recursive: true, force: true });
191057
+ rmSync10(lockDir, { recursive: true, force: true });
190987
191058
  }
190988
191059
  };
190989
191060
  } catch (error4) {
@@ -190992,7 +191063,7 @@ function acquireWhatsAppSessionLease(accountId, options = {}) {
190992
191063
  }
190993
191064
  const owner = readLeaseOwner(lockDir);
190994
191065
  if (owner.pid && !isProcessAlive(owner.pid)) {
190995
- rmSync9(lockDir, { recursive: true, force: true });
191066
+ rmSync10(lockDir, { recursive: true, force: true });
190996
191067
  continue;
190997
191068
  }
190998
191069
  const ownerLabel = owner.pid ? `PID ${owner.pid}${owner.command ? ` (${owner.command})` : ""}` : "an unknown live process";
@@ -199870,26 +199941,26 @@ function defineLazyProperty(object3, propertyName, valueGetter) {
199870
199941
  }
199871
199942
 
199872
199943
  // node_modules/default-browser-id/index.js
199873
- import { promisify as promisify8 } from "node:util";
199944
+ import { promisify as promisify9 } from "node:util";
199874
199945
  import process15 from "node:process";
199875
- import { execFile as execFile8 } from "node:child_process";
199946
+ import { execFile as execFile9 } from "node:child_process";
199876
199947
  async function defaultBrowserId() {
199877
199948
  if (process15.platform !== "darwin") {
199878
199949
  throw new Error("macOS only");
199879
199950
  }
199880
- 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"]);
199881
199952
  const match3 = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
199882
199953
  return match3?.groups.id ?? "com.apple.Safari";
199883
199954
  }
199884
- var execFileAsync5;
199955
+ var execFileAsync6;
199885
199956
  var init_default_browser_id = __esm(() => {
199886
- execFileAsync5 = promisify8(execFile8);
199957
+ execFileAsync6 = promisify9(execFile9);
199887
199958
  });
199888
199959
 
199889
199960
  // node_modules/run-applescript/index.js
199890
199961
  import process16 from "node:process";
199891
- import { promisify as promisify9 } from "node:util";
199892
- 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";
199893
199964
  async function runAppleScript(script4, { humanReadableOutput = true, signal } = {}) {
199894
199965
  if (process16.platform !== "darwin") {
199895
199966
  throw new Error("macOS only");
@@ -199899,12 +199970,12 @@ async function runAppleScript(script4, { humanReadableOutput = true, signal } =
199899
199970
  if (signal) {
199900
199971
  execOptions.signal = signal;
199901
199972
  }
199902
- const { stdout } = await execFileAsync6("osascript", ["-e", script4, outputArguments], execOptions);
199973
+ const { stdout } = await execFileAsync7("osascript", ["-e", script4, outputArguments], execOptions);
199903
199974
  return stdout.trim();
199904
199975
  }
199905
- var execFileAsync6;
199976
+ var execFileAsync7;
199906
199977
  var init_run_applescript = __esm(() => {
199907
- execFileAsync6 = promisify9(execFile9);
199978
+ execFileAsync7 = promisify10(execFile10);
199908
199979
  });
199909
199980
 
199910
199981
  // node_modules/bundle-name/index.js
@@ -199917,9 +199988,9 @@ var init_bundle_name = __esm(() => {
199917
199988
  });
199918
199989
 
199919
199990
  // node_modules/default-browser/windows.js
199920
- import { promisify as promisify10 } from "node:util";
199921
- import { execFile as execFile10 } from "node:child_process";
199922
- 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) {
199923
199994
  const { stdout } = await _execFileAsync("reg", [
199924
199995
  "QUERY",
199925
199996
  " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
@@ -199937,9 +200008,9 @@ async function defaultBrowser(_execFileAsync = execFileAsync7) {
199937
200008
  }
199938
200009
  return browser;
199939
200010
  }
199940
- var execFileAsync7, windowsBrowserProgIds, UnknownBrowserError;
200011
+ var execFileAsync8, windowsBrowserProgIds, UnknownBrowserError;
199941
200012
  var init_windows = __esm(() => {
199942
- execFileAsync7 = promisify10(execFile10);
200013
+ execFileAsync8 = promisify11(execFile11);
199943
200014
  windowsBrowserProgIds = {
199944
200015
  AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
199945
200016
  MSEdgeDHTML: { name: "Edge", id: "com.microsoft.edge" },
@@ -199956,9 +200027,9 @@ var init_windows = __esm(() => {
199956
200027
  });
199957
200028
 
199958
200029
  // node_modules/default-browser/index.js
199959
- import { promisify as promisify11 } from "node:util";
200030
+ import { promisify as promisify12 } from "node:util";
199960
200031
  import process17 from "node:process";
199961
- import { execFile as execFile11 } from "node:child_process";
200032
+ import { execFile as execFile12 } from "node:child_process";
199962
200033
  async function defaultBrowser2() {
199963
200034
  if (process17.platform === "darwin") {
199964
200035
  const id2 = await defaultBrowserId();
@@ -199966,7 +200037,7 @@ async function defaultBrowser2() {
199966
200037
  return { name, id: id2 };
199967
200038
  }
199968
200039
  if (process17.platform === "linux") {
199969
- 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"]);
199970
200041
  const id2 = stdout.trim();
199971
200042
  const name = titleize(id2.replace(/.desktop$/, "").replace("-", " "));
199972
200043
  return { name, id: id2 };
@@ -199976,12 +200047,12 @@ async function defaultBrowser2() {
199976
200047
  }
199977
200048
  throw new Error("Only macOS, Linux, and Windows are supported");
199978
200049
  }
199979
- 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());
199980
200051
  var init_default_browser = __esm(() => {
199981
200052
  init_default_browser_id();
199982
200053
  init_bundle_name();
199983
200054
  init_windows();
199984
- execFileAsync8 = promisify11(execFile11);
200055
+ execFileAsync9 = promisify12(execFile12);
199985
200056
  });
199986
200057
 
199987
200058
  // node_modules/open/index.js
@@ -199995,14 +200066,14 @@ import process18 from "node:process";
199995
200066
  import { Buffer as Buffer6 } from "node:buffer";
199996
200067
  import path31 from "node:path";
199997
200068
  import { fileURLToPath as fileURLToPath8 } from "node:url";
199998
- import { promisify as promisify12 } from "node:util";
200069
+ import { promisify as promisify13 } from "node:util";
199999
200070
  import childProcess from "node:child_process";
200000
200071
  import fs13, { constants as fsConstants2 } from "node:fs/promises";
200001
200072
  async function getWindowsDefaultBrowserFromWsl() {
200002
200073
  const powershellPath = await powerShellPath();
200003
200074
  const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
200004
200075
  const encodedCommand = Buffer6.from(rawCommand, "utf16le").toString("base64");
200005
- const { stdout } = await execFile12(powershellPath, [
200076
+ const { stdout } = await execFile13(powershellPath, [
200006
200077
  "-NoProfile",
200007
200078
  "-NonInteractive",
200008
200079
  "-ExecutionPolicy",
@@ -200038,7 +200109,7 @@ function detectPlatformBinary({ [platform6]: platformBinary }, { wsl }) {
200038
200109
  }
200039
200110
  return detectArchBinary(platformBinary);
200040
200111
  }
200041
- var execFile12, __dirname2, localXdgOpenPath, platform6, arch3, pTryEach = async (array2, mapper) => {
200112
+ var execFile13, __dirname2, localXdgOpenPath, platform6, arch3, pTryEach = async (array2, mapper) => {
200042
200113
  let latestError;
200043
200114
  for (const item of array2) {
200044
200115
  try {
@@ -200217,7 +200288,7 @@ var init_open = __esm(() => {
200217
200288
  init_wsl_utils();
200218
200289
  init_default_browser();
200219
200290
  init_is_inside_container();
200220
- execFile12 = promisify12(childProcess.execFile);
200291
+ execFile13 = promisify13(childProcess.execFile);
200221
200292
  __dirname2 = path31.dirname(fileURLToPath8(import.meta.url));
200222
200293
  localXdgOpenPath = path31.join(__dirname2, "xdg-open");
200223
200294
  ({ platform: platform6, arch: arch3 } = process18);
@@ -207662,7 +207733,7 @@ import {
207662
207733
  mkdirSync as mkdirSync28,
207663
207734
  readFileSync as readFileSync30,
207664
207735
  renameSync as renameSync6,
207665
- rmSync as rmSync10,
207736
+ rmSync as rmSync11,
207666
207737
  statSync as statSync14,
207667
207738
  writeFileSync as writeFileSync21
207668
207739
  } from "node:fs";
@@ -207808,7 +207879,7 @@ function isLockStale(lockDir) {
207808
207879
  }
207809
207880
  function stealLock(lockDir) {
207810
207881
  try {
207811
- rmSync10(lockDir, { recursive: true, force: true });
207882
+ rmSync11(lockDir, { recursive: true, force: true });
207812
207883
  } catch {}
207813
207884
  }
207814
207885
  function acquireLock() {
@@ -207830,7 +207901,7 @@ function acquireLock() {
207830
207901
  try {
207831
207902
  const current = readLockOwner(lockDir);
207832
207903
  if (current && current.token === token2) {
207833
- rmSync10(lockDir, { recursive: true, force: true });
207904
+ rmSync11(lockDir, { recursive: true, force: true });
207834
207905
  }
207835
207906
  } catch {}
207836
207907
  }
@@ -208335,11 +208406,12 @@ function safeAppendCronRunLogForTask(task2, entry) {
208335
208406
  try {
208336
208407
  appendCronRunLogForTask(task2, entry);
208337
208408
  } catch (err) {
208338
- 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);
208339
208410
  }
208340
208411
  }
208341
208412
  var DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2000000, DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2000;
208342
208413
  var init_run_log = __esm(() => {
208414
+ init_debug();
208343
208415
  init_cron_file();
208344
208416
  });
208345
208417
 
@@ -208876,7 +208948,7 @@ function scheduleQueuePump(runtime, socket, opts, processQueuedTurn) {
208876
208948
  error: error4,
208877
208949
  context: "listener_queue_pump"
208878
208950
  });
208879
- console.error("[Listen] Error in queue pump:", error4);
208951
+ debugWarn("Listen", "Error in queue pump:", error4);
208880
208952
  emitListenerStatus(runtime.listener, opts.onStatusChange, opts.connectionId);
208881
208953
  evictConversationRuntimeIfIdle(runtime);
208882
208954
  });
@@ -208884,6 +208956,7 @@ function scheduleQueuePump(runtime, socket, opts, processQueuedTurn) {
208884
208956
  var init_queue = __esm(async () => {
208885
208957
  init_queue_runtime();
208886
208958
  init_error_reporting();
208959
+ init_debug();
208887
208960
  init_protocol_outbound();
208888
208961
  init_runtime();
208889
208962
  init_transport();
@@ -209138,6 +209211,13 @@ function formatCronPrompt(task2, timing2) {
209138
209211
  var init_prompt = () => {};
209139
209212
 
209140
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
+ }
209141
209221
  function minuteKey(date) {
209142
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")}`;
209143
209223
  }
@@ -209402,7 +209482,7 @@ async function runCronTaskNow(taskId) {
209402
209482
  }
209403
209483
  function tick2(state, socket, opts, processQueuedTurn) {
209404
209484
  if (!verifySchedulerLease(state.token)) {
209405
- console.error("[Cron] Scheduler lease lost. Stopping.");
209485
+ logScheduler(opts, "Scheduler lease lost. Stopping.");
209406
209486
  stopScheduler();
209407
209487
  return;
209408
209488
  }
@@ -209439,7 +209519,7 @@ function tick2(state, socket, opts, processQueuedTurn) {
209439
209519
  return;
209440
209520
  const schedulerNow = new Date;
209441
209521
  fireCronTask(freshTask, { intendedOccurrence, schedulerNow }, socket, opts, processQueuedTurn, "automatic").catch((err) => {
209442
- console.error(`[Cron] Error firing task ${taskId}:`, err);
209522
+ logScheduler(opts, `Error firing task ${taskId}: ${err instanceof Error ? err.message : String(err)}`);
209443
209523
  setLastRunOutcome(freshTask.id, {
209444
209524
  outcome: "failed",
209445
209525
  reason: "scheduler_error",
@@ -209477,12 +209557,12 @@ function startScheduler(socket, opts, processQueuedTurn, _retryCount = 0) {
209477
209557
  token2 = claimSchedulerLease();
209478
209558
  } catch (err) {
209479
209559
  if (_retryCount < MAX_LEASE_RETRIES) {
209480
- console.warn(`[Cron] Could not claim scheduler lease (attempt ${_retryCount + 1}/${MAX_LEASE_RETRIES + 1}): ${err instanceof Error ? err.message : err}`);
209481
- 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...");
209482
209562
  setTimeout(() => startScheduler(socket, opts, processQueuedTurn, _retryCount + 1), LEASE_RETRY_MS);
209483
209563
  } else {
209484
- console.error(`[Cron] Failed to claim scheduler lease after ${MAX_LEASE_RETRIES + 1} attempts. Cron tasks will not fire.`);
209485
- 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.");
209486
209566
  }
209487
209567
  return;
209488
209568
  }
@@ -209511,7 +209591,7 @@ function startScheduler(socket, opts, processQueuedTurn, _retryCount = 0) {
209511
209591
  state.lastMtime = 0;
209512
209592
  }
209513
209593
  } catch (err) {
209514
- console.error("[Cron] GC error:", err);
209594
+ logScheduler(opts, `GC error: ${err instanceof Error ? err.message : String(err)}`);
209515
209595
  }
209516
209596
  }, GC_INTERVAL_MS);
209517
209597
  schedulerState = state;
@@ -209534,6 +209614,7 @@ function stopScheduler() {
209534
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";
209535
209615
  var init_scheduler = __esm(async () => {
209536
209616
  init_backend2();
209617
+ init_debug();
209537
209618
  init_connection();
209538
209619
  init_protocol_outbound();
209539
209620
  init_runtime();
@@ -209602,10 +209683,10 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
209602
209683
  const response = await list({ limit: 100, onlineOnly: true });
209603
209684
  const matches3 = response.connections.filter((environment3) => environment3.listenerInstanceId?.startsWith("desktop-direct-cloud:") === true && isEnvironmentOnline(environment3));
209604
209685
  if (matches3.length === 0) {
209605
- throw new Error("Desktop Local is unavailable. Open Letta Desktop, enable Remote Access, and wait for its environment to come online.");
209686
+ throw new Error("Desktop Local is unavailable. Open Letta Desktop, enable Remote Access, and wait for its computer connection to come online.");
209606
209687
  }
209607
209688
  if (matches3.length > 1) {
209608
- throw new Error(`Multiple Desktop environments are online. Run \`letta teleport list\` and choose one by name, device ID, or connection ID. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209689
+ throw new Error(`Multiple Desktop computers are online. Run \`letta teleport list\` and choose one by name, device ID, or connection ID. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209609
209690
  }
209610
209691
  const environment2 = matches3[0];
209611
209692
  if (!environment2?.connectionId) {
@@ -209616,28 +209697,28 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
209616
209697
  async function resolveEnvironmentConnectionId(selector) {
209617
209698
  const trimmed = selector.trim();
209618
209699
  if (!trimmed) {
209619
- throw new Error("Environment selector must not be empty");
209700
+ throw new Error("Computer selector must not be empty");
209620
209701
  }
209621
209702
  const response = await listEnvironments({ limit: 100 });
209622
209703
  const matches3 = response.connections.filter((environment3) => {
209623
209704
  return environment3.connectionId === trimmed || environment3.id === trimmed || environment3.deviceId === trimmed || environment3.connectionName === trimmed;
209624
209705
  });
209625
209706
  if (matches3.length === 0) {
209626
- throw new Error(`Environment "${trimmed}" not found. Run \`letta environments list\` to discover available environments.`);
209707
+ throw new Error(`Computer "${trimmed}" not found. Run \`letta computers list\` to discover available computers.`);
209627
209708
  }
209628
209709
  const onlineMatches = matches3.filter(isEnvironmentOnline);
209629
209710
  if (onlineMatches.length === 0) {
209630
- throw new Error(`Environment "${trimmed}" is offline. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209711
+ throw new Error(`Computer "${trimmed}" is offline. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209631
209712
  }
209632
209713
  if (onlineMatches.length > 1) {
209633
- throw new Error(`Environment "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
209714
+ throw new Error(`Computer "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
209634
209715
  }
209635
209716
  const environment2 = onlineMatches[0];
209636
209717
  if (!environment2) {
209637
- throw new Error(`Environment "${trimmed}" is offline`);
209718
+ throw new Error(`Computer "${trimmed}" is offline`);
209638
209719
  }
209639
209720
  if (!environment2.connectionId) {
209640
- throw new Error(`Environment "${trimmed}" has no active connection id`);
209721
+ throw new Error(`Computer "${trimmed}" has no active connection id`);
209641
209722
  }
209642
209723
  return { connectionId: environment2.connectionId, environment: environment2 };
209643
209724
  }
@@ -209908,8 +209989,8 @@ Add options:
209908
209989
  the fallback when Cloud scheduling cannot
209909
209990
  reach this computer)
209910
209991
  --computer <id> (cloud runner only) Override execution with a
209911
- connected external environment (deviceId from
209912
- \`letta environments list\`). Falls back to the Cloud
209992
+ connected external computer (deviceId from
209993
+ \`letta computers list\`). Falls back to the Cloud
209913
209994
  sandbox if the computer is offline at fire time.
209914
209995
  Managed sandboxes and Desktop-local connections are
209915
209996
  not currently valid Cloud schedule targets.
@@ -210096,7 +210177,7 @@ async function handleAdd(values3) {
210096
210177
  targetDeviceId = inferredDeviceId;
210097
210178
  } else if (resolution.kind === "local-fallback") {
210098
210179
  runner = "local";
210099
- localFallbackNote = `This schedule is local to this computer (${resolution.reason}): it only fires while a Letta session is running here. For a schedule that fires regardless, pass --runner cloud (runs in the agent's cloud sandbox) or --computer <deviceId> (runs on a connected computer, from \`letta environments list\`).`;
210180
+ localFallbackNote = `This schedule is local to this computer (${resolution.reason}): it only fires while a Letta session is running here. For a schedule that fires regardless, pass --runner cloud (runs in the agent's cloud sandbox) or --computer <deviceId> (runs on a connected computer, from \`letta computers list\`).`;
210100
210181
  }
210101
210182
  }
210102
210183
  if (runner === "cloud") {
@@ -210544,25 +210625,27 @@ import { parseArgs as parseArgs6 } from "node:util";
210544
210625
  function printUsage5() {
210545
210626
  console.log(`
210546
210627
  Usage:
210547
- letta environments list [options]
210548
- letta environments current
210628
+ letta computers list [options]
210629
+ letta computers current
210549
210630
 
210550
- Aliases:
210631
+ Legacy aliases:
210632
+ letta environments list
210633
+ letta environments current
210551
210634
  letta envs list
210552
210635
  letta envs current
210553
210636
 
210554
210637
  List options:
210555
210638
  --limit <n> Max results (default: 50)
210556
- --after <id> Pagination cursor from a previous environment id
210557
- --online-only Only include environments with a fresh active connection
210639
+ --after <id> Pagination cursor from a previous computer id
210640
+ --online-only Only include computers with a fresh active connection
210558
210641
 
210559
210642
  Notes:
210560
210643
  - Output is JSON only.
210561
210644
  - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
210562
- - Use letta environments current to get this machine's connectionId.
210563
- - Use --environment cloud to route through the target agent's cloud sandbox.
210564
- - Use --environment <name|device-id|connection-id> with headless messaging
210565
- to route a message through a specific registered environment.
210645
+ - Use letta computers current to get this computer's connectionId.
210646
+ - Use --computer cloud to route through the target agent's cloud sandbox.
210647
+ - Use --computer <name|device-id|connection-id> with headless messaging
210648
+ to route a message through a specific registered computer.
210566
210649
  `.trim());
210567
210650
  }
210568
210651
  function parseLimit2(value, fallback) {
@@ -210649,7 +210732,7 @@ async function runEnvironmentsSubcommand(argv, deps = {}) {
210649
210732
  currentVersion
210650
210733
  });
210651
210734
  if (!current2) {
210652
- console.error("No online environment found for this device. Start one with `letta server` and try again.");
210735
+ console.error("No online computer found for this device. Start one with `letta server` and try again.");
210653
210736
  return 1;
210654
210737
  }
210655
210738
  console.log(JSON.stringify(formatEnvironmentForCli(current2, {
@@ -212471,7 +212554,7 @@ function ListenerStatusUI(props) {
212471
212554
  bold: true,
212472
212555
  color: "green",
212473
212556
  children: [
212474
- "The name of your environment is: ",
212557
+ "The name of your computer is: ",
212475
212558
  envName
212476
212559
  ]
212477
212560
  }, undefined, true, undefined, this)
@@ -212504,7 +212587,7 @@ function ListenerStatusUI(props) {
212504
212587
  children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
212505
212588
  dimColor: true,
212506
212589
  children: [
212507
- 'Connect to this environment by visiting any agent and clicking the "cloud" button at the bottom left of the messenger input and swapping your environment to ',
212590
+ 'Connect to this computer by visiting any agent and clicking the "cloud" button at the bottom left of the messenger input and swapping your computer to ',
212508
212591
  envName
212509
212592
  ]
212510
212593
  }, undefined, true, undefined, this)
@@ -215280,7 +215363,7 @@ async function awaitMemoryPushBounded(commandName, agentId, memoryRoot) {
215280
215363
  });
215281
215364
  const warnOnFailure = (result2) => {
215282
215365
  if (result2.status === "push_failed" || result2.status === "conflict") {
215283
- console.warn(`[${commandName}] push failed for ${agentId}: ${result2.summary}`);
215366
+ warnMemoryCommand(`[${commandName}] push failed for ${agentId}: ${result2.summary}`);
215284
215367
  }
215285
215368
  };
215286
215369
  let timer;
@@ -215290,15 +215373,15 @@ async function awaitMemoryPushBounded(commandName, agentId, memoryRoot) {
215290
215373
  try {
215291
215374
  const result2 = await Promise.race([syncPromise, capPromise]);
215292
215375
  if (result2 === "timed_out") {
215293
- 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`);
215294
215377
  syncPromise.then(warnOnFailure).catch((err) => {
215295
- 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);
215296
215379
  });
215297
215380
  return;
215298
215381
  }
215299
215382
  warnOnFailure(result2);
215300
215383
  } catch (err) {
215301
- 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);
215302
215385
  } finally {
215303
215386
  if (timer)
215304
215387
  clearTimeout(timer);
@@ -215523,15 +215606,15 @@ function handleMemoryProtocolCommand(parsed, context3) {
215523
215606
  runDetachedListenerTask("memory_history", async () => {
215524
215607
  const { getScopedMemoryFilesystemRoot: getScopedMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
215525
215608
  const { execFile: execFileCb4 } = await import("node:child_process");
215526
- const { promisify: promisify13 } = await import("node:util");
215527
- const execFileAsync9 = promisify13(execFileCb4);
215609
+ const { promisify: promisify14 } = await import("node:util");
215610
+ const execFileAsync10 = promisify14(execFileCb4);
215528
215611
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
215529
215612
  const limit3 = parsed.limit ?? 50;
215530
215613
  const gitArgs = ["log", `--max-count=${limit3}`, "--format=%H|%s|%aI|%an"];
215531
215614
  if (parsed.file_path) {
215532
215615
  gitArgs.push("--", parsed.file_path);
215533
215616
  }
215534
- const { stdout } = await execFileAsync9("git", gitArgs, {
215617
+ const { stdout } = await execFileAsync10("git", gitArgs, {
215535
215618
  cwd: memoryRoot,
215536
215619
  timeout: 1e4
215537
215620
  });
@@ -215559,11 +215642,11 @@ function handleMemoryProtocolCommand(parsed, context3) {
215559
215642
  runDetachedListenerTask("memory_file_at_ref", async () => {
215560
215643
  const { getScopedMemoryFilesystemRoot: getScopedMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
215561
215644
  const { execFile: execFileCb4 } = await import("node:child_process");
215562
- const { promisify: promisify13 } = await import("node:util");
215563
- const execFileAsync9 = promisify13(execFileCb4);
215645
+ const { promisify: promisify14 } = await import("node:util");
215646
+ const execFileAsync10 = promisify14(execFileCb4);
215564
215647
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
215565
215648
  try {
215566
- 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 });
215567
215650
  safeSocketSend(socket, {
215568
215651
  type: "memory_file_at_ref_response",
215569
215652
  request_id: parsed.request_id,
@@ -215590,11 +215673,11 @@ function handleMemoryProtocolCommand(parsed, context3) {
215590
215673
  runDetachedListenerTask("memory_commit_diff", async () => {
215591
215674
  const { getScopedMemoryFilesystemRoot: getScopedMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
215592
215675
  const { execFile: execFileCb4 } = await import("node:child_process");
215593
- const { promisify: promisify13 } = await import("node:util");
215594
- const execFileAsync9 = promisify13(execFileCb4);
215676
+ const { promisify: promisify14 } = await import("node:util");
215677
+ const execFileAsync10 = promisify14(execFileCb4);
215595
215678
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
215596
215679
  try {
215597
- 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 });
215598
215681
  safeSocketSend(socket, {
215599
215682
  type: "memory_commit_diff_response",
215600
215683
  request_id: parsed.request_id,
@@ -215676,7 +215759,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
215676
215759
  }, "listener_read_memory_file_send_failed", "listener_read_memory_file");
215677
215760
  } catch (err) {
215678
215761
  trackListenerError("listener_read_memory_file_failed", err, "listener_memory_read");
215679
- 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"}`);
215680
215763
  sendFailure(err instanceof Error ? err.message : "Failed to read memory file");
215681
215764
  }
215682
215765
  });
@@ -215775,7 +215858,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
215775
215858
  }, "listener_write_memory_file_send_failed", "listener_write_memory_file");
215776
215859
  } catch (err) {
215777
215860
  trackListenerError("listener_write_memory_file_failed", err, "listener_memory_write");
215778
- 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"}`);
215779
215862
  sendFailure(err instanceof Error ? err.message : "Failed to write memory file");
215780
215863
  }
215781
215864
  });
@@ -215888,7 +215971,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
215888
215971
  }, "listener_delete_memory_file_send_failed", "listener_delete_memory_file");
215889
215972
  } catch (err) {
215890
215973
  trackListenerError("listener_delete_memory_file_failed", err, "listener_memory_delete");
215891
- 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"}`);
215892
215975
  sendFailure(err instanceof Error ? err.message : "Failed to delete memory file");
215893
215976
  }
215894
215977
  });
@@ -215896,10 +215979,12 @@ function handleMemoryProtocolCommand(parsed, context3) {
215896
215979
  }
215897
215980
  return false;
215898
215981
  }
215899
- 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;
215900
215983
  var init_memory6 = __esm(() => {
215901
215984
  init_error_reporting();
215985
+ init_debug();
215902
215986
  init_protocol_inbound();
215987
+ warnMemoryCommand = debugWarn.bind(null, "memory-commands");
215903
215988
  WIKI_LINK_REGEX = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
215904
215989
  IMAGE_MIME_BY_EXTENSION = {
215905
215990
  ".gif": "image/gif",
@@ -300568,7 +300653,7 @@ ${lanes.join(`
300568
300653
  if (!links2.hasReportedStatementInAmbientContext) {
300569
300654
  return links2.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
300570
300655
  }
300571
- } else {}
300656
+ }
300572
300657
  }
300573
300658
  return false;
300574
300659
  }
@@ -310032,7 +310117,7 @@ ${lanes.join(`
310032
310117
  ], 2));
310033
310118
  setParentRecursive(requireStatement, false);
310034
310119
  statements = insertStatementAfterCustomPrologue(statements.slice(), requireStatement);
310035
- } else {}
310120
+ }
310036
310121
  }
310037
310122
  }
310038
310123
  if (statements !== visited2.statements) {
@@ -385581,7 +385666,7 @@ import {
385581
385666
  existsSync as existsSync47,
385582
385667
  mkdirSync as mkdirSync33,
385583
385668
  readFileSync as readFileSync35,
385584
- rmSync as rmSync11,
385669
+ rmSync as rmSync12,
385585
385670
  writeFileSync as writeFileSync25
385586
385671
  } from "node:fs";
385587
385672
  import path37 from "node:path";
@@ -386184,7 +386269,7 @@ function removeManagedModPackage(params) {
386184
386269
  assertSafePackageRemovalRoot(match3.metadata);
386185
386270
  registry.packagesValue.splice(match3.index, 1);
386186
386271
  writePackageRegistry(registry.registryPath, registry.registry);
386187
- rmSync11(match3.metadata.packageRoot, { force: true, recursive: true });
386272
+ rmSync12(match3.metadata.packageRoot, { force: true, recursive: true });
386188
386273
  return {
386189
386274
  package: mutationItem(match3.metadata, match3.index, match3.metadata.enabled),
386190
386275
  registryPath: registry.registryPath,
@@ -387698,7 +387783,7 @@ async function syncMemfsForAgent(agentId) {
387698
387783
  debugLog("memfs-sync", `Agent ${agentId} does not have memfs tag (self-hosted), skipping`);
387699
387784
  return;
387700
387785
  }
387701
- 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).`);
387702
387787
  await applyMemfsFlags2(agentId, true, {
387703
387788
  pullOnExistingRepo: true,
387704
387789
  agentTags: agent.tags ?? []
@@ -390483,7 +390568,7 @@ function markAsFinished(b3, id2) {
390483
390568
  if (updatedLine.kind === "assistant" && "text" in updatedLine && updatedLine.text) {
390484
390569
  b3.lastAssistantMessage = updatedLine.text;
390485
390570
  }
390486
- } else {}
390571
+ }
390487
390572
  }
390488
390573
  function handleOtidTransition(b3, newOtid) {
390489
390574
  if (b3.lastOtid && b3.lastOtid !== newOtid) {
@@ -390501,7 +390586,7 @@ function markCurrentLineAsFinished(b3) {
390501
390586
  const prev = b3.byId.get(b3.lastOtid);
390502
390587
  if (prev && (prev.kind === "assistant" || prev.kind === "reasoning")) {
390503
390588
  markAsFinished(b3, b3.lastOtid);
390504
- } else {}
390589
+ }
390505
390590
  }
390506
390591
  function markIncompleteToolsAsCancelled(b3, setInterruptedFlag = true, reason = "internal_cancel", skipMarkCurrentLine = false) {
390507
390592
  if (setInterruptedFlag) {
@@ -393285,8 +393370,15 @@ function isChatGPTByokHandleInModels(handle2, models3) {
393285
393370
  const entry = models3.find((m4) => m4.handle === handle2);
393286
393371
  return entry?.providerType === "chatgpt_oauth" && entry?.providerCategory === "byok";
393287
393372
  }
393288
- async function resolveAgentModelHandle2(agentId) {
393373
+ async function resolveScopedModelHandle(agentId, conversationId) {
393289
393374
  try {
393375
+ if (conversationId !== "default") {
393376
+ const conversation = await getBackend().retrieveConversation(conversationId);
393377
+ const conversationRecord = conversation;
393378
+ if (typeof conversationRecord.model === "string" && conversationRecord.model.length > 0) {
393379
+ return conversationRecord.model;
393380
+ }
393381
+ }
393290
393382
  const agent = await getBackend().retrieveAgent(agentId);
393291
393383
  const record3 = agent;
393292
393384
  if (typeof record3.model === "string" && record3.model.length > 0) {
@@ -393298,7 +393390,7 @@ async function resolveAgentModelHandle2(agentId) {
393298
393390
  }
393299
393391
  }
393300
393392
  async function rotateChatGPTPlanOnQuotaLimit(params) {
393301
- const { agentId, error: error4 } = params;
393393
+ const { agentId, conversationId, error: error4, exhaustedProviders } = params;
393302
393394
  const parsedDetail = parseChatGPTUsageLimitDetail(error4);
393303
393395
  if (!parsedDetail)
393304
393396
  return null;
@@ -393313,9 +393405,9 @@ async function rotateChatGPTPlanOnQuotaLimit(params) {
393313
393405
  }
393314
393406
  if (!models3)
393315
393407
  return null;
393316
- let currentHandle = params.currentHandle;
393408
+ let currentHandle = await resolveScopedModelHandle(agentId, conversationId);
393317
393409
  if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
393318
- currentHandle = await resolveAgentModelHandle2(agentId);
393410
+ currentHandle = params.currentHandle;
393319
393411
  }
393320
393412
  if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
393321
393413
  return null;
@@ -393335,9 +393427,15 @@ async function rotateChatGPTPlanOnQuotaLimit(params) {
393335
393427
  if (!toProvider)
393336
393428
  return null;
393337
393429
  try {
393338
- await updateAgentLLMConfig(agentId, toHandle, {
393339
- provider_type: "chatgpt_oauth"
393340
- });
393430
+ if (conversationId === "default") {
393431
+ await updateAgentLLMConfig(agentId, toHandle, {
393432
+ provider_type: "chatgpt_oauth"
393433
+ });
393434
+ } else {
393435
+ await updateConversationLLMConfig(conversationId, toHandle, {
393436
+ provider_type: "chatgpt_oauth"
393437
+ });
393438
+ }
393341
393439
  } catch {
393342
393440
  return null;
393343
393441
  }
@@ -393356,14 +393454,13 @@ function formatPlanRotationNotice(params) {
393356
393454
  })})` : "";
393357
393455
  return `${fromProvider} hit its usage limit${resetSuffix} — switched to ${toProvider}`;
393358
393456
  }
393359
- var CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN = 3, exhaustedProviders;
393457
+ var CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN = 3;
393360
393458
  var init_chatgpt_plan_rotation = __esm(() => {
393361
393459
  init_available_models();
393362
393460
  init_model_handles();
393363
393461
  init_modify();
393364
393462
  init_turn_recovery_policy();
393365
393463
  init_backend2();
393366
- exhaustedProviders = new Set;
393367
393464
  });
393368
393465
 
393369
393466
  // src/websocket/listener/skill-injection.ts
@@ -397871,12 +397968,12 @@ function rowToolCalls(row, index, diagnostics2) {
397871
397968
  }
397872
397969
  return calls;
397873
397970
  }
397874
- function contentText2(content) {
397971
+ function contentText(content) {
397875
397972
  if (typeof content === "string") {
397876
397973
  if (content.startsWith(CONTENT_JSON_PREFIX)) {
397877
397974
  const encoded = content.slice(CONTENT_JSON_PREFIX.length);
397878
397975
  try {
397879
- return contentText2(JSON.parse(encoded));
397976
+ return contentText(JSON.parse(encoded));
397880
397977
  } catch {
397881
397978
  return encoded;
397882
397979
  }
@@ -397962,7 +398059,7 @@ var init_hermes = __esm(() => {
397962
398059
  });
397963
398060
  };
397964
398061
  if (row.role === "user") {
397965
- const content = contentText2(row.content);
398062
+ const content = contentText(row.content);
397966
398063
  if (content) {
397967
398064
  emit({
397968
398065
  type: "message",
@@ -397982,7 +398079,7 @@ var init_hermes = __esm(() => {
397982
398079
  ...timestamp ? { timestamp } : {}
397983
398080
  });
397984
398081
  }
397985
- const content = contentText2(row.content);
398082
+ const content = contentText(row.content);
397986
398083
  if (content) {
397987
398084
  emit({
397988
398085
  type: "message",
@@ -398005,7 +398102,7 @@ var init_hermes = __esm(() => {
398005
398102
  if (row.role === "tool") {
398006
398103
  emit({
398007
398104
  type: "tool_result",
398008
- content: contentText2(row.content),
398105
+ content: contentText(row.content),
398009
398106
  ...typeof row.tool_call_id === "string" && row.tool_call_id ? { callId: row.tool_call_id } : {},
398010
398107
  ...timestamp ? { timestamp } : {}
398011
398108
  });
@@ -401366,11 +401463,11 @@ import { randomUUID as randomUUID27 } from "node:crypto";
401366
401463
  import { existsSync as existsSync53 } from "node:fs";
401367
401464
  import { mkdir as mkdir13 } from "node:fs/promises";
401368
401465
  import { dirname as dirname28, isAbsolute as isAbsolute26, join as join68, resolve as resolve34 } from "node:path";
401369
- import { promisify as promisify13 } from "node:util";
401466
+ import { promisify as promisify14 } from "node:util";
401370
401467
  async function runGit4(cwd2, args) {
401371
401468
  try {
401372
401469
  const allArgs = [...GIT_DISABLE_COMMIT_SIGNING_ARGS, ...args];
401373
- const { stdout, stderr } = await execFile13("git", allArgs, {
401470
+ const { stdout, stderr } = await execFile14("git", allArgs, {
401374
401471
  cwd: cwd2,
401375
401472
  env: {
401376
401473
  ...process.env,
@@ -401734,11 +401831,11 @@ async function finalizeReflectionMemoryWorktreeImpl(worktree, options) {
401734
401831
  async function finalizeReflectionMemoryWorktree(worktree, options) {
401735
401832
  return await finalizeReflectionMemoryWorktreeImpl(worktree, options);
401736
401833
  }
401737
- var execFile13, GIT_TIMEOUT_MS = 30000, HARNESS_GIT_ENV;
401834
+ var execFile14, GIT_TIMEOUT_MS = 30000, HARNESS_GIT_ENV;
401738
401835
  var init_memory_worktree = __esm(() => {
401739
401836
  init_memory_git_signing();
401740
401837
  init_debug();
401741
- execFile13 = promisify13(execFileCb4);
401838
+ execFile14 = promisify14(execFileCb4);
401742
401839
  HARNESS_GIT_ENV = {
401743
401840
  GIT_AUTHOR_NAME: "Letta Code",
401744
401841
  GIT_AUTHOR_EMAIL: "noreply@letta.com",
@@ -402835,7 +402932,7 @@ function notifyTurnStarted(msg) {
402835
402932
  try {
402836
402933
  hooksByOtid.get(otid)?.onStarted?.();
402837
402934
  } catch (error4) {
402838
- console.error("[Listen V2] Turn observer onStarted failed", error4);
402935
+ debugWarn("Listen V2", "Turn observer onStarted failed", error4);
402839
402936
  }
402840
402937
  }
402841
402938
  }
@@ -402844,12 +402941,13 @@ function notifyTurnFinished(msg) {
402844
402941
  try {
402845
402942
  hooksByOtid.get(otid)?.onFinished();
402846
402943
  } catch (error4) {
402847
- console.error("[Listen V2] Turn observer onFinished failed", error4);
402944
+ debugWarn("Listen V2", "Turn observer onFinished failed", error4);
402848
402945
  }
402849
402946
  }
402850
402947
  }
402851
402948
  var hooksByOtid;
402852
402949
  var init_turn_observers = __esm(() => {
402950
+ init_debug();
402853
402951
  hooksByOtid = new Map;
402854
402952
  });
402855
402953
 
@@ -404261,6 +404359,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
404261
404359
  const turnWorkingDirectory = getConversationWorkingDirectory(runtime.listener, agentId, conversationId);
404262
404360
  const turnPermissionModeState = getOrCreateConversationPermissionModeStateRef(runtime.listener, agentId, conversationId);
404263
404361
  let postStopApprovalRecoveryRetries = 0, llmApiErrorRetries = 0, emptyResponseRetries = 0, chatgptPlanSwaps = 0, lastApprovalContinuationAccepted = false, activeDequeuedBatchId = dequeuedBatchId;
404362
+ const chatgptExhaustedProviders = new Set;
404264
404363
  const turnCorrelation = existingTurnCorrelation ?? createTurnCorrelation(runtime, msg, activeDequeuedBatchId);
404265
404364
  const msgRunIds = [];
404266
404365
  let lastExecutionResults = null;
@@ -404627,8 +404726,10 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
404627
404726
  if (agentId && chatgptPlanSwaps < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
404628
404727
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
404629
404728
  agentId,
404729
+ conversationId,
404630
404730
  currentHandle: null,
404631
- error: quotaError
404731
+ error: quotaError,
404732
+ exhaustedProviders: chatgptExhaustedProviders
404632
404733
  });
404633
404734
  if (rotation) {
404634
404735
  chatgptPlanSwaps += 1;
@@ -405486,7 +405587,7 @@ function handleTerminalSpawn(msg, socket, cwd2, connectionId = "legacy") {
405486
405587
  alive = false;
405487
405588
  }
405488
405589
  if (alive) {
405489
- 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}`);
405490
405591
  sendTerminalMessage(socket, {
405491
405592
  type: "terminal_spawned",
405492
405593
  terminal_id,
@@ -405498,18 +405599,18 @@ function handleTerminalSpawn(msg, socket, cwd2, connectionId = "legacy") {
405498
405599
  }
405499
405600
  killTerminal(terminal_id, connectionId);
405500
405601
  const shell2 = getDefaultShell();
405501
- 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}`);
405502
405603
  try {
405503
405604
  const session = IS_BUN ? spawnBun(shell2, cwd2, cols, rows, terminal_id, connectionId, socket) : spawnNodePty(shell2, cwd2, cols, rows, terminal_id, connectionId, socket);
405504
405605
  terminals.set(terminalKey, session);
405505
- 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}`);
405506
405607
  sendTerminalMessage(socket, {
405507
405608
  type: "terminal_spawned",
405508
405609
  terminal_id,
405509
405610
  pid: session.pid
405510
405611
  });
405511
405612
  } catch (error4) {
405512
- console.error("[Terminal] Failed to spawn PTY:", error4);
405613
+ debugWarn("Terminal", "Failed to spawn PTY:", error4);
405513
405614
  sendTerminalMessage(socket, {
405514
405615
  type: "terminal_exited",
405515
405616
  terminal_id,
@@ -405527,7 +405628,7 @@ function handleTerminalResize(msg, connectionId = "legacy") {
405527
405628
  function handleTerminalKill(msg, connectionId = "legacy") {
405528
405629
  const session = terminals.get(getTerminalKey(connectionId, msg.terminal_id));
405529
405630
  if (session && Date.now() - session.spawnedAt < 2000) {
405530
- 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)`);
405531
405632
  return;
405532
405633
  }
405533
405634
  killTerminal(msg.terminal_id, connectionId);
@@ -405536,7 +405637,7 @@ function killTerminal(terminalId, connectionId) {
405536
405637
  const terminalKey = getTerminalKey(connectionId, terminalId);
405537
405638
  const session = terminals.get(terminalKey);
405538
405639
  if (session) {
405539
- console.log(`[Terminal] killTerminal: terminalId=${terminalId}, pid=${session.pid}`);
405640
+ debugLog("Terminal", `killTerminal: terminalId=${terminalId}, pid=${session.pid}`);
405540
405641
  session.kill();
405541
405642
  terminals.delete(terminalKey);
405542
405643
  }
@@ -405555,6 +405656,7 @@ function killAllTerminals() {
405555
405656
  }
405556
405657
  var IS_BUN, FLUSH_INTERVAL_MS = 16, MAX_BUFFER_BYTES, terminals;
405557
405658
  var init_terminal_handler = __esm(() => {
405659
+ init_debug();
405558
405660
  IS_BUN = typeof Bun !== "undefined";
405559
405661
  MAX_BUFFER_BYTES = 64 * 1024;
405560
405662
  terminals = new Map;
@@ -405664,7 +405766,7 @@ var init_connection_lifecycle = __esm(async () => {
405664
405766
  });
405665
405767
 
405666
405768
  // src/websocket/listener/connection-state-sync.ts
405667
- function emitInitialConnectionState(runtime, transport, connectionId, options = {}) {
405769
+ async function emitInitialConnectionState(runtime, transport, connectionId, options = {}) {
405668
405770
  if (options.emitInitialState === false)
405669
405771
  return;
405670
405772
  const routing = toListenerConnection(connectionId);
@@ -405677,17 +405779,19 @@ function emitInitialConnectionState(runtime, transport, connectionId, options =
405677
405779
  agent_id: conversationRuntime.agentId,
405678
405780
  conversation_id: conversationRuntime.conversationId
405679
405781
  };
405782
+ await refreshDeviceGitContext(conversationRuntime, scope);
405680
405783
  emitDeviceStatusUpdate(transport, conversationRuntime, scope, routing);
405681
405784
  emitLoopStatusUpdate(transport, conversationRuntime, scope, routing);
405682
405785
  }
405683
405786
  }
405684
- function replaySubscribedConnectionState(listener, transport, runtime, scope, forceDeviceStatus) {
405787
+ async function replaySubscribedConnectionState(listener, transport, runtime, scope, options = {}) {
405788
+ await (options.refreshGitContext ?? refreshDeviceGitContext)(listener, scope);
405685
405789
  const connection = findListenerConnectionByTransport(listener, transport);
405686
405790
  if (connection) {
405687
405791
  replayPendingApprovalRequestsToConnection(runtime, connection.id);
405688
405792
  }
405689
405793
  emitStateSync(transport, listener, scope, {
405690
- forceDeviceStatus,
405794
+ forceDeviceStatus: options.forceDeviceStatus,
405691
405795
  ...connection ? { routing: toListenerConnection(connection.id) } : {}
405692
405796
  });
405693
405797
  }
@@ -405698,7 +405802,7 @@ var init_connection_state_sync = __esm(() => {
405698
405802
  });
405699
405803
 
405700
405804
  // src/websocket/listener/grep-in-files.ts
405701
- import { execFile as execFile14 } from "node:child_process";
405805
+ import { execFile as execFile15 } from "node:child_process";
405702
405806
  import { createRequire as createRequire6 } from "node:module";
405703
405807
  import * as path43 from "node:path";
405704
405808
  import { fileURLToPath as fileURLToPath10 } from "node:url";
@@ -405754,7 +405858,7 @@ async function runGrepInFiles(args) {
405754
405858
  }
405755
405859
  function runRipgrep(rgArgs) {
405756
405860
  return new Promise((resolve35, reject2) => {
405757
- const child = execFile14(rgPath, rgArgs, {
405861
+ const child = execFile15(rgPath, rgArgs, {
405758
405862
  maxBuffer: 50 * 1024 * 1024
405759
405863
  }, (error4, stdout, _stderr) => {
405760
405864
  if (error4 && error4.code !== 1) {
@@ -406222,10 +406326,10 @@ function createFileCommandSession(params) {
406222
406326
  return true;
406223
406327
  }
406224
406328
  if (isListInDirectoryCommand(parsed)) {
406225
- console.log(`[Listen] Received list_in_directory command: path=${parsed.path}`);
406329
+ logFileCommand(`[Listen] Received list_in_directory command: path=${parsed.path}`);
406226
406330
  runDetachedListenerTask("list_in_directory", async () => {
406227
406331
  try {
406228
- console.log(`[Listen] Reading directory: ${parsed.path}`);
406332
+ logFileCommand(`[Listen] Reading directory: ${parsed.path}`);
406229
406333
  const { folders: allFolders, files: allFiles } = await listDirectoryDirect(parsed.path, parsed.path, !!parsed.include_files);
406230
406334
  const total = allFolders.length + allFiles.length;
406231
406335
  const offset = parsed.offset ?? 0;
@@ -406247,11 +406351,11 @@ function createFileCommandSession(params) {
406247
406351
  if (parsed.include_files) {
406248
406352
  response.files = files;
406249
406353
  }
406250
- 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`);
406251
406355
  safeSocketSend(socket, response, "listener_list_directory_send_failed", "listener_list_in_directory");
406252
406356
  } catch (err) {
406253
406357
  trackListenerError3("listener_list_directory_failed", err, "listener_file_browser");
406254
- 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"}`);
406255
406359
  safeSocketSend(socket, {
406256
406360
  type: "list_in_directory_response",
406257
406361
  path: parsed.path,
@@ -406266,14 +406370,14 @@ function createFileCommandSession(params) {
406266
406370
  return true;
406267
406371
  }
406268
406372
  if (isGetTreeCommand(parsed)) {
406269
- 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}`);
406270
406374
  runDetachedListenerTask("get_tree", async () => {
406271
406375
  try {
406272
406376
  const { entries: results, hasMoreDepth } = await getTreeDirect({
406273
406377
  root: parsed.path,
406274
406378
  depth: parsed.depth
406275
406379
  });
406276
- 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}`);
406277
406381
  safeSocketSend(socket, {
406278
406382
  type: "get_tree_response",
406279
406383
  path: parsed.path,
@@ -406284,7 +406388,7 @@ function createFileCommandSession(params) {
406284
406388
  }, "listener_get_tree_send_failed", "listener_get_tree");
406285
406389
  } catch (err) {
406286
406390
  trackListenerError3("listener_get_tree_failed", err, "listener_file_browser");
406287
- 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"}`);
406288
406392
  safeSocketSend(socket, {
406289
406393
  type: "get_tree_response",
406290
406394
  path: parsed.path,
@@ -406300,7 +406404,7 @@ function createFileCommandSession(params) {
406300
406404
  }
406301
406405
  if (isReadFileCommand(parsed)) {
406302
406406
  const encoding = parsed.encoding ?? "utf8";
406303
- 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}`);
406304
406408
  runDetachedListenerTask("read_file", async () => {
406305
406409
  try {
406306
406410
  let content;
@@ -406315,7 +406419,7 @@ function createFileCommandSession(params) {
406315
406419
  } else {
406316
406420
  content = await readUtf8TextStrict(parsed.path);
406317
406421
  }
406318
- console.log(`[Listen] read_file success: ${parsed.path} (${content.length} bytes, ${encoding})`);
406422
+ logFileCommand(`[Listen] read_file success: ${parsed.path} (${content.length} bytes, ${encoding})`);
406319
406423
  safeSocketSend(socket, {
406320
406424
  type: "read_file_response",
406321
406425
  request_id: parsed.request_id,
@@ -406326,7 +406430,7 @@ function createFileCommandSession(params) {
406326
406430
  }, "listener_read_file_send_failed", "listener_read_file");
406327
406431
  } catch (err) {
406328
406432
  trackListenerError3("listener_read_file_failed", err, "listener_file_read");
406329
- 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"}`);
406330
406434
  safeSocketSend(socket, {
406331
406435
  type: "read_file_response",
406332
406436
  request_id: parsed.request_id,
@@ -406341,7 +406445,7 @@ function createFileCommandSession(params) {
406341
406445
  return true;
406342
406446
  }
406343
406447
  if (isWriteFileCommand(parsed)) {
406344
- 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}`);
406345
406449
  runDetachedListenerTask("write_file", async () => {
406346
406450
  try {
406347
406451
  const { edit: edit3 } = await Promise.resolve().then(() => (init_edit2(), exports_edit));
@@ -406369,7 +406473,7 @@ function createFileCommandSession(params) {
406369
406473
  });
406370
406474
  }
406371
406475
  }
406372
- console.log(`[Listen] write_file success: ${parsed.path} (${parsed.content.length} bytes)`);
406476
+ logFileCommand(`[Listen] write_file success: ${parsed.path} (${parsed.content.length} bytes)`);
406373
406477
  safeSocketSend(socket, {
406374
406478
  type: "write_file_response",
406375
406479
  request_id: parsed.request_id,
@@ -406377,7 +406481,7 @@ function createFileCommandSession(params) {
406377
406481
  success: true
406378
406482
  }, "listener_write_file_send_failed", "listener_write_file");
406379
406483
  } catch (err) {
406380
- 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"}`);
406381
406485
  safeSocketSend(socket, {
406382
406486
  type: "write_file_response",
406383
406487
  request_id: parsed.request_id,
@@ -406452,11 +406556,11 @@ function createFileCommandSession(params) {
406452
406556
  return true;
406453
406557
  }
406454
406558
  if (isEditFileCommand(parsed)) {
406455
- 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}`);
406456
406560
  runDetachedListenerTask("edit_file", async () => {
406457
406561
  try {
406458
406562
  const { edit: edit3 } = await Promise.resolve().then(() => (init_edit2(), exports_edit));
406459
- 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 ? "..." : ""}"`);
406460
406564
  const result2 = await edit3({
406461
406565
  file_path: parsed.file_path,
406462
406566
  old_string: parsed.old_string,
@@ -406464,7 +406568,7 @@ function createFileCommandSession(params) {
406464
406568
  replace_all: parsed.replace_all,
406465
406569
  expected_replacements: parsed.expected_replacements
406466
406570
  });
406467
- 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}`);
406468
406572
  if (result2.replacements > 0) {
406469
406573
  try {
406470
406574
  const contentAfter = await readUtf8TextStrict(parsed.file_path);
@@ -406489,7 +406593,7 @@ function createFileCommandSession(params) {
406489
406593
  }, "listener_edit_file_send_failed", "listener_edit_file");
406490
406594
  } catch (err) {
406491
406595
  trackListenerError3("listener_edit_file_failed", err, "listener_file_edit");
406492
- 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"}`);
406493
406597
  safeSocketSend(socket, {
406494
406598
  type: "edit_file_response",
406495
406599
  request_id: parsed.request_id,
@@ -406509,9 +406613,9 @@ function createFileCommandSession(params) {
406509
406613
  try {
406510
406614
  const content = parsed.document_content;
406511
406615
  await writeUtf8Text(parsed.path, content);
406512
- console.log(`[Listen] file_ops: wrote ${content.length} bytes to ${parsed.path}`);
406616
+ logFileCommand(`[Listen] file_ops: wrote ${content.length} bytes to ${parsed.path}`);
406513
406617
  } catch (err) {
406514
- 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"}`);
406515
406619
  }
406516
406620
  });
406517
406621
  }
@@ -406521,13 +406625,16 @@ function createFileCommandSession(params) {
406521
406625
  };
406522
406626
  return { handle: handle2, dispose };
406523
406627
  }
406524
- 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;
406525
406629
  var init_file_commands = __esm(() => {
406526
406630
  init_error_reporting();
406631
+ init_debug();
406527
406632
  init_text_files();
406528
406633
  init_grep_in_files();
406529
406634
  init_protocol_inbound();
406530
406635
  import_picomatch2 = __toESM(require_picomatch(), 1);
406636
+ logFileCommand = debugLog.bind(null, "file-commands");
406637
+ warnFileCommand = debugWarn.bind(null, "file-commands");
406531
406638
  DIR_LISTING_IGNORED_NAMES = new Set([".DS_Store", ".git", "Thumbs.db"]);
406532
406639
  RECURSIVE_IGNORED_NAMES = new Set([
406533
406640
  ...DIR_LISTING_IGNORED_NAMES,
@@ -407471,6 +407578,13 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
407471
407578
  actingUserId: command.runtime.acting_user_id
407472
407579
  });
407473
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;
407474
407588
  case "doctor":
407475
407589
  output = await handleDoctorCommand(socket, conversationRuntime, opts);
407476
407590
  break;
@@ -407625,7 +407739,7 @@ async function handleUpgradeLettaCodeCommand(opts) {
407625
407739
  if (opts.onLog) {
407626
407740
  opts.onLog(line);
407627
407741
  } else {
407628
- console.log(line);
407742
+ debugLog("upgrade-letta-code", message);
407629
407743
  }
407630
407744
  };
407631
407745
  log2(`command received (connectionName=${opts.connectionName ?? "unknown"}, execPath=${process.execPath}, entrypoint=${process.argv[1] ?? "unknown"})`);
@@ -407651,11 +407765,11 @@ function scheduleRemoteRestart(connectionName, log2) {
407651
407765
  log2(`restart skipped (entrypoint=${entrypoint ?? "missing"}, connectionName=${connectionName ?? "missing"})`);
407652
407766
  return;
407653
407767
  }
407654
- log2(`scheduling remote listener restart for env ${connectionName}`);
407768
+ log2(`scheduling remote listener restart for computer ${connectionName}`);
407655
407769
  setTimeout(async () => {
407656
407770
  await flushRemoteSettingsWrites();
407657
- log2(`spawning replacement listener: ${process.execPath} ${entrypoint} remote --env-name ${connectionName}`);
407658
- const child = spawn9(process.execPath, [entrypoint, "remote", "--env-name", connectionName], {
407771
+ log2(`spawning replacement listener: ${process.execPath} ${entrypoint} remote --computer-name ${connectionName}`);
407772
+ const child = spawn9(process.execPath, [entrypoint, "remote", "--computer-name", connectionName], {
407659
407773
  cwd: process.cwd(),
407660
407774
  detached: true,
407661
407775
  env: process.env,
@@ -407769,7 +407883,10 @@ async function handleClearCommand(_socket, conversationRuntime, opts) {
407769
407883
  if (!agentId) {
407770
407884
  throw new Error("No agent ID available for /clear command");
407771
407885
  }
407772
- 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")) {
407773
407890
  const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
407774
407891
  const client = await getClient2();
407775
407892
  await client.agents.messages.reset(agentId, {
@@ -407782,7 +407899,7 @@ async function handleClearCommand(_socket, conversationRuntime, opts) {
407782
407899
  clearConversationRuntimeState(conversationRuntime);
407783
407900
  conversationRuntime.conversationId = conversation.id;
407784
407901
  emitListenerStatus(conversationRuntime.listener, opts.onStatusChange, opts.connectionId);
407785
- 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";
407786
407903
  }
407787
407904
  async function handleDoctorCommand(socket, conversationRuntime, opts) {
407788
407905
  const agentId = conversationRuntime.agentId;
@@ -408052,7 +408169,7 @@ function getCwdScopeKeyFromRuntimeKey(runtimeKey) {
408052
408169
  const conversationId = runtimeKey.slice(markerIndex + marker.length);
408053
408170
  return conversationId === "default" ? runtimeKey : `conversation:${conversationId}`;
408054
408171
  }
408055
- function applyScopeUpdates(socket, runtime) {
408172
+ async function applyScopeUpdates(socket, runtime) {
408056
408173
  for (const [runtimeKey, state] of runtime.reminderStateByConversation) {
408057
408174
  const scopeKey = getCwdScopeKeyFromRuntimeKey(runtimeKey);
408058
408175
  if (!scopeKey || runtime.workingDirectoryByConversation.has(scopeKey)) {
@@ -408066,10 +408183,12 @@ function applyScopeUpdates(socket, runtime) {
408066
408183
  if (runtime.workingDirectoryByConversation.has(scopeKey) || conversationRuntime.activeWorkingDirectory) {
408067
408184
  continue;
408068
408185
  }
408069
- emitDeviceStatusUpdate(socket, conversationRuntime, {
408186
+ const scope = {
408070
408187
  agent_id: conversationRuntime.agentId,
408071
408188
  conversation_id: conversationRuntime.conversationId
408072
- });
408189
+ };
408190
+ await refreshDeviceGitContext(conversationRuntime, scope);
408191
+ emitDeviceStatusUpdate(socket, conversationRuntime, scope);
408073
408192
  }
408074
408193
  }
408075
408194
  async function handleSetBootWorkingDirectoryCommand(command, context3) {
@@ -408082,7 +408201,7 @@ async function handleSetBootWorkingDirectoryCommand(command, context3) {
408082
408201
  settingsManager.loadLocalProjectSettings(normalizedPath)
408083
408202
  ]);
408084
408203
  if (setBootWorkingDirectory(runtime, normalizedPath)) {
408085
- applyScopeUpdates(socket, runtime);
408204
+ await applyScopeUpdates(socket, runtime);
408086
408205
  }
408087
408206
  safeSocketSend(socket, {
408088
408207
  type: "set_boot_working_directory_response",
@@ -409161,8 +409280,8 @@ var init_connect_providers = __esm(() => {
409161
409280
  });
409162
409281
 
409163
409282
  // src/websocket/listener/commands/git-branches.ts
409164
- import { execFile as execFile15 } from "node:child_process";
409165
- import { promisify as promisify14 } from "node:util";
409283
+ import { execFile as execFile16 } from "node:child_process";
409284
+ import { promisify as promisify15 } from "node:util";
409166
409285
  function handleGitBranchCommand(parsed, context3) {
409167
409286
  const { socket, runtime, safeSocketSend, runDetachedListenerTask } = context3;
409168
409287
  if (isSearchBranchesCommand(parsed)) {
@@ -409170,8 +409289,8 @@ function handleGitBranchCommand(parsed, context3) {
409170
409289
  try {
409171
409290
  const cwd2 = parsed.cwd ?? getBootWorkingDirectory(runtime);
409172
409291
  const maxResults = parsed.max_results ?? 20;
409173
- const execFileAsync9 = promisify14(execFile15);
409174
- 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)"], {
409175
409294
  cwd: cwd2,
409176
409295
  encoding: "utf-8",
409177
409296
  timeout: 5000
@@ -409210,14 +409329,16 @@ function handleGitBranchCommand(parsed, context3) {
409210
409329
  runDetachedListenerTask("checkout_branch", async () => {
409211
409330
  try {
409212
409331
  const cwd2 = parsed.cwd ?? getBootWorkingDirectory(runtime);
409213
- const execFileAsync9 = promisify14(execFile15);
409332
+ const execFileAsync10 = promisify15(execFile16);
409214
409333
  const args = parsed.create ? ["checkout", "-b", parsed.branch] : ["checkout", parsed.branch];
409215
- await execFileAsync9("git", args, {
409334
+ await execFileAsync10("git", args, {
409216
409335
  cwd: cwd2,
409217
409336
  encoding: "utf-8",
409218
409337
  timeout: 1e4
409219
409338
  });
409220
- const gitCtx = getGitContext(cwd2);
409339
+ const gitCtx = await deviceGitContextCache.refresh(cwd2, {
409340
+ force: true
409341
+ });
409221
409342
  safeSocketSend(socket, {
409222
409343
  type: "checkout_branch_response",
409223
409344
  request_id: parsed.request_id,
@@ -409240,8 +409361,8 @@ function handleGitBranchCommand(parsed, context3) {
409240
409361
  return false;
409241
409362
  }
409242
409363
  var init_git_branches = __esm(() => {
409243
- init_git_context();
409244
409364
  init_cwd();
409365
+ init_device_git_context();
409245
409366
  init_protocol_inbound();
409246
409367
  init_protocol_outbound();
409247
409368
  });
@@ -409786,6 +409907,13 @@ var init_split_stream_lifecycle = __esm(() => {
409786
409907
  });
409787
409908
 
409788
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
+ }
409789
409917
  function createListenerMessageHandler(params) {
409790
409918
  const {
409791
409919
  runtime,
@@ -409835,7 +409963,7 @@ function createListenerMessageHandler(params) {
409835
409963
  if (!parsed) {
409836
409964
  return;
409837
409965
  }
409838
- console.log(`[Listen V2] Received ${summarizeV2Command(parsed)}`);
409966
+ logV2Command(opts, `Received ${summarizeV2Command(parsed)}`);
409839
409967
  if (parsedScope) {
409840
409968
  subscribeListenerConnection(runtime, connectionId, parsedScope);
409841
409969
  }
@@ -409911,7 +410039,7 @@ function createListenerMessageHandler(params) {
409911
410039
  }
409912
410040
  if (parsed.type === "sync") {
409913
410041
  if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
409914
- console.log(`[Listen V2] Dropping sync: runtime mismatch or closed`);
410042
+ logV2Command(opts, "Dropping sync: runtime mismatch or closed");
409915
410043
  if (parsed.request_id) {
409916
410044
  safeSocketSend(socket, {
409917
410045
  type: "sync_response",
@@ -409965,7 +410093,7 @@ function createListenerMessageHandler(params) {
409965
410093
  }, "input_accepted_response", "input");
409966
410094
  };
409967
410095
  if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
409968
- console.log(`[Listen V2] Dropping input: runtime mismatch or closed`);
410096
+ logV2Command(opts, "Dropping input: runtime mismatch or closed");
409969
410097
  acknowledgeInput(false, "Runtime is no longer active");
409970
410098
  return;
409971
410099
  }
@@ -410684,7 +410812,7 @@ async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
410684
410812
  }
410685
410813
  }
410686
410814
  }
410687
- replaySubscribedConnectionState(listenerRuntime, socket, syncScopedRuntime, scope, opts?.forceDeviceStatus);
410815
+ await replaySubscribedConnectionState(listenerRuntime, socket, syncScopedRuntime, scope, opts);
410688
410816
  (opts?.scheduleWarmupsAfterSync ?? scheduleListenerWarmupsAfterSync)(listenerRuntime, scope);
410689
410817
  }
410690
410818
  function getParsedRuntimeScope(parsed) {
@@ -410808,7 +410936,7 @@ async function startConnectedListenerRuntime(runtime, transport, opts, processQu
410808
410936
  runtime.hasSuccessfulConnection = true;
410809
410937
  runtime.everConnected = true;
410810
410938
  await opts.onConnected(opts.connectionId);
410811
- emitInitialConnectionState(runtime, transport, opts.connectionId, options);
410939
+ await emitInitialConnectionState(runtime, transport, opts.connectionId, options);
410812
410940
  for (const conversationRuntime of runtime.conversationRuntimes.values()) {
410813
410941
  replayPendingApprovalRequestsToConnection(conversationRuntime, opts.connectionId);
410814
410942
  }
@@ -411266,6 +411394,7 @@ var init_lifecycle = __esm(async () => {
411266
411394
  init_recovery_sync();
411267
411395
  init_runtime();
411268
411396
  init_split_stream_lifecycle();
411397
+ init_stream_observers();
411269
411398
  init_transport();
411270
411399
  init_worktree_watcher();
411271
411400
  await __promiseAll([
@@ -414034,7 +414163,7 @@ function PromptEnvName(props) {
414034
414163
  flexDirection: "column",
414035
414164
  children: [
414036
414165
  /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
414037
- children: "Enter environment name (or press Enter for hostname): "
414166
+ children: "Enter computer name (or press Enter for hostname): "
414038
414167
  }, undefined, false, undefined, this),
414039
414168
  /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(build_default, {
414040
414169
  value,
@@ -414111,14 +414240,14 @@ function shouldAcquireStandaloneListenerLock() {
414111
414240
  return shouldAcquireManualListenerLock(getSpawnerListenerInstanceId(), process.env.LETTA_DESKTOP_MODE === "1");
414112
414241
  }
414113
414242
  function printListenUsage() {
414114
- console.log(`Usage: letta server [--env-name <name>] [--channels <list>] [--skills <path>] [--debug]
414243
+ console.log(`Usage: letta server [--computer-name <name>] [--channels <list>] [--skills <path>] [--debug]
414115
414244
  `);
414116
- console.log(`Register this letta-code instance to receive messages from Letta Cloud.
414245
+ console.log(`Register this computer to receive messages from Letta Cloud.
414117
414246
  `);
414118
414247
  console.log("Options:");
414119
- console.log(" --env-name <name> Friendly name for this environment (uses hostname if not provided)");
414248
+ console.log(" --computer-name <name> Friendly name for this computer (uses hostname if not provided)");
414120
414249
  console.log(" --channels <list> Comma-separated channel names to enable (e.g. telegram)");
414121
- console.log(" --skills <path> Use this directory for environment-provided skills");
414250
+ console.log(" --skills <path> Use this directory for computer-provided skills");
414122
414251
  console.log(" --install-channel-runtimes Install missing runtime deps for the selected channels before startup");
414123
414252
  console.log(" --debug Plain-text mode: log all WebSocket events instead of interactive UI");
414124
414253
  console.log(` -h, --help Show this help message
@@ -414126,13 +414255,13 @@ function printListenUsage() {
414126
414255
  console.log("Examples:");
414127
414256
  console.log(" letta channels configure telegram # Configure Telegram first");
414128
414257
  console.log(" letta server # Uses hostname as default");
414129
- console.log(' letta server --env-name "work-laptop"');
414258
+ console.log(' letta server --computer-name "work-laptop"');
414130
414259
  console.log(" letta server --channels telegram # Enable Telegram channel");
414131
414260
  console.log(" letta server --channels telegram --install-channel-runtimes");
414132
414261
  console.log(` letta server --debug # Log all WS events
414133
414262
  `);
414134
414263
  console.log("Once connected, this instance will listen for incoming messages from cloud agents.");
414135
- console.log("Messages will be executed locally using your letta-code environment.");
414264
+ console.log("Messages will be executed locally on this computer.");
414136
414265
  console.log("Telegram flow: configure the bot, start the listener with --channels telegram,");
414137
414266
  console.log("then message the bot from Telegram and run /channels telegram pair <code> in the target conversation.");
414138
414267
  }
@@ -414152,6 +414281,8 @@ async function runListenSubcommand(argv) {
414152
414281
  return 1;
414153
414282
  }
414154
414283
  const debugMode = !!values3.debug;
414284
+ if (debugMode)
414285
+ process.env.LETTA_DEBUG = "1";
414155
414286
  const skillsDirectory = values3.skills ?? process.env.LETTA_SKILLS_DIRECTORY;
414156
414287
  if (values3.help) {
414157
414288
  printListenUsage();
@@ -414221,8 +414352,9 @@ async function runListenSubcommand(argv) {
414221
414352
  const restoreAgentScope = restoreEnabledChannels ? resolveChannelRestoreAgentScope(scopedRestoreAgentScope) : null;
414222
414353
  const channelNames = values3.channels ? values3.channels.split(",").map((s3) => s3.trim()).filter(Boolean) : [];
414223
414354
  let connectionName;
414224
- if (values3["env-name"]) {
414225
- connectionName = values3["env-name"];
414355
+ const explicitComputerName = values3["computer-name"] ?? values3["env-name"];
414356
+ if (explicitComputerName) {
414357
+ connectionName = explicitComputerName;
414226
414358
  settingsManager.setListenerEnvName(connectionName);
414227
414359
  } else {
414228
414360
  const savedName = settingsManager.getListenerEnvName();
@@ -414246,12 +414378,17 @@ async function runListenSubcommand(argv) {
414246
414378
  const sessionLog = new RemoteSessionLog;
414247
414379
  sessionLog.init();
414248
414380
  console.log(`Log file: ${sessionLog.path}`);
414381
+ const logListenerMessage = (message) => {
414382
+ sessionLog.log(message);
414383
+ if (debugMode)
414384
+ console.log(`[${formatTimestamp3()}] ${message}`);
414385
+ };
414249
414386
  try {
414250
414387
  const deviceId = settingsManager.getOrCreateDeviceId();
414251
414388
  const startupMode = await resolveListenerStartupMode(channelNames, channelNames.length > 0 || restoreEnabledChannels);
414252
414389
  if (startupMode.kind === "unsupported-self-hosted") {
414253
414390
  console.error(`Self-hosted listener registration is not available for ${startupMode.serverUrl}.`);
414254
- console.error("Start with --channels to run local channel adapters, or unset LETTA_BASE_URL to use Letta API remote environments.");
414391
+ console.error("Start with --channels to run local channel adapters, or unset LETTA_BASE_URL to use Letta API remote computers.");
414255
414392
  await flushListenerTelemetryEnd("listener_self_hosted_no_channels");
414256
414393
  return 1;
414257
414394
  }
@@ -414283,8 +414420,8 @@ async function runListenSubcommand(argv) {
414283
414420
  });
414284
414421
  } catch (lockError) {
414285
414422
  if (lockError instanceof ManualListenerAlreadyRunningError) {
414286
- console.error(`A letta server for environment "${connectionName}" is already running on this machine (pid ${lockError.holderPid}).`);
414287
- console.error("Stop that process, or choose a different logical listener with --env-name.");
414423
+ console.error(`A letta server for computer "${connectionName}" is already running on this machine (pid ${lockError.holderPid}).`);
414424
+ console.error("Stop that process, or choose a different logical listener with --computer-name.");
414288
414425
  console.error(`Lock: ${lockError.lockPath}`);
414289
414426
  await flushListenerTelemetryEnd("listener_already_running");
414290
414427
  return 1;
@@ -414373,15 +414510,16 @@ async function runListenSubcommand(argv) {
414373
414510
  const connectionId2 = `local-${deviceId}`;
414374
414511
  const startupLabel = startupMode.backend === "local" ? "local backend" : `self-hosted server ${startupMode.serverUrl}`;
414375
414512
  sessionLog.log(`Starting local channel listener for ${startupLabel}`);
414376
- sessionLog.log("Skipping environment registration");
414513
+ sessionLog.log("Skipping computer registration");
414377
414514
  console.log(`Starting local channel listener for ${startupLabel}`);
414378
- console.log(`Skipping environment registration. Press Ctrl+C to stop.
414515
+ console.log(`Skipping computer registration. Press Ctrl+C to stop.
414379
414516
  `);
414380
414517
  const { startLocalChannelListener: startLocalChannelListener2 } = await init_listen_client().then(() => exports_listen_client);
414381
414518
  await startLocalChannelListener2({
414382
414519
  connectionId: connectionId2,
414383
414520
  deviceId,
414384
414521
  connectionName,
414522
+ onLog: logListenerMessage,
414385
414523
  onWsEvent: process.env.LETTA_LOG_WS_EVENTS === "1" ? (direction, label, event) => {
414386
414524
  sessionLog.wsEvent(direction, label, event);
414387
414525
  } : undefined,
@@ -414482,10 +414620,7 @@ async function runListenSubcommand(argv) {
414482
414620
  sessionLog.log(`status: ${status}`);
414483
414621
  console.log(`[${formatTimestamp3()}] status: ${status}`);
414484
414622
  },
414485
- onLog: (message) => {
414486
- sessionLog.log(message);
414487
- console.log(`[${formatTimestamp3()}] ${message}`);
414488
- },
414623
+ onLog: logListenerMessage,
414489
414624
  onConnected: async () => {
414490
414625
  sessionLog.log("Connected. Awaiting instructions.");
414491
414626
  await startChannelGateway();
@@ -414497,7 +414632,7 @@ async function runListenSubcommand(argv) {
414497
414632
  console.log(`[${formatTimestamp3()}] Reconnecting (attempt ${attempt2}, retry in ${Math.round(nextRetryIn / 1000)}s)`);
414498
414633
  },
414499
414634
  onNeedsReregister: async () => {
414500
- console.log(`[${formatTimestamp3()}] Environment expired, re-registering...`);
414635
+ console.log(`[${formatTimestamp3()}] Computer connection expired, re-registering...`);
414501
414636
  try {
414502
414637
  const result2 = await reregister();
414503
414638
  await startDebugClient(result2.connectionId, result2.wsUrl, result2.supportsSplitStatusChannels, result2.supportsPairedListenerGenerations);
@@ -414550,10 +414685,7 @@ async function runListenSubcommand(argv) {
414550
414685
  clearRetryStatusCallback?.();
414551
414686
  updateStatusCallback?.(status);
414552
414687
  },
414553
- onLog: (message) => {
414554
- sessionLog.log(message);
414555
- console.log(`[${formatTimestamp3()}] ${message}`);
414556
- },
414688
+ onLog: logListenerMessage,
414557
414689
  onConnected: async () => {
414558
414690
  sessionLog.log("Connected. Awaiting instructions.");
414559
414691
  await startChannelGateway();
@@ -414565,7 +414697,7 @@ async function runListenSubcommand(argv) {
414565
414697
  updateRetryStatusCallback?.(attempt2, nextRetryIn);
414566
414698
  },
414567
414699
  onNeedsReregister: async () => {
414568
- sessionLog.log("Environment expired, re-registering...");
414700
+ sessionLog.log("Computer connection expired, re-registering...");
414569
414701
  try {
414570
414702
  const result2 = await reregister();
414571
414703
  await startNormalClient(result2.connectionId, result2.wsUrl, result2.supportsSplitStatusChannels, result2.supportsPairedListenerGenerations);
@@ -414634,6 +414766,7 @@ var init_listen = __esm(async () => {
414634
414766
  jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
414635
414767
  activeListenerProcessAnchors = new Set;
414636
414768
  LISTEN_OPTIONS = {
414769
+ "computer-name": { type: "string" },
414637
414770
  "env-name": { type: "string" },
414638
414771
  channels: { type: "string" },
414639
414772
  skills: { type: "string" },
@@ -419021,7 +419154,7 @@ function finalize(ctx, schema5) {
419021
419154
  result2.$schema = "http://json-schema.org/draft-07/schema#";
419022
419155
  } else if (ctx.target === "draft-04") {
419023
419156
  result2.$schema = "http://json-schema.org/draft-04/schema#";
419024
- } else if (ctx.target === "openapi-3.0") {} else {}
419157
+ } else if (ctx.target === "openapi-3.0") {}
419025
419158
  if (ctx.external?.uri) {
419026
419159
  const id2 = ctx.external.registry.get(schema5)?.id;
419027
419160
  if (!id2)
@@ -419236,7 +419369,7 @@ var formatMap2, stringProcessor = (schema5, ctx, _json, _params) => {
419236
419369
  if (val === undefined) {
419237
419370
  if (ctx.unrepresentable === "throw") {
419238
419371
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
419239
- } else {}
419372
+ }
419240
419373
  } else if (typeof val === "bigint") {
419241
419374
  if (ctx.unrepresentable === "throw") {
419242
419375
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -431950,7 +432083,7 @@ var init_mcp_client = __esm(() => {
431950
432083
  init_streamableHttp();
431951
432084
  DEFAULT_CLIENT_INFO = {
431952
432085
  name: "letta-code",
431953
- version: "0.31.11"
432086
+ version: "0.31.13"
431954
432087
  };
431955
432088
  });
431956
432089
 
@@ -432238,7 +432371,6 @@ async function replaceClientMcpServers(agentId, configs, options = {}) {
432238
432371
  const generation2 = ++runtime.generation;
432239
432372
  await closeActiveServers(runtime);
432240
432373
  runtime.agentId = agentId;
432241
- const usedToolNames = new Set;
432242
432374
  const states2 = await Promise.all(configs.map(async (config2) => {
432243
432375
  let oauth;
432244
432376
  try {
@@ -432257,20 +432389,8 @@ async function replaceClientMcpServers(agentId, configs, options = {}) {
432257
432389
  await connection.close();
432258
432390
  return { config: config2, status: "failed", tools: [], error: "Superseded" };
432259
432391
  }
432260
- const tools = connection.tools.map((tool) => {
432261
- const name = uniqueToolName(formatClientMcpToolName(config2.name, tool.name), usedToolNames);
432262
- const definition = {
432263
- name,
432264
- label: tool.title ?? tool.name,
432265
- description: tool.description ?? `Tool ${tool.name} from MCP server ${config2.name}`,
432266
- parameters: tool.inputSchema,
432267
- executor: async (_toolCallId, _toolName, input) => toExternalToolResult(await connection.callTool(tool.name, input))
432268
- };
432269
- return definition;
432270
- });
432271
- registerExternalTools(tools);
432272
- runtime.active.set(config2.name, { connection, tools });
432273
- return { config: config2, status: "connected", tools };
432392
+ runtime.active.set(config2.name, { connection });
432393
+ return { config: config2, status: "connected", tools: connection.tools };
432274
432394
  } catch (error5) {
432275
432395
  return {
432276
432396
  config: config2,
@@ -432318,23 +432438,11 @@ async function closeActiveServers(runtime) {
432318
432438
  runtime.pendingOAuth.clear();
432319
432439
  runtime.active.clear();
432320
432440
  runtime.states = [];
432321
- for (const server2 of active)
432322
- unregisterExternalTools(server2.tools);
432323
432441
  await Promise.allSettled([
432324
432442
  ...pendingOAuth.map((oauth) => oauth.close()),
432325
432443
  ...active.map((server2) => server2.connection.close())
432326
432444
  ]);
432327
432445
  }
432328
- function uniqueToolName(base2, used) {
432329
- let name = base2;
432330
- let suffix = 2;
432331
- while (used.has(name)) {
432332
- name = `${base2}_${suffix}`;
432333
- suffix++;
432334
- }
432335
- used.add(name);
432336
- return name;
432337
- }
432338
432446
  function formatClientMcpToolName(serverName, toolName) {
432339
432447
  return `mcp__${normalizeMcpName(serverName)}__${normalizeMcpName(toolName)}`;
432340
432448
  }
@@ -432342,35 +432450,10 @@ function normalizeMcpName(value) {
432342
432450
  const normalized = value.replace(/[^a-zA-Z0-9_-]/g, "_");
432343
432451
  return normalized || "tool";
432344
432452
  }
432345
- function toExternalToolResult(result2) {
432346
- return {
432347
- content: result2.content.map((item) => normalizeContent2(item)),
432348
- isError: result2.isError === true
432349
- };
432350
- }
432351
- function normalizeContent2(item) {
432352
- if (isRecord17(item)) {
432353
- if (item.type === "text" && typeof item.text === "string") {
432354
- return { type: "text", text: item.text };
432355
- }
432356
- if ((item.type === "image" || item.type === "audio") && typeof item.data === "string") {
432357
- return {
432358
- type: item.type,
432359
- data: item.data,
432360
- ...typeof item.mimeType === "string" ? { mimeType: item.mimeType } : {}
432361
- };
432362
- }
432363
- }
432364
- return { type: "text", text: JSON.stringify(item) };
432365
- }
432366
- function isRecord17(value) {
432367
- return typeof value === "object" && value !== null && !Array.isArray(value);
432368
- }
432369
432453
  var CLIENT_MCP_RUNTIME_KEY;
432370
- var init_mcp_runtime = __esm(async () => {
432454
+ var init_mcp_runtime = __esm(() => {
432371
432455
  init_mcp_client();
432372
432456
  init_mcp_oauth();
432373
- await init_manager4();
432374
432457
  CLIENT_MCP_RUNTIME_KEY = Symbol.for("@letta/clientMcpRuntime");
432375
432458
  });
432376
432459
 
@@ -432611,8 +432694,8 @@ function formatServerMcpToolName(serverName, alias, toolName) {
432611
432694
  const rawName = toolName.startsWith(sourcePrefix) ? toolName.slice(sourcePrefix.length) : toolName;
432612
432695
  return formatClientMcpToolName(alias, rawName);
432613
432696
  }
432614
- var init_mcp_tool_names = __esm(async () => {
432615
- await init_mcp_runtime();
432697
+ var init_mcp_tool_names = __esm(() => {
432698
+ init_mcp_runtime();
432616
432699
  });
432617
432700
 
432618
432701
  // src/cli/subcommands/mcp.ts
@@ -433139,7 +433222,7 @@ async function runMcpSubcommand(argv, deps = {}) {
433139
433222
  }
433140
433223
  }
433141
433224
  var SENSITIVE_NAME;
433142
- var init_mcp = __esm(async () => {
433225
+ var init_mcp = __esm(() => {
433143
433226
  init_oauth();
433144
433227
  init_backend2();
433145
433228
  init_client2();
@@ -433147,13 +433230,11 @@ var init_mcp = __esm(async () => {
433147
433230
  init_unified_mcp();
433148
433231
  init_mcp_client();
433149
433232
  init_mcp_oauth();
433233
+ init_mcp_runtime();
433150
433234
  init_settings_manager();
433151
433235
  init_mcp_io();
433152
433236
  init_mcp_search();
433153
- await __promiseAll([
433154
- init_mcp_runtime(),
433155
- init_mcp_tool_names()
433156
- ]);
433237
+ init_mcp_tool_names();
433157
433238
  SENSITIVE_NAME = /token|key|secret|password|signature|credential|auth/i;
433158
433239
  });
433159
433240
 
@@ -433236,7 +433317,7 @@ var init_memory_tokens = __esm(() => {
433236
433317
  });
433237
433318
 
433238
433319
  // src/cli/subcommands/memory.ts
433239
- 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";
433240
433321
  import { readdir as readdir12 } from "node:fs/promises";
433241
433322
  import { dirname as dirname31, join as join72 } from "node:path";
433242
433323
  import { parseArgs as parseArgs11 } from "node:util";
@@ -433373,10 +433454,10 @@ async function runMemorySubcommand(argv) {
433373
433454
  return 1;
433374
433455
  }
433375
433456
  const { execFile: execFileCb5 } = await import("node:child_process");
433376
- const { promisify: promisify15 } = await import("node:util");
433377
- const execFile16 = promisify15(execFileCb5);
433457
+ const { promisify: promisify16 } = await import("node:util");
433458
+ const execFile17 = promisify16(execFileCb5);
433378
433459
  const dir = getScopedMemoryFilesystemRoot(agentId);
433379
- const { stdout } = await execFile16("git", ["diff"], { cwd: dir });
433460
+ const { stdout } = await execFile17("git", ["diff"], { cwd: dir });
433380
433461
  if (stdout.trim()) {
433381
433462
  console.log(stdout);
433382
433463
  return 2;
@@ -433443,7 +433524,7 @@ async function runMemorySubcommand(argv) {
433443
433524
  return 1;
433444
433525
  }
433445
433526
  const root2 = getMemoryRoot(agentId);
433446
- rmSync12(root2, { recursive: true, force: true });
433527
+ rmSync13(root2, { recursive: true, force: true });
433447
433528
  cpSync(backupPath, root2, { recursive: true });
433448
433529
  console.log(JSON.stringify({ restoredFrom: backupPath }, null, 2));
433449
433530
  return 0;
@@ -434229,12 +434310,12 @@ import {
434229
434310
  readdirSync as readdirSync22,
434230
434311
  readFileSync as readFileSync39,
434231
434312
  renameSync as renameSync7,
434232
- rmSync as rmSync13,
434313
+ rmSync as rmSync14,
434233
434314
  writeFileSync as writeFileSync29
434234
434315
  } from "node:fs";
434235
434316
  import { tmpdir as tmpdir10 } from "node:os";
434236
434317
  import path46 from "node:path";
434237
- function isRecord18(value) {
434318
+ function isRecord17(value) {
434238
434319
  return typeof value === "object" && value !== null && !Array.isArray(value);
434239
434320
  }
434240
434321
  function isPathInsideOrEqual2(childPath, parentPath) {
@@ -434250,7 +434331,7 @@ function readPackageJson(packageJsonPath) {
434250
434331
  } catch (error5) {
434251
434332
  throw new Error(`Could not read package.json: ${error5 instanceof Error ? error5.message : String(error5)}`);
434252
434333
  }
434253
- if (!isRecord18(parsed)) {
434334
+ if (!isRecord17(parsed)) {
434254
434335
  throw new Error("package.json must be an object");
434255
434336
  }
434256
434337
  return parsed;
@@ -434260,7 +434341,7 @@ function formatRepository(repository) {
434260
434341
  const trimmed2 = repository.trim();
434261
434342
  return trimmed2 || undefined;
434262
434343
  }
434263
- if (!isRecord18(repository))
434344
+ if (!isRecord17(repository))
434264
434345
  return;
434265
434346
  const url2 = repository.url;
434266
434347
  if (typeof url2 !== "string")
@@ -434450,7 +434531,7 @@ function copyPackageInternalNodeModules(params) {
434450
434531
  }
434451
434532
  function restoreRegistry(registryPath, previousContents) {
434452
434533
  if (previousContents === null) {
434453
- rmSync13(registryPath, { force: true });
434534
+ rmSync14(registryPath, { force: true });
434454
434535
  return;
434455
434536
  }
434456
434537
  mkdirSync40(path46.dirname(registryPath), { recursive: true });
@@ -434459,17 +434540,17 @@ function restoreRegistry(registryPath, previousContents) {
434459
434540
  function removeIfExists(targetPath) {
434460
434541
  if (!targetPath)
434461
434542
  return;
434462
- rmSync13(targetPath, { force: true, recursive: true });
434543
+ rmSync14(targetPath, { force: true, recursive: true });
434463
434544
  }
434464
434545
  function restoreDestination(params) {
434465
- rmSync13(params.destinationRoot, { force: true, recursive: true });
434546
+ rmSync14(params.destinationRoot, { force: true, recursive: true });
434466
434547
  if (params.backupRoot && existsSync59(params.backupRoot)) {
434467
434548
  renameSync7(params.backupRoot, params.destinationRoot);
434468
434549
  }
434469
434550
  }
434470
434551
  function restoreDestinationIfNeeded(params) {
434471
434552
  if (!params.backupRoot || !existsSync59(params.backupRoot)) {
434472
- rmSync13(params.destinationRoot, { force: true, recursive: true });
434553
+ rmSync14(params.destinationRoot, { force: true, recursive: true });
434473
434554
  return;
434474
434555
  }
434475
434556
  restoreDestination(params);
@@ -434511,7 +434592,7 @@ function installPreparedManagedModPackage(params) {
434511
434592
  }
434512
434593
  if (existsSync59(destinationRoot)) {
434513
434594
  backupRoot = makeSiblingTempDirectory(destinationRoot, "backup");
434514
- rmSync13(backupRoot, { force: true, recursive: true });
434595
+ rmSync14(backupRoot, { force: true, recursive: true });
434515
434596
  renameSync7(destinationRoot, backupRoot);
434516
434597
  destinationNeedsRollback = true;
434517
434598
  }
@@ -434790,7 +434871,7 @@ function hasRuntimeDependencies(packageJson) {
434790
434871
  if (!packageJson)
434791
434872
  return false;
434792
434873
  const dependencies4 = packageJson.dependencies;
434793
- return isRecord18(dependencies4) && Object.keys(dependencies4).length > 0;
434874
+ return isRecord17(dependencies4) && Object.keys(dependencies4).length > 0;
434794
434875
  }
434795
434876
  function readPackageJsonIfExists(packageDirectory) {
434796
434877
  const packageJsonPath = path46.join(packageDirectory, "package.json");
@@ -434962,7 +435043,7 @@ async function installNpmManagedModPackage(params) {
434962
435043
  packageDirectory
434963
435044
  });
434964
435045
  } finally {
434965
- rmSync13(tempRoot, { force: true, recursive: true });
435046
+ rmSync14(tempRoot, { force: true, recursive: true });
434966
435047
  }
434967
435048
  }
434968
435049
  async function installGitManagedModPackage(params) {
@@ -434994,7 +435075,7 @@ async function installGitManagedModPackage(params) {
434994
435075
  packageInfo
434995
435076
  });
434996
435077
  } finally {
434997
- rmSync13(tempRoot, { force: true, recursive: true });
435078
+ rmSync14(tempRoot, { force: true, recursive: true });
434998
435079
  }
434999
435080
  }
435000
435081
  async function updateNpmManagedModPackage(params) {
@@ -435025,7 +435106,7 @@ async function updateNpmManagedModPackage(params) {
435025
435106
  previousVersion: existing.version
435026
435107
  };
435027
435108
  } finally {
435028
- rmSync13(tempRoot, { force: true, recursive: true });
435109
+ rmSync14(tempRoot, { force: true, recursive: true });
435029
435110
  }
435030
435111
  }
435031
435112
  async function updateGitManagedModPackage(params) {
@@ -435067,7 +435148,7 @@ async function updateGitManagedModPackage(params) {
435067
435148
  previousVersion: existing.version
435068
435149
  };
435069
435150
  } finally {
435070
- rmSync13(tempRoot, { force: true, recursive: true });
435151
+ rmSync14(tempRoot, { force: true, recursive: true });
435071
435152
  }
435072
435153
  }
435073
435154
  var SKIPPED_PACKAGE_COPY_NAMES, spawnNpmInstallProcessOverride = null, spawnGitInstallProcess, platformOverride2 = null;
@@ -435086,7 +435167,7 @@ import {
435086
435167
  existsSync as existsSync60,
435087
435168
  lstatSync as lstatSync4,
435088
435169
  mkdirSync as mkdirSync41,
435089
- rmSync as rmSync14,
435170
+ rmSync as rmSync15,
435090
435171
  writeFileSync as writeFileSync30
435091
435172
  } from "node:fs";
435092
435173
  import path47 from "node:path";
@@ -435195,7 +435276,7 @@ function scaffoldLocalModPackage(options) {
435195
435276
  writeFileSync30(readmePath, createReadme(packageName));
435196
435277
  writeFileSync30(modGuidePath, createModGuide(packageName, manifestEntry));
435197
435278
  } catch (error5) {
435198
- rmSync14(outputDirectory, { force: true, recursive: true });
435279
+ rmSync15(outputDirectory, { force: true, recursive: true });
435199
435280
  throw error5;
435200
435281
  }
435201
435282
  return {
@@ -436028,10 +436109,10 @@ function printServerHelp() {
436028
436109
  letta server [remote options]
436029
436110
  letta server --listen [url] [App Server options]
436030
436111
 
436031
- Run the local agent server as a remote environment, with messaging channels, or as an App Server.
436112
+ Run the local agent server as a remote computer, with messaging channels, or as an App Server.
436032
436113
 
436033
- Remote environment options:
436034
- --env-name <name> Friendly name for this environment (uses hostname if not provided)
436114
+ Remote computer options:
436115
+ --computer-name <name> Friendly name for this computer (uses hostname if not provided)
436035
436116
  --channels <list> Comma-separated channel names to enable (e.g. telegram)
436036
436117
  --install-channel-runtimes Install missing runtime dependencies for selected channels
436037
436118
  --debug Log WebSocket events instead of showing the interactive status UI
@@ -436052,7 +436133,7 @@ Common options:
436052
436133
 
436053
436134
  Examples:
436054
436135
  letta server
436055
- letta server --env-name "work-laptop"
436136
+ letta server --computer-name "work-laptop"
436056
436137
  letta server --channels telegram
436057
436138
  letta server --listen
436058
436139
  letta server --listen ws://127.0.0.1:4500
@@ -436091,7 +436172,7 @@ function resolveServerCommand(argv) {
436091
436172
  }
436092
436173
  }
436093
436174
  if (foundListen) {
436094
- const conflictingOption = argv.find((arg) => arg === "--env-name" || arg.startsWith("--env-name=") || arg === "--channels" || arg.startsWith("--channels="));
436175
+ const conflictingOption = argv.find((arg) => arg === "--computer-name" || arg.startsWith("--computer-name=") || arg === "--env-name" || arg.startsWith("--env-name=") || arg === "--channels" || arg.startsWith("--channels="));
436095
436176
  if (conflictingOption) {
436096
436177
  throw new Error(`${conflictingOption.split("=")[0]} cannot be used with --listen`);
436097
436178
  }
@@ -438298,7 +438379,7 @@ import {
438298
438379
  existsSync as existsSync62,
438299
438380
  mkdtempSync as mkdtempSync5,
438300
438381
  readFileSync as readFileSync40,
438301
- rmSync as rmSync15,
438382
+ rmSync as rmSync16,
438302
438383
  statSync as statSync21,
438303
438384
  writeFileSync as writeFileSync31
438304
438385
  } from "node:fs";
@@ -438567,15 +438648,15 @@ function resolveSkillSourceSpecifier(input) {
438567
438648
  }
438568
438649
  return null;
438569
438650
  }
438570
- async function execFile16(command, args, options = {}) {
438651
+ async function execFile17(command, args, options = {}) {
438571
438652
  const { execFile: execFileCb5 } = await import("node:child_process");
438572
- const { promisify: promisify15 } = await import("node:util");
438573
- return promisify15(execFileCb5)(command, args, options);
438653
+ const { promisify: promisify16 } = await import("node:util");
438654
+ return promisify16(execFileCb5)(command, args, options);
438574
438655
  }
438575
438656
  async function resolveBranchAndSubdir(location) {
438576
438657
  if (!location.subdir)
438577
438658
  return location;
438578
- const { stdout } = await execFile16("git", ["ls-remote", "--heads", location.repoUrl], {
438659
+ const { stdout } = await execFile17("git", ["ls-remote", "--heads", location.repoUrl], {
438579
438660
  timeout: 60000
438580
438661
  });
438581
438662
  const branches = stdout.split(`
@@ -438602,7 +438683,7 @@ async function cloneSkillSource(location) {
438602
438683
  args.push("--branch", resolvedLocation.branch);
438603
438684
  }
438604
438685
  args.push(resolvedLocation.repoUrl, tmpDir);
438605
- await execFile16("git", args, { timeout: 120000 });
438686
+ await execFile17("git", args, { timeout: 120000 });
438606
438687
  const sourceDir = resolvedLocation.subdir ? join76(tmpDir, resolvedLocation.subdir) : tmpDir;
438607
438688
  return { tmpDir, sourceDir };
438608
438689
  }
@@ -438665,7 +438746,7 @@ async function downloadDirectSkillFileSource(location, options = {}) {
438665
438746
  writeFileSync31(join76(sourceDir, "SKILL.md"), skillText, "utf8");
438666
438747
  return { tmpDir, sourceDir };
438667
438748
  } catch (error5) {
438668
- rmSync15(tmpDir, { recursive: true, force: true });
438749
+ rmSync16(tmpDir, { recursive: true, force: true });
438669
438750
  throw error5;
438670
438751
  }
438671
438752
  }
@@ -438715,7 +438796,7 @@ async function downloadClawHubSkillSource(location) {
438715
438796
  throw new Error(`ClawHub download failed for ${location.slug}@${version2}: ${response.status}`);
438716
438797
  }
438717
438798
  writeFileSync31(zipPath, Buffer.from(await response.arrayBuffer()));
438718
- const { stdout } = await execFile16("unzip", ["-Z1", zipPath], {
438799
+ const { stdout } = await execFile17("unzip", ["-Z1", zipPath], {
438719
438800
  timeout: 30000
438720
438801
  });
438721
438802
  const members = stdout.split(`
@@ -438724,7 +438805,7 @@ async function downloadClawHubSkillSource(location) {
438724
438805
  throw new Error(`ClawHub download was empty for ${location.slug}@${version2}`);
438725
438806
  }
438726
438807
  members.forEach(assertSafeZipMember);
438727
- await execFile16("unzip", ["-q", zipPath, "-d", sourceDir], {
438808
+ await execFile17("unzip", ["-q", zipPath, "-d", sourceDir], {
438728
438809
  timeout: 30000
438729
438810
  });
438730
438811
  return { tmpDir, sourceDir };
@@ -438768,7 +438849,7 @@ async function installSkillDirectory(params) {
438768
438849
  if (!params.force) {
438769
438850
  throw new Error(`Skill "${name}" already exists at ${targetPath}. Re-run with --force to replace it.`);
438770
438851
  }
438771
- rmSync15(targetPath, { recursive: true, force: true });
438852
+ rmSync16(targetPath, { recursive: true, force: true });
438772
438853
  }
438773
438854
  await mkdir14(skillsDir, { recursive: true });
438774
438855
  cpSync2(sourceDir, targetPath, {
@@ -438819,7 +438900,7 @@ async function deleteSkillDirectory(params) {
438819
438900
  if (!statSync21(targetPath).isDirectory()) {
438820
438901
  throw new Error(`Skill path is not a directory: ${targetPath}`);
438821
438902
  }
438822
- rmSync15(targetPath, { recursive: true, force: true });
438903
+ rmSync16(targetPath, { recursive: true, force: true });
438823
438904
  return { name, path: normalize5(targetPath) };
438824
438905
  }
438825
438906
  async function loadSkillMemorySyncFn() {
@@ -438883,7 +438964,7 @@ async function installSkill(specifier, agentId, force) {
438883
438964
  };
438884
438965
  } finally {
438885
438966
  if (tmpDir)
438886
- rmSync15(tmpDir, { recursive: true, force: true });
438967
+ rmSync16(tmpDir, { recursive: true, force: true });
438887
438968
  }
438888
438969
  }
438889
438970
  async function getAgentMemoryDir(agentId) {
@@ -439192,19 +439273,19 @@ Usage:
439192
439273
  letta teleport list
439193
439274
  letta teleport cloud
439194
439275
  letta teleport local
439195
- letta teleport <environment>
439276
+ letta teleport <computer>
439196
439277
 
439197
439278
  Notes:
439198
439279
  - Operates on the current agent/conversation from LETTA_AGENT_ID /
439199
439280
  LETTA_CONVERSATION_ID (or AGENT_ID / CONVERSATION_ID), falling back to the
439200
439281
  last active session.
439201
439282
  - Requires a Letta Cloud agent and an active conversation.
439202
- - list: prints accessible online remote environments as JSON.
439283
+ - list: prints accessible online remote computers as JSON.
439203
439284
  - cloud: teleports to the agent's Cloud sandbox.
439204
- - local: teleports to the one online Desktop environment. Desktop Remote
439285
+ - local: teleports to the one online Desktop computer. Desktop Remote
439205
439286
  Access must be enabled; if several are online, choose one explicitly.
439206
- - <environment>: teleports to a specific remote environment by name,
439207
- device-id, connection-id, or environment id.
439287
+ - <computer>: teleports to a specific remote computer by name,
439288
+ device-id, connection-id, or computer id.
439208
439289
  - Output is JSON only.
439209
439290
  `.trim());
439210
439291
  }
@@ -439269,7 +439350,7 @@ function isTeleportableRemoteEnvironment(environment2) {
439269
439350
  }
439270
439351
  function assertTeleportableRemoteEnvironment(environment2) {
439271
439352
  if (!isTeleportableRemoteEnvironment(environment2)) {
439272
- throw new Error("The Desktop-local connection is not Cloud-routable. Use `letta teleport local` to resolve its Remote Access environment.");
439353
+ throw new Error("The Desktop-local connection is not Cloud-routable. Use `letta teleport local` to resolve its Remote Access computer.");
439273
439354
  }
439274
439355
  }
439275
439356
  async function initializeTeleportSettings() {
@@ -439312,7 +439393,7 @@ async function runTeleportSubcommand(argv, deps = {}) {
439312
439393
  const result3 = await resolve38();
439313
439394
  targetConnectionId = result3.connectionId;
439314
439395
  } else if (action3 === "back") {
439315
- throw new Error("Teleport back is not supported. Use `letta teleport local` or choose an explicit environment.");
439396
+ throw new Error("Teleport back is not supported. Use `letta teleport local` or choose an explicit computer.");
439316
439397
  } else {
439317
439398
  const resolve38 = deps.resolveEnvironmentConnectionId ?? resolveEnvironmentConnectionId;
439318
439399
  const resolved = await resolve38(action3);
@@ -441276,7 +441357,9 @@ function bindProactiveSlackThreadRoute(params) {
441276
441357
  }
441277
441358
  }
441278
441359
  function createProactiveSlackTransport(params) {
441360
+ const listCustomEmojis = params.adapter.listCustomEmojis?.bind(params.adapter);
441279
441361
  return {
441362
+ ...listCustomEmojis ? { listCustomEmojis } : {},
441280
441363
  sendMessage: async (message) => {
441281
441364
  const result2 = await params.adapter.sendMessage(message);
441282
441365
  const isRootChannelPost = params.target.chatType === "channel" && !message.threadId?.trim() && !message.replyToMessageId?.trim() && !message.reaction;
@@ -443120,6 +443203,7 @@ Replies to routed Slack threads stay in the current thread automatically.` : "";
443120
443203
  Replies to routed Telegram topics stay in the current topic automatically.` : "";
443121
443204
  const slackCapabilities = discovery.activeChannels.includes("slack") ? [
443122
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' : "",
443123
443207
  hasAction("upload-file") ? 'action="upload-file" with media' : "",
443124
443208
  hasAction("download-file") ? 'action="download-file" with attachmentId + messageId' : ""
443125
443209
  ].filter(Boolean) : [];
@@ -443249,7 +443333,7 @@ var init_message_channel_gateway_tool = __esm(() => {
443249
443333
  });
443250
443334
 
443251
443335
  // src/channels/custom/scaffolding.ts
443252
- 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";
443253
443337
  function removeUserPlugin(channelId) {
443254
443338
  if (FIRST_PARTY_SET.has(channelId)) {
443255
443339
  return;
@@ -443262,7 +443346,7 @@ function removeUserPlugin(channelId) {
443262
443346
  return;
443263
443347
  }
443264
443348
  try {
443265
- rmSync16(channelDir, { recursive: true, force: true });
443349
+ rmSync17(channelDir, { recursive: true, force: true });
443266
443350
  } catch (err) {
443267
443351
  console.error(`[channels] Failed to remove plugin folder ${channelDir}:`, err);
443268
443352
  }
@@ -444885,6 +444969,7 @@ function subcommandNeedsEarlyBackendMode(command) {
444885
444969
  case "channel-gateway":
444886
444970
  case "agents":
444887
444971
  case "connect":
444972
+ case "computers":
444888
444973
  case "environments":
444889
444974
  case "envs":
444890
444975
  case "feedback":
@@ -444929,6 +445014,7 @@ async function runSubcommand(argv) {
444929
445014
  return runMessagesSubcommand(rest4);
444930
445015
  case "mcp":
444931
445016
  return runMcpSubcommand(rest4);
445017
+ case "computers":
444932
445018
  case "environments":
444933
445019
  case "envs":
444934
445020
  return runEnvironmentsSubcommand(rest4);
@@ -444983,6 +445069,7 @@ var init_router = __esm(async () => {
444983
445069
  init_environments3();
444984
445070
  init_feedback3();
444985
445071
  init_local_backend2();
445072
+ init_mcp();
444986
445073
  init_memory7();
444987
445074
  init_messages10();
444988
445075
  init_sandbox2();
@@ -444994,13 +445081,57 @@ var init_router = __esm(async () => {
444994
445081
  await __promiseAll([
444995
445082
  init_cron2(),
444996
445083
  init_listen(),
444997
- init_mcp(),
444998
445084
  init_mods(),
444999
445085
  init_server(),
445000
445086
  init_setup7()
445001
445087
  ]);
445002
445088
  });
445003
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
+
445004
445135
  // src/startup-auto-update.ts
445005
445136
  function startStartupAutoUpdateCheck(checkAndAutoUpdate2, logError = console.error) {
445006
445137
  return checkAndAutoUpdate2().then((result2) => {
@@ -445154,38 +445285,6 @@ var init_kitty_protocol_detector = __esm(() => {
445154
445285
  DISABLED = process.env.LETTA_DISABLE_KITTY === "1";
445155
445286
  });
445156
445287
 
445157
- // src/utils/version.ts
445158
- function parseSemver(version2) {
445159
- const match3 = version2.match(/^(\d+)\.(\d+)\.(\d+)/);
445160
- if (!match3)
445161
- return null;
445162
- const [, major, minor, patch2] = match3;
445163
- return [
445164
- parseInt(major ?? "0", 10),
445165
- parseInt(minor ?? "0", 10),
445166
- parseInt(patch2 ?? "0", 10)
445167
- ];
445168
- }
445169
- function compareSemver(a2, b3) {
445170
- const aParts = parseSemver(a2);
445171
- const bParts = parseSemver(b3);
445172
- if (!aParts || !bParts)
445173
- return null;
445174
- for (let i4 = 0;i4 < 3; i4++) {
445175
- const a3 = aParts[i4] ?? 0;
445176
- const b4 = bParts[i4] ?? 0;
445177
- if (a3 < b4)
445178
- return -1;
445179
- if (a3 > b4)
445180
- return 1;
445181
- }
445182
- return 0;
445183
- }
445184
- function isVersionBelow(version2, minimum3) {
445185
- const result2 = compareSemver(version2, minimum3);
445186
- return result2 === -1;
445187
- }
445188
-
445189
445288
  // src/startup-docker-check.ts
445190
445289
  var exports_startup_docker_check = {};
445191
445290
  __export(exports_startup_docker_check, {
@@ -447156,7 +447255,7 @@ function getEnvironmentRoutedMessagingUnsupportedReason(environment2) {
447156
447255
  if (environment2.metadata?.environmentMessageProtocol === "v2-input") {
447157
447256
  return null;
447158
447257
  }
447159
- return `Environment ${environment2.connectionName} (${environment2.deviceId}) is running Letta Code ${environment2.metadata?.lettaCodeVersion ?? "unknown"} and does not advertise environment-routed headless messaging support. Update that runtime or omit --environment to use same-environment messaging.`;
447258
+ return `Computer ${environment2.connectionName} (${environment2.deviceId}) is running Letta Code ${environment2.metadata?.lettaCodeVersion ?? "unknown"} and does not advertise computer-routed headless messaging support. Update that runtime or omit --computer to use same-computer messaging.`;
447160
447259
  }
447161
447260
  async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride, skillSourcesOverride, systemInfoReminderEnabledOverride, startupOptions = {}) {
447162
447261
  const { values: values3, positionals } = parsedArgs;
@@ -447229,7 +447328,7 @@ In headless mode, use:
447229
447328
  }
447230
447329
  let forceNewConversation = values3.new ?? false;
447231
447330
  const fromAgentId = values3["from-agent"];
447232
- const explicitEnvironmentSelector = values3.environment || values3.env;
447331
+ const explicitEnvironmentSelector = values3.computer ?? values3.environment ?? values3.env;
447233
447332
  const usesRemoteEnvironment = typeof explicitEnvironmentSelector === "string" && explicitEnvironmentSelector.trim().length > 0;
447234
447333
  let agent = null;
447235
447334
  let ephemeralConversationId = null;
@@ -447597,9 +447696,6 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
447597
447696
  markMilestone("HEADLESS_AGENT_RESOLVED");
447598
447697
  const publicAgentId = ephemeralFlag ? null : agent.id;
447599
447698
  telemetry.setCurrentAgent(publicAgentId, agent.tags);
447600
- if (!ephemeralFlag) {
447601
- await replaceClientMcpServers(agent.id, settingsManager.getMcpServers(agent.id), { stderr: "pipe" });
447602
- }
447603
447699
  const isResumingAgent = !ephemeralFlag && !!(specifiedAgentId || !forceNew && !fromAfFile);
447604
447700
  if (isResumingAgent) {
447605
447701
  if (model) {
@@ -447788,7 +447884,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
447788
447884
  process.exit(1);
447789
447885
  }
447790
447886
  if (usesRemoteEnvironment && isBidirectionalMode) {
447791
- console.error("Error: remote environment routing cannot be used with --input-format stream-json");
447887
+ console.error("Error: remote computer routing cannot be used with --input-format stream-json");
447792
447888
  process.exit(1);
447793
447889
  }
447794
447890
  const sessionStats = new SessionStats;
@@ -448225,6 +448321,7 @@ ${loadedContents.join(`
448225
448321
  let emptyResponseRetries = 0;
448226
448322
  let conversationBusyRetries = 0;
448227
448323
  let chatgptPlanSwaps = 0;
448324
+ const chatgptExhaustedProviders = new Set;
448228
448325
  markMilestone("HEADLESS_FIRST_STREAM_START");
448229
448326
  measureSinceMilestone("headless-setup-total", "HEADLESS_CLIENT_READY");
448230
448327
  const checkMaxTurns = async () => {
@@ -448492,6 +448589,7 @@ ${loadedContents.join(`
448492
448589
  emptyResponseRetries = 0;
448493
448590
  conversationBusyRetries = 0;
448494
448591
  chatgptPlanSwaps = 0;
448592
+ chatgptExhaustedProviders.clear();
448495
448593
  const continueMessage = await emitHeadlessTurnEnd({
448496
448594
  agent,
448497
448595
  conversationId,
@@ -448595,8 +448693,10 @@ ${loadedContents.join(`
448595
448693
  if (chatgptPlanSwaps < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
448596
448694
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
448597
448695
  agentId: agent.id,
448696
+ conversationId,
448598
448697
  currentHandle: null,
448599
- error: runErrorInfo2 ?? detailFromRun ?? latestErrorText
448698
+ error: runErrorInfo2 ?? detailFromRun ?? latestErrorText,
448699
+ exhaustedProviders: chatgptExhaustedProviders
448600
448700
  });
448601
448701
  if (rotation) {
448602
448702
  chatgptPlanSwaps += 1;
@@ -450012,6 +450112,7 @@ var init_headless = __esm(async () => {
450012
450112
  init_headless_environment_response();
450013
450113
  init_headless_reflection_settings();
450014
450114
  init_diff_preview();
450115
+ init_mcp_runtime();
450015
450116
  init_format_denial();
450016
450117
  init_startup();
450017
450118
  init_queue_runtime();
@@ -450030,7 +450131,6 @@ var init_headless = __esm(async () => {
450030
450131
  init_headless_ephemeral_startup(),
450031
450132
  init_headless_mod_adapter(),
450032
450133
  init_headless_tool_events(),
450033
- init_mcp_runtime(),
450034
450134
  init_manager4(),
450035
450135
  init_toolset()
450036
450136
  ]);
@@ -451352,7 +451452,7 @@ import { existsSync as existsSync67 } from "node:fs";
451352
451452
  import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir17, writeFile as writeFile20 } from "node:fs/promises";
451353
451453
  import { homedir as homedir46 } from "node:os";
451354
451454
  import { join as join84 } from "node:path";
451355
- import { promisify as promisify15 } from "node:util";
451455
+ import { promisify as promisify16 } from "node:util";
451356
451456
  function buildGitEnv(token2, askpassPath) {
451357
451457
  return {
451358
451458
  ...process.env,
@@ -451375,7 +451475,7 @@ function formatTokenStatus(token2) {
451375
451475
  }
451376
451476
  async function runGit6(cwd2, args, env4) {
451377
451477
  try {
451378
- await execFile17("git", args, {
451478
+ await execFile18("git", args, {
451379
451479
  cwd: cwd2,
451380
451480
  env: env4,
451381
451481
  encoding: "utf-8",
@@ -451460,11 +451560,11 @@ async function maybeUploadReflectionArenaChoiceToHf(row) {
451460
451560
  };
451461
451561
  }
451462
451562
  }
451463
- 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";
451464
451564
  var init_reflection_arena_hf_upload = __esm(() => {
451465
451565
  init_secrets_store();
451466
451566
  init_version();
451467
- execFile17 = promisify15(execFileCb5);
451567
+ execFile18 = promisify16(execFileCb5);
451468
451568
  HF_REPO_URL = `https://huggingface.co/datasets/${HF_REPO_ID}`;
451469
451569
  HF_CACHE_ROOT = join84(homedir46(), ".letta", "reflection-arena", "hf-upload");
451470
451570
  HF_REPO_DIR = join84(HF_CACHE_ROOT, "repo");
@@ -451476,7 +451576,7 @@ import { randomInt as randomInt2, randomUUID as randomUUID37 } from "node:crypto
451476
451576
  import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile30, writeFile as writeFile21 } from "node:fs/promises";
451477
451577
  import { homedir as homedir47 } from "node:os";
451478
451578
  import { join as join85 } from "node:path";
451479
- import { promisify as promisify16 } from "node:util";
451579
+ import { promisify as promisify17 } from "node:util";
451480
451580
  function sampleReflectionArenaComparisonModel(excludedModels = []) {
451481
451581
  const excluded = new Set(excludedModels);
451482
451582
  const candidates2 = REFLECTION_ARENA_COMPARISON_MODEL_POOL.filter((entry) => !excluded.has(entry.model));
@@ -451493,7 +451593,7 @@ function sampleReflectionArenaComparisonModel(excludedModels = []) {
451493
451593
  }
451494
451594
  async function getGitOutput(cwd2, args) {
451495
451595
  try {
451496
- const { stdout } = await execFile18("git", args, {
451596
+ const { stdout } = await execFile19("git", args, {
451497
451597
  cwd: cwd2,
451498
451598
  encoding: "utf-8",
451499
451599
  timeout: 30000,
@@ -452068,7 +452168,7 @@ async function finalizeReflectionArenaChoice(options) {
452068
452168
  run: completedRun
452069
452169
  };
452070
452170
  }
452071
- 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;
452072
452172
  var init_reflection_arena = __esm(() => {
452073
452173
  init_memory_filesystem2();
452074
452174
  init_memory_worktree();
@@ -452080,7 +452180,7 @@ var init_reflection_arena = __esm(() => {
452080
452180
  init_reflection_transcript();
452081
452181
  init_telemetry();
452082
452182
  init_debug();
452083
- execFile18 = promisify16(execFileCb6);
452183
+ execFile19 = promisify17(execFileCb6);
452084
452184
  REFLECTION_ARENA_COMPARISON_MODEL_POOL = [
452085
452185
  { model: "lc-anthropic/claude-sonnet-5", weight: 1 },
452086
452186
  { model: "lc-anthropic/claude-opus-4-8", weight: 3 },
@@ -453312,6 +453412,14 @@ var init_registry2 = __esm(() => {
453312
453412
  return "Clearing in-context messages...";
453313
453413
  }
453314
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
+ },
453315
453423
  "/chdir": {
453316
453424
  desc: "Change working directory for this TUI session (/chdir <path>)",
453317
453425
  args: "<path>",
@@ -464470,7 +464578,7 @@ import {
464470
464578
  mkdirSync as mkdirSync46,
464471
464579
  mkdtempSync as mkdtempSync6,
464472
464580
  readFileSync as readFileSync44,
464473
- rmSync as rmSync17,
464581
+ rmSync as rmSync18,
464474
464582
  writeFileSync as writeFileSync36
464475
464583
  } from "node:fs";
464476
464584
  import { tmpdir as tmpdir12 } from "node:os";
@@ -464840,7 +464948,7 @@ async function installGithubApp(options) {
464840
464948
  agentUrl: resolvedAgentId ? buildAgentReference(resolvedAgentId) : null
464841
464949
  };
464842
464950
  } finally {
464843
- rmSync17(tempDir, { recursive: true, force: true });
464951
+ rmSync18(tempDir, { recursive: true, force: true });
464844
464952
  }
464845
464953
  }
464846
464954
  var DEFAULT_WORKFLOW_PATH = ".github/workflows/letta.yml", ALTERNATE_WORKFLOW_PATH = ".github/workflows/letta-code.yml";
@@ -465913,11 +466021,11 @@ var init_McpSelector = __esm(async () => {
465913
466021
  init_truncate_text();
465914
466022
  init_use_terminal_width();
465915
466023
  init_mcp_oauth();
466024
+ init_mcp_runtime();
465916
466025
  init_settings_manager();
465917
466026
  init_colors();
465918
466027
  await __promiseAll([
465919
466028
  init_build4(),
465920
- init_mcp_runtime(),
465921
466029
  init_Text2()
465922
466030
  ]);
465923
466031
  import_react87 = __toESM(require_react(), 1);
@@ -466219,7 +466327,7 @@ var init_McpSelector = __esm(async () => {
466219
466327
  flexDirection: "column",
466220
466328
  children: [
466221
466329
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
466222
- children: tool.label ?? tool.name
466330
+ children: tool.title ?? tool.name
466223
466331
  }, undefined, false, undefined, this),
466224
466332
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
466225
466333
  dimColor: true,
@@ -466229,7 +466337,7 @@ var init_McpSelector = __esm(async () => {
466229
466337
  ]
466230
466338
  }, undefined, true, undefined, this)
466231
466339
  ]
466232
- }, tool.registrationKey ?? tool.name, true, undefined, this)),
466340
+ }, tool.name, true, undefined, this)),
466233
466341
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Box_default, {
466234
466342
  marginTop: 1,
466235
466343
  children: /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
@@ -468606,7 +468714,7 @@ import { execFile as execFileCb7 } from "node:child_process";
468606
468714
  import { chmodSync as chmodSync7, existsSync as existsSync70, mkdirSync as mkdirSync47, writeFileSync as writeFileSync37 } from "node:fs";
468607
468715
  import { homedir as homedir51 } from "node:os";
468608
468716
  import { join as join89 } from "node:path";
468609
- import { promisify as promisify17 } from "node:util";
468717
+ import { promisify as promisify18 } from "node:util";
468610
468718
  function messagesFromOverview(overview) {
468611
468719
  return overview.messages?.map((message) => ({
468612
468720
  id: message.id,
@@ -468633,7 +468741,7 @@ function contextFromOverview(overview, model, contextWindow) {
468633
468741
  }
468634
468742
  async function runGitSafe(cwd2, args) {
468635
468743
  try {
468636
- const { stdout } = await execFile19("git", args, {
468744
+ const { stdout } = await execFile20("git", args, {
468637
468745
  cwd: cwd2,
468638
468746
  maxBuffer: 10 * 1024 * 1024,
468639
468747
  timeout: 60000
@@ -468944,7 +469052,7 @@ async function generateAndOpenMemoryViewer(agentId, options) {
468944
469052
  }
468945
469053
  return { filePath, opened: !skipOpen };
468946
469054
  }
468947
- 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;
468948
469056
  var init_generate_memory_viewer = __esm(() => {
468949
469057
  init_memory_filesystem2();
468950
469058
  init_memory_scanner();
@@ -468955,7 +469063,7 @@ var init_generate_memory_viewer = __esm(() => {
468955
469063
  init_context_usage();
468956
469064
  init_local_memory_context();
468957
469065
  init_memory_viewer_template();
468958
- execFile19 = promisify17(execFileCb7);
469066
+ execFile20 = promisify18(execFileCb7);
468959
469067
  VIEWERS_DIR = join89(homedir51(), ".letta", "viewers");
468960
469068
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
468961
469069
  });
@@ -492375,10 +492483,10 @@ import { execFile as execFileCb8 } from "node:child_process";
492375
492483
  import { chmodSync as chmodSync8, existsSync as existsSync72, mkdirSync as mkdirSync48, writeFileSync as writeFileSync38 } from "node:fs";
492376
492484
  import { homedir as homedir53 } from "node:os";
492377
492485
  import { isAbsolute as isAbsolute30, join as join92, resolve as resolve42 } from "node:path";
492378
- import { promisify as promisify18 } from "node:util";
492486
+ import { promisify as promisify19 } from "node:util";
492379
492487
  async function runGit8(cwd2, args) {
492380
492488
  try {
492381
- const { stdout } = await execFile20("git", args, {
492489
+ const { stdout } = await execFile21("git", args, {
492382
492490
  cwd: cwd2,
492383
492491
  maxBuffer: GIT_MAX_BUFFER,
492384
492492
  timeout: GIT_TIMEOUT_MS3
@@ -492613,7 +492721,7 @@ async function generateAndOpenDiffViewer(targetPath) {
492613
492721
  }
492614
492722
  return { filePath, opened: !skipOpen, fileCount: rendered.files.length };
492615
492723
  }
492616
- 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 = `
492617
492725
  :host {
492618
492726
  --diffs-addition-color-override: #15803d;
492619
492727
  --diffs-deletion-color-override: #b91c1c;
@@ -492669,7 +492777,7 @@ var init_generate_diff_viewer = __esm(() => {
492669
492777
  init_dist15();
492670
492778
  init_ssr();
492671
492779
  init_diff_viewer_template();
492672
- execFile20 = promisify18(execFileCb8);
492780
+ execFile21 = promisify19(execFileCb8);
492673
492781
  VIEWERS_DIR2 = join92(homedir53(), ".letta", "viewers");
492674
492782
  GIT_MAX_BUFFER = 50 * 1024 * 1024;
492675
492783
  });
@@ -493860,20 +493968,20 @@ var init_session3 = __esm(() => {
493860
493968
  });
493861
493969
 
493862
493970
  // src/cli/app/use-agent-mcp-servers.ts
493863
- function useAgentMcpServers(agentId) {
493971
+ function useMcpCleanup(agentId) {
493972
+ const previousAgentId = import_react110.useRef(agentId);
493864
493973
  import_react110.useEffect(() => {
493865
- const refresh = agentId ? replaceClientMcpServers(agentId, settingsManager.getMcpServers(agentId)) : closeClientMcpServers();
493866
- refresh.catch((error5) => debugWarn("mcp", `Failed to switch agent MCP servers: ${String(error5)}`));
493974
+ if (previousAgentId.current === agentId)
493975
+ return;
493976
+ previousAgentId.current = agentId;
493977
+ closeClientMcpServers().catch((error5) => debugWarn("mcp", `Failed to close client MCP servers: ${String(error5)}`));
493867
493978
  }, [agentId]);
493868
493979
  }
493869
493980
  var import_react110;
493870
- var init_use_agent_mcp_servers = __esm(async () => {
493871
- init_settings_manager();
493981
+ var init_use_agent_mcp_servers = __esm(() => {
493982
+ init_mcp_runtime();
493983
+ init_mcp_runtime();
493872
493984
  init_debug();
493873
- await __promiseAll([
493874
- init_mcp_runtime(),
493875
- init_mcp_runtime()
493876
- ]);
493877
493985
  import_react110 = __toESM(require_react(), 1);
493878
493986
  });
493879
493987
 
@@ -495059,7 +495167,7 @@ function useConfigurationHandlers(ctx) {
495059
495167
  registryHandle,
495060
495168
  contextWindow: selectedContextWindow,
495061
495169
  reasoningCapabilities
495062
- }) : getReasoningTierOptionsForHandle2(modelHandle, selectedContextWindow, reasoningCapabilities);
495170
+ }) : getReasoningTierOptionsForHandle2(registryHandle, selectedContextWindow, reasoningCapabilities);
495063
495171
  const reasoningTierOptions = baseReasoningTierOptions.map((option2) => {
495064
495172
  const optionModel = models3.find((entry) => entry.id === option2.modelId);
495065
495173
  const serviceTier = modelUpdateArgs?.service_tier;
@@ -495863,6 +495971,7 @@ function useConversationLoop(ctx) {
495863
495971
  clearApprovalToolContext,
495864
495972
  closeTrajectorySegment,
495865
495973
  chatgptPlanSwapsRef,
495974
+ chatgptExhaustedProvidersRef,
495866
495975
  consumeQueuedMessages,
495867
495976
  queueModeRef,
495868
495977
  contextTrackerRef,
@@ -496095,6 +496204,7 @@ function useConversationLoop(ctx) {
496095
496204
  conversationBusyRetriesRef.current = 0;
496096
496205
  quotaAutoSwapAttemptedRef.current = false;
496097
496206
  chatgptPlanSwapsRef.current = 0;
496207
+ chatgptExhaustedProvidersRef.current.clear();
496098
496208
  }
496099
496209
  let currentRunId;
496100
496210
  let preserveTranscriptStartForApproval = false;
@@ -497062,8 +497172,10 @@ ${feedback}
497062
497172
  if (chatgptPlanSwapsRef.current < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
497063
497173
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
497064
497174
  agentId: agentIdRef.current,
497175
+ conversationId: conversationIdRef.current,
497065
497176
  currentHandle: currentModelId,
497066
- error: runErrorInfo2 ?? detailFromRun ?? fallbackError
497177
+ error: runErrorInfo2 ?? detailFromRun ?? fallbackError,
497178
+ exhaustedProviders: chatgptExhaustedProvidersRef.current
497067
497179
  });
497068
497180
  if (rotation) {
497069
497181
  chatgptPlanSwapsRef.current += 1;
@@ -501399,10 +501511,10 @@ function mcpHelpText() {
501399
501511
  `);
501400
501512
  }
501401
501513
  var activeCommandId2 = null;
501402
- var init_mcp2 = __esm(async () => {
501514
+ var init_mcp2 = __esm(() => {
501403
501515
  init_error_formatter();
501516
+ init_mcp_runtime();
501404
501517
  init_settings_manager();
501405
- await init_mcp_runtime();
501406
501518
  });
501407
501519
 
501408
501520
  // src/cli/commands/listen.ts
@@ -501465,24 +501577,24 @@ Listener disconnected from Letta Cloud.`, true);
501465
501577
  return;
501466
501578
  }
501467
501579
  if (msg.includes("--help") || msg.includes("-h")) {
501468
- addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--env-name <name>]
501580
+ addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--computer-name <name>]
501469
501581
  /server off
501470
501582
 
501471
- Register this letta-code instance to receive messages from Letta Cloud.
501583
+ Register this computer to receive messages from Letta Cloud.
501472
501584
  Alias: /remote
501473
501585
 
501474
501586
  Options:
501475
- --env-name <name> Friendly name for this environment (uses hostname if not provided)
501587
+ --computer-name <name> Friendly name for this computer (uses hostname if not provided)
501476
501588
  off Stop the active listener connection
501477
501589
  -h, --help Show this help message
501478
501590
 
501479
501591
  Examples:
501480
501592
  /server # Start listener with hostname
501481
- /server --env-name "work-laptop" # Start with custom name
501593
+ /server --computer-name "work-laptop" # Start with custom name
501482
501594
  /server off # Stop listening
501483
501595
 
501484
501596
  Once connected, this instance will listen for incoming messages from cloud agents.
501485
- Messages will be executed locally using your letta-code environment.`, true);
501597
+ Messages will be executed locally on this computer.`, true);
501486
501598
  return;
501487
501599
  }
501488
501600
  let connectionName;
@@ -501532,7 +501644,7 @@ Retry ${attempt2} in ${Math.round(delayMs / 1000)}s: ${error5.message}`, true, "
501532
501644
  updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Registered successfully!
501533
501645
 
501534
501646
  ` + `Connection ID: ${connectionId}
501535
- Environment: "${connectionName}"
501647
+ Computer: "${connectionName}"
501536
501648
  WebSocket: ${wsUrl}
501537
501649
 
501538
501650
  Starting WebSocket connection...`, true, "running");
@@ -501550,18 +501662,18 @@ Starting WebSocket connection...`, true, "running");
501550
501662
  const url2 = buildConnectionUrl(id2);
501551
501663
  const urlText = url2 ? `
501552
501664
 
501553
- Connect to this environment:
501665
+ Connect to this computer:
501554
501666
  ${url2}` : "";
501555
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501667
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501556
501668
  ${statusText}${urlText}`, true, "finished");
501557
501669
  },
501558
501670
  onRetrying: (attempt2, _maxAttempts, nextRetryIn, id2) => {
501559
501671
  const url2 = buildConnectionUrl(id2);
501560
501672
  const urlText = url2 ? `
501561
501673
 
501562
- Connect to this environment:
501674
+ Connect to this computer:
501563
501675
  ${url2}` : "";
501564
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501676
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501565
501677
  Reconnecting to Letta Cloud...
501566
501678
  Attempt ${attempt2}, retrying in ${Math.round(nextRetryIn / 1000)}s${urlText}`, true, "running");
501567
501679
  },
@@ -501569,14 +501681,14 @@ Attempt ${attempt2}, retrying in ${Math.round(nextRetryIn / 1000)}s${urlText}`,
501569
501681
  const url2 = buildConnectionUrl(id2);
501570
501682
  const urlText = url2 ? `
501571
501683
 
501572
- Connect to this environment:
501684
+ Connect to this computer:
501573
501685
  ${url2}` : "";
501574
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501686
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501575
501687
  Awaiting instructions${urlText}`, true, "finished");
501576
501688
  ctx.setCommandRunning(false);
501577
501689
  },
501578
501690
  onNeedsReregister: async () => {
501579
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment expired, re-registering "${connectionName}"...`, true, "running");
501691
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer connection expired, re-registering "${connectionName}"...`, true, "running");
501580
501692
  try {
501581
501693
  const nextRegisterOptions = await resolveRegisterOptions();
501582
501694
  const reregisterResult = await registerWithCloudRetry(nextRegisterOptions, {
@@ -501702,7 +501814,7 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
501702
501814
  for (let i4 = 1;i4 < parts.length; i4++) {
501703
501815
  const part = parts[i4];
501704
501816
  const nextPart = parts[i4 + 1];
501705
- if (part === "--env-name" && nextPart) {
501817
+ if ((part === "--computer-name" || part === "--env-name") && nextPart) {
501706
501818
  name = nextPart;
501707
501819
  i4++;
501708
501820
  }
@@ -501725,8 +501837,8 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
501725
501837
  }
501726
501838
  return null;
501727
501839
  }
501728
- var init_submit_connection_commands = __esm(async () => {
501729
- await init_mcp2();
501840
+ var init_submit_connection_commands = __esm(() => {
501841
+ init_mcp2();
501730
501842
  });
501731
501843
 
501732
501844
  // src/cli/helpers/context-chart.ts
@@ -502652,10 +502764,10 @@ __export(exports_worktree_diff_list, {
502652
502764
  });
502653
502765
  import { execFile as execFileCb9 } from "node:child_process";
502654
502766
  import { basename as basename31 } from "node:path";
502655
- import { promisify as promisify19 } from "node:util";
502767
+ import { promisify as promisify20 } from "node:util";
502656
502768
  async function runGit9(cwd2, args) {
502657
502769
  try {
502658
- const { stdout } = await execFile21("git", args, {
502770
+ const { stdout } = await execFile22("git", args, {
502659
502771
  cwd: cwd2,
502660
502772
  maxBuffer: GIT_MAX_BUFFER2,
502661
502773
  timeout: GIT_TIMEOUT_MS4
@@ -502784,9 +502896,9 @@ async function listWorktreeDiffOptions(cwd2 = process.cwd()) {
502784
502896
  const worktrees = parseWorktreeList(output, currentPath);
502785
502897
  return Promise.all(worktrees.map((worktree) => summarizeWorktree(worktree)));
502786
502898
  }
502787
- var execFile21, GIT_TIMEOUT_MS4 = 60000, GIT_MAX_BUFFER2;
502899
+ var execFile22, GIT_TIMEOUT_MS4 = 60000, GIT_MAX_BUFFER2;
502788
502900
  var init_worktree_diff_list = __esm(() => {
502789
- execFile21 = promisify19(execFileCb9);
502901
+ execFile22 = promisify20(execFileCb9);
502790
502902
  GIT_MAX_BUFFER2 = 10 * 1024 * 1024;
502791
502903
  });
502792
502904
 
@@ -504064,15 +504176,19 @@ Tip: Use /clear instead to clear the current message buffer.`;
504064
504176
  });
504065
504177
  return { submitted: true };
504066
504178
  }
504067
- if (msg.trim() === "/clear") {
504068
- 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...");
504069
504182
  resetPendingReasoningCycle();
504070
504183
  setCommandRunning(true);
504071
504184
  const clearPrevConversationId = conversationIdRef.current;
504072
- await runEndHooks("new");
504073
504185
  try {
504074
504186
  const backend3 = getBackend();
504075
- 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")) {
504076
504192
  const client = await getClient();
504077
504193
  await client.agents.messages.reset(agentId, {
504078
504194
  add_default_initial_messages: false
@@ -504106,7 +504222,7 @@ Tip: Use /clear instead to clear the current message buffer.`;
504106
504222
  previousConversationId: clearPrevConversationId ?? null,
504107
504223
  reason: "new"
504108
504224
  }, modAdapter.context);
504109
- 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);
504110
504226
  } catch (error5) {
504111
504227
  const errorDetails = formatErrorDetails2(error5, agentId);
504112
504228
  cmd.fail(`Failed: ${errorDetails}`);
@@ -505508,6 +505624,7 @@ var init_use_submit_handler = __esm(async () => {
505508
505624
  init_command_routing();
505509
505625
  init_ids();
505510
505626
  init_session3();
505627
+ init_submit_connection_commands();
505511
505628
  init_submit_diagnostics_commands();
505512
505629
  init_submit_profile_commands();
505513
505630
  await __promiseAll([
@@ -505515,7 +505632,6 @@ var init_use_submit_handler = __esm(async () => {
505515
505632
  init_mods2(),
505516
505633
  init_PinDialog(),
505517
505634
  init_accumulator(),
505518
- init_submit_connection_commands(),
505519
505635
  init_submit_navigation_commands()
505520
505636
  ]);
505521
505637
  import_react120 = __toESM(require_react(), 1);
@@ -506211,6 +506327,7 @@ function App2({
506211
506327
  const quotaAutoSwapAttemptedRef = import_react121.useRef(false);
506212
506328
  const emptyResponseRetriesRef = import_react121.useRef(0);
506213
506329
  const chatgptPlanSwapsRef = import_react121.useRef(0);
506330
+ const chatgptExhaustedProvidersRef = import_react121.useRef(new Set);
506214
506331
  const conversationBusyRetriesRef = import_react121.useRef(0);
506215
506332
  const [queueDisplay, setQueueDisplay] = import_react121.useState([]);
506216
506333
  const tuiQueueRef = import_react121.useRef(null);
@@ -506867,7 +506984,7 @@ function App2({
506867
506984
  import_react121.useEffect(() => {
506868
506985
  buffersRef.current.agentId = agentState?.id;
506869
506986
  }, [agentState?.id]);
506870
- useAgentMcpServers(agentState?.id);
506987
+ useMcpCleanup(agentState?.id);
506871
506988
  const precomputedDiffsRef = import_react121.useRef(new Map);
506872
506989
  const eagerCommittedPreviewsRef = import_react121.useRef(new Set);
506873
506990
  const estimateApprovalPreviewLines = import_react121.useCallback((approval) => {
@@ -507700,6 +507817,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
507700
507817
  buffersRef,
507701
507818
  clearApprovalToolContext,
507702
507819
  chatgptPlanSwapsRef,
507820
+ chatgptExhaustedProvidersRef,
507703
507821
  closeTrajectorySegment,
507704
507822
  consumeQueuedMessages,
507705
507823
  queueModeRef,
@@ -508861,6 +508979,7 @@ var init_AppCoordinator = __esm(async () => {
508861
508979
  init_ids();
508862
508980
  init_model_config();
508863
508981
  init_session3();
508982
+ init_use_agent_mcp_servers();
508864
508983
  init_use_feedback_handler();
508865
508984
  init_use_queued_approval_submit();
508866
508985
  init_use_reasoning_cycle();
@@ -508876,7 +508995,6 @@ var init_AppCoordinator = __esm(async () => {
508876
508995
  init_manager4(),
508877
508996
  init_toolset(),
508878
508997
  init_AppView(),
508879
- init_use_agent_mcp_servers(),
508880
508998
  init_use_approval_flow(),
508881
508999
  init_use_bash_handlers(),
508882
509000
  init_use_configuration_handlers(),
@@ -509093,13 +509211,13 @@ USAGE
509093
509211
  letta update Check for updates and install (aliases: upgrade, --update, --upgrade)
509094
509212
  letta memory ... Memory filesystem subcommands
509095
509213
  letta agents ... Agents subcommands (JSON-only)
509096
- letta environments ... List available remote environments (JSON-only)
509097
- letta teleport ... Move the current conversation between environments
509214
+ letta computers ... List available remote computers (JSON-only)
509215
+ letta teleport ... Move the current conversation between computers
509098
509216
  letta messages ... Messages subcommands (JSON-only)
509099
509217
  letta mcp ... List, search, and call MCP servers available to an agent
509100
509218
  letta mods ... List and manage local mods
509101
509219
  letta sandbox ... Transfer files to or from the current Cloud sandbox
509102
- letta server ... Run a remote environment, channels, or the App Server
509220
+ letta server ... Run a remote computer, channels, or the App Server
509103
509221
  letta connect ... Connect providers from terminal
509104
509222
  letta backend ... Show or set the default backend
509105
509223
  letta setup Re-run first-run setup
@@ -509118,9 +509236,9 @@ SUBCOMMANDS
509118
509236
  letta memory pull --agent <id>
509119
509237
  letta memory tokens [--memory-dir <path>] [--agent <id>] [--format text|json]
509120
509238
  letta agents list [--query <text> | --name <name> | --tags <tags>]
509121
- letta environments list [--online-only]
509122
- letta environments current
509123
- letta teleport list|cloud|local|<environment>
509239
+ letta computers list [--online-only]
509240
+ letta computers current
509241
+ letta teleport list|cloud|local|<computer>
509124
509242
  letta messages search --query <text> [--all-agents]
509125
509243
  letta messages list [--agent <id>]
509126
509244
  letta messages transcript --conversation <id> [--out <path>]
@@ -509130,7 +509248,7 @@ SUBCOMMANDS
509130
509248
  letta mods disable <package-spec>
509131
509249
  letta mods remove <package-spec>
509132
509250
  letta mcp list|get|tools|search|call ... [--agent <id>]
509133
- letta server [--env-name <name> | --listen [url]] [options]
509251
+ letta server [--computer-name <name> | --listen [url]] [options]
509134
509252
  letta connect <provider> [options]
509135
509253
  letta install <thing> [--agent <id> | -n <name>]
509136
509254
  letta skills list [--agent <id> | -n <name>]
@@ -509891,7 +510009,7 @@ Error: ${message}`);
509891
510009
  markMilestone("REACT_IMPORT_DONE");
509892
510010
  await terminalPreflightPromise;
509893
510011
  markMilestone("TERMINAL_PREFLIGHT_DONE");
509894
- const { useState: useState56, useEffect: useEffect50, useRef: useRef20 } = React14;
510012
+ const { useState: useState56, useEffect: useEffect50, useRef: useRef21 } = React14;
509895
510013
  const App3 = AppModule.App;
509896
510014
  function LoadingApp({
509897
510015
  forceNew: forceNew2,
@@ -509915,7 +510033,7 @@ Error: ${message}`);
509915
510033
  const [resumedExistingConversation, setResumedExistingConversation] = useState56(false);
509916
510034
  const [agentProvenance, setAgentProvenance] = useState56(null);
509917
510035
  const [selectedGlobalAgentId, setSelectedGlobalAgentId] = useState56(null);
509918
- const startupCreatedAgentRef = useRef20(null);
510036
+ const startupCreatedAgentRef = useRef21(null);
509919
510037
  const [startupHasCloudCredentials, setStartupHasCloudCredentials] = useState56(Boolean(settings3.refreshToken || apiKey));
509920
510038
  const [fileAutocompleteFdPath, setFileAutocompleteFdPath] = useState56(() => resolveFdPath());
509921
510039
  const [startupHasAvailableLocalModels, setStartupHasAvailableLocalModels] = useState56(true);
@@ -510740,6 +510858,7 @@ var init_src5 = __esm(async () => {
510740
510858
  init_terminal_theme();
510741
510859
  init_startup_backend_mode();
510742
510860
  init_startup();
510861
+ init_runtime_version();
510743
510862
  init_settings_manager();
510744
510863
  init_startup_auto_update();
510745
510864
  init_debug();
@@ -510753,6 +510872,7 @@ var init_src5 = __esm(async () => {
510753
510872
  ]);
510754
510873
  EMPTY_APPROVAL_ARRAY = [];
510755
510874
  EMPTY_MESSAGE_ARRAY = [];
510875
+ assertSupportedBunRuntime();
510756
510876
  main2();
510757
510877
  });
510758
510878
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js
@@ -512950,4 +513070,4 @@ function registerBunOAuthFlows() {
512950
513070
  registerBunOAuthFlows();
512951
513071
  await init_src5().then(() => exports_src2);
512952
513072
 
512953
- //# debugId=A04282B12C1CC94F64756E2164756E21
513073
+ //# debugId=67341FA9FF6344CE64756E2164756E21