@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.
- package/README.md +16 -14
- package/dist/agent-presets.js +3 -3
- package/dist/agent-presets.js.map +1 -1
- package/dist/channels-slack.js +20 -1
- package/dist/channels-slack.js.map +3 -3
- package/dist/gateway-core.js +2 -1
- package/dist/gateway-core.js.map +3 -3
- package/dist/mcp-client.js +4 -4
- package/dist/mcp-client.js.map +2 -2
- package/dist/types/agent/subagents/manager.d.ts +1 -1
- package/dist/types/agent/subagents/manager.d.ts.map +1 -1
- package/dist/types/backend/api/client.d.ts.map +1 -1
- package/dist/types/backend/backend.d.ts +1 -0
- package/dist/types/backend/backend.d.ts.map +1 -1
- package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
- package/dist/types/channels/plugin-types.d.ts +1 -1
- package/dist/types/channels/plugin-types.d.ts.map +1 -1
- package/dist/types/channels/slack/internal-types.d.ts +5 -0
- package/dist/types/channels/slack/internal-types.d.ts.map +1 -1
- package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
- package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
- package/dist/types/channels/types.d.ts +1 -0
- package/dist/types/channels/types.d.ts.map +1 -1
- package/dist/types/cli/helpers/git-context.d.ts +1 -1
- package/dist/types/cli/helpers/git-context.d.ts.map +1 -1
- package/dist/types/tools/impl/bash.d.ts +2 -0
- package/dist/types/tools/impl/bash.d.ts.map +1 -1
- package/dist/types/tools/impl/exec-command.d.ts +8 -0
- package/dist/types/tools/impl/exec-command.d.ts.map +1 -1
- package/dist/types/tools/impl/task.d.ts +2 -2
- package/dist/types/websocket/listener/cwd-change.d.ts.map +1 -1
- package/dist/types/websocket/listener/device-git-context.d.ts +17 -0
- package/dist/types/websocket/listener/device-git-context.d.ts.map +1 -0
- package/dist/types/websocket/listener/listener-constants.d.ts.map +1 -1
- package/dist/types/websocket/listener/protocol-outbound.d.ts +1 -0
- package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
- package/dist/types/websocket/listener/stream-observers.d.ts.map +1 -1
- package/dist/types/websocket/listener/worktree-watcher.d.ts.map +1 -1
- package/letta.js +1008 -888
- package/package.json +3 -2
- package/scripts/codex-watch/release-analysis.test.ts +87 -0
- package/scripts/codex-watch/release-analysis.ts +57 -7
- package/scripts/postinstall-patches.js +37 -14
- package/scripts/source-file-size-baseline.json +3 -3
- package/skills/browser-use/SKILL.md +22 -61
- package/skills/dispatching-coding-agents/SKILL.md +6 -6
- package/skills/messaging-agents/SKILL.md +34 -21
- package/skills/scheduling-tasks/SKILL.md +1 -1
- package/skills/submitting-feedback/SKILL.md +4 -2
- package/skills/teleporting-between-environments/SKILL.md +12 -12
- package/dist/types/tools/impl/foreground-sleep.d.ts +0 -13
- 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.
|
|
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.
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
-
|
|
88364
|
-
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
95829
|
-
|
|
95830
|
-
|
|
95831
|
-
|
|
95832
|
-
|
|
95833
|
-
|
|
95834
|
-
|
|
95835
|
-
|
|
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
|
-
|
|
95894
|
-
|
|
95895
|
-
|
|
95896
|
-
|
|
95897
|
-
|
|
95898
|
-
|
|
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
|
-
|
|
95902
|
-
|
|
95903
|
-
|
|
95904
|
-
|
|
95905
|
-
|
|
95906
|
-
|
|
95907
|
-
|
|
95908
|
-
|
|
95909
|
-
|
|
95910
|
-
|
|
95911
|
-
|
|
95912
|
-
|
|
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
|
-
|
|
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
|
|
95930
|
-
detail
|
|
95830
|
+
status,
|
|
95831
|
+
detail
|
|
95931
95832
|
});
|
|
95932
95833
|
scheduleBackgroundProcessCleanup(bashId);
|
|
95933
95834
|
});
|
|
95934
|
-
|
|
95935
|
-
|
|
95936
|
-
|
|
95937
|
-
|
|
95938
|
-
|
|
95939
|
-
|
|
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
|
-
|
|
95943
|
-
|
|
95944
|
-
|
|
95945
|
-
|
|
95946
|
-
|
|
95947
|
-
|
|
95948
|
-
|
|
95949
|
-
|
|
95950
|
-
|
|
95951
|
-
|
|
95952
|
-
|
|
95953
|
-
|
|
95954
|
-
|
|
95955
|
-
|
|
95956
|
-
|
|
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
|
-
|
|
95861
|
+
}
|
|
95862
|
+
],
|
|
95863
|
+
status: "error"
|
|
95864
|
+
};
|
|
95865
|
+
}
|
|
95866
|
+
return {
|
|
95867
|
+
content: [{ type: "text", text: `${recoveryNote}${truncatedOutput}` }],
|
|
95868
|
+
status: "success"
|
|
95976
95869
|
};
|
|
95977
95870
|
}
|
|
95978
|
-
|
|
95979
|
-
|
|
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:
|
|
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: "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
100097
|
-
|
|
100098
|
-
|
|
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
|
|
100328
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
100306
100329
|
import * as path20 from "node:path";
|
|
100307
|
-
import { promisify as
|
|
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
|
|
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
|
|
100392
|
+
var execFileAsync2;
|
|
100370
100393
|
var init_glob = __esm(() => {
|
|
100371
100394
|
init_runtime_context();
|
|
100372
100395
|
init_ripgrep_manager();
|
|
100373
100396
|
init_truncation();
|
|
100374
|
-
|
|
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
|
|
100416
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
100394
100417
|
import * as path21 from "node:path";
|
|
100395
|
-
import { promisify as
|
|
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
|
|
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
|
|
100575
|
+
var execFileAsync3;
|
|
100553
100576
|
var init_grep = __esm(() => {
|
|
100554
100577
|
init_runtime_context();
|
|
100555
100578
|
init_ripgrep_manager();
|
|
100556
100579
|
init_truncation();
|
|
100557
|
-
|
|
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
|
|
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
|
|
104436
|
+
function execFileAsync4(file, args) {
|
|
104414
104437
|
return new Promise((resolve19, reject) => {
|
|
104415
|
-
|
|
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
|
|
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("--
|
|
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
|
|
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: "
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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'
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
164602
|
+
}
|
|
164558
164603
|
} else {
|
|
164559
164604
|
ruleId = _RuleFactory.getCompiledRuleId(externalGrammar.repository.$self, helper, externalGrammar.repository);
|
|
164560
164605
|
}
|
|
164561
|
-
}
|
|
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
|
|
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
|
-
|
|
175638
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: () =>
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
199944
|
+
import { promisify as promisify9 } from "node:util";
|
|
199874
199945
|
import process15 from "node:process";
|
|
199875
|
-
import { execFile as
|
|
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
|
|
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
|
|
199955
|
+
var execFileAsync6;
|
|
199885
199956
|
var init_default_browser_id = __esm(() => {
|
|
199886
|
-
|
|
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
|
|
199892
|
-
import { execFile as
|
|
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
|
|
199973
|
+
const { stdout } = await execFileAsync7("osascript", ["-e", script4, outputArguments], execOptions);
|
|
199903
199974
|
return stdout.trim();
|
|
199904
199975
|
}
|
|
199905
|
-
var
|
|
199976
|
+
var execFileAsync7;
|
|
199906
199977
|
var init_run_applescript = __esm(() => {
|
|
199907
|
-
|
|
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
|
|
199921
|
-
import { execFile as
|
|
199922
|
-
async function defaultBrowser(_execFileAsync =
|
|
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
|
|
200011
|
+
var execFileAsync8, windowsBrowserProgIds, UnknownBrowserError;
|
|
199941
200012
|
var init_windows = __esm(() => {
|
|
199942
|
-
|
|
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
|
|
200030
|
+
import { promisify as promisify12 } from "node:util";
|
|
199960
200031
|
import process17 from "node:process";
|
|
199961
|
-
import { execFile as
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
209481
|
-
|
|
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
|
-
|
|
209485
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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("
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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(`
|
|
209718
|
+
throw new Error(`Computer "${trimmed}" is offline`);
|
|
209638
209719
|
}
|
|
209639
209720
|
if (!environment2.connectionId) {
|
|
209640
|
-
throw new Error(`
|
|
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
|
|
209912
|
-
\`letta
|
|
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
|
|
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
|
|
210548
|
-
letta
|
|
210628
|
+
letta computers list [options]
|
|
210629
|
+
letta computers current
|
|
210549
210630
|
|
|
210550
|
-
|
|
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
|
|
210557
|
-
--online-only Only include
|
|
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
|
|
210563
|
-
- Use --
|
|
210564
|
-
- Use --
|
|
210565
|
-
to route a message through a specific registered
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
215527
|
-
const
|
|
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
|
|
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:
|
|
215563
|
-
const
|
|
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
|
|
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:
|
|
215594
|
-
const
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
|
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 =
|
|
393408
|
+
let currentHandle = await resolveScopedModelHandle(agentId, conversationId);
|
|
393317
393409
|
if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
|
|
393318
|
-
currentHandle =
|
|
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
|
-
|
|
393339
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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 =
|
|
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
|
-
|
|
406329
|
+
logFileCommand(`[Listen] Received list_in_directory command: path=${parsed.path}`);
|
|
406226
406330
|
runDetachedListenerTask("list_in_directory", async () => {
|
|
406227
406331
|
try {
|
|
406228
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
406616
|
+
logFileCommand(`[Listen] file_ops: wrote ${content.length} bytes to ${parsed.path}`);
|
|
406513
406617
|
} catch (err) {
|
|
406514
|
-
|
|
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
|
-
|
|
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
|
|
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 --
|
|
407658
|
-
const child = spawn9(process.execPath, [entrypoint, "remote", "--
|
|
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 (
|
|
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
|
-
|
|
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
|
|
409165
|
-
import { promisify as
|
|
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
|
|
409174
|
-
const { stdout } = await
|
|
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
|
|
409332
|
+
const execFileAsync10 = promisify15(execFile16);
|
|
409214
409333
|
const args = parsed.create ? ["checkout", "-b", parsed.branch] : ["checkout", parsed.branch];
|
|
409215
|
-
await
|
|
409334
|
+
await execFileAsync10("git", args, {
|
|
409216
409335
|
cwd: cwd2,
|
|
409217
409336
|
encoding: "utf-8",
|
|
409218
409337
|
timeout: 1e4
|
|
409219
409338
|
});
|
|
409220
|
-
const gitCtx =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 [--
|
|
414243
|
+
console.log(`Usage: letta server [--computer-name <name>] [--channels <list>] [--skills <path>] [--debug]
|
|
414115
414244
|
`);
|
|
414116
|
-
console.log(`Register this
|
|
414245
|
+
console.log(`Register this computer to receive messages from Letta Cloud.
|
|
414117
414246
|
`);
|
|
414118
414247
|
console.log("Options:");
|
|
414119
|
-
console.log(" --
|
|
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
|
|
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 --
|
|
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
|
|
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
|
-
|
|
414225
|
-
|
|
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
|
|
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
|
|
414287
|
-
console.error("Stop that process, or choose a different logical listener with --
|
|
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
|
|
414513
|
+
sessionLog.log("Skipping computer registration");
|
|
414377
414514
|
console.log(`Starting local channel listener for ${startupLabel}`);
|
|
414378
|
-
console.log(`Skipping
|
|
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:
|
|
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()}]
|
|
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:
|
|
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("
|
|
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") {}
|
|
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
|
-
}
|
|
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.
|
|
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
|
-
|
|
432261
|
-
|
|
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(
|
|
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(
|
|
432615
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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:
|
|
433377
|
-
const
|
|
433457
|
+
const { promisify: promisify16 } = await import("node:util");
|
|
433458
|
+
const execFile17 = promisify16(execFileCb5);
|
|
433378
433459
|
const dir = getScopedMemoryFilesystemRoot(agentId);
|
|
433379
|
-
const { stdout } = await
|
|
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
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
434543
|
+
rmSync14(targetPath, { force: true, recursive: true });
|
|
434463
434544
|
}
|
|
434464
434545
|
function restoreDestination(params) {
|
|
434465
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
436112
|
+
Run the local agent server as a remote computer, with messaging channels, or as an App Server.
|
|
436032
436113
|
|
|
436033
|
-
Remote
|
|
436034
|
-
--
|
|
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 --
|
|
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
|
|
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
|
|
438651
|
+
async function execFile17(command, args, options = {}) {
|
|
438571
438652
|
const { execFile: execFileCb5 } = await import("node:child_process");
|
|
438572
|
-
const { promisify:
|
|
438573
|
-
return
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 <
|
|
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
|
|
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
|
|
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
|
-
- <
|
|
439207
|
-
device-id, connection-id, or
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 `
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
492486
|
+
import { promisify as promisify19 } from "node:util";
|
|
492379
492487
|
async function runGit8(cwd2, args) {
|
|
492380
492488
|
try {
|
|
492381
|
-
const { stdout } = await
|
|
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
|
|
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
|
-
|
|
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
|
|
493971
|
+
function useMcpCleanup(agentId) {
|
|
493972
|
+
const previousAgentId = import_react110.useRef(agentId);
|
|
493864
493973
|
import_react110.useEffect(() => {
|
|
493865
|
-
|
|
493866
|
-
|
|
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(
|
|
493871
|
-
|
|
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(
|
|
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(
|
|
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 [--
|
|
501580
|
+
addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--computer-name <name>]
|
|
501469
501581
|
/server off
|
|
501470
501582
|
|
|
501471
|
-
Register this
|
|
501583
|
+
Register this computer to receive messages from Letta Cloud.
|
|
501472
501584
|
Alias: /remote
|
|
501473
501585
|
|
|
501474
501586
|
Options:
|
|
501475
|
-
--
|
|
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 --
|
|
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
|
|
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
|
-
|
|
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
|
|
501665
|
+
Connect to this computer:
|
|
501554
501666
|
${url2}` : "";
|
|
501555
|
-
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `
|
|
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
|
|
501674
|
+
Connect to this computer:
|
|
501563
501675
|
${url2}` : "";
|
|
501564
|
-
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `
|
|
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
|
|
501684
|
+
Connect to this computer:
|
|
501573
501685
|
${url2}` : "";
|
|
501574
|
-
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `
|
|
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, `
|
|
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(
|
|
501729
|
-
|
|
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
|
|
502767
|
+
import { promisify as promisify20 } from "node:util";
|
|
502656
502768
|
async function runGit9(cwd2, args) {
|
|
502657
502769
|
try {
|
|
502658
|
-
const { stdout } = await
|
|
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
|
|
502899
|
+
var execFile22, GIT_TIMEOUT_MS4 = 60000, GIT_MAX_BUFFER2;
|
|
502788
502900
|
var init_worktree_diff_list = __esm(() => {
|
|
502789
|
-
|
|
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
|
-
|
|
504068
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
509097
|
-
letta teleport ... Move the current conversation between
|
|
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
|
|
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
|
|
509122
|
-
letta
|
|
509123
|
-
letta teleport list|cloud|local|<
|
|
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 [--
|
|
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:
|
|
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 =
|
|
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=
|
|
513073
|
+
//# debugId=67341FA9FF6344CE64756E2164756E21
|