@letta-ai/letta-code 0.23.8 → 0.23.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/letta.js +1324 -875
- package/package.json +1 -1
- package/skills/messaging-agents/SKILL.md +11 -0
- package/skills/scheduling-tasks/SKILL.md +33 -2
package/letta.js
CHANGED
|
@@ -3269,7 +3269,7 @@ var package_default;
|
|
|
3269
3269
|
var init_package = __esm(() => {
|
|
3270
3270
|
package_default = {
|
|
3271
3271
|
name: "@letta-ai/letta-code",
|
|
3272
|
-
version: "0.23.
|
|
3272
|
+
version: "0.23.9",
|
|
3273
3273
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3274
3274
|
type: "module",
|
|
3275
3275
|
bin: {
|
|
@@ -4751,7 +4751,10 @@ If you experience this issue multiple times, move ~/.letta to ~/.letta_backup, a
|
|
|
4751
4751
|
timeout: Number(process.env.LETTA_REQUEST_TIMEOUT_MS) || 10 * 60 * 1000,
|
|
4752
4752
|
defaultHeaders: {
|
|
4753
4753
|
"X-Letta-Source": "letta-code",
|
|
4754
|
-
"User-Agent": `letta-code/${package_default.version}
|
|
4754
|
+
"User-Agent": `letta-code/${package_default.version}`,
|
|
4755
|
+
...process.env.LETTA_NODE === "1" && {
|
|
4756
|
+
"x-letta-node": "1"
|
|
4757
|
+
}
|
|
4755
4758
|
},
|
|
4756
4759
|
...isTimingsEnabled() && { fetch: createTimingFetch(fetch) }
|
|
4757
4760
|
});
|
|
@@ -9936,6 +9939,17 @@ var init_models2 = __esm(() => {
|
|
|
9936
9939
|
parallel_tool_calls: true
|
|
9937
9940
|
}
|
|
9938
9941
|
},
|
|
9942
|
+
{
|
|
9943
|
+
id: "kimi-k2.6",
|
|
9944
|
+
handle: "openrouter/moonshotai/kimi-k2.6",
|
|
9945
|
+
label: "Kimi K2.6",
|
|
9946
|
+
description: "Moonshot AI's next-gen multimodal coding and agent model",
|
|
9947
|
+
isFeatured: true,
|
|
9948
|
+
updateArgs: {
|
|
9949
|
+
context_window: 200000,
|
|
9950
|
+
parallel_tool_calls: true
|
|
9951
|
+
}
|
|
9952
|
+
},
|
|
9939
9953
|
{
|
|
9940
9954
|
id: "deepseek-chat-v3.1",
|
|
9941
9955
|
handle: "openrouter/deepseek/deepseek-chat-v3.1",
|
|
@@ -38755,7 +38769,9 @@ __export(exports_memoryGit, {
|
|
|
38755
38769
|
getGitRemoteUrl: () => getGitRemoteUrl,
|
|
38756
38770
|
getAgentRootDir: () => getAgentRootDir,
|
|
38757
38771
|
formatGitCredentialHelperPath: () => formatGitCredentialHelperPath,
|
|
38772
|
+
commitAndSyncMemoryWrite: () => commitAndSyncMemoryWrite,
|
|
38758
38773
|
cloneMemoryRepo: () => cloneMemoryRepo,
|
|
38774
|
+
assertMemoryRepoReadyForWrite: () => assertMemoryRepoReadyForWrite,
|
|
38759
38775
|
addGitMemoryTag: () => addGitMemoryTag,
|
|
38760
38776
|
PRE_COMMIT_HOOK_SCRIPT: () => PRE_COMMIT_HOOK_SCRIPT,
|
|
38761
38777
|
GIT_MEMORY_ENABLED_TAG: () => GIT_MEMORY_ENABLED_TAG
|
|
@@ -38930,6 +38946,185 @@ function installPreCommitHook(dir) {
|
|
|
38930
38946
|
chmodSync(hookPath, 493);
|
|
38931
38947
|
debugLog("memfs-git", "Installed pre-commit hook");
|
|
38932
38948
|
}
|
|
38949
|
+
function normalizePathspecs(pathspecs) {
|
|
38950
|
+
return Array.from(new Set(pathspecs)).filter((path2) => path2.trim().length > 0);
|
|
38951
|
+
}
|
|
38952
|
+
function isNonFastForwardPushError(error) {
|
|
38953
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38954
|
+
return NON_FAST_FORWARD_PUSH_ERROR_RE.test(message);
|
|
38955
|
+
}
|
|
38956
|
+
async function prepareMemoryRepoForGitOps(memoryDir, agentId, token) {
|
|
38957
|
+
await maybeUpdateMemoryRemoteOrigin(memoryDir, agentId);
|
|
38958
|
+
await configureLocalCredentialHelper(memoryDir, token);
|
|
38959
|
+
installPreCommitHook(memoryDir);
|
|
38960
|
+
}
|
|
38961
|
+
async function stageMemoryPaths(memoryDir, pathspecs) {
|
|
38962
|
+
if (pathspecs.length === 0) {
|
|
38963
|
+
return;
|
|
38964
|
+
}
|
|
38965
|
+
await runGit(memoryDir, ["add", "-A", "--", ...pathspecs]);
|
|
38966
|
+
}
|
|
38967
|
+
async function hasStagedMemoryChanges(memoryDir, pathspecs) {
|
|
38968
|
+
if (pathspecs.length === 0) {
|
|
38969
|
+
return false;
|
|
38970
|
+
}
|
|
38971
|
+
const status = await runGit(memoryDir, [
|
|
38972
|
+
"status",
|
|
38973
|
+
"--porcelain",
|
|
38974
|
+
"--",
|
|
38975
|
+
...pathspecs
|
|
38976
|
+
]);
|
|
38977
|
+
return status.stdout.trim().length > 0;
|
|
38978
|
+
}
|
|
38979
|
+
async function commitMemoryPaths(memoryDir, pathspecs, reason, author) {
|
|
38980
|
+
const normalizedPathspecs = normalizePathspecs(pathspecs);
|
|
38981
|
+
await stageMemoryPaths(memoryDir, normalizedPathspecs);
|
|
38982
|
+
if (!await hasStagedMemoryChanges(memoryDir, normalizedPathspecs)) {
|
|
38983
|
+
return { committed: false };
|
|
38984
|
+
}
|
|
38985
|
+
try {
|
|
38986
|
+
await runGit(memoryDir, [
|
|
38987
|
+
"-c",
|
|
38988
|
+
`user.name=${author.authorName.trim() || author.agentId}`,
|
|
38989
|
+
"-c",
|
|
38990
|
+
`user.email=${author.authorEmail}`,
|
|
38991
|
+
"commit",
|
|
38992
|
+
"-m",
|
|
38993
|
+
reason
|
|
38994
|
+
]);
|
|
38995
|
+
} catch (error) {
|
|
38996
|
+
await unstageMemoryPaths(memoryDir, normalizedPathspecs);
|
|
38997
|
+
throw error;
|
|
38998
|
+
}
|
|
38999
|
+
const head = await runGit(memoryDir, ["rev-parse", "HEAD"]);
|
|
39000
|
+
return {
|
|
39001
|
+
committed: true,
|
|
39002
|
+
sha: head.stdout.trim()
|
|
39003
|
+
};
|
|
39004
|
+
}
|
|
39005
|
+
async function unstageMemoryPaths(memoryDir, pathspecs) {
|
|
39006
|
+
if (pathspecs.length === 0) {
|
|
39007
|
+
return;
|
|
39008
|
+
}
|
|
39009
|
+
try {
|
|
39010
|
+
await runGit(memoryDir, ["reset", "HEAD", "--", ...pathspecs]);
|
|
39011
|
+
} catch {}
|
|
39012
|
+
}
|
|
39013
|
+
async function fetchMemoryRemote(memoryDir, token) {
|
|
39014
|
+
await runGitWithRetry(memoryDir, ["fetch", "origin"], token, {
|
|
39015
|
+
operation: "fetch origin"
|
|
39016
|
+
});
|
|
39017
|
+
}
|
|
39018
|
+
async function resetMemoryToUpstream(memoryDir, token) {
|
|
39019
|
+
await runGit(memoryDir, ["reset", "--hard", "@{u}"], token);
|
|
39020
|
+
}
|
|
39021
|
+
function buildMemoryConflictRef(sha) {
|
|
39022
|
+
const timestamp = new Date().toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
|
|
39023
|
+
return `refs/letta-conflicts/${timestamp}-${sha.slice(0, 7)}`;
|
|
39024
|
+
}
|
|
39025
|
+
async function preserveMemoryCommit(memoryDir, sha) {
|
|
39026
|
+
const ref = buildMemoryConflictRef(sha);
|
|
39027
|
+
await runGit(memoryDir, ["update-ref", ref, sha]);
|
|
39028
|
+
return ref;
|
|
39029
|
+
}
|
|
39030
|
+
function formatCommittedButPushFailed(sha, error) {
|
|
39031
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39032
|
+
return `Memory changes were committed (${sha.slice(0, 7)}) but push failed: ${message}`;
|
|
39033
|
+
}
|
|
39034
|
+
function formatReplayConflict(sha, rescueRef, error) {
|
|
39035
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39036
|
+
return `Memory changes conflicted with newer remote memory and could not be replayed safely. Preserved local commit ${sha.slice(0, 7)} at ${rescueRef}; local branch was reset to upstream. Replay error: ${message}`;
|
|
39037
|
+
}
|
|
39038
|
+
function formatReplayPushFailure(originalSha, originalRef, replaySha, replayRef, error) {
|
|
39039
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39040
|
+
const replaySummary = replaySha && replayRef ? ` Replayed commit ${replaySha.slice(0, 7)} was preserved at ${replayRef}.` : "";
|
|
39041
|
+
return `Memory changes conflicted with newer remote memory and the replayed update could not be pushed safely. Original commit ${originalSha.slice(0, 7)} was preserved at ${originalRef}.${replaySummary} Local branch was reset to upstream. Push error: ${message}`;
|
|
39042
|
+
}
|
|
39043
|
+
async function recoverMemoryPushConflict(params, token, initialSha) {
|
|
39044
|
+
const rescueRef = await preserveMemoryCommit(params.memoryDir, initialSha);
|
|
39045
|
+
await fetchMemoryRemote(params.memoryDir, token);
|
|
39046
|
+
await resetMemoryToUpstream(params.memoryDir, token);
|
|
39047
|
+
let replayedPathspecs = [];
|
|
39048
|
+
try {
|
|
39049
|
+
replayedPathspecs = normalizePathspecs(await params.replay?.() ?? []);
|
|
39050
|
+
} catch (error) {
|
|
39051
|
+
await resetMemoryToUpstream(params.memoryDir, token);
|
|
39052
|
+
throw new Error(formatReplayConflict(initialSha, rescueRef, error));
|
|
39053
|
+
}
|
|
39054
|
+
let replayCommit;
|
|
39055
|
+
try {
|
|
39056
|
+
replayCommit = await commitMemoryPaths(params.memoryDir, replayedPathspecs, params.reason, params.author);
|
|
39057
|
+
} catch (error) {
|
|
39058
|
+
await resetMemoryToUpstream(params.memoryDir, token);
|
|
39059
|
+
throw new Error(formatReplayConflict(initialSha, rescueRef, error));
|
|
39060
|
+
}
|
|
39061
|
+
if (!replayCommit.committed) {
|
|
39062
|
+
return {
|
|
39063
|
+
committed: true,
|
|
39064
|
+
replayed: true,
|
|
39065
|
+
replayNoop: true,
|
|
39066
|
+
rescueRef
|
|
39067
|
+
};
|
|
39068
|
+
}
|
|
39069
|
+
try {
|
|
39070
|
+
await runGit(params.memoryDir, ["push"], token);
|
|
39071
|
+
} catch (error) {
|
|
39072
|
+
const replayRef = replayCommit.sha ? await preserveMemoryCommit(params.memoryDir, replayCommit.sha) : undefined;
|
|
39073
|
+
await resetMemoryToUpstream(params.memoryDir, token);
|
|
39074
|
+
throw new Error(formatReplayPushFailure(initialSha, rescueRef, replayCommit.sha, replayRef, error));
|
|
39075
|
+
}
|
|
39076
|
+
return {
|
|
39077
|
+
committed: true,
|
|
39078
|
+
sha: replayCommit.sha,
|
|
39079
|
+
replayed: true,
|
|
39080
|
+
rescueRef
|
|
39081
|
+
};
|
|
39082
|
+
}
|
|
39083
|
+
async function assertMemoryRepoReadyForWrite(memoryDir) {
|
|
39084
|
+
const status = await runGit(memoryDir, ["status", "--porcelain"]);
|
|
39085
|
+
if (status.stdout.trim().length > 0) {
|
|
39086
|
+
throw new Error("Memory repo has uncommitted changes. Commit, discard, or sync them before using memory tools.");
|
|
39087
|
+
}
|
|
39088
|
+
try {
|
|
39089
|
+
const { stdout } = await runGit(memoryDir, [
|
|
39090
|
+
"rev-list",
|
|
39091
|
+
"--count",
|
|
39092
|
+
"@{u}..HEAD"
|
|
39093
|
+
]);
|
|
39094
|
+
const aheadCount = parseInt(stdout.trim(), 10);
|
|
39095
|
+
if (aheadCount > 0) {
|
|
39096
|
+
throw new Error("Memory repo has local commits that are not pushed to remote. Sync the repo before using memory tools.");
|
|
39097
|
+
}
|
|
39098
|
+
} catch (error) {
|
|
39099
|
+
if (error instanceof Error && error.message.includes("not pushed to remote")) {
|
|
39100
|
+
throw error;
|
|
39101
|
+
}
|
|
39102
|
+
}
|
|
39103
|
+
}
|
|
39104
|
+
async function commitAndSyncMemoryWrite(params) {
|
|
39105
|
+
const normalizedPathspecs = normalizePathspecs(params.pathspecs);
|
|
39106
|
+
if (normalizedPathspecs.length === 0) {
|
|
39107
|
+
return { committed: false };
|
|
39108
|
+
}
|
|
39109
|
+
const token = await getAuthToken();
|
|
39110
|
+
await prepareMemoryRepoForGitOps(params.memoryDir, params.author.agentId, token);
|
|
39111
|
+
const commitResult = await commitMemoryPaths(params.memoryDir, normalizedPathspecs, params.reason, params.author);
|
|
39112
|
+
if (!commitResult.committed || !commitResult.sha) {
|
|
39113
|
+
return { committed: false };
|
|
39114
|
+
}
|
|
39115
|
+
try {
|
|
39116
|
+
await runGit(params.memoryDir, ["push"], token);
|
|
39117
|
+
} catch (error) {
|
|
39118
|
+
if (!params.replay || !isNonFastForwardPushError(error)) {
|
|
39119
|
+
throw new Error(formatCommittedButPushFailed(commitResult.sha, error));
|
|
39120
|
+
}
|
|
39121
|
+
return recoverMemoryPushConflict(params, token, commitResult.sha);
|
|
39122
|
+
}
|
|
39123
|
+
return {
|
|
39124
|
+
committed: true,
|
|
39125
|
+
sha: commitResult.sha
|
|
39126
|
+
};
|
|
39127
|
+
}
|
|
38933
39128
|
function isGitRepo(agentId) {
|
|
38934
39129
|
return existsSync8(join7(getMemoryRepoDir(agentId), ".git"));
|
|
38935
39130
|
}
|
|
@@ -39000,25 +39195,8 @@ Hint: verify remote and auth:
|
|
|
39000
39195
|
async function pushMemory(agentId) {
|
|
39001
39196
|
const token = await getAuthToken();
|
|
39002
39197
|
const dir = getMemoryRepoDir(agentId);
|
|
39003
|
-
await
|
|
39004
|
-
await
|
|
39005
|
-
try {
|
|
39006
|
-
await runGit(dir, ["push"], token);
|
|
39007
|
-
return;
|
|
39008
|
-
} catch (pushError) {
|
|
39009
|
-
debugWarn("memfs-git", `Push failed, attempting pull --rebase: ${pushError instanceof Error ? pushError.message : String(pushError)}`);
|
|
39010
|
-
}
|
|
39011
|
-
try {
|
|
39012
|
-
await runGit(dir, ["pull", "--rebase"], token);
|
|
39013
|
-
} catch (pullError) {
|
|
39014
|
-
debugWarn("memfs-git", `Pull --rebase also failed (remote may be empty): ${pullError instanceof Error ? pullError.message : String(pullError)}`);
|
|
39015
|
-
return;
|
|
39016
|
-
}
|
|
39017
|
-
try {
|
|
39018
|
-
await runGit(dir, ["push"], token);
|
|
39019
|
-
} catch (retryError) {
|
|
39020
|
-
debugWarn("memfs-git", `Push failed after rebase: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
|
|
39021
|
-
}
|
|
39198
|
+
await prepareMemoryRepoForGitOps(dir, agentId, token);
|
|
39199
|
+
await runGit(dir, ["push"], token);
|
|
39022
39200
|
}
|
|
39023
39201
|
async function getMemoryGitStatus(agentId) {
|
|
39024
39202
|
const dir = getMemoryRepoDir(agentId);
|
|
@@ -39079,7 +39257,7 @@ async function removeGitMemoryTag(agentId) {
|
|
|
39079
39257
|
debugWarn("memfs-git", `Failed to remove git-memory tag: ${err instanceof Error ? err.message : String(err)}`);
|
|
39080
39258
|
}
|
|
39081
39259
|
}
|
|
39082
|
-
var execFile, GIT_MEMORY_ENABLED_TAG = "git-memory-enabled", RETRYABLE_GIT_HTTP_ERROR_RE, RETRYABLE_GIT_NETWORK_ERROR_RE, MISSING_CWD_GIT_ERROR_RE, PRE_COMMIT_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
39260
|
+
var execFile, GIT_MEMORY_ENABLED_TAG = "git-memory-enabled", RETRYABLE_GIT_HTTP_ERROR_RE, RETRYABLE_GIT_NETWORK_ERROR_RE, MISSING_CWD_GIT_ERROR_RE, NON_FAST_FORWARD_PUSH_ERROR_RE, PRE_COMMIT_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
39083
39261
|
# Validate frontmatter in staged memory .md files
|
|
39084
39262
|
# Installed by Letta Code CLI
|
|
39085
39263
|
|
|
@@ -39224,6 +39402,7 @@ var init_memoryGit = __esm(() => {
|
|
|
39224
39402
|
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;
|
|
39225
39403
|
RETRYABLE_GIT_NETWORK_ERROR_RE = /(remote end hung up unexpectedly|connection reset by peer|operation timed out|timed out)/i;
|
|
39226
39404
|
MISSING_CWD_GIT_ERROR_RE = /(Unable to read current working directory: No such file or directory|\buv_cwd\b|\bcwd\b.*\bENOENT\b)/i;
|
|
39405
|
+
NON_FAST_FORWARD_PUSH_ERROR_RE = /(non-fast-forward|fetch first|failed to push some refs|updates were rejected|remote contains work that you do not have locally|tip of your current branch is behind)/i;
|
|
39227
39406
|
});
|
|
39228
39407
|
|
|
39229
39408
|
// src/agent/personality.ts
|
|
@@ -39492,33 +39671,36 @@ function detectPersonalityFromPersonaFile(personaFileContent) {
|
|
|
39492
39671
|
}
|
|
39493
39672
|
return null;
|
|
39494
39673
|
}
|
|
39495
|
-
function
|
|
39496
|
-
|
|
39497
|
-
return false;
|
|
39498
|
-
const code = error.code;
|
|
39499
|
-
return code === expectedCode;
|
|
39500
|
-
}
|
|
39501
|
-
async function runGit2(cwd2, args) {
|
|
39502
|
-
const result = await execFile2("git", args, {
|
|
39503
|
-
cwd: cwd2,
|
|
39504
|
-
maxBuffer: 10485760,
|
|
39505
|
-
timeout: 60000
|
|
39506
|
-
});
|
|
39507
|
-
return result.stdout?.toString() ?? "";
|
|
39508
|
-
}
|
|
39509
|
-
async function hasStagedChanges(cwd2, relativePaths) {
|
|
39510
|
-
if (relativePaths.length === 0) {
|
|
39511
|
-
return false;
|
|
39512
|
-
}
|
|
39674
|
+
async function getMemoryCommitAuthor(agentId) {
|
|
39675
|
+
let authorName = agentId;
|
|
39513
39676
|
try {
|
|
39514
|
-
|
|
39515
|
-
|
|
39516
|
-
|
|
39517
|
-
|
|
39518
|
-
return true;
|
|
39677
|
+
const client = await getClient();
|
|
39678
|
+
const agent = await client.agents.retrieve(agentId);
|
|
39679
|
+
if (agent.name?.trim()) {
|
|
39680
|
+
authorName = agent.name.trim();
|
|
39519
39681
|
}
|
|
39520
|
-
|
|
39682
|
+
} catch {}
|
|
39683
|
+
return {
|
|
39684
|
+
agentId,
|
|
39685
|
+
authorName,
|
|
39686
|
+
authorEmail: `${agentId}@letta.com`
|
|
39687
|
+
};
|
|
39688
|
+
}
|
|
39689
|
+
function applyPersonalityFiles(filesToUpdate) {
|
|
39690
|
+
const changedPaths = [];
|
|
39691
|
+
for (const file of filesToUpdate) {
|
|
39692
|
+
const existingContent = existsSync9(file.absolutePath) ? readFileSync6(file.absolutePath, "utf-8") : null;
|
|
39693
|
+
const nextContent = existingContent ? replaceBodyPreservingFrontmatter(existingContent, file.content, {
|
|
39694
|
+
description: file.description
|
|
39695
|
+
}) : buildDefaultMemoryFile(file.templatePromptAssetName, file.content, file.description);
|
|
39696
|
+
if (existingContent !== null && normalizeComparableContent(existingContent) === normalizeComparableContent(nextContent)) {
|
|
39697
|
+
continue;
|
|
39698
|
+
}
|
|
39699
|
+
mkdirSync7(dirname3(file.absolutePath), { recursive: true });
|
|
39700
|
+
writeFileSync5(file.absolutePath, nextContent, "utf-8");
|
|
39701
|
+
changedPaths.push(file.relativePath);
|
|
39521
39702
|
}
|
|
39703
|
+
return changedPaths;
|
|
39522
39704
|
}
|
|
39523
39705
|
async function applyPersonalityToMemory(params) {
|
|
39524
39706
|
const personality = getPersonalityOption(params.personalityId);
|
|
@@ -39552,19 +39734,7 @@ async function applyPersonalityToMemory(params) {
|
|
|
39552
39734
|
description: blockDefinitions.human.description
|
|
39553
39735
|
}
|
|
39554
39736
|
];
|
|
39555
|
-
const changedPaths =
|
|
39556
|
-
for (const file of filesToUpdate) {
|
|
39557
|
-
const existingContent = existsSync9(file.absolutePath) ? readFileSync6(file.absolutePath, "utf-8") : null;
|
|
39558
|
-
const nextContent = existingContent ? replaceBodyPreservingFrontmatter(existingContent, file.content, {
|
|
39559
|
-
description: file.description
|
|
39560
|
-
}) : buildDefaultMemoryFile(file.templatePromptAssetName, file.content, file.description);
|
|
39561
|
-
if (existingContent !== null && normalizeComparableContent(existingContent) === normalizeComparableContent(nextContent)) {
|
|
39562
|
-
continue;
|
|
39563
|
-
}
|
|
39564
|
-
mkdirSync7(dirname3(file.absolutePath), { recursive: true });
|
|
39565
|
-
writeFileSync5(file.absolutePath, nextContent, "utf-8");
|
|
39566
|
-
changedPaths.push(file.relativePath);
|
|
39567
|
-
}
|
|
39737
|
+
const changedPaths = applyPersonalityFiles(filesToUpdate);
|
|
39568
39738
|
if (changedPaths.length === 0) {
|
|
39569
39739
|
return {
|
|
39570
39740
|
changed: false,
|
|
@@ -39573,8 +39743,16 @@ async function applyPersonalityToMemory(params) {
|
|
|
39573
39743
|
humanRelativePath
|
|
39574
39744
|
};
|
|
39575
39745
|
}
|
|
39576
|
-
|
|
39577
|
-
|
|
39746
|
+
const commitMessage = params.commitMessage ?? `chore(personality): switch to ${personality.label}`;
|
|
39747
|
+
const author = await getMemoryCommitAuthor(params.agentId);
|
|
39748
|
+
const commitResult = await commitAndSyncMemoryWrite({
|
|
39749
|
+
memoryDir: repoDir,
|
|
39750
|
+
pathspecs: changedPaths,
|
|
39751
|
+
reason: commitMessage,
|
|
39752
|
+
author,
|
|
39753
|
+
replay: async () => applyPersonalityFiles(filesToUpdate)
|
|
39754
|
+
});
|
|
39755
|
+
if (!commitResult.committed) {
|
|
39578
39756
|
return {
|
|
39579
39757
|
changed: false,
|
|
39580
39758
|
personality,
|
|
@@ -39582,16 +39760,6 @@ async function applyPersonalityToMemory(params) {
|
|
|
39582
39760
|
humanRelativePath
|
|
39583
39761
|
};
|
|
39584
39762
|
}
|
|
39585
|
-
const commitMessage = params.commitMessage ?? `chore(personality): switch to ${personality.label}`;
|
|
39586
|
-
await runGit2(repoDir, [
|
|
39587
|
-
"commit",
|
|
39588
|
-
"--only",
|
|
39589
|
-
"-m",
|
|
39590
|
-
commitMessage,
|
|
39591
|
-
"--",
|
|
39592
|
-
...changedPaths
|
|
39593
|
-
]);
|
|
39594
|
-
await pushMemory(params.agentId);
|
|
39595
39763
|
return {
|
|
39596
39764
|
changed: true,
|
|
39597
39765
|
personality,
|
|
@@ -39603,6 +39771,7 @@ async function applyPersonalityToMemory(params) {
|
|
|
39603
39771
|
var execFile2, 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", PERSONALITY_OPTIONS, DEFAULT_CREATE_AGENT_PERSONALITIES, PERSONALITY_ALIASES, FRONTMATTER_REGEX, EDITABLE_FRONTMATTER_KEYS;
|
|
39604
39772
|
var init_personality = __esm(() => {
|
|
39605
39773
|
init_settings_manager();
|
|
39774
|
+
init_client2();
|
|
39606
39775
|
init_memory();
|
|
39607
39776
|
init_memoryGit();
|
|
39608
39777
|
init_promptAssets();
|
|
@@ -43368,7 +43537,7 @@ var init_targets = __esm(() => {
|
|
|
43368
43537
|
|
|
43369
43538
|
// src/cli/helpers/gitContext.ts
|
|
43370
43539
|
import { execFileSync } from "node:child_process";
|
|
43371
|
-
function
|
|
43540
|
+
function runGit2(args, cwd2) {
|
|
43372
43541
|
try {
|
|
43373
43542
|
return execFileSync("git", args, {
|
|
43374
43543
|
cwd: cwd2,
|
|
@@ -43401,7 +43570,7 @@ function formatGitUser(name, email) {
|
|
|
43401
43570
|
function gatherGitContextSnapshot(options = {}) {
|
|
43402
43571
|
const cwd2 = options.cwd ?? process.cwd();
|
|
43403
43572
|
const recentCommitLimit = options.recentCommitLimit ?? 3;
|
|
43404
|
-
if (!
|
|
43573
|
+
if (!runGit2(["rev-parse", "--git-dir"], cwd2)) {
|
|
43405
43574
|
return {
|
|
43406
43575
|
isGitRepo: false,
|
|
43407
43576
|
branch: null,
|
|
@@ -43410,16 +43579,16 @@ function gatherGitContextSnapshot(options = {}) {
|
|
|
43410
43579
|
gitUser: null
|
|
43411
43580
|
};
|
|
43412
43581
|
}
|
|
43413
|
-
const branch =
|
|
43414
|
-
const fullStatus =
|
|
43582
|
+
const branch = runGit2(["branch", "--show-current"], cwd2);
|
|
43583
|
+
const fullStatus = runGit2(["status", "--short"], cwd2);
|
|
43415
43584
|
const status = typeof fullStatus === "string" && options.statusLineLimit ? truncateLines(fullStatus, options.statusLineLimit) : fullStatus;
|
|
43416
|
-
const recentCommits = options.recentCommitFormat ?
|
|
43585
|
+
const recentCommits = options.recentCommitFormat ? runGit2([
|
|
43417
43586
|
"log",
|
|
43418
43587
|
`--format=${options.recentCommitFormat}`,
|
|
43419
43588
|
"-n",
|
|
43420
43589
|
String(recentCommitLimit)
|
|
43421
|
-
], cwd2) :
|
|
43422
|
-
const userConfig =
|
|
43590
|
+
], cwd2) : runGit2(["log", "--oneline", "-n", String(recentCommitLimit)], cwd2);
|
|
43591
|
+
const userConfig = runGit2(["config", "--get-regexp", "^user\\.(name|email)$"], cwd2);
|
|
43423
43592
|
let userName = null;
|
|
43424
43593
|
let userEmail = null;
|
|
43425
43594
|
if (userConfig) {
|
|
@@ -43441,11 +43610,11 @@ function gatherGitContextSnapshot(options = {}) {
|
|
|
43441
43610
|
};
|
|
43442
43611
|
}
|
|
43443
43612
|
function getGitContext(cwd2) {
|
|
43444
|
-
if (!
|
|
43613
|
+
if (!runGit2(["rev-parse", "--git-dir"], cwd2)) {
|
|
43445
43614
|
return null;
|
|
43446
43615
|
}
|
|
43447
|
-
const branch =
|
|
43448
|
-
const branchList =
|
|
43616
|
+
const branch = runGit2(["branch", "--show-current"], cwd2);
|
|
43617
|
+
const branchList = runGit2([
|
|
43449
43618
|
"branch",
|
|
43450
43619
|
"--sort=-committerdate",
|
|
43451
43620
|
"--format=%(refname:short)",
|
|
@@ -46325,6 +46494,100 @@ var init_hooks = __esm(() => {
|
|
|
46325
46494
|
init_types2();
|
|
46326
46495
|
});
|
|
46327
46496
|
|
|
46497
|
+
// src/permissions/canonical.ts
|
|
46498
|
+
function canonicalToolName(toolName) {
|
|
46499
|
+
if (SHELL_TOOL_NAMES.has(toolName))
|
|
46500
|
+
return "Bash";
|
|
46501
|
+
if (READ_TOOL_NAMES.has(toolName))
|
|
46502
|
+
return "Read";
|
|
46503
|
+
if (WRITE_TOOL_NAMES.has(toolName))
|
|
46504
|
+
return "Write";
|
|
46505
|
+
if (EDIT_TOOL_NAMES.has(toolName))
|
|
46506
|
+
return "Edit";
|
|
46507
|
+
if (GLOB_TOOL_NAMES.has(toolName))
|
|
46508
|
+
return "Glob";
|
|
46509
|
+
if (GREP_TOOL_NAMES.has(toolName))
|
|
46510
|
+
return "Grep";
|
|
46511
|
+
if (LIST_TOOL_NAMES.has(toolName))
|
|
46512
|
+
return "ListDir";
|
|
46513
|
+
if (TASK_TOOL_NAMES.has(toolName))
|
|
46514
|
+
return "Task";
|
|
46515
|
+
return toolName;
|
|
46516
|
+
}
|
|
46517
|
+
function isShellToolName(toolName) {
|
|
46518
|
+
return canonicalToolName(toolName) === "Bash";
|
|
46519
|
+
}
|
|
46520
|
+
function isFileToolName(toolName) {
|
|
46521
|
+
return FILE_TOOL_FAMILIES.has(canonicalToolName(toolName));
|
|
46522
|
+
}
|
|
46523
|
+
function canonicalizePathLike(value) {
|
|
46524
|
+
let normalized = value.replace(/\\/g, "/").trim();
|
|
46525
|
+
if (/^\/+[a-zA-Z]:\//.test(normalized)) {
|
|
46526
|
+
normalized = normalized.replace(/^\/+/, "");
|
|
46527
|
+
}
|
|
46528
|
+
if (/^[a-zA-Z]:\//.test(normalized)) {
|
|
46529
|
+
normalized = `${normalized[0]?.toUpperCase() ?? ""}${normalized.slice(1)}`;
|
|
46530
|
+
}
|
|
46531
|
+
return normalized;
|
|
46532
|
+
}
|
|
46533
|
+
var SHELL_TOOL_NAMES, READ_TOOL_NAMES, WRITE_TOOL_NAMES, EDIT_TOOL_NAMES, GLOB_TOOL_NAMES, GREP_TOOL_NAMES, LIST_TOOL_NAMES, TASK_TOOL_NAMES, FILE_TOOL_FAMILIES;
|
|
46534
|
+
var init_canonical = __esm(() => {
|
|
46535
|
+
SHELL_TOOL_NAMES = new Set([
|
|
46536
|
+
"Bash",
|
|
46537
|
+
"shell",
|
|
46538
|
+
"Shell",
|
|
46539
|
+
"shell_command",
|
|
46540
|
+
"ShellCommand",
|
|
46541
|
+
"run_shell_command",
|
|
46542
|
+
"RunShellCommand"
|
|
46543
|
+
]);
|
|
46544
|
+
READ_TOOL_NAMES = new Set([
|
|
46545
|
+
"Read",
|
|
46546
|
+
"read_file",
|
|
46547
|
+
"ReadFile",
|
|
46548
|
+
"read_file_gemini",
|
|
46549
|
+
"ReadFileGemini"
|
|
46550
|
+
]);
|
|
46551
|
+
WRITE_TOOL_NAMES = new Set([
|
|
46552
|
+
"Write",
|
|
46553
|
+
"write_file",
|
|
46554
|
+
"WriteFile",
|
|
46555
|
+
"write_file_gemini",
|
|
46556
|
+
"WriteFileGemini"
|
|
46557
|
+
]);
|
|
46558
|
+
EDIT_TOOL_NAMES = new Set([
|
|
46559
|
+
"Edit",
|
|
46560
|
+
"MultiEdit",
|
|
46561
|
+
"NotebookEdit",
|
|
46562
|
+
"replace",
|
|
46563
|
+
"Replace"
|
|
46564
|
+
]);
|
|
46565
|
+
GLOB_TOOL_NAMES = new Set(["Glob", "glob_gemini", "GlobGemini"]);
|
|
46566
|
+
GREP_TOOL_NAMES = new Set([
|
|
46567
|
+
"Grep",
|
|
46568
|
+
"grep_files",
|
|
46569
|
+
"GrepFiles",
|
|
46570
|
+
"search_file_content",
|
|
46571
|
+
"SearchFileContent"
|
|
46572
|
+
]);
|
|
46573
|
+
LIST_TOOL_NAMES = new Set([
|
|
46574
|
+
"list_dir",
|
|
46575
|
+
"ListDir",
|
|
46576
|
+
"list_directory",
|
|
46577
|
+
"ListDirectory",
|
|
46578
|
+
"LS"
|
|
46579
|
+
]);
|
|
46580
|
+
TASK_TOOL_NAMES = new Set(["Task", "task"]);
|
|
46581
|
+
FILE_TOOL_FAMILIES = new Set([
|
|
46582
|
+
"Read",
|
|
46583
|
+
"Write",
|
|
46584
|
+
"Edit",
|
|
46585
|
+
"Glob",
|
|
46586
|
+
"Grep",
|
|
46587
|
+
"ListDir"
|
|
46588
|
+
]);
|
|
46589
|
+
});
|
|
46590
|
+
|
|
46328
46591
|
// src/utils/directoryLimits.ts
|
|
46329
46592
|
function parsePositiveIntEnv(value, fallback, min, max) {
|
|
46330
46593
|
if (!value || value.trim() === "") {
|
|
@@ -47133,32 +47396,39 @@ function addRootAndSiblingWorktree(root, acc) {
|
|
|
47133
47396
|
acc.add(normalizeScopedPath(resolve4(dirname5(normalizedRoot), "memory-worktrees")));
|
|
47134
47397
|
}
|
|
47135
47398
|
}
|
|
47136
|
-
function
|
|
47137
|
-
|
|
47138
|
-
|
|
47139
|
-
|
|
47140
|
-
|
|
47141
|
-
|
|
47142
|
-
const
|
|
47399
|
+
function parseScopeList(value) {
|
|
47400
|
+
if (!value)
|
|
47401
|
+
return [];
|
|
47402
|
+
return value.split(/[\s,]+/).map((id) => id.trim()).filter((id) => id.length > 0);
|
|
47403
|
+
}
|
|
47404
|
+
function getExplicitEnvRoots(env3, homeDir) {
|
|
47405
|
+
const orderedRoots = [env3.MEMORY_DIR, env3.LETTA_MEMORY_DIR].map((value) => value?.trim() ?? "").filter((value) => value.length > 0);
|
|
47406
|
+
const rootSet = new Set;
|
|
47143
47407
|
for (const root of orderedRoots) {
|
|
47144
|
-
addRootAndSiblingWorktree(root,
|
|
47408
|
+
addRootAndSiblingWorktree(root, rootSet);
|
|
47409
|
+
}
|
|
47410
|
+
const scopeIds = new Set([
|
|
47411
|
+
...parseScopeList(env3.LETTA_MEMORY_SCOPE),
|
|
47412
|
+
...cliPermissions.getMemoryScope()
|
|
47413
|
+
]);
|
|
47414
|
+
for (const id of scopeIds) {
|
|
47415
|
+
addRootAndSiblingWorktree(getMemoryFilesystemRoot(id, homeDir), rootSet);
|
|
47145
47416
|
}
|
|
47146
47417
|
return {
|
|
47147
|
-
|
|
47418
|
+
roots: [...rootSet],
|
|
47148
47419
|
primaryRoot: orderedRoots.length > 0 ? normalizeScopedPath(orderedRoots[0]) : null
|
|
47149
47420
|
};
|
|
47150
47421
|
}
|
|
47151
47422
|
function deriveAgentId(env3, explicitAgentId) {
|
|
47152
47423
|
const explicit = explicitAgentId?.trim();
|
|
47153
|
-
if (explicit)
|
|
47424
|
+
if (explicit)
|
|
47154
47425
|
return explicit;
|
|
47155
|
-
}
|
|
47156
47426
|
const envAgentId = (env3.AGENT_ID || env3.LETTA_AGENT_ID || "").trim();
|
|
47157
|
-
if (envAgentId)
|
|
47427
|
+
if (envAgentId)
|
|
47158
47428
|
return envAgentId;
|
|
47159
|
-
}
|
|
47160
47429
|
try {
|
|
47161
|
-
|
|
47430
|
+
const fromContext = getCurrentAgentId().trim();
|
|
47431
|
+
return fromContext || null;
|
|
47162
47432
|
} catch {
|
|
47163
47433
|
return null;
|
|
47164
47434
|
}
|
|
@@ -47188,11 +47458,10 @@ function getFallbackRoots(env3, homeDir, currentAgentId, parentAgentId) {
|
|
|
47188
47458
|
function resolveAllowedMemoryRoots(options = {}) {
|
|
47189
47459
|
const env3 = options.env ?? process.env;
|
|
47190
47460
|
const homeDir = options.homeDir ?? homedir11();
|
|
47191
|
-
const explicit = getExplicitEnvRoots(env3);
|
|
47192
|
-
if (explicit.
|
|
47461
|
+
const explicit = getExplicitEnvRoots(env3, homeDir);
|
|
47462
|
+
if (explicit.roots.length > 0) {
|
|
47193
47463
|
return {
|
|
47194
|
-
roots: explicit.
|
|
47195
|
-
explicitRoots: explicit.explicitRoots,
|
|
47464
|
+
roots: explicit.roots,
|
|
47196
47465
|
primaryRoot: explicit.primaryRoot,
|
|
47197
47466
|
usedFallback: false
|
|
47198
47467
|
};
|
|
@@ -47200,7 +47469,6 @@ function resolveAllowedMemoryRoots(options = {}) {
|
|
|
47200
47469
|
const fallback = getFallbackRoots(env3, homeDir, options.currentAgentId, options.parentAgentId);
|
|
47201
47470
|
return {
|
|
47202
47471
|
roots: fallback.roots,
|
|
47203
|
-
explicitRoots: [],
|
|
47204
47472
|
primaryRoot: fallback.primaryRoot,
|
|
47205
47473
|
usedFallback: fallback.roots.length > 0
|
|
47206
47474
|
};
|
|
@@ -47208,6 +47476,320 @@ function resolveAllowedMemoryRoots(options = {}) {
|
|
|
47208
47476
|
var init_memoryScope = __esm(() => {
|
|
47209
47477
|
init_context();
|
|
47210
47478
|
init_memoryFilesystem();
|
|
47479
|
+
init_cli();
|
|
47480
|
+
});
|
|
47481
|
+
|
|
47482
|
+
// src/permissions/shell-command-normalization.ts
|
|
47483
|
+
function trimMatchingQuotes(value) {
|
|
47484
|
+
const trimmed = value.trim();
|
|
47485
|
+
if (trimmed.length < 2) {
|
|
47486
|
+
return trimmed;
|
|
47487
|
+
}
|
|
47488
|
+
const first = trimmed[0];
|
|
47489
|
+
const last = trimmed[trimmed.length - 1];
|
|
47490
|
+
if ((first === '"' || first === "'") && last === first) {
|
|
47491
|
+
return trimmed.slice(1, -1);
|
|
47492
|
+
}
|
|
47493
|
+
return trimmed;
|
|
47494
|
+
}
|
|
47495
|
+
function normalizeExecutableToken(token) {
|
|
47496
|
+
const normalized = trimMatchingQuotes(token).replace(/\\/g, "/");
|
|
47497
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
47498
|
+
const executable = parts[parts.length - 1] ?? normalized;
|
|
47499
|
+
return executable.toLowerCase();
|
|
47500
|
+
}
|
|
47501
|
+
function tokenizeShell(input) {
|
|
47502
|
+
const tokens = [];
|
|
47503
|
+
let current = "";
|
|
47504
|
+
let quote = null;
|
|
47505
|
+
let escaping = false;
|
|
47506
|
+
const flush = () => {
|
|
47507
|
+
if (current.length > 0) {
|
|
47508
|
+
tokens.push(current);
|
|
47509
|
+
current = "";
|
|
47510
|
+
}
|
|
47511
|
+
};
|
|
47512
|
+
for (let i = 0;i < input.length; i += 1) {
|
|
47513
|
+
const ch = input[i];
|
|
47514
|
+
if (ch === undefined) {
|
|
47515
|
+
continue;
|
|
47516
|
+
}
|
|
47517
|
+
if (escaping) {
|
|
47518
|
+
current += ch;
|
|
47519
|
+
escaping = false;
|
|
47520
|
+
continue;
|
|
47521
|
+
}
|
|
47522
|
+
if (ch === "\\" && quote !== "single") {
|
|
47523
|
+
escaping = true;
|
|
47524
|
+
continue;
|
|
47525
|
+
}
|
|
47526
|
+
if (quote === "single") {
|
|
47527
|
+
if (ch === "'") {
|
|
47528
|
+
quote = null;
|
|
47529
|
+
} else {
|
|
47530
|
+
current += ch;
|
|
47531
|
+
}
|
|
47532
|
+
continue;
|
|
47533
|
+
}
|
|
47534
|
+
if (quote === "double") {
|
|
47535
|
+
if (ch === '"') {
|
|
47536
|
+
quote = null;
|
|
47537
|
+
} else {
|
|
47538
|
+
current += ch;
|
|
47539
|
+
}
|
|
47540
|
+
continue;
|
|
47541
|
+
}
|
|
47542
|
+
if (ch === "'") {
|
|
47543
|
+
quote = "single";
|
|
47544
|
+
continue;
|
|
47545
|
+
}
|
|
47546
|
+
if (ch === '"') {
|
|
47547
|
+
quote = "double";
|
|
47548
|
+
continue;
|
|
47549
|
+
}
|
|
47550
|
+
if (/\s/.test(ch)) {
|
|
47551
|
+
flush();
|
|
47552
|
+
continue;
|
|
47553
|
+
}
|
|
47554
|
+
current += ch;
|
|
47555
|
+
}
|
|
47556
|
+
if (escaping) {
|
|
47557
|
+
current += "\\";
|
|
47558
|
+
}
|
|
47559
|
+
flush();
|
|
47560
|
+
return tokens;
|
|
47561
|
+
}
|
|
47562
|
+
function isDashCFlag(token) {
|
|
47563
|
+
return token === "-c" || /^-[a-zA-Z]*c[a-zA-Z]*$/.test(token);
|
|
47564
|
+
}
|
|
47565
|
+
function extractInnerShellCommand(tokens) {
|
|
47566
|
+
if (tokens.length === 0) {
|
|
47567
|
+
return null;
|
|
47568
|
+
}
|
|
47569
|
+
let index = 0;
|
|
47570
|
+
if (normalizeExecutableToken(tokens[0] ?? "") === "env") {
|
|
47571
|
+
index += 1;
|
|
47572
|
+
while (index < tokens.length) {
|
|
47573
|
+
const token = tokens[index] ?? "";
|
|
47574
|
+
if (!token) {
|
|
47575
|
+
index += 1;
|
|
47576
|
+
continue;
|
|
47577
|
+
}
|
|
47578
|
+
if (/^-[A-Za-z]+$/.test(token)) {
|
|
47579
|
+
index += 1;
|
|
47580
|
+
continue;
|
|
47581
|
+
}
|
|
47582
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) {
|
|
47583
|
+
index += 1;
|
|
47584
|
+
continue;
|
|
47585
|
+
}
|
|
47586
|
+
break;
|
|
47587
|
+
}
|
|
47588
|
+
}
|
|
47589
|
+
const executableToken = tokens[index];
|
|
47590
|
+
if (!executableToken) {
|
|
47591
|
+
return null;
|
|
47592
|
+
}
|
|
47593
|
+
if (!SHELL_EXECUTORS.has(normalizeExecutableToken(executableToken))) {
|
|
47594
|
+
return null;
|
|
47595
|
+
}
|
|
47596
|
+
for (let i = index + 1;i < tokens.length; i += 1) {
|
|
47597
|
+
const token = tokens[i];
|
|
47598
|
+
if (!token) {
|
|
47599
|
+
continue;
|
|
47600
|
+
}
|
|
47601
|
+
if (!isDashCFlag(token)) {
|
|
47602
|
+
continue;
|
|
47603
|
+
}
|
|
47604
|
+
const innerCommand = tokens[i + 1];
|
|
47605
|
+
if (!innerCommand) {
|
|
47606
|
+
return null;
|
|
47607
|
+
}
|
|
47608
|
+
return trimMatchingQuotes(innerCommand);
|
|
47609
|
+
}
|
|
47610
|
+
return null;
|
|
47611
|
+
}
|
|
47612
|
+
function unwrapShellLauncherCommand(command) {
|
|
47613
|
+
let current = command.trim();
|
|
47614
|
+
for (let depth = 0;depth < 5; depth += 1) {
|
|
47615
|
+
if (!current) {
|
|
47616
|
+
break;
|
|
47617
|
+
}
|
|
47618
|
+
const tokens = tokenizeShell(current);
|
|
47619
|
+
const inner = extractInnerShellCommand(tokens);
|
|
47620
|
+
if (!inner || inner === current) {
|
|
47621
|
+
break;
|
|
47622
|
+
}
|
|
47623
|
+
current = inner.trim();
|
|
47624
|
+
}
|
|
47625
|
+
return current;
|
|
47626
|
+
}
|
|
47627
|
+
function normalizeBashRulePayload(payload) {
|
|
47628
|
+
const trimmed = payload.trim();
|
|
47629
|
+
if (!trimmed) {
|
|
47630
|
+
return "";
|
|
47631
|
+
}
|
|
47632
|
+
const hasWildcardSuffix = trimmed.endsWith(":*");
|
|
47633
|
+
const withoutWildcard = hasWildcardSuffix ? trimmed.slice(0, -2).trimEnd() : trimmed;
|
|
47634
|
+
const unwrapped = unwrapShellLauncherCommand(withoutWildcard);
|
|
47635
|
+
const normalized = normalizeGitCommandPrefix(unwrapped);
|
|
47636
|
+
if (hasWildcardSuffix) {
|
|
47637
|
+
return `${normalized}:*`;
|
|
47638
|
+
}
|
|
47639
|
+
return normalized;
|
|
47640
|
+
}
|
|
47641
|
+
function normalizeGitCommandPrefix(command) {
|
|
47642
|
+
const trimmed = command.trim();
|
|
47643
|
+
if (!trimmed.startsWith("git ")) {
|
|
47644
|
+
return trimmed;
|
|
47645
|
+
}
|
|
47646
|
+
const tokens = tokenizeShell(trimmed);
|
|
47647
|
+
if (tokens[0] !== "git") {
|
|
47648
|
+
return trimmed;
|
|
47649
|
+
}
|
|
47650
|
+
const normalizedTokens = ["git"];
|
|
47651
|
+
let index = 1;
|
|
47652
|
+
while (index < tokens.length) {
|
|
47653
|
+
const token = tokens[index];
|
|
47654
|
+
if (!token) {
|
|
47655
|
+
index += 1;
|
|
47656
|
+
continue;
|
|
47657
|
+
}
|
|
47658
|
+
if (token === "-C") {
|
|
47659
|
+
index += 2;
|
|
47660
|
+
continue;
|
|
47661
|
+
}
|
|
47662
|
+
normalizedTokens.push(...tokens.slice(index));
|
|
47663
|
+
return normalizedTokens.join(" ");
|
|
47664
|
+
}
|
|
47665
|
+
return normalizedTokens.join(" ");
|
|
47666
|
+
}
|
|
47667
|
+
var SHELL_EXECUTORS;
|
|
47668
|
+
var init_shell_command_normalization = __esm(() => {
|
|
47669
|
+
SHELL_EXECUTORS = new Set(["bash", "sh", "zsh", "dash", "ksh"]);
|
|
47670
|
+
});
|
|
47671
|
+
|
|
47672
|
+
// src/permissions/rule-normalization.ts
|
|
47673
|
+
function splitRule(rule) {
|
|
47674
|
+
const match = rule.trim().match(/^([^(]+)(?:\(([\s\S]*)\))?$/);
|
|
47675
|
+
if (!match?.[1]) {
|
|
47676
|
+
return { tool: rule.trim(), payload: null };
|
|
47677
|
+
}
|
|
47678
|
+
return {
|
|
47679
|
+
tool: match[1].trim(),
|
|
47680
|
+
payload: match[2] !== undefined ? match[2] : null
|
|
47681
|
+
};
|
|
47682
|
+
}
|
|
47683
|
+
function normalizePermissionRule(rule) {
|
|
47684
|
+
const { tool, payload } = splitRule(rule);
|
|
47685
|
+
const canonicalTool = canonicalToolName(tool);
|
|
47686
|
+
if (payload === null) {
|
|
47687
|
+
return canonicalTool;
|
|
47688
|
+
}
|
|
47689
|
+
if (isShellToolName(canonicalTool)) {
|
|
47690
|
+
return `Bash(${normalizeBashRulePayload(payload)})`;
|
|
47691
|
+
}
|
|
47692
|
+
if (isFileToolName(canonicalTool)) {
|
|
47693
|
+
return `${canonicalTool}(${canonicalizePathLike(payload)})`;
|
|
47694
|
+
}
|
|
47695
|
+
return `${canonicalTool}(${payload.trim()})`;
|
|
47696
|
+
}
|
|
47697
|
+
function permissionRulesEquivalent(left, right) {
|
|
47698
|
+
return normalizePermissionRule(left) === normalizePermissionRule(right);
|
|
47699
|
+
}
|
|
47700
|
+
var init_rule_normalization = __esm(() => {
|
|
47701
|
+
init_canonical();
|
|
47702
|
+
init_shell_command_normalization();
|
|
47703
|
+
});
|
|
47704
|
+
|
|
47705
|
+
// src/permissions/cli.ts
|
|
47706
|
+
var exports_cli = {};
|
|
47707
|
+
__export(exports_cli, {
|
|
47708
|
+
cliPermissions: () => cliPermissions
|
|
47709
|
+
});
|
|
47710
|
+
|
|
47711
|
+
class CliPermissions {
|
|
47712
|
+
allowedTools = [];
|
|
47713
|
+
disallowedTools = [];
|
|
47714
|
+
memoryScope = [];
|
|
47715
|
+
setAllowedTools(toolsString) {
|
|
47716
|
+
this.allowedTools = this.parseToolList(toolsString);
|
|
47717
|
+
}
|
|
47718
|
+
setDisallowedTools(toolsString) {
|
|
47719
|
+
this.disallowedTools = this.parseToolList(toolsString);
|
|
47720
|
+
}
|
|
47721
|
+
setMemoryScope(scopeString) {
|
|
47722
|
+
this.memoryScope = parseScopeList(scopeString);
|
|
47723
|
+
}
|
|
47724
|
+
parseToolList(toolsString) {
|
|
47725
|
+
if (!toolsString)
|
|
47726
|
+
return [];
|
|
47727
|
+
const tools = [];
|
|
47728
|
+
let current = "";
|
|
47729
|
+
let depth = 0;
|
|
47730
|
+
for (let i = 0;i < toolsString.length; i++) {
|
|
47731
|
+
const char = toolsString[i];
|
|
47732
|
+
if (char === "(") {
|
|
47733
|
+
depth++;
|
|
47734
|
+
current += char;
|
|
47735
|
+
} else if (char === ")") {
|
|
47736
|
+
depth--;
|
|
47737
|
+
current += char;
|
|
47738
|
+
} else if (char === "," && depth === 0) {
|
|
47739
|
+
if (current.trim()) {
|
|
47740
|
+
tools.push(this.normalizePattern(current.trim()));
|
|
47741
|
+
}
|
|
47742
|
+
current = "";
|
|
47743
|
+
} else {
|
|
47744
|
+
current += char;
|
|
47745
|
+
}
|
|
47746
|
+
}
|
|
47747
|
+
if (current.trim()) {
|
|
47748
|
+
tools.push(this.normalizePattern(current.trim()));
|
|
47749
|
+
}
|
|
47750
|
+
return tools;
|
|
47751
|
+
}
|
|
47752
|
+
normalizePattern(pattern) {
|
|
47753
|
+
const trimmed = pattern.trim();
|
|
47754
|
+
if (trimmed.includes("(")) {
|
|
47755
|
+
return normalizePermissionRule(trimmed);
|
|
47756
|
+
}
|
|
47757
|
+
const canonicalTool = canonicalToolName(trimmed);
|
|
47758
|
+
if (isShellToolName(canonicalTool)) {
|
|
47759
|
+
return "Bash(:*)";
|
|
47760
|
+
}
|
|
47761
|
+
if (isFileToolName(canonicalTool)) {
|
|
47762
|
+
return `${canonicalTool}(**)`;
|
|
47763
|
+
}
|
|
47764
|
+
return canonicalTool;
|
|
47765
|
+
}
|
|
47766
|
+
getAllowedTools() {
|
|
47767
|
+
return [...this.allowedTools];
|
|
47768
|
+
}
|
|
47769
|
+
getDisallowedTools() {
|
|
47770
|
+
return [...this.disallowedTools];
|
|
47771
|
+
}
|
|
47772
|
+
getMemoryScope() {
|
|
47773
|
+
return [...this.memoryScope];
|
|
47774
|
+
}
|
|
47775
|
+
hasMemoryScope() {
|
|
47776
|
+
return this.memoryScope.length > 0;
|
|
47777
|
+
}
|
|
47778
|
+
hasOverrides() {
|
|
47779
|
+
return this.allowedTools.length > 0 || this.disallowedTools.length > 0 || this.memoryScope.length > 0;
|
|
47780
|
+
}
|
|
47781
|
+
clear() {
|
|
47782
|
+
this.allowedTools = [];
|
|
47783
|
+
this.disallowedTools = [];
|
|
47784
|
+
this.memoryScope = [];
|
|
47785
|
+
}
|
|
47786
|
+
}
|
|
47787
|
+
var cliPermissions;
|
|
47788
|
+
var init_cli = __esm(() => {
|
|
47789
|
+
init_canonical();
|
|
47790
|
+
init_memoryScope();
|
|
47791
|
+
init_rule_normalization();
|
|
47792
|
+
cliPermissions = new CliPermissions;
|
|
47211
47793
|
});
|
|
47212
47794
|
|
|
47213
47795
|
// src/permissions/shellAnalysis.ts
|
|
@@ -47533,8 +48115,315 @@ function parseShellAnalysis(command) {
|
|
|
47533
48115
|
return parseShellAnalysisSegments(segments);
|
|
47534
48116
|
}
|
|
47535
48117
|
|
|
47536
|
-
// src/permissions/
|
|
48118
|
+
// src/permissions/crossAgentGuard.ts
|
|
47537
48119
|
import { homedir as homedir12 } from "node:os";
|
|
48120
|
+
function resolveAllowedAgents(options = {}) {
|
|
48121
|
+
const env3 = options.env ?? process.env;
|
|
48122
|
+
const self = deriveAgentId(env3, options.currentAgentId);
|
|
48123
|
+
const envScope = parseScopeList(env3.LETTA_MEMORY_SCOPE);
|
|
48124
|
+
const cliScope = options.cliMemoryScope ?? cliPermissions.getMemoryScope();
|
|
48125
|
+
const ids = new Set;
|
|
48126
|
+
if (self)
|
|
48127
|
+
ids.add(self);
|
|
48128
|
+
for (const id of envScope)
|
|
48129
|
+
ids.add(id);
|
|
48130
|
+
for (const id of cliScope)
|
|
48131
|
+
ids.add(id);
|
|
48132
|
+
return {
|
|
48133
|
+
ids,
|
|
48134
|
+
sources: {
|
|
48135
|
+
self,
|
|
48136
|
+
env: envScope,
|
|
48137
|
+
cli: [...cliScope]
|
|
48138
|
+
}
|
|
48139
|
+
};
|
|
48140
|
+
}
|
|
48141
|
+
function escapeRegex2(value) {
|
|
48142
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
48143
|
+
}
|
|
48144
|
+
function getAgentsTreeRoot(homeDir) {
|
|
48145
|
+
const normalizedHome = homeDir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
48146
|
+
return `${normalizedHome}/.letta/agents`;
|
|
48147
|
+
}
|
|
48148
|
+
function normalizePathForCompare(path3) {
|
|
48149
|
+
const normalized = path3.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
48150
|
+
return normalized.length === 0 ? "/" : normalized;
|
|
48151
|
+
}
|
|
48152
|
+
function classifyAgentsTreePath(path3, homeDir) {
|
|
48153
|
+
const root = getAgentsTreeRoot(homeDir);
|
|
48154
|
+
const normalized = normalizePathForCompare(path3);
|
|
48155
|
+
if (normalized === root) {
|
|
48156
|
+
return { kind: "agents-root" };
|
|
48157
|
+
}
|
|
48158
|
+
if (normalized.startsWith(`${root}/`)) {
|
|
48159
|
+
const rest = normalized.slice(root.length + 1);
|
|
48160
|
+
const slash = rest.indexOf("/");
|
|
48161
|
+
const id = slash === -1 ? rest : rest.slice(0, slash);
|
|
48162
|
+
return { kind: "agent", id };
|
|
48163
|
+
}
|
|
48164
|
+
const prefix = normalized === "/" ? "/" : `${normalized}/`;
|
|
48165
|
+
if (root.startsWith(prefix)) {
|
|
48166
|
+
return { kind: "ancestor" };
|
|
48167
|
+
}
|
|
48168
|
+
return { kind: "outside" };
|
|
48169
|
+
}
|
|
48170
|
+
function extractApplyPatchPaths(input) {
|
|
48171
|
+
const paths = [];
|
|
48172
|
+
const fileDirectivePattern = /\*\*\* (?:Add|Update|Delete) File:\s*(.+)/g;
|
|
48173
|
+
const moveDirectivePattern = /\*\*\* Move to:\s*(.+)/g;
|
|
48174
|
+
for (const match of input.matchAll(fileDirectivePattern)) {
|
|
48175
|
+
const matchPath = match[1]?.trim();
|
|
48176
|
+
if (matchPath)
|
|
48177
|
+
paths.push(matchPath);
|
|
48178
|
+
}
|
|
48179
|
+
for (const match of input.matchAll(moveDirectivePattern)) {
|
|
48180
|
+
const matchPath = match[1]?.trim();
|
|
48181
|
+
if (matchPath)
|
|
48182
|
+
paths.push(matchPath);
|
|
48183
|
+
}
|
|
48184
|
+
return paths;
|
|
48185
|
+
}
|
|
48186
|
+
function extractFilePath(toolArgs) {
|
|
48187
|
+
if (typeof toolArgs.file_path === "string" && toolArgs.file_path.length > 0) {
|
|
48188
|
+
return toolArgs.file_path;
|
|
48189
|
+
}
|
|
48190
|
+
if (typeof toolArgs.path === "string" && toolArgs.path.length > 0) {
|
|
48191
|
+
return toolArgs.path;
|
|
48192
|
+
}
|
|
48193
|
+
if (typeof toolArgs.notebook_path === "string" && toolArgs.notebook_path.length > 0) {
|
|
48194
|
+
return toolArgs.notebook_path;
|
|
48195
|
+
}
|
|
48196
|
+
return null;
|
|
48197
|
+
}
|
|
48198
|
+
function extractMultiEditPaths(toolArgs) {
|
|
48199
|
+
const single = extractFilePath(toolArgs);
|
|
48200
|
+
return single ? [single] : [];
|
|
48201
|
+
}
|
|
48202
|
+
function extractShellCommand(toolArgs) {
|
|
48203
|
+
const command = toolArgs.command;
|
|
48204
|
+
if (typeof command === "string")
|
|
48205
|
+
return command;
|
|
48206
|
+
if (Array.isArray(command)) {
|
|
48207
|
+
return command.map((c) => String(c)).join(" ");
|
|
48208
|
+
}
|
|
48209
|
+
return null;
|
|
48210
|
+
}
|
|
48211
|
+
function lookupShellVar(name, env3, homeDir) {
|
|
48212
|
+
if (name === "HOME")
|
|
48213
|
+
return homeDir;
|
|
48214
|
+
const value = env3[name];
|
|
48215
|
+
return typeof value === "string" ? value : undefined;
|
|
48216
|
+
}
|
|
48217
|
+
function expandShellToken(token, env3, homeDir) {
|
|
48218
|
+
let result = token;
|
|
48219
|
+
if (result.startsWith("~/")) {
|
|
48220
|
+
result = `${homeDir}/${result.slice(2)}`;
|
|
48221
|
+
} else if (result === "~") {
|
|
48222
|
+
result = homeDir;
|
|
48223
|
+
}
|
|
48224
|
+
let unresolved = false;
|
|
48225
|
+
result = result.replace(SHELL_VAR_REGEX, (_match, bracedName, bareName) => {
|
|
48226
|
+
const name = bracedName || bareName;
|
|
48227
|
+
if (!name) {
|
|
48228
|
+
unresolved = true;
|
|
48229
|
+
return "";
|
|
48230
|
+
}
|
|
48231
|
+
const value = lookupShellVar(name, env3, homeDir);
|
|
48232
|
+
if (value === undefined) {
|
|
48233
|
+
unresolved = true;
|
|
48234
|
+
return "";
|
|
48235
|
+
}
|
|
48236
|
+
return value;
|
|
48237
|
+
});
|
|
48238
|
+
return unresolved ? null : result;
|
|
48239
|
+
}
|
|
48240
|
+
function collectShellAgentTargets(command, env3, homeDir) {
|
|
48241
|
+
const targets = new Map;
|
|
48242
|
+
const segments = splitShellSegments(command) ?? [command];
|
|
48243
|
+
for (const segment of segments) {
|
|
48244
|
+
for (const token of tokenizeShellWords(segment)) {
|
|
48245
|
+
scanToken(token, env3, homeDir, targets);
|
|
48246
|
+
}
|
|
48247
|
+
}
|
|
48248
|
+
return targets;
|
|
48249
|
+
}
|
|
48250
|
+
function stripAllOuterQuotes(value) {
|
|
48251
|
+
let result = value;
|
|
48252
|
+
while (result.length >= 2 && (result.startsWith('"') && result.endsWith('"') || result.startsWith("'") && result.endsWith("'"))) {
|
|
48253
|
+
result = result.slice(1, -1);
|
|
48254
|
+
}
|
|
48255
|
+
return result;
|
|
48256
|
+
}
|
|
48257
|
+
function scanToken(rawToken, env3, homeDir, out) {
|
|
48258
|
+
if (!rawToken)
|
|
48259
|
+
return;
|
|
48260
|
+
const assignmentMatch = rawToken.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
48261
|
+
const candidateValue = assignmentMatch ? assignmentMatch[2] ?? "" : rawToken;
|
|
48262
|
+
const candidates = [rawToken, candidateValue].filter((v) => v.length > 0).map((v) => stripAllOuterQuotes(v));
|
|
48263
|
+
for (const value of candidates) {
|
|
48264
|
+
const expanded = expandShellToken(value, env3, homeDir);
|
|
48265
|
+
if (expanded === null)
|
|
48266
|
+
continue;
|
|
48267
|
+
const normalized = normalizeScopedPath(expanded);
|
|
48268
|
+
const classification = classifyAgentsTreePath(normalized, homeDir);
|
|
48269
|
+
if (classification.kind === "agent") {
|
|
48270
|
+
out.set(value, classification.id);
|
|
48271
|
+
} else if (classification.kind === "agents-root") {
|
|
48272
|
+
out.set(value, UNRESOLVED_AGENT_ID);
|
|
48273
|
+
}
|
|
48274
|
+
}
|
|
48275
|
+
}
|
|
48276
|
+
function scanRawCommandForUnresolvedAgentRefs(rawCommand, allowedAgentIds, env3, homeDir) {
|
|
48277
|
+
const expanded = expandCommandVariables(rawCommand, env3, homeDir);
|
|
48278
|
+
const escapedRoot = escapeRegex2(getAgentsTreeRoot(homeDir));
|
|
48279
|
+
const pattern = new RegExp(`${escapedRoot}(?:/([^/\\s"'\`$(){}\\[\\]|&;,#]*))?`, "g");
|
|
48280
|
+
const unresolved = [];
|
|
48281
|
+
for (const match of expanded.matchAll(pattern)) {
|
|
48282
|
+
const candidate = (match[1] ?? "").trim();
|
|
48283
|
+
if (candidate.length === 0) {
|
|
48284
|
+
unresolved.push(UNRESOLVED_AGENT_ID);
|
|
48285
|
+
continue;
|
|
48286
|
+
}
|
|
48287
|
+
if (!allowedAgentIds.has(candidate)) {
|
|
48288
|
+
unresolved.push(candidate);
|
|
48289
|
+
}
|
|
48290
|
+
}
|
|
48291
|
+
return unresolved;
|
|
48292
|
+
}
|
|
48293
|
+
function expandCommandVariables(command, env3, homeDir) {
|
|
48294
|
+
let result = command.replace(/(^|[\s="'`:])~\//g, (_match, prefix) => `${prefix}${homeDir}/`);
|
|
48295
|
+
result = result.replace(SHELL_VAR_REGEX, (match, bracedName, bareName) => {
|
|
48296
|
+
const name = bracedName || bareName;
|
|
48297
|
+
if (!name)
|
|
48298
|
+
return match;
|
|
48299
|
+
return lookupShellVar(name, env3, homeDir) ?? match;
|
|
48300
|
+
});
|
|
48301
|
+
return result;
|
|
48302
|
+
}
|
|
48303
|
+
function isRecursivePathTool(toolName) {
|
|
48304
|
+
if (RECURSIVE_PATH_TOOLS.has(toolName))
|
|
48305
|
+
return true;
|
|
48306
|
+
const canonical = canonicalToolName(toolName);
|
|
48307
|
+
return RECURSIVE_PATH_TOOLS.has(canonical);
|
|
48308
|
+
}
|
|
48309
|
+
function extractTargetAgentPaths(toolName, toolArgs, workingDirectory, env3 = process.env, homeDir = homedir12()) {
|
|
48310
|
+
const agentIds = new Set;
|
|
48311
|
+
let anyAgentScoped = false;
|
|
48312
|
+
const recursive = isRecursivePathTool(toolName);
|
|
48313
|
+
const addFromPath = (rawPath) => {
|
|
48314
|
+
if (!rawPath || typeof rawPath !== "string")
|
|
48315
|
+
return;
|
|
48316
|
+
const resolvedPath = resolveScopedTargetPath(rawPath, workingDirectory);
|
|
48317
|
+
if (!resolvedPath)
|
|
48318
|
+
return;
|
|
48319
|
+
const classification = classifyAgentsTreePath(resolvedPath, homeDir);
|
|
48320
|
+
switch (classification.kind) {
|
|
48321
|
+
case "outside":
|
|
48322
|
+
return;
|
|
48323
|
+
case "agents-root":
|
|
48324
|
+
anyAgentScoped = true;
|
|
48325
|
+
agentIds.add(UNRESOLVED_AGENT_ID);
|
|
48326
|
+
return;
|
|
48327
|
+
case "ancestor":
|
|
48328
|
+
if (recursive) {
|
|
48329
|
+
anyAgentScoped = true;
|
|
48330
|
+
agentIds.add(UNRESOLVED_AGENT_ID);
|
|
48331
|
+
}
|
|
48332
|
+
return;
|
|
48333
|
+
case "agent":
|
|
48334
|
+
anyAgentScoped = true;
|
|
48335
|
+
agentIds.add(classification.id);
|
|
48336
|
+
return;
|
|
48337
|
+
}
|
|
48338
|
+
};
|
|
48339
|
+
const canonical = canonicalToolName(toolName);
|
|
48340
|
+
if (toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") {
|
|
48341
|
+
if (typeof toolArgs.input === "string") {
|
|
48342
|
+
for (const p of extractApplyPatchPaths(toolArgs.input)) {
|
|
48343
|
+
addFromPath(p);
|
|
48344
|
+
}
|
|
48345
|
+
}
|
|
48346
|
+
return { agentIds, anyAgentScoped };
|
|
48347
|
+
}
|
|
48348
|
+
if (isShellToolName(toolName) || canonical === "Bash") {
|
|
48349
|
+
const command = extractShellCommand(toolArgs);
|
|
48350
|
+
if (command) {
|
|
48351
|
+
const hits = collectShellAgentTargets(command, env3, homeDir);
|
|
48352
|
+
for (const id of hits.values()) {
|
|
48353
|
+
anyAgentScoped = true;
|
|
48354
|
+
agentIds.add(id);
|
|
48355
|
+
}
|
|
48356
|
+
}
|
|
48357
|
+
return { agentIds, anyAgentScoped };
|
|
48358
|
+
}
|
|
48359
|
+
if (toolName === "MultiEdit") {
|
|
48360
|
+
for (const p of extractMultiEditPaths(toolArgs)) {
|
|
48361
|
+
addFromPath(p);
|
|
48362
|
+
}
|
|
48363
|
+
return { agentIds, anyAgentScoped };
|
|
48364
|
+
}
|
|
48365
|
+
addFromPath(extractFilePath(toolArgs));
|
|
48366
|
+
if (recursive && typeof toolArgs.pattern === "string") {
|
|
48367
|
+
addFromPath(toolArgs.pattern);
|
|
48368
|
+
}
|
|
48369
|
+
return { agentIds, anyAgentScoped };
|
|
48370
|
+
}
|
|
48371
|
+
function buildReason(offending, allowed) {
|
|
48372
|
+
const offendingDesc = offending.join(", ");
|
|
48373
|
+
const allowedList = [...allowed.ids];
|
|
48374
|
+
const allowedDesc = allowedList.length > 0 ? allowedList.join(", ") : "(none)";
|
|
48375
|
+
return `Permission denied by cross-agent memory guard (${offendingDesc}). ` + `Allowed: ${allowedDesc}. ` + `Set LETTA_MEMORY_SCOPE or pass --memory-scope to opt in.`;
|
|
48376
|
+
}
|
|
48377
|
+
function evaluateCrossAgentGuard(toolName, toolArgs, workingDirectory, options = {}) {
|
|
48378
|
+
const env3 = options.env ?? process.env;
|
|
48379
|
+
const homeDir = env3.HOME ?? homedir12();
|
|
48380
|
+
const targets = extractTargetAgentPaths(toolName, toolArgs, workingDirectory, env3, homeDir);
|
|
48381
|
+
const allowed = resolveAllowedAgents(options);
|
|
48382
|
+
const offending = new Set;
|
|
48383
|
+
for (const id of targets.agentIds) {
|
|
48384
|
+
if (!allowed.ids.has(id)) {
|
|
48385
|
+
offending.add(id);
|
|
48386
|
+
}
|
|
48387
|
+
}
|
|
48388
|
+
const canonical = canonicalToolName(toolName);
|
|
48389
|
+
if (isShellToolName(toolName) || canonical === "Bash") {
|
|
48390
|
+
const command = extractShellCommand(toolArgs);
|
|
48391
|
+
if (command) {
|
|
48392
|
+
const unresolved = scanRawCommandForUnresolvedAgentRefs(command, allowed.ids, env3, homeDir);
|
|
48393
|
+
for (const id of unresolved) {
|
|
48394
|
+
offending.add(id);
|
|
48395
|
+
}
|
|
48396
|
+
}
|
|
48397
|
+
}
|
|
48398
|
+
if (offending.size === 0) {
|
|
48399
|
+
return null;
|
|
48400
|
+
}
|
|
48401
|
+
const offendingList = [...offending];
|
|
48402
|
+
return {
|
|
48403
|
+
matchedRule: "cross-agent guard",
|
|
48404
|
+
reason: buildReason(offendingList, allowed),
|
|
48405
|
+
offendingAgentIds: offendingList
|
|
48406
|
+
};
|
|
48407
|
+
}
|
|
48408
|
+
var UNRESOLVED_AGENT_ID = "<unresolved>", SHELL_VAR_REGEX, RECURSIVE_PATH_TOOLS;
|
|
48409
|
+
var init_crossAgentGuard = __esm(() => {
|
|
48410
|
+
init_canonical();
|
|
48411
|
+
init_cli();
|
|
48412
|
+
init_memoryScope();
|
|
48413
|
+
SHELL_VAR_REGEX = /\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g;
|
|
48414
|
+
RECURSIVE_PATH_TOOLS = new Set([
|
|
48415
|
+
"Grep",
|
|
48416
|
+
"Glob",
|
|
48417
|
+
"ListDir",
|
|
48418
|
+
"LS",
|
|
48419
|
+
"list_dir",
|
|
48420
|
+
"grep",
|
|
48421
|
+
"glob"
|
|
48422
|
+
]);
|
|
48423
|
+
});
|
|
48424
|
+
|
|
48425
|
+
// src/permissions/readOnlyShell.ts
|
|
48426
|
+
import { homedir as homedir13 } from "node:os";
|
|
47538
48427
|
import { resolve as resolve5 } from "node:path";
|
|
47539
48428
|
function isSafeConditionalTest(condition, options) {
|
|
47540
48429
|
let tokens = tokenizeShellWords(condition);
|
|
@@ -47997,7 +48886,7 @@ function parseGitInvocation(tokens, options) {
|
|
|
47997
48886
|
return { subcommand: null, subcommandIndex: -1, isSafePath: true };
|
|
47998
48887
|
}
|
|
47999
48888
|
function getAllowedMemoryPrefixes(agentId) {
|
|
48000
|
-
const home =
|
|
48889
|
+
const home = homedir13();
|
|
48001
48890
|
const prefixes = [
|
|
48002
48891
|
normalizeSeparators(resolve5(home, ".letta", "agents", agentId, "memory")),
|
|
48003
48892
|
normalizeSeparators(resolve5(home, ".letta", "agents", agentId, "memory-worktrees"))
|
|
@@ -48023,7 +48912,7 @@ function expandScopedVariables(value, env3, shellVars) {
|
|
|
48023
48912
|
return "";
|
|
48024
48913
|
}
|
|
48025
48914
|
if (name === "HOME") {
|
|
48026
|
-
return
|
|
48915
|
+
return homedir13();
|
|
48027
48916
|
}
|
|
48028
48917
|
const scopedValue = shellVars[name];
|
|
48029
48918
|
if (typeof scopedValue === "string") {
|
|
@@ -48481,202 +49370,12 @@ var init_readOnlyShell = __esm(() => {
|
|
|
48481
49370
|
SAFE_FILE_TEST_FLAGS = new Set(["-e", "-f", "-d", "-s", "-L"]);
|
|
48482
49371
|
});
|
|
48483
49372
|
|
|
48484
|
-
// src/permissions/shell-command-normalization.ts
|
|
48485
|
-
function trimMatchingQuotes(value) {
|
|
48486
|
-
const trimmed = value.trim();
|
|
48487
|
-
if (trimmed.length < 2) {
|
|
48488
|
-
return trimmed;
|
|
48489
|
-
}
|
|
48490
|
-
const first = trimmed[0];
|
|
48491
|
-
const last = trimmed[trimmed.length - 1];
|
|
48492
|
-
if ((first === '"' || first === "'") && last === first) {
|
|
48493
|
-
return trimmed.slice(1, -1);
|
|
48494
|
-
}
|
|
48495
|
-
return trimmed;
|
|
48496
|
-
}
|
|
48497
|
-
function normalizeExecutableToken(token) {
|
|
48498
|
-
const normalized = trimMatchingQuotes(token).replace(/\\/g, "/");
|
|
48499
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
48500
|
-
const executable = parts[parts.length - 1] ?? normalized;
|
|
48501
|
-
return executable.toLowerCase();
|
|
48502
|
-
}
|
|
48503
|
-
function tokenizeShell(input) {
|
|
48504
|
-
const tokens = [];
|
|
48505
|
-
let current = "";
|
|
48506
|
-
let quote = null;
|
|
48507
|
-
let escaping = false;
|
|
48508
|
-
const flush = () => {
|
|
48509
|
-
if (current.length > 0) {
|
|
48510
|
-
tokens.push(current);
|
|
48511
|
-
current = "";
|
|
48512
|
-
}
|
|
48513
|
-
};
|
|
48514
|
-
for (let i = 0;i < input.length; i += 1) {
|
|
48515
|
-
const ch = input[i];
|
|
48516
|
-
if (ch === undefined) {
|
|
48517
|
-
continue;
|
|
48518
|
-
}
|
|
48519
|
-
if (escaping) {
|
|
48520
|
-
current += ch;
|
|
48521
|
-
escaping = false;
|
|
48522
|
-
continue;
|
|
48523
|
-
}
|
|
48524
|
-
if (ch === "\\" && quote !== "single") {
|
|
48525
|
-
escaping = true;
|
|
48526
|
-
continue;
|
|
48527
|
-
}
|
|
48528
|
-
if (quote === "single") {
|
|
48529
|
-
if (ch === "'") {
|
|
48530
|
-
quote = null;
|
|
48531
|
-
} else {
|
|
48532
|
-
current += ch;
|
|
48533
|
-
}
|
|
48534
|
-
continue;
|
|
48535
|
-
}
|
|
48536
|
-
if (quote === "double") {
|
|
48537
|
-
if (ch === '"') {
|
|
48538
|
-
quote = null;
|
|
48539
|
-
} else {
|
|
48540
|
-
current += ch;
|
|
48541
|
-
}
|
|
48542
|
-
continue;
|
|
48543
|
-
}
|
|
48544
|
-
if (ch === "'") {
|
|
48545
|
-
quote = "single";
|
|
48546
|
-
continue;
|
|
48547
|
-
}
|
|
48548
|
-
if (ch === '"') {
|
|
48549
|
-
quote = "double";
|
|
48550
|
-
continue;
|
|
48551
|
-
}
|
|
48552
|
-
if (/\s/.test(ch)) {
|
|
48553
|
-
flush();
|
|
48554
|
-
continue;
|
|
48555
|
-
}
|
|
48556
|
-
current += ch;
|
|
48557
|
-
}
|
|
48558
|
-
if (escaping) {
|
|
48559
|
-
current += "\\";
|
|
48560
|
-
}
|
|
48561
|
-
flush();
|
|
48562
|
-
return tokens;
|
|
48563
|
-
}
|
|
48564
|
-
function isDashCFlag(token) {
|
|
48565
|
-
return token === "-c" || /^-[a-zA-Z]*c[a-zA-Z]*$/.test(token);
|
|
48566
|
-
}
|
|
48567
|
-
function extractInnerShellCommand(tokens) {
|
|
48568
|
-
if (tokens.length === 0) {
|
|
48569
|
-
return null;
|
|
48570
|
-
}
|
|
48571
|
-
let index = 0;
|
|
48572
|
-
if (normalizeExecutableToken(tokens[0] ?? "") === "env") {
|
|
48573
|
-
index += 1;
|
|
48574
|
-
while (index < tokens.length) {
|
|
48575
|
-
const token = tokens[index] ?? "";
|
|
48576
|
-
if (!token) {
|
|
48577
|
-
index += 1;
|
|
48578
|
-
continue;
|
|
48579
|
-
}
|
|
48580
|
-
if (/^-[A-Za-z]+$/.test(token)) {
|
|
48581
|
-
index += 1;
|
|
48582
|
-
continue;
|
|
48583
|
-
}
|
|
48584
|
-
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) {
|
|
48585
|
-
index += 1;
|
|
48586
|
-
continue;
|
|
48587
|
-
}
|
|
48588
|
-
break;
|
|
48589
|
-
}
|
|
48590
|
-
}
|
|
48591
|
-
const executableToken = tokens[index];
|
|
48592
|
-
if (!executableToken) {
|
|
48593
|
-
return null;
|
|
48594
|
-
}
|
|
48595
|
-
if (!SHELL_EXECUTORS.has(normalizeExecutableToken(executableToken))) {
|
|
48596
|
-
return null;
|
|
48597
|
-
}
|
|
48598
|
-
for (let i = index + 1;i < tokens.length; i += 1) {
|
|
48599
|
-
const token = tokens[i];
|
|
48600
|
-
if (!token) {
|
|
48601
|
-
continue;
|
|
48602
|
-
}
|
|
48603
|
-
if (!isDashCFlag(token)) {
|
|
48604
|
-
continue;
|
|
48605
|
-
}
|
|
48606
|
-
const innerCommand = tokens[i + 1];
|
|
48607
|
-
if (!innerCommand) {
|
|
48608
|
-
return null;
|
|
48609
|
-
}
|
|
48610
|
-
return trimMatchingQuotes(innerCommand);
|
|
48611
|
-
}
|
|
48612
|
-
return null;
|
|
48613
|
-
}
|
|
48614
|
-
function unwrapShellLauncherCommand(command) {
|
|
48615
|
-
let current = command.trim();
|
|
48616
|
-
for (let depth = 0;depth < 5; depth += 1) {
|
|
48617
|
-
if (!current) {
|
|
48618
|
-
break;
|
|
48619
|
-
}
|
|
48620
|
-
const tokens = tokenizeShell(current);
|
|
48621
|
-
const inner = extractInnerShellCommand(tokens);
|
|
48622
|
-
if (!inner || inner === current) {
|
|
48623
|
-
break;
|
|
48624
|
-
}
|
|
48625
|
-
current = inner.trim();
|
|
48626
|
-
}
|
|
48627
|
-
return current;
|
|
48628
|
-
}
|
|
48629
|
-
function normalizeBashRulePayload(payload) {
|
|
48630
|
-
const trimmed = payload.trim();
|
|
48631
|
-
if (!trimmed) {
|
|
48632
|
-
return "";
|
|
48633
|
-
}
|
|
48634
|
-
const hasWildcardSuffix = trimmed.endsWith(":*");
|
|
48635
|
-
const withoutWildcard = hasWildcardSuffix ? trimmed.slice(0, -2).trimEnd() : trimmed;
|
|
48636
|
-
const unwrapped = unwrapShellLauncherCommand(withoutWildcard);
|
|
48637
|
-
const normalized = normalizeGitCommandPrefix(unwrapped);
|
|
48638
|
-
if (hasWildcardSuffix) {
|
|
48639
|
-
return `${normalized}:*`;
|
|
48640
|
-
}
|
|
48641
|
-
return normalized;
|
|
48642
|
-
}
|
|
48643
|
-
function normalizeGitCommandPrefix(command) {
|
|
48644
|
-
const trimmed = command.trim();
|
|
48645
|
-
if (!trimmed.startsWith("git ")) {
|
|
48646
|
-
return trimmed;
|
|
48647
|
-
}
|
|
48648
|
-
const tokens = tokenizeShell(trimmed);
|
|
48649
|
-
if (tokens[0] !== "git") {
|
|
48650
|
-
return trimmed;
|
|
48651
|
-
}
|
|
48652
|
-
const normalizedTokens = ["git"];
|
|
48653
|
-
let index = 1;
|
|
48654
|
-
while (index < tokens.length) {
|
|
48655
|
-
const token = tokens[index];
|
|
48656
|
-
if (!token) {
|
|
48657
|
-
index += 1;
|
|
48658
|
-
continue;
|
|
48659
|
-
}
|
|
48660
|
-
if (token === "-C") {
|
|
48661
|
-
index += 2;
|
|
48662
|
-
continue;
|
|
48663
|
-
}
|
|
48664
|
-
normalizedTokens.push(...tokens.slice(index));
|
|
48665
|
-
return normalizedTokens.join(" ");
|
|
48666
|
-
}
|
|
48667
|
-
return normalizedTokens.join(" ");
|
|
48668
|
-
}
|
|
48669
|
-
var SHELL_EXECUTORS;
|
|
48670
|
-
var init_shell_command_normalization = __esm(() => {
|
|
48671
|
-
SHELL_EXECUTORS = new Set(["bash", "sh", "zsh", "dash", "ksh"]);
|
|
48672
|
-
});
|
|
48673
|
-
|
|
48674
49373
|
// src/permissions/mode.ts
|
|
48675
49374
|
var exports_mode = {};
|
|
48676
49375
|
__export(exports_mode, {
|
|
48677
49376
|
permissionMode: () => permissionMode
|
|
48678
49377
|
});
|
|
48679
|
-
import { homedir as
|
|
49378
|
+
import { homedir as homedir14 } from "node:os";
|
|
48680
49379
|
import { isAbsolute as isAbsolute3, join as join15, relative as relative3 } from "node:path";
|
|
48681
49380
|
function everyResolvedTargetIsWithinRoots(candidatePaths, roots, workingDirectory) {
|
|
48682
49381
|
return candidatePaths.length > 0 && candidatePaths.every((path3) => {
|
|
@@ -48720,22 +49419,6 @@ function isPathInPlansDir(path3, plansDir) {
|
|
|
48720
49419
|
const rel = relative3(plansDir, path3);
|
|
48721
49420
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
|
|
48722
49421
|
}
|
|
48723
|
-
function extractApplyPatchPaths(input) {
|
|
48724
|
-
const paths = [];
|
|
48725
|
-
const fileDirectivePattern = /\*\*\* (?:Add|Update|Delete) File:\s*(.+)/g;
|
|
48726
|
-
const moveDirectivePattern = /\*\*\* Move to:\s*(.+)/g;
|
|
48727
|
-
for (const match of input.matchAll(fileDirectivePattern)) {
|
|
48728
|
-
const matchPath = match[1]?.trim();
|
|
48729
|
-
if (matchPath)
|
|
48730
|
-
paths.push(matchPath);
|
|
48731
|
-
}
|
|
48732
|
-
for (const match of input.matchAll(moveDirectivePattern)) {
|
|
48733
|
-
const matchPath = match[1]?.trim();
|
|
48734
|
-
if (matchPath)
|
|
48735
|
-
paths.push(matchPath);
|
|
48736
|
-
}
|
|
48737
|
-
return paths;
|
|
48738
|
-
}
|
|
48739
49422
|
function stripMatchingQuotes(value) {
|
|
48740
49423
|
const trimmed = value.trim();
|
|
48741
49424
|
if (trimmed.length < 2) {
|
|
@@ -48906,7 +49589,7 @@ class PermissionModeManager {
|
|
|
48906
49589
|
return "allow";
|
|
48907
49590
|
}
|
|
48908
49591
|
if (writeTools.includes(toolName)) {
|
|
48909
|
-
const plansDir = join15(
|
|
49592
|
+
const plansDir = join15(homedir14(), ".letta", "plans");
|
|
48910
49593
|
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
48911
49594
|
let candidatePaths = [];
|
|
48912
49595
|
if ((toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") && toolArgs?.input) {
|
|
@@ -48957,7 +49640,7 @@ class PermissionModeManager {
|
|
|
48957
49640
|
}
|
|
48958
49641
|
const planWritePath = extractPlanFileWritePathFromShellCommand(command);
|
|
48959
49642
|
if (planWritePath) {
|
|
48960
|
-
const plansDir = join15(
|
|
49643
|
+
const plansDir = join15(homedir14(), ".letta", "plans");
|
|
48961
49644
|
const resolvedPath = resolvePlanTargetPath(planWritePath, workingDirectory);
|
|
48962
49645
|
if (resolvedPath && isPathInPlansDir(resolvedPath, plansDir)) {
|
|
48963
49646
|
return "allow";
|
|
@@ -49068,6 +49751,7 @@ class PermissionModeManager {
|
|
|
49068
49751
|
}
|
|
49069
49752
|
var MODE_KEY, PLAN_FILE_KEY, MODE_BEFORE_PLAN_KEY, permissionMode;
|
|
49070
49753
|
var init_mode = __esm(() => {
|
|
49754
|
+
init_crossAgentGuard();
|
|
49071
49755
|
init_memoryScope();
|
|
49072
49756
|
init_readOnlyShell();
|
|
49073
49757
|
init_shell_command_normalization();
|
|
@@ -52202,7 +52886,7 @@ async function edit(args) {
|
|
|
52202
52886
|
var init_Edit2 = () => {};
|
|
52203
52887
|
|
|
52204
52888
|
// src/cli/helpers/planName.ts
|
|
52205
|
-
import { homedir as
|
|
52889
|
+
import { homedir as homedir16 } from "node:os";
|
|
52206
52890
|
import { join as join18 } from "node:path";
|
|
52207
52891
|
function randomElement(arr) {
|
|
52208
52892
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
@@ -52215,7 +52899,7 @@ function generatePlanName() {
|
|
|
52215
52899
|
}
|
|
52216
52900
|
function generatePlanFilePath() {
|
|
52217
52901
|
const name = generatePlanName();
|
|
52218
|
-
return join18(
|
|
52902
|
+
return join18(homedir16(), ".letta", "plans", `${name}.md`);
|
|
52219
52903
|
}
|
|
52220
52904
|
var adjectives, nouns;
|
|
52221
52905
|
var init_planName = __esm(() => {
|
|
@@ -53363,7 +54047,6 @@ var activeRuntime = null;
|
|
|
53363
54047
|
var init_runtime3 = () => {};
|
|
53364
54048
|
|
|
53365
54049
|
// src/tools/impl/Memory.ts
|
|
53366
|
-
import { execFile as execFileCb3 } from "node:child_process";
|
|
53367
54050
|
import { existsSync as existsSync19 } from "node:fs";
|
|
53368
54051
|
import {
|
|
53369
54052
|
mkdir as mkdir5,
|
|
@@ -53374,9 +54057,8 @@ import {
|
|
|
53374
54057
|
unlink,
|
|
53375
54058
|
writeFile as writeFile5
|
|
53376
54059
|
} from "node:fs/promises";
|
|
53377
|
-
import { homedir as
|
|
54060
|
+
import { homedir as homedir17 } from "node:os";
|
|
53378
54061
|
import { dirname as dirname8, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve13 } from "node:path";
|
|
53379
|
-
import { promisify as promisify6 } from "node:util";
|
|
53380
54062
|
async function getAgentIdentity() {
|
|
53381
54063
|
const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
53382
54064
|
const contextAgentId = (() => {
|
|
@@ -53401,6 +54083,10 @@ async function getAgentIdentity() {
|
|
|
53401
54083
|
}
|
|
53402
54084
|
return { agentId, agentName };
|
|
53403
54085
|
}
|
|
54086
|
+
function normalizeComparableContent2(content) {
|
|
54087
|
+
return content.replace(/\r\n/g, `
|
|
54088
|
+
`).trim();
|
|
54089
|
+
}
|
|
53404
54090
|
async function memory(args) {
|
|
53405
54091
|
validateRequiredParams(args, ["command", "reason"], "memory");
|
|
53406
54092
|
const reason = args.reason.trim();
|
|
@@ -53409,7 +54095,46 @@ async function memory(args) {
|
|
|
53409
54095
|
}
|
|
53410
54096
|
const memoryDir = resolveMemoryDir();
|
|
53411
54097
|
ensureMemoryRepo(memoryDir);
|
|
53412
|
-
|
|
54098
|
+
await assertMemoryRepoReadyForWrite(memoryDir);
|
|
54099
|
+
const affectedPaths = await applyMemoryCommand(memoryDir, args);
|
|
54100
|
+
if (affectedPaths.length === 0) {
|
|
54101
|
+
return {
|
|
54102
|
+
message: `Memory ${args.command} completed with no changed paths.`
|
|
54103
|
+
};
|
|
54104
|
+
}
|
|
54105
|
+
const { agentId, agentName } = await getAgentIdentity();
|
|
54106
|
+
const commitResult = await commitAndSyncMemoryWrite({
|
|
54107
|
+
memoryDir,
|
|
54108
|
+
pathspecs: affectedPaths,
|
|
54109
|
+
reason,
|
|
54110
|
+
author: {
|
|
54111
|
+
agentId,
|
|
54112
|
+
authorName: agentName.trim() || agentId,
|
|
54113
|
+
authorEmail: `${agentId}@letta.com`
|
|
54114
|
+
},
|
|
54115
|
+
replay: async () => applyMemoryCommand(memoryDir, args, { replaying: true })
|
|
54116
|
+
});
|
|
54117
|
+
if (!commitResult.committed) {
|
|
54118
|
+
return {
|
|
54119
|
+
message: `Memory ${args.command} made no effective changes; skipped commit and push.`
|
|
54120
|
+
};
|
|
54121
|
+
}
|
|
54122
|
+
emitMemoryUpdated(affectedPaths);
|
|
54123
|
+
if (commitResult.replayed && commitResult.replayNoop) {
|
|
54124
|
+
return {
|
|
54125
|
+
message: `Memory ${args.command} matched newer remote memory; skipped an extra commit.`
|
|
54126
|
+
};
|
|
54127
|
+
}
|
|
54128
|
+
if (commitResult.replayed) {
|
|
54129
|
+
return {
|
|
54130
|
+
message: `Memory ${args.command} reapplied on top of newer remote memory and pushed (${commitResult.sha?.slice(0, 7) ?? "unknown"}).`
|
|
54131
|
+
};
|
|
54132
|
+
}
|
|
54133
|
+
return {
|
|
54134
|
+
message: `Memory ${args.command} applied and pushed (${commitResult.sha?.slice(0, 7) ?? "unknown"}).`
|
|
54135
|
+
};
|
|
54136
|
+
}
|
|
54137
|
+
async function applyMemoryCommand(memoryDir, args, options) {
|
|
53413
54138
|
const command = args.command;
|
|
53414
54139
|
if (command === "create") {
|
|
53415
54140
|
const pathArg = requireString(args.file_path, "file_path", "create");
|
|
@@ -53417,17 +54142,25 @@ async function memory(args) {
|
|
|
53417
54142
|
const label = normalizeMemoryLabel(memoryDir, pathArg, "file_path");
|
|
53418
54143
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
53419
54144
|
const relPath = toRepoRelative(memoryDir, filePath);
|
|
53420
|
-
if (existsSync19(filePath)) {
|
|
53421
|
-
throw new Error(`memory create: block already exists at ${pathArg}`);
|
|
53422
|
-
}
|
|
53423
54145
|
const body = args.file_text ?? "";
|
|
53424
54146
|
const rendered = renderMemoryFile({
|
|
53425
54147
|
description
|
|
53426
54148
|
}, body);
|
|
54149
|
+
if (existsSync19(filePath)) {
|
|
54150
|
+
if (!options?.replaying) {
|
|
54151
|
+
throw new Error(`memory create: block already exists at ${pathArg}`);
|
|
54152
|
+
}
|
|
54153
|
+
const existingContent = await readFile5(filePath, "utf8");
|
|
54154
|
+
if (normalizeComparableContent2(existingContent) === normalizeComparableContent2(rendered)) {
|
|
54155
|
+
return [relPath];
|
|
54156
|
+
}
|
|
54157
|
+
throw new Error(`memory create: block already exists at ${pathArg}`);
|
|
54158
|
+
}
|
|
53427
54159
|
await mkdir5(dirname8(filePath), { recursive: true });
|
|
53428
54160
|
await writeFile5(filePath, rendered, "utf8");
|
|
53429
|
-
|
|
53430
|
-
}
|
|
54161
|
+
return [relPath];
|
|
54162
|
+
}
|
|
54163
|
+
if (command === "str_replace") {
|
|
53431
54164
|
const pathArg = requireString(args.file_path, "file_path", "str_replace");
|
|
53432
54165
|
const oldString = requireString(args.old_string, "old_string", "str_replace");
|
|
53433
54166
|
const newString = requireString(args.new_string, "new_string", "str_replace");
|
|
@@ -53442,8 +54175,9 @@ async function memory(args) {
|
|
|
53442
54175
|
const nextBody = `${file.body.slice(0, idx)}${newString}${file.body.slice(idx + oldString.length)}`;
|
|
53443
54176
|
const rendered = renderMemoryFile(file.frontmatter, nextBody);
|
|
53444
54177
|
await writeFile5(filePath, rendered, "utf8");
|
|
53445
|
-
|
|
53446
|
-
}
|
|
54178
|
+
return [relPath];
|
|
54179
|
+
}
|
|
54180
|
+
if (command === "insert") {
|
|
53447
54181
|
const pathArg = requireString(args.file_path, "file_path", "insert");
|
|
53448
54182
|
const insertText = requireString(args.insert_text, "insert_text", "insert");
|
|
53449
54183
|
if (typeof args.insert_line !== "number" || Number.isNaN(args.insert_line)) {
|
|
@@ -53464,23 +54198,27 @@ async function memory(args) {
|
|
|
53464
54198
|
`);
|
|
53465
54199
|
const rendered = renderMemoryFile(file.frontmatter, nextBody);
|
|
53466
54200
|
await writeFile5(filePath, rendered, "utf8");
|
|
53467
|
-
|
|
53468
|
-
}
|
|
54201
|
+
return [relPath];
|
|
54202
|
+
}
|
|
54203
|
+
if (command === "delete") {
|
|
54204
|
+
if (options?.replaying) {
|
|
54205
|
+
throw new Error("memory delete could not be replayed safely after remote changes");
|
|
54206
|
+
}
|
|
53469
54207
|
const pathArg = requireString(args.file_path, "file_path", "delete");
|
|
53470
54208
|
const label = normalizeMemoryLabel(memoryDir, pathArg, "file_path");
|
|
53471
54209
|
const targetPath = resolveMemoryPath(memoryDir, label);
|
|
53472
54210
|
if (existsSync19(targetPath) && (await stat2(targetPath)).isDirectory()) {
|
|
53473
|
-
const
|
|
54211
|
+
const relPath2 = toRepoRelative(memoryDir, targetPath);
|
|
53474
54212
|
await rm(targetPath, { recursive: true, force: false });
|
|
53475
|
-
|
|
53476
|
-
} else {
|
|
53477
|
-
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
53478
|
-
const relPath = toRepoRelative(memoryDir, filePath);
|
|
53479
|
-
await loadEditableMemoryFile(filePath, pathArg);
|
|
53480
|
-
await unlink(filePath);
|
|
53481
|
-
affectedPaths = [relPath];
|
|
54213
|
+
return [relPath2];
|
|
53482
54214
|
}
|
|
53483
|
-
|
|
54215
|
+
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
54216
|
+
const relPath = toRepoRelative(memoryDir, filePath);
|
|
54217
|
+
await loadEditableMemoryFile(filePath, pathArg);
|
|
54218
|
+
await unlink(filePath);
|
|
54219
|
+
return [relPath];
|
|
54220
|
+
}
|
|
54221
|
+
if (command === "rename") {
|
|
53484
54222
|
const oldPathArg = requireString(args.old_path, "old_path", "rename");
|
|
53485
54223
|
const newPathArg = requireString(args.new_path, "new_path", "rename");
|
|
53486
54224
|
const oldLabel = normalizeMemoryLabel(memoryDir, oldPathArg, "old_path");
|
|
@@ -53495,8 +54233,9 @@ async function memory(args) {
|
|
|
53495
54233
|
await loadEditableMemoryFile(oldFilePath, oldPathArg);
|
|
53496
54234
|
await mkdir5(dirname8(newFilePath), { recursive: true });
|
|
53497
54235
|
await rename(oldFilePath, newFilePath);
|
|
53498
|
-
|
|
53499
|
-
}
|
|
54236
|
+
return [oldRelPath, newRelPath];
|
|
54237
|
+
}
|
|
54238
|
+
if (command === "update_description") {
|
|
53500
54239
|
const pathArg = requireString(args.file_path, "file_path", "update_description");
|
|
53501
54240
|
const newDescription = requireString(args.description, "description", "update_description");
|
|
53502
54241
|
const label = normalizeMemoryLabel(memoryDir, pathArg, "file_path");
|
|
@@ -53508,24 +54247,9 @@ async function memory(args) {
|
|
|
53508
54247
|
description: newDescription
|
|
53509
54248
|
}, file.body);
|
|
53510
54249
|
await writeFile5(filePath, rendered, "utf8");
|
|
53511
|
-
|
|
53512
|
-
} else {
|
|
53513
|
-
throw new Error(`Unsupported memory command: ${command}`);
|
|
53514
|
-
}
|
|
53515
|
-
affectedPaths = Array.from(new Set(affectedPaths)).filter((p) => p.length > 0);
|
|
53516
|
-
if (affectedPaths.length === 0) {
|
|
53517
|
-
return { message: `Memory ${command} completed with no changed paths.` };
|
|
54250
|
+
return [relPath];
|
|
53518
54251
|
}
|
|
53519
|
-
|
|
53520
|
-
if (!commitResult.committed) {
|
|
53521
|
-
return {
|
|
53522
|
-
message: `Memory ${command} made no effective changes; skipped commit and push.`
|
|
53523
|
-
};
|
|
53524
|
-
}
|
|
53525
|
-
emitMemoryUpdated(affectedPaths);
|
|
53526
|
-
return {
|
|
53527
|
-
message: `Memory ${command} applied and pushed (${commitResult.sha?.slice(0, 7) ?? "unknown"}).`
|
|
53528
|
-
};
|
|
54252
|
+
throw new Error(`Unsupported memory command: ${command}`);
|
|
53529
54253
|
}
|
|
53530
54254
|
function resolveMemoryDir() {
|
|
53531
54255
|
const direct = process.env.MEMORY_DIR || process.env.LETTA_MEMORY_DIR;
|
|
@@ -53541,7 +54265,7 @@ function resolveMemoryDir() {
|
|
|
53541
54265
|
})();
|
|
53542
54266
|
const agentId = contextAgentId || (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
53543
54267
|
if (agentId && agentId.trim().length > 0) {
|
|
53544
|
-
return resolve13(
|
|
54268
|
+
return resolve13(homedir17(), ".letta", "agents", agentId, "memory");
|
|
53545
54269
|
}
|
|
53546
54270
|
throw new Error("memory: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
|
|
53547
54271
|
}
|
|
@@ -53691,78 +54415,6 @@ ${body}`;
|
|
|
53691
54415
|
function sanitizeFrontmatterValue(value) {
|
|
53692
54416
|
return value.replace(/\r?\n/g, " ").trim();
|
|
53693
54417
|
}
|
|
53694
|
-
async function runGit4(memoryDir, args) {
|
|
53695
|
-
try {
|
|
53696
|
-
const result = await execFile6("git", args, {
|
|
53697
|
-
cwd: memoryDir,
|
|
53698
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
53699
|
-
env: {
|
|
53700
|
-
...process.env,
|
|
53701
|
-
PAGER: "cat",
|
|
53702
|
-
GIT_PAGER: "cat"
|
|
53703
|
-
}
|
|
53704
|
-
});
|
|
53705
|
-
return {
|
|
53706
|
-
stdout: result.stdout?.toString() ?? "",
|
|
53707
|
-
stderr: result.stderr?.toString() ?? ""
|
|
53708
|
-
};
|
|
53709
|
-
} catch (error) {
|
|
53710
|
-
const stderr = typeof error === "object" && error !== null && "stderr" in error ? String(error.stderr ?? "") : "";
|
|
53711
|
-
const stdout = typeof error === "object" && error !== null && "stdout" in error ? String(error.stdout ?? "") : "";
|
|
53712
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
53713
|
-
throw new Error(`git ${args.join(" ")} failed: ${stderr || stdout || message}`.trim());
|
|
53714
|
-
}
|
|
53715
|
-
}
|
|
53716
|
-
async function commitAndPush(memoryDir, pathspecs, reason) {
|
|
53717
|
-
await runGit4(memoryDir, ["add", "-A", "--", ...pathspecs]);
|
|
53718
|
-
const status = await runGit4(memoryDir, [
|
|
53719
|
-
"status",
|
|
53720
|
-
"--porcelain",
|
|
53721
|
-
"--",
|
|
53722
|
-
...pathspecs
|
|
53723
|
-
]);
|
|
53724
|
-
if (!status.stdout.trim()) {
|
|
53725
|
-
return { committed: false };
|
|
53726
|
-
}
|
|
53727
|
-
const { agentId, agentName } = await getAgentIdentity();
|
|
53728
|
-
const authorName = agentName.trim() || agentId;
|
|
53729
|
-
const authorEmail = `${agentId}@letta.com`;
|
|
53730
|
-
try {
|
|
53731
|
-
await runGit4(memoryDir, [
|
|
53732
|
-
"-c",
|
|
53733
|
-
`user.name=${authorName}`,
|
|
53734
|
-
"-c",
|
|
53735
|
-
`user.email=${authorEmail}`,
|
|
53736
|
-
"commit",
|
|
53737
|
-
"-m",
|
|
53738
|
-
reason
|
|
53739
|
-
]);
|
|
53740
|
-
} catch (error) {
|
|
53741
|
-
await unstagePaths(memoryDir, pathspecs);
|
|
53742
|
-
throw error;
|
|
53743
|
-
}
|
|
53744
|
-
const head = await runGit4(memoryDir, ["rev-parse", "HEAD"]);
|
|
53745
|
-
const sha = head.stdout.trim();
|
|
53746
|
-
await maybeUpdateMemoryRemoteOrigin(memoryDir, agentId);
|
|
53747
|
-
try {
|
|
53748
|
-
await runGit4(memoryDir, ["push"]);
|
|
53749
|
-
} catch (error) {
|
|
53750
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
53751
|
-
throw new Error(`Memory changes were committed (${sha.slice(0, 7)}) but push failed: ${message}`);
|
|
53752
|
-
}
|
|
53753
|
-
return {
|
|
53754
|
-
committed: true,
|
|
53755
|
-
sha
|
|
53756
|
-
};
|
|
53757
|
-
}
|
|
53758
|
-
async function unstagePaths(memoryDir, pathspecs) {
|
|
53759
|
-
if (pathspecs.length === 0) {
|
|
53760
|
-
return;
|
|
53761
|
-
}
|
|
53762
|
-
try {
|
|
53763
|
-
await runGit4(memoryDir, ["reset", "HEAD", "--", ...pathspecs]);
|
|
53764
|
-
} catch {}
|
|
53765
|
-
}
|
|
53766
54418
|
function requireString(value, field, command) {
|
|
53767
54419
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
53768
54420
|
throw new Error(`memory ${command}: '${field}' must be a non-empty string`);
|
|
@@ -53784,16 +54436,13 @@ function emitMemoryUpdated(affectedPaths) {
|
|
|
53784
54436
|
}));
|
|
53785
54437
|
} catch {}
|
|
53786
54438
|
}
|
|
53787
|
-
var execFile6;
|
|
53788
54439
|
var init_Memory2 = __esm(() => {
|
|
53789
54440
|
init_client2();
|
|
53790
54441
|
init_context();
|
|
53791
54442
|
init_memoryGit();
|
|
53792
|
-
execFile6 = promisify6(execFileCb3);
|
|
53793
54443
|
});
|
|
53794
54444
|
|
|
53795
54445
|
// src/tools/impl/MemoryApplyPatch.ts
|
|
53796
|
-
import { execFile as execFileCb4 } from "node:child_process";
|
|
53797
54446
|
import { existsSync as existsSync20 } from "node:fs";
|
|
53798
54447
|
import {
|
|
53799
54448
|
access,
|
|
@@ -53804,9 +54453,8 @@ import {
|
|
|
53804
54453
|
unlink as unlink2,
|
|
53805
54454
|
writeFile as writeFile6
|
|
53806
54455
|
} from "node:fs/promises";
|
|
53807
|
-
import { homedir as
|
|
54456
|
+
import { homedir as homedir18 } from "node:os";
|
|
53808
54457
|
import { dirname as dirname9, isAbsolute as isAbsolute10, relative as relative6, resolve as resolve14 } from "node:path";
|
|
53809
|
-
import { promisify as promisify7 } from "node:util";
|
|
53810
54458
|
async function getAgentIdentity2() {
|
|
53811
54459
|
const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
53812
54460
|
const contextAgentId = (() => {
|
|
@@ -53843,6 +54491,43 @@ async function memory_apply_patch(args) {
|
|
|
53843
54491
|
}
|
|
53844
54492
|
const memoryDir = resolveMemoryDir2();
|
|
53845
54493
|
ensureMemoryRepo2(memoryDir);
|
|
54494
|
+
await assertMemoryRepoReadyForWrite(memoryDir);
|
|
54495
|
+
const pathspecs = await applyMemoryPatch(memoryDir, input);
|
|
54496
|
+
if (pathspecs.length === 0) {
|
|
54497
|
+
return { message: "memory_apply_patch completed with no changed paths." };
|
|
54498
|
+
}
|
|
54499
|
+
const { agentId, agentName } = await getAgentIdentity2();
|
|
54500
|
+
const commitResult = await commitAndSyncMemoryWrite({
|
|
54501
|
+
memoryDir,
|
|
54502
|
+
pathspecs,
|
|
54503
|
+
reason,
|
|
54504
|
+
author: {
|
|
54505
|
+
agentId,
|
|
54506
|
+
authorName: agentName.trim() || agentId,
|
|
54507
|
+
authorEmail: `${agentId}@letta.com`
|
|
54508
|
+
},
|
|
54509
|
+
replay: async () => applyMemoryPatch(memoryDir, input)
|
|
54510
|
+
});
|
|
54511
|
+
if (!commitResult.committed) {
|
|
54512
|
+
return {
|
|
54513
|
+
message: "memory_apply_patch made no effective changes; skipped commit and push."
|
|
54514
|
+
};
|
|
54515
|
+
}
|
|
54516
|
+
if (commitResult.replayed && commitResult.replayNoop) {
|
|
54517
|
+
return {
|
|
54518
|
+
message: "memory_apply_patch matched newer remote memory; skipped an extra commit."
|
|
54519
|
+
};
|
|
54520
|
+
}
|
|
54521
|
+
if (commitResult.replayed) {
|
|
54522
|
+
return {
|
|
54523
|
+
message: `memory_apply_patch reapplied on top of newer remote memory and pushed (${commitResult.sha?.slice(0, 7) ?? "unknown"}).`
|
|
54524
|
+
};
|
|
54525
|
+
}
|
|
54526
|
+
return {
|
|
54527
|
+
message: `memory_apply_patch applied and pushed (${commitResult.sha?.slice(0, 7) ?? "unknown"}).`
|
|
54528
|
+
};
|
|
54529
|
+
}
|
|
54530
|
+
async function applyMemoryPatch(memoryDir, input) {
|
|
53846
54531
|
const ops = parsePatchOperations(memoryDir, input);
|
|
53847
54532
|
if (ops.length === 0) {
|
|
53848
54533
|
throw new Error("memory_apply_patch: no file operations found in patch");
|
|
@@ -53934,18 +54619,7 @@ async function memory_apply_patch(args) {
|
|
|
53934
54619
|
}
|
|
53935
54620
|
}
|
|
53936
54621
|
const pathspecs = Array.from(affectedPaths).filter((p) => p.length > 0);
|
|
53937
|
-
|
|
53938
|
-
return { message: "memory_apply_patch completed with no changed paths." };
|
|
53939
|
-
}
|
|
53940
|
-
const commitResult = await commitAndPush2(memoryDir, pathspecs, reason);
|
|
53941
|
-
if (!commitResult.committed) {
|
|
53942
|
-
return {
|
|
53943
|
-
message: "memory_apply_patch made no effective changes; skipped commit and push."
|
|
53944
|
-
};
|
|
53945
|
-
}
|
|
53946
|
-
return {
|
|
53947
|
-
message: `memory_apply_patch applied and pushed (${commitResult.sha?.slice(0, 7) ?? "unknown"}).`
|
|
53948
|
-
};
|
|
54622
|
+
return pathspecs;
|
|
53949
54623
|
}
|
|
53950
54624
|
function parsePatchOperations(memoryDir, input) {
|
|
53951
54625
|
const lines = input.split(/\r?\n/);
|
|
@@ -54092,7 +54766,7 @@ function resolveMemoryDir2() {
|
|
|
54092
54766
|
})();
|
|
54093
54767
|
const agentId = contextAgentId || (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
54094
54768
|
if (agentId && agentId.trim().length > 0) {
|
|
54095
|
-
return resolve14(
|
|
54769
|
+
return resolve14(homedir18(), ".letta", "agents", agentId, "memory");
|
|
54096
54770
|
}
|
|
54097
54771
|
throw new Error("memory_apply_patch: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
|
|
54098
54772
|
}
|
|
@@ -54241,65 +54915,6 @@ ${body}`;
|
|
|
54241
54915
|
function sanitizeFrontmatterValue2(value) {
|
|
54242
54916
|
return value.replace(/\r?\n/g, " ").trim();
|
|
54243
54917
|
}
|
|
54244
|
-
async function runGit5(memoryDir, args) {
|
|
54245
|
-
try {
|
|
54246
|
-
const result = await execFile7("git", args, {
|
|
54247
|
-
cwd: memoryDir,
|
|
54248
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
54249
|
-
env: {
|
|
54250
|
-
...process.env,
|
|
54251
|
-
PAGER: "cat",
|
|
54252
|
-
GIT_PAGER: "cat"
|
|
54253
|
-
}
|
|
54254
|
-
});
|
|
54255
|
-
return {
|
|
54256
|
-
stdout: result.stdout?.toString() ?? "",
|
|
54257
|
-
stderr: result.stderr?.toString() ?? ""
|
|
54258
|
-
};
|
|
54259
|
-
} catch (error) {
|
|
54260
|
-
const stderr = typeof error === "object" && error !== null && "stderr" in error ? String(error.stderr ?? "") : "";
|
|
54261
|
-
const stdout = typeof error === "object" && error !== null && "stdout" in error ? String(error.stdout ?? "") : "";
|
|
54262
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
54263
|
-
throw new Error(`git ${args.join(" ")} failed: ${stderr || stdout || message}`.trim());
|
|
54264
|
-
}
|
|
54265
|
-
}
|
|
54266
|
-
async function commitAndPush2(memoryDir, pathspecs, reason) {
|
|
54267
|
-
await runGit5(memoryDir, ["add", "-A", "--", ...pathspecs]);
|
|
54268
|
-
const status = await runGit5(memoryDir, [
|
|
54269
|
-
"status",
|
|
54270
|
-
"--porcelain",
|
|
54271
|
-
"--",
|
|
54272
|
-
...pathspecs
|
|
54273
|
-
]);
|
|
54274
|
-
if (!status.stdout.trim()) {
|
|
54275
|
-
return { committed: false };
|
|
54276
|
-
}
|
|
54277
|
-
const { agentId, agentName } = await getAgentIdentity2();
|
|
54278
|
-
const authorName = agentName.trim() || agentId;
|
|
54279
|
-
const authorEmail = `${agentId}@letta.com`;
|
|
54280
|
-
await runGit5(memoryDir, [
|
|
54281
|
-
"-c",
|
|
54282
|
-
`user.name=${authorName}`,
|
|
54283
|
-
"-c",
|
|
54284
|
-
`user.email=${authorEmail}`,
|
|
54285
|
-
"commit",
|
|
54286
|
-
"-m",
|
|
54287
|
-
reason
|
|
54288
|
-
]);
|
|
54289
|
-
const head = await runGit5(memoryDir, ["rev-parse", "HEAD"]);
|
|
54290
|
-
const sha = head.stdout.trim();
|
|
54291
|
-
await maybeUpdateMemoryRemoteOrigin(memoryDir, agentId);
|
|
54292
|
-
try {
|
|
54293
|
-
await runGit5(memoryDir, ["push"]);
|
|
54294
|
-
} catch (error) {
|
|
54295
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
54296
|
-
throw new Error(`Memory changes were committed (${sha.slice(0, 7)}) but push failed: ${message}`);
|
|
54297
|
-
}
|
|
54298
|
-
return {
|
|
54299
|
-
committed: true,
|
|
54300
|
-
sha
|
|
54301
|
-
};
|
|
54302
|
-
}
|
|
54303
54918
|
async function isMissing(filePath) {
|
|
54304
54919
|
try {
|
|
54305
54920
|
await access(filePath);
|
|
@@ -54360,12 +54975,10 @@ function buildOldNewChunks(lines) {
|
|
|
54360
54975
|
newChunk: newParts.join("")
|
|
54361
54976
|
};
|
|
54362
54977
|
}
|
|
54363
|
-
var execFile7;
|
|
54364
54978
|
var init_MemoryApplyPatch2 = __esm(() => {
|
|
54365
54979
|
init_client2();
|
|
54366
54980
|
init_context();
|
|
54367
54981
|
init_memoryGit();
|
|
54368
|
-
execFile7 = promisify7(execFileCb4);
|
|
54369
54982
|
});
|
|
54370
54983
|
|
|
54371
54984
|
// src/tools/impl/MessageChannel.ts
|
|
@@ -68955,211 +69568,6 @@ var init_subagentState = __esm(() => {
|
|
|
68955
69568
|
streamEventListeners = new Set;
|
|
68956
69569
|
});
|
|
68957
69570
|
|
|
68958
|
-
// src/permissions/canonical.ts
|
|
68959
|
-
function canonicalToolName(toolName) {
|
|
68960
|
-
if (SHELL_TOOL_NAMES.has(toolName))
|
|
68961
|
-
return "Bash";
|
|
68962
|
-
if (READ_TOOL_NAMES.has(toolName))
|
|
68963
|
-
return "Read";
|
|
68964
|
-
if (WRITE_TOOL_NAMES.has(toolName))
|
|
68965
|
-
return "Write";
|
|
68966
|
-
if (EDIT_TOOL_NAMES.has(toolName))
|
|
68967
|
-
return "Edit";
|
|
68968
|
-
if (GLOB_TOOL_NAMES.has(toolName))
|
|
68969
|
-
return "Glob";
|
|
68970
|
-
if (GREP_TOOL_NAMES.has(toolName))
|
|
68971
|
-
return "Grep";
|
|
68972
|
-
if (LIST_TOOL_NAMES.has(toolName))
|
|
68973
|
-
return "ListDir";
|
|
68974
|
-
if (TASK_TOOL_NAMES.has(toolName))
|
|
68975
|
-
return "Task";
|
|
68976
|
-
return toolName;
|
|
68977
|
-
}
|
|
68978
|
-
function isShellToolName(toolName) {
|
|
68979
|
-
return canonicalToolName(toolName) === "Bash";
|
|
68980
|
-
}
|
|
68981
|
-
function isFileToolName(toolName) {
|
|
68982
|
-
return FILE_TOOL_FAMILIES.has(canonicalToolName(toolName));
|
|
68983
|
-
}
|
|
68984
|
-
function canonicalizePathLike(value) {
|
|
68985
|
-
let normalized = value.replace(/\\/g, "/").trim();
|
|
68986
|
-
if (/^\/+[a-zA-Z]:\//.test(normalized)) {
|
|
68987
|
-
normalized = normalized.replace(/^\/+/, "");
|
|
68988
|
-
}
|
|
68989
|
-
if (/^[a-zA-Z]:\//.test(normalized)) {
|
|
68990
|
-
normalized = `${normalized[0]?.toUpperCase() ?? ""}${normalized.slice(1)}`;
|
|
68991
|
-
}
|
|
68992
|
-
return normalized;
|
|
68993
|
-
}
|
|
68994
|
-
var SHELL_TOOL_NAMES, READ_TOOL_NAMES, WRITE_TOOL_NAMES, EDIT_TOOL_NAMES, GLOB_TOOL_NAMES, GREP_TOOL_NAMES, LIST_TOOL_NAMES, TASK_TOOL_NAMES, FILE_TOOL_FAMILIES;
|
|
68995
|
-
var init_canonical = __esm(() => {
|
|
68996
|
-
SHELL_TOOL_NAMES = new Set([
|
|
68997
|
-
"Bash",
|
|
68998
|
-
"shell",
|
|
68999
|
-
"Shell",
|
|
69000
|
-
"shell_command",
|
|
69001
|
-
"ShellCommand",
|
|
69002
|
-
"run_shell_command",
|
|
69003
|
-
"RunShellCommand"
|
|
69004
|
-
]);
|
|
69005
|
-
READ_TOOL_NAMES = new Set([
|
|
69006
|
-
"Read",
|
|
69007
|
-
"read_file",
|
|
69008
|
-
"ReadFile",
|
|
69009
|
-
"read_file_gemini",
|
|
69010
|
-
"ReadFileGemini"
|
|
69011
|
-
]);
|
|
69012
|
-
WRITE_TOOL_NAMES = new Set([
|
|
69013
|
-
"Write",
|
|
69014
|
-
"write_file",
|
|
69015
|
-
"WriteFile",
|
|
69016
|
-
"write_file_gemini",
|
|
69017
|
-
"WriteFileGemini"
|
|
69018
|
-
]);
|
|
69019
|
-
EDIT_TOOL_NAMES = new Set([
|
|
69020
|
-
"Edit",
|
|
69021
|
-
"MultiEdit",
|
|
69022
|
-
"NotebookEdit",
|
|
69023
|
-
"replace",
|
|
69024
|
-
"Replace"
|
|
69025
|
-
]);
|
|
69026
|
-
GLOB_TOOL_NAMES = new Set(["Glob", "glob_gemini", "GlobGemini"]);
|
|
69027
|
-
GREP_TOOL_NAMES = new Set([
|
|
69028
|
-
"Grep",
|
|
69029
|
-
"grep_files",
|
|
69030
|
-
"GrepFiles",
|
|
69031
|
-
"search_file_content",
|
|
69032
|
-
"SearchFileContent"
|
|
69033
|
-
]);
|
|
69034
|
-
LIST_TOOL_NAMES = new Set([
|
|
69035
|
-
"list_dir",
|
|
69036
|
-
"ListDir",
|
|
69037
|
-
"list_directory",
|
|
69038
|
-
"ListDirectory",
|
|
69039
|
-
"LS"
|
|
69040
|
-
]);
|
|
69041
|
-
TASK_TOOL_NAMES = new Set(["Task", "task"]);
|
|
69042
|
-
FILE_TOOL_FAMILIES = new Set([
|
|
69043
|
-
"Read",
|
|
69044
|
-
"Write",
|
|
69045
|
-
"Edit",
|
|
69046
|
-
"Glob",
|
|
69047
|
-
"Grep",
|
|
69048
|
-
"ListDir"
|
|
69049
|
-
]);
|
|
69050
|
-
});
|
|
69051
|
-
|
|
69052
|
-
// src/permissions/rule-normalization.ts
|
|
69053
|
-
function splitRule(rule) {
|
|
69054
|
-
const match2 = rule.trim().match(/^([^(]+)(?:\(([\s\S]*)\))?$/);
|
|
69055
|
-
if (!match2?.[1]) {
|
|
69056
|
-
return { tool: rule.trim(), payload: null };
|
|
69057
|
-
}
|
|
69058
|
-
return {
|
|
69059
|
-
tool: match2[1].trim(),
|
|
69060
|
-
payload: match2[2] !== undefined ? match2[2] : null
|
|
69061
|
-
};
|
|
69062
|
-
}
|
|
69063
|
-
function normalizePermissionRule(rule) {
|
|
69064
|
-
const { tool, payload } = splitRule(rule);
|
|
69065
|
-
const canonicalTool = canonicalToolName(tool);
|
|
69066
|
-
if (payload === null) {
|
|
69067
|
-
return canonicalTool;
|
|
69068
|
-
}
|
|
69069
|
-
if (isShellToolName(canonicalTool)) {
|
|
69070
|
-
return `Bash(${normalizeBashRulePayload(payload)})`;
|
|
69071
|
-
}
|
|
69072
|
-
if (isFileToolName(canonicalTool)) {
|
|
69073
|
-
return `${canonicalTool}(${canonicalizePathLike(payload)})`;
|
|
69074
|
-
}
|
|
69075
|
-
return `${canonicalTool}(${payload.trim()})`;
|
|
69076
|
-
}
|
|
69077
|
-
function permissionRulesEquivalent(left, right) {
|
|
69078
|
-
return normalizePermissionRule(left) === normalizePermissionRule(right);
|
|
69079
|
-
}
|
|
69080
|
-
var init_rule_normalization = __esm(() => {
|
|
69081
|
-
init_canonical();
|
|
69082
|
-
init_shell_command_normalization();
|
|
69083
|
-
});
|
|
69084
|
-
|
|
69085
|
-
// src/permissions/cli.ts
|
|
69086
|
-
var exports_cli = {};
|
|
69087
|
-
__export(exports_cli, {
|
|
69088
|
-
cliPermissions: () => cliPermissions
|
|
69089
|
-
});
|
|
69090
|
-
|
|
69091
|
-
class CliPermissions {
|
|
69092
|
-
allowedTools = [];
|
|
69093
|
-
disallowedTools = [];
|
|
69094
|
-
setAllowedTools(toolsString) {
|
|
69095
|
-
this.allowedTools = this.parseToolList(toolsString);
|
|
69096
|
-
}
|
|
69097
|
-
setDisallowedTools(toolsString) {
|
|
69098
|
-
this.disallowedTools = this.parseToolList(toolsString);
|
|
69099
|
-
}
|
|
69100
|
-
parseToolList(toolsString) {
|
|
69101
|
-
if (!toolsString)
|
|
69102
|
-
return [];
|
|
69103
|
-
const tools = [];
|
|
69104
|
-
let current = "";
|
|
69105
|
-
let depth = 0;
|
|
69106
|
-
for (let i = 0;i < toolsString.length; i++) {
|
|
69107
|
-
const char = toolsString[i];
|
|
69108
|
-
if (char === "(") {
|
|
69109
|
-
depth++;
|
|
69110
|
-
current += char;
|
|
69111
|
-
} else if (char === ")") {
|
|
69112
|
-
depth--;
|
|
69113
|
-
current += char;
|
|
69114
|
-
} else if (char === "," && depth === 0) {
|
|
69115
|
-
if (current.trim()) {
|
|
69116
|
-
tools.push(this.normalizePattern(current.trim()));
|
|
69117
|
-
}
|
|
69118
|
-
current = "";
|
|
69119
|
-
} else {
|
|
69120
|
-
current += char;
|
|
69121
|
-
}
|
|
69122
|
-
}
|
|
69123
|
-
if (current.trim()) {
|
|
69124
|
-
tools.push(this.normalizePattern(current.trim()));
|
|
69125
|
-
}
|
|
69126
|
-
return tools;
|
|
69127
|
-
}
|
|
69128
|
-
normalizePattern(pattern) {
|
|
69129
|
-
const trimmed = pattern.trim();
|
|
69130
|
-
if (trimmed.includes("(")) {
|
|
69131
|
-
return normalizePermissionRule(trimmed);
|
|
69132
|
-
}
|
|
69133
|
-
const canonicalTool = canonicalToolName(trimmed);
|
|
69134
|
-
if (isShellToolName(canonicalTool)) {
|
|
69135
|
-
return "Bash(:*)";
|
|
69136
|
-
}
|
|
69137
|
-
if (isFileToolName(canonicalTool)) {
|
|
69138
|
-
return `${canonicalTool}(**)`;
|
|
69139
|
-
}
|
|
69140
|
-
return canonicalTool;
|
|
69141
|
-
}
|
|
69142
|
-
getAllowedTools() {
|
|
69143
|
-
return [...this.allowedTools];
|
|
69144
|
-
}
|
|
69145
|
-
getDisallowedTools() {
|
|
69146
|
-
return [...this.disallowedTools];
|
|
69147
|
-
}
|
|
69148
|
-
hasOverrides() {
|
|
69149
|
-
return this.allowedTools.length > 0 || this.disallowedTools.length > 0;
|
|
69150
|
-
}
|
|
69151
|
-
clear() {
|
|
69152
|
-
this.allowedTools = [];
|
|
69153
|
-
this.disallowedTools = [];
|
|
69154
|
-
}
|
|
69155
|
-
}
|
|
69156
|
-
var cliPermissions;
|
|
69157
|
-
var init_cli = __esm(() => {
|
|
69158
|
-
init_canonical();
|
|
69159
|
-
init_rule_normalization();
|
|
69160
|
-
cliPermissions = new CliPermissions;
|
|
69161
|
-
});
|
|
69162
|
-
|
|
69163
69571
|
// src/agent/prompts/recall_subagent.md
|
|
69164
69572
|
var recall_subagent_default = `Your task is to recall past experience based on a query. Use the CLI commands and search strategies below to search conversation history. Try to finish quickly with just 1-2 tool calls if possible (but use more if needed).
|
|
69165
69573
|
|
|
@@ -69639,11 +70047,14 @@ async function executeSubagent(type, config, model, userPrompt, baseURL, subagen
|
|
|
69639
70047
|
delete childEnv.MEMORY_DIR;
|
|
69640
70048
|
delete childEnv.LETTA_MEMORY_DIR;
|
|
69641
70049
|
}
|
|
69642
|
-
const
|
|
69643
|
-
if (
|
|
69644
|
-
|
|
70050
|
+
const nextScope = new Set(parseScopeList(process.env.LETTA_MEMORY_SCOPE));
|
|
70051
|
+
if (parentAgentId) {
|
|
70052
|
+
nextScope.add(parentAgentId);
|
|
70053
|
+
}
|
|
70054
|
+
if (nextScope.size > 0) {
|
|
70055
|
+
childEnv.LETTA_MEMORY_SCOPE = [...nextScope].join(",");
|
|
69645
70056
|
} else {
|
|
69646
|
-
delete childEnv.
|
|
70057
|
+
delete childEnv.LETTA_MEMORY_SCOPE;
|
|
69647
70058
|
}
|
|
69648
70059
|
}
|
|
69649
70060
|
const proc2 = spawn5(launcher.command, launcher.args, {
|
|
@@ -70247,7 +70658,10 @@ async function task(args) {
|
|
|
70247
70658
|
const parentAgentId = getCurrentAgentId();
|
|
70248
70659
|
const parentConvId = getConversationId() ?? "default";
|
|
70249
70660
|
const forkedConv = await client.post(`/v1/conversations/${encodeURIComponent(parentConvId)}/fork`, {
|
|
70250
|
-
query:
|
|
70661
|
+
query: {
|
|
70662
|
+
...parentConvId === "default" ? { agent_id: parentAgentId } : {},
|
|
70663
|
+
hidden: true
|
|
70664
|
+
}
|
|
70251
70665
|
});
|
|
70252
70666
|
effectiveAgentId = parentAgentId;
|
|
70253
70667
|
effectiveConversationId = forkedConv.id;
|
|
@@ -73459,8 +73873,8 @@ function matchesFilePattern(query, pattern, workingDirectory, options) {
|
|
|
73459
73873
|
globPattern = globPattern.slice(2);
|
|
73460
73874
|
}
|
|
73461
73875
|
if (globPattern.startsWith("~/")) {
|
|
73462
|
-
const
|
|
73463
|
-
globPattern = globPattern.replace(/^~/,
|
|
73876
|
+
const homedir19 = __require("node:os").homedir();
|
|
73877
|
+
globPattern = globPattern.replace(/^~/, homedir19);
|
|
73464
73878
|
}
|
|
73465
73879
|
globPattern = normalizeAbsolutePattern(globPattern, workingDirectory);
|
|
73466
73880
|
const windowsContext = isWindowsContext(workingDirectory);
|
|
@@ -73655,6 +74069,18 @@ function checkPermissionForEngine(engine, toolName, toolArgs, permissions, worki
|
|
|
73655
74069
|
const trace = createTrace(engine, toolName, canonicalTool, query);
|
|
73656
74070
|
const sessionRules = sessionPermissions.getRules();
|
|
73657
74071
|
const workingDirectoryTools = engine === "v2" ? WORKING_DIRECTORY_TOOLS_V2 : WORKING_DIRECTORY_TOOLS_V1;
|
|
74072
|
+
const guardResult = evaluateCrossAgentGuard(toolName, toolArgs, workingDirectory);
|
|
74073
|
+
if (guardResult) {
|
|
74074
|
+
traceEvent(trace, "cross-agent-guard", guardResult.reason);
|
|
74075
|
+
return {
|
|
74076
|
+
result: {
|
|
74077
|
+
decision: "deny",
|
|
74078
|
+
matchedRule: guardResult.matchedRule,
|
|
74079
|
+
reason: guardResult.reason
|
|
74080
|
+
},
|
|
74081
|
+
trace
|
|
74082
|
+
};
|
|
74083
|
+
}
|
|
73658
74084
|
if (permissions.deny) {
|
|
73659
74085
|
for (const pattern of permissions.deny) {
|
|
73660
74086
|
const matched = matchesPattern(toolName, query, pattern, workingDirectory, engine);
|
|
@@ -73731,7 +74157,7 @@ function checkPermissionForEngine(engine, toolName, toolArgs, permissions, worki
|
|
|
73731
74157
|
};
|
|
73732
74158
|
}
|
|
73733
74159
|
if (READ_ONLY_SHELL_TOOLS.has(toolName) || isShellToolName(canonicalTool)) {
|
|
73734
|
-
const shellCommand =
|
|
74160
|
+
const shellCommand = extractShellCommand2(toolArgs);
|
|
73735
74161
|
if (shellCommand && isReadOnlyShellCommand(shellCommand, {
|
|
73736
74162
|
allowedPathRoots: getAllowedShellPathRoots(permissions, workingDirectory)
|
|
73737
74163
|
})) {
|
|
@@ -73833,18 +74259,6 @@ function checkPermissionForEngine(engine, toolName, toolArgs, permissions, worki
|
|
|
73833
74259
|
trace
|
|
73834
74260
|
};
|
|
73835
74261
|
}
|
|
73836
|
-
function extractFilePath(toolArgs) {
|
|
73837
|
-
if (typeof toolArgs.file_path === "string" && toolArgs.file_path.length > 0) {
|
|
73838
|
-
return toolArgs.file_path;
|
|
73839
|
-
}
|
|
73840
|
-
if (typeof toolArgs.path === "string" && toolArgs.path.length > 0) {
|
|
73841
|
-
return toolArgs.path;
|
|
73842
|
-
}
|
|
73843
|
-
if (typeof toolArgs.notebook_path === "string" && toolArgs.notebook_path.length > 0) {
|
|
73844
|
-
return toolArgs.notebook_path;
|
|
73845
|
-
}
|
|
73846
|
-
return null;
|
|
73847
|
-
}
|
|
73848
74262
|
function isWithinAllowedDirectories(filePath, permissions, workingDirectory) {
|
|
73849
74263
|
const absolutePath = resolve22(workingDirectory, filePath);
|
|
73850
74264
|
if (absolutePath.startsWith(workingDirectory)) {
|
|
@@ -73918,7 +74332,7 @@ function buildPermissionQuery(toolName, toolArgs, engine) {
|
|
|
73918
74332
|
return toolName;
|
|
73919
74333
|
}
|
|
73920
74334
|
}
|
|
73921
|
-
function
|
|
74335
|
+
function extractShellCommand2(toolArgs) {
|
|
73922
74336
|
const command = toolArgs.command;
|
|
73923
74337
|
if (typeof command === "string" || Array.isArray(command)) {
|
|
73924
74338
|
return command;
|
|
@@ -74013,6 +74427,7 @@ var init_checker = __esm(() => {
|
|
|
74013
74427
|
init_hooks();
|
|
74014
74428
|
init_canonical();
|
|
74015
74429
|
init_cli();
|
|
74430
|
+
init_crossAgentGuard();
|
|
74016
74431
|
init_matcher();
|
|
74017
74432
|
init_mode();
|
|
74018
74433
|
init_readOnlyShell();
|
|
@@ -74092,10 +74507,10 @@ __export(exports_loader, {
|
|
|
74092
74507
|
loadPermissions: () => loadPermissions,
|
|
74093
74508
|
getUserSettingsPaths: () => getUserSettingsPaths
|
|
74094
74509
|
});
|
|
74095
|
-
import { homedir as
|
|
74510
|
+
import { homedir as homedir19 } from "node:os";
|
|
74096
74511
|
import { join as join24 } from "node:path";
|
|
74097
74512
|
function getUserSettingsPaths(options = {}) {
|
|
74098
|
-
const homeDir = options.homeDir ||
|
|
74513
|
+
const homeDir = options.homeDir || homedir19();
|
|
74099
74514
|
const xdgConfigHome = options.xdgConfigHome || process.env.XDG_CONFIG_HOME || join24(homeDir, ".config");
|
|
74100
74515
|
return {
|
|
74101
74516
|
canonical: join24(homeDir, ".letta", "settings.json"),
|
|
@@ -74217,7 +74632,7 @@ var exports_analyzer = {};
|
|
|
74217
74632
|
__export(exports_analyzer, {
|
|
74218
74633
|
analyzeApprovalContext: () => analyzeApprovalContext
|
|
74219
74634
|
});
|
|
74220
|
-
import { homedir as
|
|
74635
|
+
import { homedir as homedir20 } from "node:os";
|
|
74221
74636
|
import { dirname as dirname13, relative as relative8, resolve as resolve23, win32 as win322 } from "node:path";
|
|
74222
74637
|
function normalizeOsPath(path19) {
|
|
74223
74638
|
return path19.replace(/\\/g, "/");
|
|
@@ -74254,7 +74669,7 @@ function formatAbsoluteRulePath(path19) {
|
|
|
74254
74669
|
return `//${normalized.replace(/^\/+/, "")}`;
|
|
74255
74670
|
}
|
|
74256
74671
|
function formatDisplayPath(path19) {
|
|
74257
|
-
return normalizeOsPath(path19).replace(normalizeOsPath(
|
|
74672
|
+
return normalizeOsPath(path19).replace(normalizeOsPath(homedir20()), "~");
|
|
74258
74673
|
}
|
|
74259
74674
|
function analyzeApprovalContext(toolName, toolArgs, workingDirectory) {
|
|
74260
74675
|
const canonicalTool = canonicalToolName(toolName);
|
|
@@ -74416,7 +74831,7 @@ function containsDangerousCommand(command) {
|
|
|
74416
74831
|
}
|
|
74417
74832
|
return false;
|
|
74418
74833
|
}
|
|
74419
|
-
function
|
|
74834
|
+
function escapeRegex3(text) {
|
|
74420
74835
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
74421
74836
|
}
|
|
74422
74837
|
function normalizePathSeparators(path19) {
|
|
@@ -74448,7 +74863,7 @@ function detectSkillScript(command, workingDir) {
|
|
|
74448
74863
|
return null;
|
|
74449
74864
|
}
|
|
74450
74865
|
const normalizedWorkingDir = normalizePathSeparators(workingDir).replace(/\/$/, "");
|
|
74451
|
-
const normalizedHomeDir = normalizePathSeparators(
|
|
74866
|
+
const normalizedHomeDir = normalizePathSeparators(homedir20()).replace(/\/$/, "");
|
|
74452
74867
|
const detect = (source, regex2) => {
|
|
74453
74868
|
for (const candidate of pathCandidates) {
|
|
74454
74869
|
const match3 = candidate.match(regex2);
|
|
@@ -74461,17 +74876,17 @@ function detectSkillScript(command, workingDir) {
|
|
|
74461
74876
|
}
|
|
74462
74877
|
return null;
|
|
74463
74878
|
};
|
|
74464
|
-
const projectRegex = new RegExp(`^${
|
|
74879
|
+
const projectRegex = new RegExp(`^${escapeRegex3(normalizedWorkingDir)}/\\.skills/(.+?)/scripts/`);
|
|
74465
74880
|
const projectSkill = detect("project", projectRegex);
|
|
74466
74881
|
if (projectSkill) {
|
|
74467
74882
|
return projectSkill;
|
|
74468
74883
|
}
|
|
74469
|
-
const agentRegex = new RegExp(`^${
|
|
74884
|
+
const agentRegex = new RegExp(`^${escapeRegex3(normalizedHomeDir)}/\\.letta/agents/[^/]+/skills/(.+?)/scripts/`);
|
|
74470
74885
|
const agentSkill = detect("agent-scoped", agentRegex);
|
|
74471
74886
|
if (agentSkill) {
|
|
74472
74887
|
return agentSkill;
|
|
74473
74888
|
}
|
|
74474
|
-
const globalRegex = new RegExp(`^${
|
|
74889
|
+
const globalRegex = new RegExp(`^${escapeRegex3(normalizedHomeDir)}/\\.letta/skills/(.+?)/scripts/`);
|
|
74475
74890
|
const globalSkill = detect("global", globalRegex);
|
|
74476
74891
|
if (globalSkill) {
|
|
74477
74892
|
return globalSkill;
|
|
@@ -77164,9 +77579,9 @@ function defineLazyProperty(object, propertyName, valueGetter) {
|
|
|
77164
77579
|
}
|
|
77165
77580
|
|
|
77166
77581
|
// node_modules/default-browser-id/index.js
|
|
77167
|
-
import { promisify as
|
|
77582
|
+
import { promisify as promisify6 } from "node:util";
|
|
77168
77583
|
import process15 from "node:process";
|
|
77169
|
-
import { execFile as
|
|
77584
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
77170
77585
|
async function defaultBrowserId() {
|
|
77171
77586
|
if (process15.platform !== "darwin") {
|
|
77172
77587
|
throw new Error("macOS only");
|
|
@@ -77177,13 +77592,13 @@ async function defaultBrowserId() {
|
|
|
77177
77592
|
}
|
|
77178
77593
|
var execFileAsync4;
|
|
77179
77594
|
var init_default_browser_id = __esm(() => {
|
|
77180
|
-
execFileAsync4 =
|
|
77595
|
+
execFileAsync4 = promisify6(execFile6);
|
|
77181
77596
|
});
|
|
77182
77597
|
|
|
77183
77598
|
// node_modules/run-applescript/index.js
|
|
77184
77599
|
import process16 from "node:process";
|
|
77185
|
-
import { promisify as
|
|
77186
|
-
import { execFile as
|
|
77600
|
+
import { promisify as promisify7 } from "node:util";
|
|
77601
|
+
import { execFile as execFile7, execFileSync as execFileSync2 } from "node:child_process";
|
|
77187
77602
|
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
77188
77603
|
if (process16.platform !== "darwin") {
|
|
77189
77604
|
throw new Error("macOS only");
|
|
@@ -77198,7 +77613,7 @@ async function runAppleScript(script, { humanReadableOutput = true, signal } = {
|
|
|
77198
77613
|
}
|
|
77199
77614
|
var execFileAsync5;
|
|
77200
77615
|
var init_run_applescript = __esm(() => {
|
|
77201
|
-
execFileAsync5 =
|
|
77616
|
+
execFileAsync5 = promisify7(execFile7);
|
|
77202
77617
|
});
|
|
77203
77618
|
|
|
77204
77619
|
// node_modules/bundle-name/index.js
|
|
@@ -77211,8 +77626,8 @@ var init_bundle_name = __esm(() => {
|
|
|
77211
77626
|
});
|
|
77212
77627
|
|
|
77213
77628
|
// node_modules/default-browser/windows.js
|
|
77214
|
-
import { promisify as
|
|
77215
|
-
import { execFile as
|
|
77629
|
+
import { promisify as promisify8 } from "node:util";
|
|
77630
|
+
import { execFile as execFile8 } from "node:child_process";
|
|
77216
77631
|
async function defaultBrowser(_execFileAsync = execFileAsync6) {
|
|
77217
77632
|
const { stdout } = await _execFileAsync("reg", [
|
|
77218
77633
|
"QUERY",
|
|
@@ -77233,7 +77648,7 @@ async function defaultBrowser(_execFileAsync = execFileAsync6) {
|
|
|
77233
77648
|
}
|
|
77234
77649
|
var execFileAsync6, windowsBrowserProgIds, UnknownBrowserError;
|
|
77235
77650
|
var init_windows = __esm(() => {
|
|
77236
|
-
execFileAsync6 =
|
|
77651
|
+
execFileAsync6 = promisify8(execFile8);
|
|
77237
77652
|
windowsBrowserProgIds = {
|
|
77238
77653
|
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
|
|
77239
77654
|
MSEdgeDHTML: { name: "Edge", id: "com.microsoft.edge" },
|
|
@@ -77250,9 +77665,9 @@ var init_windows = __esm(() => {
|
|
|
77250
77665
|
});
|
|
77251
77666
|
|
|
77252
77667
|
// node_modules/default-browser/index.js
|
|
77253
|
-
import { promisify as
|
|
77668
|
+
import { promisify as promisify9 } from "node:util";
|
|
77254
77669
|
import process17 from "node:process";
|
|
77255
|
-
import { execFile as
|
|
77670
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
77256
77671
|
async function defaultBrowser2() {
|
|
77257
77672
|
if (process17.platform === "darwin") {
|
|
77258
77673
|
const id = await defaultBrowserId();
|
|
@@ -77275,7 +77690,7 @@ var init_default_browser = __esm(() => {
|
|
|
77275
77690
|
init_default_browser_id();
|
|
77276
77691
|
init_bundle_name();
|
|
77277
77692
|
init_windows();
|
|
77278
|
-
execFileAsync7 =
|
|
77693
|
+
execFileAsync7 = promisify9(execFile9);
|
|
77279
77694
|
});
|
|
77280
77695
|
|
|
77281
77696
|
// node_modules/open/index.js
|
|
@@ -77289,14 +77704,14 @@ import process18 from "node:process";
|
|
|
77289
77704
|
import { Buffer as Buffer3 } from "node:buffer";
|
|
77290
77705
|
import path19 from "node:path";
|
|
77291
77706
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
77292
|
-
import { promisify as
|
|
77707
|
+
import { promisify as promisify10 } from "node:util";
|
|
77293
77708
|
import childProcess from "node:child_process";
|
|
77294
77709
|
import fs14, { constants as fsConstants2 } from "node:fs/promises";
|
|
77295
77710
|
async function getWindowsDefaultBrowserFromWsl() {
|
|
77296
77711
|
const powershellPath = await powerShellPath();
|
|
77297
77712
|
const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
77298
77713
|
const encodedCommand = Buffer3.from(rawCommand, "utf16le").toString("base64");
|
|
77299
|
-
const { stdout } = await
|
|
77714
|
+
const { stdout } = await execFile10(powershellPath, [
|
|
77300
77715
|
"-NoProfile",
|
|
77301
77716
|
"-NonInteractive",
|
|
77302
77717
|
"-ExecutionPolicy",
|
|
@@ -77332,7 +77747,7 @@ function detectPlatformBinary({ [platform4]: platformBinary }, { wsl }) {
|
|
|
77332
77747
|
}
|
|
77333
77748
|
return detectArchBinary(platformBinary);
|
|
77334
77749
|
}
|
|
77335
|
-
var
|
|
77750
|
+
var execFile10, __dirname2, localXdgOpenPath, platform4, arch, pTryEach = async (array, mapper) => {
|
|
77336
77751
|
let latestError;
|
|
77337
77752
|
for (const item of array) {
|
|
77338
77753
|
try {
|
|
@@ -77511,7 +77926,7 @@ var init_open = __esm(() => {
|
|
|
77511
77926
|
init_wsl_utils();
|
|
77512
77927
|
init_default_browser();
|
|
77513
77928
|
init_is_inside_container();
|
|
77514
|
-
|
|
77929
|
+
execFile10 = promisify10(childProcess.execFile);
|
|
77515
77930
|
__dirname2 = path19.dirname(fileURLToPath7(import.meta.url));
|
|
77516
77931
|
localXdgOpenPath = path19.join(__dirname2, "xdg-open");
|
|
77517
77932
|
({ platform: platform4, arch } = process18);
|
|
@@ -83385,7 +83800,7 @@ import {
|
|
|
83385
83800
|
readFile as readFile10,
|
|
83386
83801
|
writeFile as writeFile7
|
|
83387
83802
|
} from "node:fs/promises";
|
|
83388
|
-
import { homedir as
|
|
83803
|
+
import { homedir as homedir22, tmpdir as tmpdir3 } from "node:os";
|
|
83389
83804
|
import { join as join28 } from "node:path";
|
|
83390
83805
|
function buildReflectionSubagentPrompt(input) {
|
|
83391
83806
|
const lines = [];
|
|
@@ -83579,7 +83994,7 @@ function getTranscriptRoot() {
|
|
|
83579
83994
|
if (envRoot) {
|
|
83580
83995
|
return envRoot;
|
|
83581
83996
|
}
|
|
83582
|
-
return join28(
|
|
83997
|
+
return join28(homedir22(), ".letta", DEFAULT_TRANSCRIPT_DIR);
|
|
83583
83998
|
}
|
|
83584
83999
|
function defaultState() {
|
|
83585
84000
|
return { auto_cursor_line: 0 };
|
|
@@ -83819,7 +84234,7 @@ import {
|
|
|
83819
84234
|
unlinkSync as unlinkSync7,
|
|
83820
84235
|
writeFileSync as writeFileSync16
|
|
83821
84236
|
} from "node:fs";
|
|
83822
|
-
import { homedir as
|
|
84237
|
+
import { homedir as homedir23 } from "node:os";
|
|
83823
84238
|
import { join as join29 } from "node:path";
|
|
83824
84239
|
function truncateStr(value, maxLen) {
|
|
83825
84240
|
if (value === null || value === undefined)
|
|
@@ -83960,7 +84375,7 @@ class ChunkLog {
|
|
|
83960
84375
|
var MAX_ENTRIES = 100, CONTENT_TRUNCATE_LEN = 200, MAX_SESSION_FILES2 = 5, LOG_BASE_DIR, chunkLog;
|
|
83961
84376
|
var init_chunkLog = __esm(() => {
|
|
83962
84377
|
init_debug();
|
|
83963
|
-
LOG_BASE_DIR = join29(
|
|
84378
|
+
LOG_BASE_DIR = join29(homedir23(), ".letta", "logs", "chunk-logs");
|
|
83964
84379
|
chunkLog = new ChunkLog;
|
|
83965
84380
|
});
|
|
83966
84381
|
|
|
@@ -84960,10 +85375,10 @@ var init_constants2 = __esm(() => {
|
|
|
84960
85375
|
// src/websocket/listener/remote-settings.ts
|
|
84961
85376
|
import { existsSync as existsSync26, readFileSync as readFileSync17 } from "node:fs";
|
|
84962
85377
|
import { mkdir as mkdir8, writeFile as writeFile8 } from "node:fs/promises";
|
|
84963
|
-
import { homedir as
|
|
85378
|
+
import { homedir as homedir24 } from "node:os";
|
|
84964
85379
|
import path20 from "node:path";
|
|
84965
85380
|
function getRemoteSettingsPath() {
|
|
84966
|
-
return path20.join(
|
|
85381
|
+
return path20.join(homedir24(), ".letta", "remote-settings.json");
|
|
84967
85382
|
}
|
|
84968
85383
|
function loadRemoteSettings() {
|
|
84969
85384
|
if (_cache !== null) {
|
|
@@ -85007,7 +85422,7 @@ function saveRemoteSettings(updates) {
|
|
|
85007
85422
|
}
|
|
85008
85423
|
function loadLegacyCwdCache() {
|
|
85009
85424
|
try {
|
|
85010
|
-
const legacyPath = path20.join(
|
|
85425
|
+
const legacyPath = path20.join(homedir24(), ".letta", "cwd-cache.json");
|
|
85011
85426
|
if (!existsSync26(legacyPath))
|
|
85012
85427
|
return {};
|
|
85013
85428
|
const raw = readFileSync17(legacyPath, "utf-8");
|
|
@@ -92475,6 +92890,9 @@ async function handleNewWorktree(params) {
|
|
|
92475
92890
|
const newWorktreePath = path22.join(worktreesDir, filename);
|
|
92476
92891
|
if (!await directoryExists(newWorktreePath))
|
|
92477
92892
|
return;
|
|
92893
|
+
const conversationRuntime = getConversationRuntime(runtime, agentId, conversationId);
|
|
92894
|
+
if (!conversationRuntime?.isProcessing)
|
|
92895
|
+
return;
|
|
92478
92896
|
const currentCwd = getConversationWorkingDirectory(runtime, agentId, conversationId);
|
|
92479
92897
|
if (currentCwd === newWorktreePath)
|
|
92480
92898
|
return;
|
|
@@ -92519,6 +92937,7 @@ async function safeReaddir(dir) {
|
|
|
92519
92937
|
var WORKTREES_DIR = ".letta/worktrees", DEBOUNCE_MS = 500;
|
|
92520
92938
|
var init_worktree_watcher = __esm(async () => {
|
|
92521
92939
|
init_cwd();
|
|
92940
|
+
init_runtime3();
|
|
92522
92941
|
await init_protocol_outbound();
|
|
92523
92942
|
});
|
|
92524
92943
|
|
|
@@ -92602,10 +93021,10 @@ function readFileContent(fullPath) {
|
|
|
92602
93021
|
var init_memoryScanner = () => {};
|
|
92603
93022
|
|
|
92604
93023
|
// src/websocket/listener/client.ts
|
|
92605
|
-
import { execFile as
|
|
93024
|
+
import { execFile as execFile11 } from "node:child_process";
|
|
92606
93025
|
import { realpath as realpath3, stat as stat6 } from "node:fs/promises";
|
|
92607
93026
|
import path23 from "node:path";
|
|
92608
|
-
import { promisify as
|
|
93027
|
+
import { promisify as promisify11 } from "node:util";
|
|
92609
93028
|
import WebSocket5 from "ws";
|
|
92610
93029
|
async function loadChannelsService() {
|
|
92611
93030
|
if (channelsServiceLoaderOverride) {
|
|
@@ -95491,9 +95910,9 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
95491
95910
|
if (isMemoryHistoryCommand(parsed)) {
|
|
95492
95911
|
runDetachedListenerTask("memory_history", async () => {
|
|
95493
95912
|
const { getMemoryFilesystemRoot: getMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
95494
|
-
const { execFile:
|
|
95495
|
-
const { promisify:
|
|
95496
|
-
const execFileAsync8 =
|
|
95913
|
+
const { execFile: execFileCb3 } = await import("node:child_process");
|
|
95914
|
+
const { promisify: promisify12 } = await import("node:util");
|
|
95915
|
+
const execFileAsync8 = promisify12(execFileCb3);
|
|
95497
95916
|
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
95498
95917
|
const limit2 = parsed.limit ?? 50;
|
|
95499
95918
|
const { stdout } = await execFileAsync8("git", [
|
|
@@ -95526,9 +95945,9 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
95526
95945
|
if (isMemoryFileAtRefCommand(parsed)) {
|
|
95527
95946
|
runDetachedListenerTask("memory_file_at_ref", async () => {
|
|
95528
95947
|
const { getMemoryFilesystemRoot: getMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
95529
|
-
const { execFile:
|
|
95530
|
-
const { promisify:
|
|
95531
|
-
const execFileAsync8 =
|
|
95948
|
+
const { execFile: execFileCb3 } = await import("node:child_process");
|
|
95949
|
+
const { promisify: promisify12 } = await import("node:util");
|
|
95950
|
+
const execFileAsync8 = promisify12(execFileCb3);
|
|
95532
95951
|
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
95533
95952
|
try {
|
|
95534
95953
|
const { stdout } = await execFileAsync8("git", ["show", `${parsed.ref}:${parsed.file_path}`], { cwd: memoryRoot, timeout: 1e4 });
|
|
@@ -95599,7 +96018,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
95599
96018
|
try {
|
|
95600
96019
|
const cwd2 = parsed.cwd ?? runtime.bootWorkingDirectory;
|
|
95601
96020
|
const maxResults = parsed.max_results ?? 20;
|
|
95602
|
-
const execFileAsync8 =
|
|
96021
|
+
const execFileAsync8 = promisify11(execFile11);
|
|
95603
96022
|
const { stdout } = await execFileAsync8("git", ["branch", "-a", "--format=%(refname:short)\t%(HEAD)"], {
|
|
95604
96023
|
cwd: cwd2,
|
|
95605
96024
|
encoding: "utf-8",
|
|
@@ -95639,7 +96058,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
95639
96058
|
runDetachedListenerTask("checkout_branch", async () => {
|
|
95640
96059
|
try {
|
|
95641
96060
|
const cwd2 = parsed.cwd ?? runtime.bootWorkingDirectory;
|
|
95642
|
-
const execFileAsync8 =
|
|
96061
|
+
const execFileAsync8 = promisify11(execFile11);
|
|
95643
96062
|
const args = parsed.create ? ["checkout", "-b", parsed.branch] : ["checkout", parsed.branch];
|
|
95644
96063
|
await execFileAsync8("git", args, {
|
|
95645
96064
|
cwd: cwd2,
|
|
@@ -96127,7 +96546,7 @@ import {
|
|
|
96127
96546
|
readFileSync as readFileSync19,
|
|
96128
96547
|
unlinkSync as unlinkSync8
|
|
96129
96548
|
} from "node:fs";
|
|
96130
|
-
import { homedir as
|
|
96549
|
+
import { homedir as homedir28 } from "node:os";
|
|
96131
96550
|
import { join as join34 } from "node:path";
|
|
96132
96551
|
import { format as format2 } from "node:util";
|
|
96133
96552
|
function isDebugEnabled2() {
|
|
@@ -96233,7 +96652,7 @@ function debugWarn2(prefix, message, ...args) {
|
|
|
96233
96652
|
}
|
|
96234
96653
|
var DEBUG_LOG_DIR2, MAX_SESSION_FILES3 = 5, DEFAULT_TAIL_LINES2 = 50, debugLogFile2;
|
|
96235
96654
|
var init_debug2 = __esm(() => {
|
|
96236
|
-
DEBUG_LOG_DIR2 = join34(
|
|
96655
|
+
DEBUG_LOG_DIR2 = join34(homedir28(), ".letta", "logs", "debug");
|
|
96237
96656
|
debugLogFile2 = new DebugLogFile2;
|
|
96238
96657
|
});
|
|
96239
96658
|
|
|
@@ -96610,7 +97029,7 @@ __export(exports_bootstrap_tools, {
|
|
|
96610
97029
|
bootstrapBaseToolsIfNeeded: () => bootstrapBaseToolsIfNeeded
|
|
96611
97030
|
});
|
|
96612
97031
|
import { existsSync as existsSync31, mkdirSync as mkdirSync23, writeFileSync as writeFileSync17 } from "node:fs";
|
|
96613
|
-
import { homedir as
|
|
97032
|
+
import { homedir as homedir29 } from "node:os";
|
|
96614
97033
|
import { join as join36 } from "node:path";
|
|
96615
97034
|
async function bootstrapBaseToolsIfNeeded() {
|
|
96616
97035
|
if (existsSync31(MARKER_PATH))
|
|
@@ -96619,7 +97038,7 @@ async function bootstrapBaseToolsIfNeeded() {
|
|
|
96619
97038
|
try {
|
|
96620
97039
|
const success = await addBaseToolsToServer();
|
|
96621
97040
|
if (success) {
|
|
96622
|
-
mkdirSync23(join36(
|
|
97041
|
+
mkdirSync23(join36(homedir29(), ".letta"), { recursive: true });
|
|
96623
97042
|
writeFileSync17(MARKER_PATH, new Date().toISOString(), "utf-8");
|
|
96624
97043
|
}
|
|
96625
97044
|
} catch (err) {
|
|
@@ -96630,7 +97049,7 @@ var MARKER_PATH;
|
|
|
96630
97049
|
var init_bootstrap_tools = __esm(() => {
|
|
96631
97050
|
init_debug();
|
|
96632
97051
|
init_create();
|
|
96633
|
-
MARKER_PATH = join36(
|
|
97052
|
+
MARKER_PATH = join36(homedir29(), ".letta", ".bootstrapped");
|
|
96634
97053
|
});
|
|
96635
97054
|
|
|
96636
97055
|
// src/lsp/manager.ts
|
|
@@ -96822,11 +97241,11 @@ __export(exports_auto_update, {
|
|
|
96822
97241
|
buildInstallCommand: () => buildInstallCommand,
|
|
96823
97242
|
buildInstallArgs: () => buildInstallArgs
|
|
96824
97243
|
});
|
|
96825
|
-
import { execFile as
|
|
97244
|
+
import { execFile as execFile12 } from "node:child_process";
|
|
96826
97245
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
96827
97246
|
import { readdir as readdir9, rm as rm3 } from "node:fs/promises";
|
|
96828
97247
|
import { join as join37 } from "node:path";
|
|
96829
|
-
import { promisify as
|
|
97248
|
+
import { promisify as promisify12 } from "node:util";
|
|
96830
97249
|
function debugLog4(...args) {
|
|
96831
97250
|
if (DEBUG2) {
|
|
96832
97251
|
console.error("[auto-update]", ...args);
|
|
@@ -97151,7 +97570,7 @@ var execFileAsync8, DEBUG2, DEFAULT_UPDATE_PACKAGE_NAME = "@letta-ai/letta-code"
|
|
|
97151
97570
|
var init_auto_update2 = __esm(() => {
|
|
97152
97571
|
init_errorReporting();
|
|
97153
97572
|
init_version();
|
|
97154
|
-
execFileAsync8 =
|
|
97573
|
+
execFileAsync8 = promisify12(execFile12);
|
|
97155
97574
|
DEBUG2 = process.env.LETTA_DEBUG_AUTOUPDATE === "1";
|
|
97156
97575
|
INSTALL_ARG_PREFIX2 = {
|
|
97157
97576
|
npm: ["install", "-g"],
|
|
@@ -97860,12 +98279,16 @@ __export(exports_cli2, {
|
|
|
97860
98279
|
class CliPermissions2 {
|
|
97861
98280
|
allowedTools = [];
|
|
97862
98281
|
disallowedTools = [];
|
|
98282
|
+
memoryScope = [];
|
|
97863
98283
|
setAllowedTools(toolsString) {
|
|
97864
98284
|
this.allowedTools = this.parseToolList(toolsString);
|
|
97865
98285
|
}
|
|
97866
98286
|
setDisallowedTools(toolsString) {
|
|
97867
98287
|
this.disallowedTools = this.parseToolList(toolsString);
|
|
97868
98288
|
}
|
|
98289
|
+
setMemoryScope(scopeString) {
|
|
98290
|
+
this.memoryScope = parseScopeList(scopeString);
|
|
98291
|
+
}
|
|
97869
98292
|
parseToolList(toolsString) {
|
|
97870
98293
|
if (!toolsString)
|
|
97871
98294
|
return [];
|
|
@@ -97914,17 +98337,25 @@ class CliPermissions2 {
|
|
|
97914
98337
|
getDisallowedTools() {
|
|
97915
98338
|
return [...this.disallowedTools];
|
|
97916
98339
|
}
|
|
98340
|
+
getMemoryScope() {
|
|
98341
|
+
return [...this.memoryScope];
|
|
98342
|
+
}
|
|
98343
|
+
hasMemoryScope() {
|
|
98344
|
+
return this.memoryScope.length > 0;
|
|
98345
|
+
}
|
|
97917
98346
|
hasOverrides() {
|
|
97918
|
-
return this.allowedTools.length > 0 || this.disallowedTools.length > 0;
|
|
98347
|
+
return this.allowedTools.length > 0 || this.disallowedTools.length > 0 || this.memoryScope.length > 0;
|
|
97919
98348
|
}
|
|
97920
98349
|
clear() {
|
|
97921
98350
|
this.allowedTools = [];
|
|
97922
98351
|
this.disallowedTools = [];
|
|
98352
|
+
this.memoryScope = [];
|
|
97923
98353
|
}
|
|
97924
98354
|
}
|
|
97925
98355
|
var cliPermissions2;
|
|
97926
98356
|
var init_cli2 = __esm(() => {
|
|
97927
98357
|
init_canonical();
|
|
98358
|
+
init_memoryScope();
|
|
97928
98359
|
init_rule_normalization();
|
|
97929
98360
|
cliPermissions2 = new CliPermissions2;
|
|
97930
98361
|
});
|
|
@@ -98748,7 +99179,7 @@ async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride,
|
|
|
98748
99179
|
}
|
|
98749
99180
|
}
|
|
98750
99181
|
}
|
|
98751
|
-
if (values.allowedTools || values.disallowedTools) {
|
|
99182
|
+
if (values.allowedTools || values.disallowedTools || values["memory-scope"]) {
|
|
98752
99183
|
const { cliPermissions: cliPermissions3 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
|
|
98753
99184
|
if (values.allowedTools) {
|
|
98754
99185
|
cliPermissions3.setAllowedTools(values.allowedTools);
|
|
@@ -98756,6 +99187,9 @@ async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride,
|
|
|
98756
99187
|
if (values.disallowedTools) {
|
|
98757
99188
|
cliPermissions3.setDisallowedTools(values.disallowedTools);
|
|
98758
99189
|
}
|
|
99190
|
+
if (values["memory-scope"]) {
|
|
99191
|
+
cliPermissions3.setMemoryScope(values["memory-scope"]);
|
|
99192
|
+
}
|
|
98759
99193
|
}
|
|
98760
99194
|
const inputFormat = values["input-format"];
|
|
98761
99195
|
const isBidirectionalMode = inputFormat === "stream-json";
|
|
@@ -99272,10 +99706,14 @@ In headless mode, use:
|
|
|
99272
99706
|
}
|
|
99273
99707
|
}
|
|
99274
99708
|
} else if (forceNewConversation) {
|
|
99275
|
-
const
|
|
99709
|
+
const createParams = {
|
|
99276
99710
|
agent_id: agent.id,
|
|
99277
99711
|
isolated_block_labels: isolatedBlockLabels
|
|
99278
|
-
}
|
|
99712
|
+
};
|
|
99713
|
+
if (fromAgentId) {
|
|
99714
|
+
createParams.hidden = true;
|
|
99715
|
+
}
|
|
99716
|
+
const conversation = await client.conversations.create(createParams);
|
|
99279
99717
|
conversationId = conversation.id;
|
|
99280
99718
|
} else if (isSubagent) {
|
|
99281
99719
|
conversationId = "default";
|
|
@@ -101657,10 +102095,10 @@ __export(exports_settings, {
|
|
|
101657
102095
|
loadProjectSettings: () => loadProjectSettings,
|
|
101658
102096
|
getSetting: () => getSetting
|
|
101659
102097
|
});
|
|
101660
|
-
import { homedir as
|
|
102098
|
+
import { homedir as homedir32 } from "node:os";
|
|
101661
102099
|
import { join as join40 } from "node:path";
|
|
101662
102100
|
function getSettingsPath() {
|
|
101663
|
-
return join40(
|
|
102101
|
+
return join40(homedir32(), ".letta", "settings.json");
|
|
101664
102102
|
}
|
|
101665
102103
|
async function loadSettings() {
|
|
101666
102104
|
const settingsPath = getSettingsPath();
|
|
@@ -121209,7 +121647,7 @@ var init_plan_viewer_template = () => {};
|
|
|
121209
121647
|
|
|
121210
121648
|
// src/web/generate-plan-viewer.ts
|
|
121211
121649
|
import { chmodSync as chmodSync2, existsSync as existsSync34, mkdirSync as mkdirSync26, writeFileSync as writeFileSync20 } from "node:fs";
|
|
121212
|
-
import { homedir as
|
|
121650
|
+
import { homedir as homedir33 } from "node:os";
|
|
121213
121651
|
import { join as join41 } from "node:path";
|
|
121214
121652
|
async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
121215
121653
|
const data = {
|
|
@@ -121243,7 +121681,7 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
|
121243
121681
|
var VIEWERS_DIR;
|
|
121244
121682
|
var init_generate_plan_viewer = __esm(() => {
|
|
121245
121683
|
init_plan_viewer_template();
|
|
121246
|
-
VIEWERS_DIR = join41(
|
|
121684
|
+
VIEWERS_DIR = join41(homedir33(), ".letta", "viewers");
|
|
121247
121685
|
});
|
|
121248
121686
|
|
|
121249
121687
|
// src/cli/components/StaticPlanApproval.tsx
|
|
@@ -124408,7 +124846,7 @@ import {
|
|
|
124408
124846
|
readFileSync as readFileSync22,
|
|
124409
124847
|
writeFileSync as writeFileSync21
|
|
124410
124848
|
} from "node:fs";
|
|
124411
|
-
import { homedir as
|
|
124849
|
+
import { homedir as homedir34, platform as platform6 } from "node:os";
|
|
124412
124850
|
import { dirname as dirname17, join as join43 } from "node:path";
|
|
124413
124851
|
function detectTerminalType() {
|
|
124414
124852
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
@@ -124441,7 +124879,7 @@ function getKeybindingsPath(terminal) {
|
|
|
124441
124879
|
}[terminal];
|
|
124442
124880
|
const os7 = platform6();
|
|
124443
124881
|
if (os7 === "darwin") {
|
|
124444
|
-
return join43(
|
|
124882
|
+
return join43(homedir34(), "Library", "Application Support", appName, "User", "keybindings.json");
|
|
124445
124883
|
}
|
|
124446
124884
|
if (os7 === "win32") {
|
|
124447
124885
|
const appData = process.env.APPDATA;
|
|
@@ -124450,7 +124888,7 @@ function getKeybindingsPath(terminal) {
|
|
|
124450
124888
|
return join43(appData, appName, "User", "keybindings.json");
|
|
124451
124889
|
}
|
|
124452
124890
|
if (os7 === "linux") {
|
|
124453
|
-
return join43(
|
|
124891
|
+
return join43(homedir34(), ".config", appName, "User", "keybindings.json");
|
|
124454
124892
|
}
|
|
124455
124893
|
return null;
|
|
124456
124894
|
}
|
|
@@ -124607,10 +125045,10 @@ function getWezTermConfigPath() {
|
|
|
124607
125045
|
if (existsSync36(xdgPath))
|
|
124608
125046
|
return xdgPath;
|
|
124609
125047
|
}
|
|
124610
|
-
const configPath = join43(
|
|
125048
|
+
const configPath = join43(homedir34(), ".config", "wezterm", "wezterm.lua");
|
|
124611
125049
|
if (existsSync36(configPath))
|
|
124612
125050
|
return configPath;
|
|
124613
|
-
return join43(
|
|
125051
|
+
return join43(homedir34(), ".wezterm.lua");
|
|
124614
125052
|
}
|
|
124615
125053
|
function wezTermDeleteFixExists(configPath) {
|
|
124616
125054
|
if (!existsSync36(configPath))
|
|
@@ -125658,10 +126096,10 @@ var init_HelpDialog = __esm(async () => {
|
|
|
125658
126096
|
});
|
|
125659
126097
|
|
|
125660
126098
|
// src/hooks/writer.ts
|
|
125661
|
-
import { homedir as
|
|
126099
|
+
import { homedir as homedir35 } from "node:os";
|
|
125662
126100
|
import { resolve as resolve30 } from "node:path";
|
|
125663
126101
|
function isProjectSettingsPathCollidingWithGlobal2(workingDirectory) {
|
|
125664
|
-
const home = process.env.HOME ||
|
|
126102
|
+
const home = process.env.HOME || homedir35();
|
|
125665
126103
|
const globalSettingsPath = resolve30(home, ".letta", "settings.json");
|
|
125666
126104
|
const projectSettingsPath = resolve30(workingDirectory, ".letta", "settings.json");
|
|
125667
126105
|
return globalSettingsPath === projectSettingsPath;
|
|
@@ -128559,6 +128997,11 @@ function FileAutocomplete({
|
|
|
128559
128997
|
const [isLoading, setIsLoading] = import_react70.useState(false);
|
|
128560
128998
|
const [lastValidQuery, setLastValidQuery] = import_react70.useState("");
|
|
128561
128999
|
const debounceTimeout = import_react70.useRef(null);
|
|
129000
|
+
const searchGenRef = import_react70.useRef(0);
|
|
129001
|
+
const lastValidQueryRef = import_react70.useRef(lastValidQuery);
|
|
129002
|
+
lastValidQueryRef.current = lastValidQuery;
|
|
129003
|
+
const matchesRef = import_react70.useRef(matches);
|
|
129004
|
+
matchesRef.current = matches;
|
|
128562
129005
|
const { selectedIndex } = useAutocompleteNavigation({
|
|
128563
129006
|
matches,
|
|
128564
129007
|
maxVisible: 10,
|
|
@@ -128591,8 +129034,8 @@ function FileAutocomplete({
|
|
|
128591
129034
|
onActiveChange?.(false);
|
|
128592
129035
|
return;
|
|
128593
129036
|
}
|
|
128594
|
-
if (query ===
|
|
128595
|
-
if (
|
|
129037
|
+
if (query === lastValidQueryRef.current && lastValidQueryRef.current.length > 0) {
|
|
129038
|
+
if (matchesRef.current[0]?.path !== query) {
|
|
128596
129039
|
setMatches([{ path: query, type: "file" }]);
|
|
128597
129040
|
}
|
|
128598
129041
|
setIsLoading(false);
|
|
@@ -128604,14 +129047,19 @@ function FileAutocomplete({
|
|
|
128604
129047
|
onActiveChange?.(false);
|
|
128605
129048
|
return;
|
|
128606
129049
|
}
|
|
129050
|
+
const gen = ++searchGenRef.current;
|
|
128607
129051
|
if (query.length === 0) {
|
|
128608
129052
|
setIsLoading(true);
|
|
128609
129053
|
onActiveChange?.(true);
|
|
128610
129054
|
searchFiles("", false).then((results) => {
|
|
129055
|
+
if (searchGenRef.current !== gen)
|
|
129056
|
+
return;
|
|
128611
129057
|
setMatches(results);
|
|
128612
129058
|
setIsLoading(false);
|
|
128613
129059
|
onActiveChange?.(results.length > 0);
|
|
128614
129060
|
}).catch(() => {
|
|
129061
|
+
if (searchGenRef.current !== gen)
|
|
129062
|
+
return;
|
|
128615
129063
|
setMatches([]);
|
|
128616
129064
|
setIsLoading(false);
|
|
128617
129065
|
onActiveChange?.(false);
|
|
@@ -128628,6 +129076,8 @@ function FileAutocomplete({
|
|
|
128628
129076
|
onActiveChange?.(true);
|
|
128629
129077
|
debounceTimeout.current = setTimeout(() => {
|
|
128630
129078
|
searchFiles(query, true).then((results) => {
|
|
129079
|
+
if (searchGenRef.current !== gen)
|
|
129080
|
+
return;
|
|
128631
129081
|
setMatches(results);
|
|
128632
129082
|
setIsLoading(false);
|
|
128633
129083
|
onActiveChange?.(results.length > 0);
|
|
@@ -128635,6 +129085,8 @@ function FileAutocomplete({
|
|
|
128635
129085
|
setLastValidQuery(query);
|
|
128636
129086
|
}
|
|
128637
129087
|
}).catch(() => {
|
|
129088
|
+
if (searchGenRef.current !== gen)
|
|
129089
|
+
return;
|
|
128638
129090
|
setMatches([]);
|
|
128639
129091
|
setIsLoading(false);
|
|
128640
129092
|
onActiveChange?.(false);
|
|
@@ -128645,13 +129097,7 @@ function FileAutocomplete({
|
|
|
128645
129097
|
clearTimeout(debounceTimeout.current);
|
|
128646
129098
|
}
|
|
128647
129099
|
};
|
|
128648
|
-
}, [
|
|
128649
|
-
currentInput,
|
|
128650
|
-
cursorPosition,
|
|
128651
|
-
onActiveChange,
|
|
128652
|
-
lastValidQuery,
|
|
128653
|
-
matches[0]?.path
|
|
128654
|
-
]);
|
|
129100
|
+
}, [currentInput, cursorPosition, onActiveChange]);
|
|
128655
129101
|
if (!currentInput.includes("@")) {
|
|
128656
129102
|
return null;
|
|
128657
129103
|
}
|
|
@@ -130719,7 +131165,7 @@ function cloneRepoToTemp(repo) {
|
|
|
130719
131165
|
function createBranchName() {
|
|
130720
131166
|
return `letta/install-github-app-${Date.now().toString(36)}`;
|
|
130721
131167
|
}
|
|
130722
|
-
function
|
|
131168
|
+
function runGit3(args, cwd2) {
|
|
130723
131169
|
return runCommand("git", args, cwd2);
|
|
130724
131170
|
}
|
|
130725
131171
|
function writeWorkflow(repoDir, workflowPath, content) {
|
|
@@ -130740,7 +131186,7 @@ function writeWorkflow(repoDir, workflowPath, content) {
|
|
|
130740
131186
|
}
|
|
130741
131187
|
function getDefaultBaseBranch(repoDir) {
|
|
130742
131188
|
try {
|
|
130743
|
-
const headRef =
|
|
131189
|
+
const headRef = runGit3(["symbolic-ref", "refs/remotes/origin/HEAD"], repoDir);
|
|
130744
131190
|
return headRef.replace("refs/remotes/origin/", "").trim() || "main";
|
|
130745
131191
|
} catch {
|
|
130746
131192
|
return "main";
|
|
@@ -130816,7 +131262,7 @@ async function installGithubApp(options) {
|
|
|
130816
131262
|
includeAgentId: resolvedAgentId != null
|
|
130817
131263
|
});
|
|
130818
131264
|
const branchName = createBranchName();
|
|
130819
|
-
|
|
131265
|
+
runGit3(["checkout", "-b", branchName], repoDir);
|
|
130820
131266
|
progress(onProgress, "Creating workflow files");
|
|
130821
131267
|
const changed = writeWorkflow(repoDir, workflowPath, workflowContent);
|
|
130822
131268
|
progress(onProgress, "Setting up LETTA_API_KEY secret");
|
|
@@ -130839,10 +131285,10 @@ async function installGithubApp(options) {
|
|
|
130839
131285
|
agentUrl: resolvedAgentId ? buildChatUrl(resolvedAgentId) : null
|
|
130840
131286
|
};
|
|
130841
131287
|
}
|
|
130842
|
-
|
|
130843
|
-
|
|
131288
|
+
runGit3(["add", workflowPath], repoDir);
|
|
131289
|
+
runGit3(["commit", "-m", "Add Letta Code GitHub Workflow"], repoDir);
|
|
130844
131290
|
progress(onProgress, "Opening pull request page");
|
|
130845
|
-
|
|
131291
|
+
runGit3(["push", "-u", "origin", branchName], repoDir);
|
|
130846
131292
|
const pullRequest = createPullRequest(repo, branchName, workflowPath, repoDir);
|
|
130847
131293
|
return {
|
|
130848
131294
|
repo,
|
|
@@ -134966,14 +135412,14 @@ var exports_generate_memory_viewer = {};
|
|
|
134966
135412
|
__export(exports_generate_memory_viewer, {
|
|
134967
135413
|
generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
|
|
134968
135414
|
});
|
|
134969
|
-
import { execFile as
|
|
135415
|
+
import { execFile as execFileCb3 } from "node:child_process";
|
|
134970
135416
|
import { chmodSync as chmodSync3, existsSync as existsSync39, mkdirSync as mkdirSync29, writeFileSync as writeFileSync23 } from "node:fs";
|
|
134971
|
-
import { homedir as
|
|
135417
|
+
import { homedir as homedir36 } from "node:os";
|
|
134972
135418
|
import { join as join47 } from "node:path";
|
|
134973
|
-
import { promisify as
|
|
135419
|
+
import { promisify as promisify13 } from "node:util";
|
|
134974
135420
|
async function runGitSafe(cwd2, args) {
|
|
134975
135421
|
try {
|
|
134976
|
-
const { stdout } = await
|
|
135422
|
+
const { stdout } = await execFile13("git", args, {
|
|
134977
135423
|
cwd: cwd2,
|
|
134978
135424
|
maxBuffer: 10 * 1024 * 1024,
|
|
134979
135425
|
timeout: 60000
|
|
@@ -135307,15 +135753,15 @@ async function generateAndOpenMemoryViewer(agentId, options) {
|
|
|
135307
135753
|
}
|
|
135308
135754
|
return { filePath, opened: !skipOpen };
|
|
135309
135755
|
}
|
|
135310
|
-
var
|
|
135756
|
+
var execFile13, VIEWERS_DIR2, MAX_COMMITS = 500, RECENT_DIFF_COUNT = 50, PER_DIFF_CAP = 1e5, TOTAL_PAYLOAD_CAP = 5000000, RECORD_SEP = "\x1E", REFLECTION_PATTERN;
|
|
135311
135757
|
var init_generate_memory_viewer = __esm(() => {
|
|
135312
135758
|
init_client2();
|
|
135313
135759
|
init_memoryFilesystem();
|
|
135314
135760
|
init_memoryGit();
|
|
135315
135761
|
init_memoryScanner();
|
|
135316
135762
|
init_memory_viewer_template();
|
|
135317
|
-
|
|
135318
|
-
VIEWERS_DIR2 = join47(
|
|
135763
|
+
execFile13 = promisify13(execFileCb3);
|
|
135764
|
+
VIEWERS_DIR2 = join47(homedir36(), ".letta", "viewers");
|
|
135319
135765
|
REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
|
|
135320
135766
|
});
|
|
135321
135767
|
|
|
@@ -138040,11 +138486,11 @@ var init_PersonalitySelector = __esm(async () => {
|
|
|
138040
138486
|
|
|
138041
138487
|
// src/utils/aws-credentials.ts
|
|
138042
138488
|
import { readFile as readFile16 } from "node:fs/promises";
|
|
138043
|
-
import { homedir as
|
|
138489
|
+
import { homedir as homedir37 } from "node:os";
|
|
138044
138490
|
import { join as join48 } from "node:path";
|
|
138045
138491
|
async function parseAwsCredentials() {
|
|
138046
|
-
const credentialsPath = join48(
|
|
138047
|
-
const configPath = join48(
|
|
138492
|
+
const credentialsPath = join48(homedir37(), ".aws", "credentials");
|
|
138493
|
+
const configPath = join48(homedir37(), ".aws", "config");
|
|
138048
138494
|
const profiles = new Map;
|
|
138049
138495
|
try {
|
|
138050
138496
|
const content = await readFile16(credentialsPath, "utf-8");
|
|
@@ -143990,7 +144436,7 @@ __export(exports_shellAliases, {
|
|
|
143990
144436
|
clearAliasCache: () => clearAliasCache
|
|
143991
144437
|
});
|
|
143992
144438
|
import { existsSync as existsSync42, readFileSync as readFileSync25 } from "node:fs";
|
|
143993
|
-
import { homedir as
|
|
144439
|
+
import { homedir as homedir38 } from "node:os";
|
|
143994
144440
|
import { join as join50 } from "node:path";
|
|
143995
144441
|
function parseAliasesFromFile(filePath) {
|
|
143996
144442
|
const aliases = new Map;
|
|
@@ -144060,7 +144506,7 @@ function loadAliases(forceReload = false) {
|
|
|
144060
144506
|
if (aliasCache && !forceReload) {
|
|
144061
144507
|
return aliasCache;
|
|
144062
144508
|
}
|
|
144063
|
-
const home =
|
|
144509
|
+
const home = homedir38();
|
|
144064
144510
|
const allAliases = new Map;
|
|
144065
144511
|
for (const file of ALIAS_FILES) {
|
|
144066
144512
|
const filePath = join50(home, file);
|
|
@@ -144910,7 +145356,7 @@ __export(exports_App, {
|
|
|
144910
145356
|
});
|
|
144911
145357
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
144912
145358
|
import { existsSync as existsSync43, readFileSync as readFileSync26, renameSync as renameSync3, writeFileSync as writeFileSync24 } from "node:fs";
|
|
144913
|
-
import { homedir as
|
|
145359
|
+
import { homedir as homedir39, tmpdir as tmpdir6 } from "node:os";
|
|
144914
145360
|
import { join as join51, relative as relative18 } from "node:path";
|
|
144915
145361
|
function deriveReasoningEffort(modelSettings, llmConfig) {
|
|
144916
145362
|
if (modelSettings && "provider_type" in modelSettings) {
|
|
@@ -153276,7 +153722,7 @@ ${guidance}`);
|
|
|
153276
153722
|
}
|
|
153277
153723
|
if (mode === "bypassPermissions") {
|
|
153278
153724
|
const planFilePath = activePlanPath ?? fallbackPlanPath;
|
|
153279
|
-
const plansDir = join51(
|
|
153725
|
+
const plansDir = join51(homedir39(), ".letta", "plans");
|
|
153280
153726
|
handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
|
|
153281
153727
|
` + (planFilePath ? `Plan file path: ${planFilePath}
|
|
153282
153728
|
` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
|
|
@@ -153311,7 +153757,7 @@ ${guidance}`);
|
|
|
153311
153757
|
if (!hasUsablePlan) {
|
|
153312
153758
|
lastAutoHandledExitPlanToolCallIdRef.current = approval.toolCallId;
|
|
153313
153759
|
const planFilePath = activePlanPath ?? fallbackPlanPath;
|
|
153314
|
-
const plansDir = join51(
|
|
153760
|
+
const plansDir = join51(homedir39(), ".letta", "plans");
|
|
153315
153761
|
handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
|
|
153316
153762
|
` + (planFilePath ? `Plan file path: ${planFilePath}
|
|
153317
153763
|
` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
|
|
@@ -154727,7 +155173,7 @@ import {
|
|
|
154727
155173
|
readFileSync as readFileSync27,
|
|
154728
155174
|
writeFileSync as writeFileSync25
|
|
154729
155175
|
} from "node:fs";
|
|
154730
|
-
import { homedir as
|
|
155176
|
+
import { homedir as homedir40, platform as platform7 } from "node:os";
|
|
154731
155177
|
import { dirname as dirname20, join as join52 } from "node:path";
|
|
154732
155178
|
function detectTerminalType2() {
|
|
154733
155179
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
@@ -154760,7 +155206,7 @@ function getKeybindingsPath2(terminal) {
|
|
|
154760
155206
|
}[terminal];
|
|
154761
155207
|
const os8 = platform7();
|
|
154762
155208
|
if (os8 === "darwin") {
|
|
154763
|
-
return join52(
|
|
155209
|
+
return join52(homedir40(), "Library", "Application Support", appName, "User", "keybindings.json");
|
|
154764
155210
|
}
|
|
154765
155211
|
if (os8 === "win32") {
|
|
154766
155212
|
const appData = process.env.APPDATA;
|
|
@@ -154769,7 +155215,7 @@ function getKeybindingsPath2(terminal) {
|
|
|
154769
155215
|
return join52(appData, appName, "User", "keybindings.json");
|
|
154770
155216
|
}
|
|
154771
155217
|
if (os8 === "linux") {
|
|
154772
|
-
return join52(
|
|
155218
|
+
return join52(homedir40(), ".config", appName, "User", "keybindings.json");
|
|
154773
155219
|
}
|
|
154774
155220
|
return null;
|
|
154775
155221
|
}
|
|
@@ -154926,10 +155372,10 @@ function getWezTermConfigPath2() {
|
|
|
154926
155372
|
if (existsSync44(xdgPath))
|
|
154927
155373
|
return xdgPath;
|
|
154928
155374
|
}
|
|
154929
|
-
const configPath = join52(
|
|
155375
|
+
const configPath = join52(homedir40(), ".config", "wezterm", "wezterm.lua");
|
|
154930
155376
|
if (existsSync44(configPath))
|
|
154931
155377
|
return configPath;
|
|
154932
|
-
return join52(
|
|
155378
|
+
return join52(homedir40(), ".wezterm.lua");
|
|
154933
155379
|
}
|
|
154934
155380
|
function wezTermDeleteFixExists2(configPath) {
|
|
154935
155381
|
if (!existsSync44(configPath))
|
|
@@ -155027,10 +155473,10 @@ __export(exports_settings2, {
|
|
|
155027
155473
|
loadProjectSettings: () => loadProjectSettings2,
|
|
155028
155474
|
getSetting: () => getSetting2
|
|
155029
155475
|
});
|
|
155030
|
-
import { homedir as
|
|
155476
|
+
import { homedir as homedir41 } from "node:os";
|
|
155031
155477
|
import { join as join53 } from "node:path";
|
|
155032
155478
|
function getSettingsPath2() {
|
|
155033
|
-
return join53(
|
|
155479
|
+
return join53(homedir41(), ".letta", "settings.json");
|
|
155034
155480
|
}
|
|
155035
155481
|
async function loadSettings2() {
|
|
155036
155482
|
const settingsPath = getSettingsPath2();
|
|
@@ -155717,15 +156163,15 @@ __export(exports_memoryFilesystem2, {
|
|
|
155717
156163
|
MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
|
|
155718
156164
|
});
|
|
155719
156165
|
import { existsSync as existsSync45, mkdirSync as mkdirSync31 } from "node:fs";
|
|
155720
|
-
import { homedir as
|
|
156166
|
+
import { homedir as homedir42 } from "node:os";
|
|
155721
156167
|
import { join as join54 } from "node:path";
|
|
155722
|
-
function getMemoryFilesystemRoot2(agentId, homeDir =
|
|
156168
|
+
function getMemoryFilesystemRoot2(agentId, homeDir = homedir42()) {
|
|
155723
156169
|
return join54(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
|
|
155724
156170
|
}
|
|
155725
|
-
function getMemorySystemDir2(agentId, homeDir =
|
|
156171
|
+
function getMemorySystemDir2(agentId, homeDir = homedir42()) {
|
|
155726
156172
|
return join54(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
|
|
155727
156173
|
}
|
|
155728
|
-
function ensureMemoryFilesystemDirs2(agentId, homeDir =
|
|
156174
|
+
function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir42()) {
|
|
155729
156175
|
const root = getMemoryFilesystemRoot2(agentId, homeDir);
|
|
155730
156176
|
const systemDir = getMemorySystemDir2(agentId, homeDir);
|
|
155731
156177
|
if (!existsSync45(root)) {
|
|
@@ -156533,7 +156979,10 @@ If you experience this issue multiple times, move ~/.letta to ~/.letta_backup, a
|
|
|
156533
156979
|
timeout: Number(process.env.LETTA_REQUEST_TIMEOUT_MS) || 10 * 60 * 1000,
|
|
156534
156980
|
defaultHeaders: {
|
|
156535
156981
|
"X-Letta-Source": "letta-code",
|
|
156536
|
-
"User-Agent": `letta-code/${package_default.version}
|
|
156982
|
+
"User-Agent": `letta-code/${package_default.version}`,
|
|
156983
|
+
...process.env.LETTA_NODE === "1" && {
|
|
156984
|
+
"x-letta-node": "1"
|
|
156985
|
+
}
|
|
156537
156986
|
},
|
|
156538
156987
|
...isTimingsEnabled() && { fetch: createTimingFetch(fetch) }
|
|
156539
156988
|
});
|
|
@@ -156949,6 +157398,18 @@ var CLI_FLAG_CATALOG = {
|
|
|
156949
157398
|
allowedTools: { parser: { type: "string" }, mode: "both" },
|
|
156950
157399
|
disallowedTools: { parser: { type: "string" }, mode: "both" },
|
|
156951
157400
|
"permission-mode": { parser: { type: "string" }, mode: "both" },
|
|
157401
|
+
"memory-scope": {
|
|
157402
|
+
parser: { type: "string" },
|
|
157403
|
+
mode: "both",
|
|
157404
|
+
help: {
|
|
157405
|
+
argLabel: "<ids>",
|
|
157406
|
+
description: "Comma-separated agent IDs this session may access in addition to self.",
|
|
157407
|
+
continuationLines: [
|
|
157408
|
+
"Example: --memory-scope agent-abc,agent-def",
|
|
157409
|
+
"Required to read or write another agent's memory directory."
|
|
157410
|
+
]
|
|
157411
|
+
}
|
|
157412
|
+
},
|
|
156952
157413
|
yolo: { parser: { type: "boolean" }, mode: "both" },
|
|
156953
157414
|
"output-format": {
|
|
156954
157415
|
parser: { type: "string" },
|
|
@@ -160391,9 +160852,9 @@ import {
|
|
|
160391
160852
|
readdirSync as readdirSync7,
|
|
160392
160853
|
unlinkSync as unlinkSync6
|
|
160393
160854
|
} from "node:fs";
|
|
160394
|
-
import { homedir as
|
|
160855
|
+
import { homedir as homedir21 } from "node:os";
|
|
160395
160856
|
import { join as join26 } from "node:path";
|
|
160396
|
-
var REMOTE_LOG_DIR = join26(
|
|
160857
|
+
var REMOTE_LOG_DIR = join26(homedir21(), ".letta", "logs", "remote");
|
|
160397
160858
|
var MAX_LOG_FILES = 10;
|
|
160398
160859
|
function formatTimestamp2() {
|
|
160399
160860
|
const now = new Date;
|
|
@@ -160956,7 +161417,7 @@ async function runListenSubcommand(argv) {
|
|
|
160956
161417
|
init_memoryGit();
|
|
160957
161418
|
import { cpSync, existsSync as existsSync27, mkdirSync as mkdirSync20, rmSync as rmSync3, statSync as statSync8 } from "node:fs";
|
|
160958
161419
|
import { readdir as readdir7 } from "node:fs/promises";
|
|
160959
|
-
import { homedir as
|
|
161420
|
+
import { homedir as homedir25 } from "node:os";
|
|
160960
161421
|
import { join as join31 } from "node:path";
|
|
160961
161422
|
import { parseArgs as parseArgs8 } from "node:util";
|
|
160962
161423
|
function printUsage5() {
|
|
@@ -161002,10 +161463,10 @@ function parseMemfsArgs(argv) {
|
|
|
161002
161463
|
});
|
|
161003
161464
|
}
|
|
161004
161465
|
function getMemoryRoot(agentId) {
|
|
161005
|
-
return join31(
|
|
161466
|
+
return join31(homedir25(), ".letta", "agents", agentId, "memory");
|
|
161006
161467
|
}
|
|
161007
161468
|
function getAgentRoot(agentId) {
|
|
161008
|
-
return join31(
|
|
161469
|
+
return join31(homedir25(), ".letta", "agents", agentId);
|
|
161009
161470
|
}
|
|
161010
161471
|
function formatBackupTimestamp(date = new Date) {
|
|
161011
161472
|
const pad = (value) => String(value).padStart(2, "0");
|
|
@@ -161083,11 +161544,11 @@ async function runMemfsSubcommand(argv) {
|
|
|
161083
161544
|
console.error("Not a git repo. Enable git-backed memory first.");
|
|
161084
161545
|
return 1;
|
|
161085
161546
|
}
|
|
161086
|
-
const { execFile:
|
|
161087
|
-
const { promisify:
|
|
161088
|
-
const
|
|
161547
|
+
const { execFile: execFileCb3 } = await import("node:child_process");
|
|
161548
|
+
const { promisify: promisify12 } = await import("node:util");
|
|
161549
|
+
const execFile12 = promisify12(execFileCb3);
|
|
161089
161550
|
const dir = getMemoryRepoDir(agentId);
|
|
161090
|
-
const { stdout } = await
|
|
161551
|
+
const { stdout } = await execFile12("git", ["diff"], { cwd: dir });
|
|
161091
161552
|
if (stdout.trim()) {
|
|
161092
161553
|
console.log(stdout);
|
|
161093
161554
|
return 2;
|
|
@@ -161558,10 +162019,11 @@ async function runSubcommand(argv) {
|
|
|
161558
162019
|
}
|
|
161559
162020
|
|
|
161560
162021
|
// src/permissions/mode.ts
|
|
162022
|
+
init_crossAgentGuard();
|
|
161561
162023
|
init_memoryScope();
|
|
161562
162024
|
init_readOnlyShell();
|
|
161563
162025
|
init_shell_command_normalization();
|
|
161564
|
-
import { homedir as
|
|
162026
|
+
import { homedir as homedir26 } from "node:os";
|
|
161565
162027
|
import { isAbsolute as isAbsolute18, join as join32, relative as relative13 } from "node:path";
|
|
161566
162028
|
var MODE_KEY2 = Symbol.for("@letta/permissionMode");
|
|
161567
162029
|
var PLAN_FILE_KEY2 = Symbol.for("@letta/planFilePath");
|
|
@@ -161608,22 +162070,6 @@ function isPathInPlansDir2(path24, plansDir) {
|
|
|
161608
162070
|
const rel = relative13(plansDir, path24);
|
|
161609
162071
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute18(rel);
|
|
161610
162072
|
}
|
|
161611
|
-
function extractApplyPatchPaths2(input) {
|
|
161612
|
-
const paths = [];
|
|
161613
|
-
const fileDirectivePattern = /\*\*\* (?:Add|Update|Delete) File:\s*(.+)/g;
|
|
161614
|
-
const moveDirectivePattern = /\*\*\* Move to:\s*(.+)/g;
|
|
161615
|
-
for (const match3 of input.matchAll(fileDirectivePattern)) {
|
|
161616
|
-
const matchPath = match3[1]?.trim();
|
|
161617
|
-
if (matchPath)
|
|
161618
|
-
paths.push(matchPath);
|
|
161619
|
-
}
|
|
161620
|
-
for (const match3 of input.matchAll(moveDirectivePattern)) {
|
|
161621
|
-
const matchPath = match3[1]?.trim();
|
|
161622
|
-
if (matchPath)
|
|
161623
|
-
paths.push(matchPath);
|
|
161624
|
-
}
|
|
161625
|
-
return paths;
|
|
161626
|
-
}
|
|
161627
162073
|
function stripMatchingQuotes2(value) {
|
|
161628
162074
|
const trimmed = value.trim();
|
|
161629
162075
|
if (trimmed.length < 2) {
|
|
@@ -161794,12 +162240,12 @@ class PermissionModeManager2 {
|
|
|
161794
162240
|
return "allow";
|
|
161795
162241
|
}
|
|
161796
162242
|
if (writeTools.includes(toolName)) {
|
|
161797
|
-
const plansDir = join32(
|
|
162243
|
+
const plansDir = join32(homedir26(), ".letta", "plans");
|
|
161798
162244
|
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
161799
162245
|
let candidatePaths = [];
|
|
161800
162246
|
if ((toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") && toolArgs?.input) {
|
|
161801
162247
|
const input = toolArgs.input;
|
|
161802
|
-
candidatePaths =
|
|
162248
|
+
candidatePaths = extractApplyPatchPaths(input);
|
|
161803
162249
|
} else if (typeof targetPath === "string") {
|
|
161804
162250
|
candidatePaths = [targetPath];
|
|
161805
162251
|
}
|
|
@@ -161845,7 +162291,7 @@ class PermissionModeManager2 {
|
|
|
161845
162291
|
}
|
|
161846
162292
|
const planWritePath = extractPlanFileWritePathFromShellCommand2(command);
|
|
161847
162293
|
if (planWritePath) {
|
|
161848
|
-
const plansDir = join32(
|
|
162294
|
+
const plansDir = join32(homedir26(), ".letta", "plans");
|
|
161849
162295
|
const resolvedPath = resolvePlanTargetPath2(planWritePath, workingDirectory);
|
|
161850
162296
|
if (resolvedPath && isPathInPlansDir2(resolvedPath, plansDir)) {
|
|
161851
162297
|
return "allow";
|
|
@@ -161919,7 +162365,7 @@ class PermissionModeManager2 {
|
|
|
161919
162365
|
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
161920
162366
|
let candidatePaths = [];
|
|
161921
162367
|
if ((toolName === "ApplyPatch" || toolName === "apply_patch") && toolArgs?.input) {
|
|
161922
|
-
candidatePaths =
|
|
162368
|
+
candidatePaths = extractApplyPatchPaths(toolArgs.input);
|
|
161923
162369
|
} else if (typeof targetPath === "string") {
|
|
161924
162370
|
candidatePaths = [targetPath];
|
|
161925
162371
|
}
|
|
@@ -161962,7 +162408,7 @@ init_debug();
|
|
|
161962
162408
|
init_fs();
|
|
161963
162409
|
init_secrets();
|
|
161964
162410
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
161965
|
-
import { homedir as
|
|
162411
|
+
import { homedir as homedir27 } from "node:os";
|
|
161966
162412
|
import { join as join33, resolve as resolve26 } from "node:path";
|
|
161967
162413
|
var DEFAULT_SETTINGS3 = {
|
|
161968
162414
|
lastAgent: null,
|
|
@@ -162349,7 +162795,7 @@ class SettingsManager2 {
|
|
|
162349
162795
|
if (!this.settings)
|
|
162350
162796
|
return;
|
|
162351
162797
|
const settingsPath = this.getSettingsPath();
|
|
162352
|
-
const home = process.env.HOME ||
|
|
162798
|
+
const home = process.env.HOME || homedir27();
|
|
162353
162799
|
const dirPath = join33(home, ".letta");
|
|
162354
162800
|
try {
|
|
162355
162801
|
if (!exists(dirPath)) {
|
|
@@ -162410,7 +162856,7 @@ class SettingsManager2 {
|
|
|
162410
162856
|
}
|
|
162411
162857
|
}
|
|
162412
162858
|
getSettingsPath() {
|
|
162413
|
-
const home = process.env.HOME ||
|
|
162859
|
+
const home = process.env.HOME || homedir27();
|
|
162414
162860
|
return join33(home, ".letta", "settings.json");
|
|
162415
162861
|
}
|
|
162416
162862
|
getProjectSettingsPath(workingDirectory) {
|
|
@@ -164253,7 +164699,7 @@ Error: ${message}`);
|
|
|
164253
164699
|
const { toolFilter: toolFilter3 } = await Promise.resolve().then(() => (init_filter2(), exports_filter2));
|
|
164254
164700
|
toolFilter3.setEnabledTools(values.tools);
|
|
164255
164701
|
}
|
|
164256
|
-
if (values.allowedTools || values.disallowedTools) {
|
|
164702
|
+
if (values.allowedTools || values.disallowedTools || values["memory-scope"]) {
|
|
164257
164703
|
const { cliPermissions: cliPermissions3 } = await Promise.resolve().then(() => (init_cli2(), exports_cli2));
|
|
164258
164704
|
if (values.allowedTools) {
|
|
164259
164705
|
cliPermissions3.setAllowedTools(values.allowedTools);
|
|
@@ -164261,6 +164707,9 @@ Error: ${message}`);
|
|
|
164261
164707
|
if (values.disallowedTools) {
|
|
164262
164708
|
cliPermissions3.setDisallowedTools(values.disallowedTools);
|
|
164263
164709
|
}
|
|
164710
|
+
if (values["memory-scope"]) {
|
|
164711
|
+
cliPermissions3.setMemoryScope(values["memory-scope"]);
|
|
164712
|
+
}
|
|
164264
164713
|
}
|
|
164265
164714
|
const permissionModeValue = values["permission-mode"];
|
|
164266
164715
|
const yoloMode = values.yolo;
|
|
@@ -165038,4 +165487,4 @@ Error during initialization: ${message}`);
|
|
|
165038
165487
|
}
|
|
165039
165488
|
main();
|
|
165040
165489
|
|
|
165041
|
-
//# debugId=
|
|
165490
|
+
//# debugId=1D3F2BB144427E1064756E2164756E21
|