@letta-ai/letta-code 0.24.4 → 0.24.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/letta.js
CHANGED
|
@@ -3269,7 +3269,7 @@ var package_default;
|
|
|
3269
3269
|
var init_package = __esm(() => {
|
|
3270
3270
|
package_default = {
|
|
3271
3271
|
name: "@letta-ai/letta-code",
|
|
3272
|
-
version: "0.24.
|
|
3272
|
+
version: "0.24.6",
|
|
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: {
|
|
@@ -4723,10 +4723,12 @@ var exports_client = {};
|
|
|
4723
4723
|
__export(exports_client, {
|
|
4724
4724
|
getServerUrl: () => getServerUrl,
|
|
4725
4725
|
getMemfsServerUrl: () => getMemfsServerUrl,
|
|
4726
|
+
getMemfsGitProxyRewriteConfig: () => getMemfsGitProxyRewriteConfig,
|
|
4726
4727
|
getClient: () => getClient,
|
|
4727
4728
|
consumeLastSDKDiagnostic: () => consumeLastSDKDiagnostic,
|
|
4728
4729
|
clearLastSDKDiagnostic: () => clearLastSDKDiagnostic,
|
|
4729
|
-
__testOverrideGetClient: () => __testOverrideGetClient
|
|
4730
|
+
__testOverrideGetClient: () => __testOverrideGetClient,
|
|
4731
|
+
LETTA_MEMFS_GIT_PROXY_BASE_URL_ENV: () => LETTA_MEMFS_GIT_PROXY_BASE_URL_ENV
|
|
4730
4732
|
});
|
|
4731
4733
|
import { hostname } from "node:os";
|
|
4732
4734
|
function __testOverrideGetClient(factory) {
|
|
@@ -4774,12 +4776,50 @@ function getServerUrl() {
|
|
|
4774
4776
|
const settings = settingsManager.getSettings();
|
|
4775
4777
|
return process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL;
|
|
4776
4778
|
}
|
|
4779
|
+
function isLocalhostUrl(value) {
|
|
4780
|
+
if (!value)
|
|
4781
|
+
return false;
|
|
4782
|
+
try {
|
|
4783
|
+
const parsed = new URL(value);
|
|
4784
|
+
return ["localhost", "127.0.0.1", "::1", "[::1]"].includes(parsed.hostname);
|
|
4785
|
+
} catch {
|
|
4786
|
+
return false;
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
function trimBaseUrl(value) {
|
|
4790
|
+
return value.trim().replace(/\/+$/, "");
|
|
4791
|
+
}
|
|
4792
|
+
function getMemfsGitProxyRewriteConfig(env = process.env) {
|
|
4793
|
+
const rawProxyBaseUrl = env[LETTA_MEMFS_GIT_PROXY_BASE_URL_ENV]?.trim();
|
|
4794
|
+
if (!rawProxyBaseUrl || !isLocalhostUrl(rawProxyBaseUrl)) {
|
|
4795
|
+
return null;
|
|
4796
|
+
}
|
|
4797
|
+
const memfsBaseUrl = trimBaseUrl(getMemfsServerUrl());
|
|
4798
|
+
if (!memfsBaseUrl.includes("api.letta.com")) {
|
|
4799
|
+
return null;
|
|
4800
|
+
}
|
|
4801
|
+
const proxyBaseUrl = trimBaseUrl(rawProxyBaseUrl);
|
|
4802
|
+
const proxyPrefix = `${proxyBaseUrl}/v1/git/`;
|
|
4803
|
+
const memfsPrefix = `${memfsBaseUrl}/v1/git/`;
|
|
4804
|
+
return {
|
|
4805
|
+
proxyBaseUrl,
|
|
4806
|
+
memfsBaseUrl,
|
|
4807
|
+
proxyPrefix,
|
|
4808
|
+
memfsPrefix,
|
|
4809
|
+
configKey: `url.${proxyPrefix}.insteadOf`,
|
|
4810
|
+
configValue: memfsPrefix
|
|
4811
|
+
};
|
|
4812
|
+
}
|
|
4777
4813
|
function getMemfsServerUrl() {
|
|
4778
4814
|
let settings = null;
|
|
4779
4815
|
try {
|
|
4780
4816
|
settings = settingsManager.getSettings();
|
|
4781
4817
|
} catch {}
|
|
4782
|
-
|
|
4818
|
+
const configuredMemfsUrl = process.env.LETTA_MEMFS_BASE_URL || settings?.env?.LETTA_MEMFS_BASE_URL;
|
|
4819
|
+
if (configuredMemfsUrl) {
|
|
4820
|
+
return configuredMemfsUrl;
|
|
4821
|
+
}
|
|
4822
|
+
return LETTA_CLOUD_API_URL;
|
|
4783
4823
|
}
|
|
4784
4824
|
async function getClient() {
|
|
4785
4825
|
if (_testClientOverride) {
|
|
@@ -4854,7 +4894,7 @@ If you experience this issue multiple times, move ~/.letta to ~/.letta_backup, a
|
|
|
4854
4894
|
...isTimingsEnabled() && { fetch: createTimingFetch(fetch) }
|
|
4855
4895
|
});
|
|
4856
4896
|
}
|
|
4857
|
-
var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnostic = null, _cachedApiKey, _testClientOverride = null, sdkLogger;
|
|
4897
|
+
var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnostic = null, _cachedApiKey, _testClientOverride = null, sdkLogger, LETTA_MEMFS_GIT_PROXY_BASE_URL_ENV = "LETTA_MEMFS_GIT_PROXY_BASE_URL";
|
|
4858
4898
|
var init_client2 = __esm(() => {
|
|
4859
4899
|
init_letta_client();
|
|
4860
4900
|
init_package();
|
|
@@ -7128,6 +7168,13 @@ If worktree creation fails (locked index), retry up to 3 times with backoff (sle
|
|
|
7128
7168
|
### 2. Read existing memory
|
|
7129
7169
|
Read the memory files in your worktree, to understand what already exists in the memory filesystem.
|
|
7130
7170
|
|
|
7171
|
+
Before adding or expanding \`system/\` memory, measure its current token footprint:
|
|
7172
|
+
\`\`\`bash
|
|
7173
|
+
letta memory tokens --format json --quiet --memory-dir "$WORKTREE_DIR/$BRANCH_NAME"
|
|
7174
|
+
\`\`\`
|
|
7175
|
+
|
|
7176
|
+
This command is memory-mode safe. Treat it as measurement only: use the reported \`total_tokens\` and per-file breakdown to decide whether new findings belong in \`system/\` or external memory. Do not use custom token-counting scripts, \`npx\`, \`awk\`, or \`find -exec wc\` for this.
|
|
7177
|
+
|
|
7131
7178
|
### 3. Read and analyze history
|
|
7132
7179
|
|
|
7133
7180
|
Your prompt will specify a pre-split JSONL chunk file and its source format. Use these patterns to read it:
|
|
@@ -7765,6 +7812,11 @@ You can create, delete, or modify files — including their contents, names, and
|
|
|
7765
7812
|
- Why did the agent make the mistakes it did? What was missing from context?
|
|
7766
7813
|
- Why did the user have to make corrections?
|
|
7767
7814
|
- Does anything in memory contradict the observed conversation history, or need updating?
|
|
7815
|
+
- Check the current size of \`system/\` before adding or expanding in-context memory:
|
|
7816
|
+
\`\`\`bash
|
|
7817
|
+
letta memory tokens --format json --quiet
|
|
7818
|
+
\`\`\`
|
|
7819
|
+
This command is memory-mode safe. Treat it as measurement only: decide whether a size is concerning based on the actual context and the value of the proposed change. Prefer adding durable detail to external memory unless the information is important enough to stay in-context.
|
|
7768
7820
|
|
|
7769
7821
|
### Step 4: Update memory files (if needed)
|
|
7770
7822
|
|
|
@@ -9669,6 +9721,17 @@ var init_models2 = __esm(() => {
|
|
|
9669
9721
|
parallel_tool_calls: true
|
|
9670
9722
|
}
|
|
9671
9723
|
},
|
|
9724
|
+
{
|
|
9725
|
+
id: "deepseek-v4-pro",
|
|
9726
|
+
handle: "openrouter/deepseek/deepseek-v4-pro",
|
|
9727
|
+
label: "DeepSeek V4 Pro",
|
|
9728
|
+
description: "DeepSeek's V4 Pro model",
|
|
9729
|
+
updateArgs: {
|
|
9730
|
+
context_window: 1048576,
|
|
9731
|
+
max_output_tokens: 384000,
|
|
9732
|
+
parallel_tool_calls: true
|
|
9733
|
+
}
|
|
9734
|
+
},
|
|
9672
9735
|
{
|
|
9673
9736
|
id: "glm-5.1",
|
|
9674
9737
|
handle: "zai/glm-5.1",
|
|
@@ -38492,6 +38555,7 @@ var init_create = __esm(() => {
|
|
|
38492
38555
|
var exports_memoryGit = {};
|
|
38493
38556
|
__export(exports_memoryGit, {
|
|
38494
38557
|
unsetMemoryRepositoryUrl: () => unsetMemoryRepositoryUrl,
|
|
38558
|
+
shouldConfigurePersistentMemfsCredentialHelper: () => shouldConfigurePersistentMemfsCredentialHelper,
|
|
38495
38559
|
setMemoryRepositoryUrl: () => setMemoryRepositoryUrl,
|
|
38496
38560
|
removeGitMemoryTag: () => removeGitMemoryTag,
|
|
38497
38561
|
readMemoryRepositoryPushLog: () => readMemoryRepositoryPushLog,
|
|
@@ -38503,6 +38567,7 @@ __export(exports_memoryGit, {
|
|
|
38503
38567
|
isRetryableGitTransientError: () => isRetryableGitTransientError,
|
|
38504
38568
|
isMissingCwdGitError: () => isMissingCwdGitError,
|
|
38505
38569
|
isMemfsRemoteUrlForAgent: () => isMemfsRemoteUrlForAgent,
|
|
38570
|
+
isMemfsGitNetworkCommand: () => isMemfsGitNetworkCommand,
|
|
38506
38571
|
isGitRepo: () => isGitRepo,
|
|
38507
38572
|
getMemoryRepositoryUrl: () => getMemoryRepositoryUrl,
|
|
38508
38573
|
getMemoryRepoDir: () => getMemoryRepoDir,
|
|
@@ -38513,6 +38578,9 @@ __export(exports_memoryGit, {
|
|
|
38513
38578
|
ensureLocalMemfsGitConfig: () => ensureLocalMemfsGitConfig,
|
|
38514
38579
|
commitAndSyncMemoryWrite: () => commitAndSyncMemoryWrite,
|
|
38515
38580
|
cloneMemoryRepo: () => cloneMemoryRepo,
|
|
38581
|
+
buildNonInteractiveGitEnv: () => buildNonInteractiveGitEnv,
|
|
38582
|
+
buildMemfsGitProxyArgs: () => buildMemfsGitProxyArgs,
|
|
38583
|
+
buildGitAuthArgs: () => buildGitAuthArgs,
|
|
38516
38584
|
assertMemoryRepoReadyForWrite: () => assertMemoryRepoReadyForWrite,
|
|
38517
38585
|
addGitMemoryTag: () => addGitMemoryTag,
|
|
38518
38586
|
PRE_COMMIT_HOOK_SCRIPT: () => PRE_COMMIT_HOOK_SCRIPT,
|
|
@@ -38622,12 +38690,44 @@ async function getAuthToken() {
|
|
|
38622
38690
|
const client = await getClient();
|
|
38623
38691
|
return client._options?.apiKey ?? "";
|
|
38624
38692
|
}
|
|
38625
|
-
|
|
38626
|
-
|
|
38693
|
+
function buildGitAuthArgs(token) {
|
|
38694
|
+
return [
|
|
38695
|
+
"-c",
|
|
38696
|
+
"credential.helper=",
|
|
38697
|
+
"-c",
|
|
38698
|
+
"core.askPass=",
|
|
38627
38699
|
"-c",
|
|
38628
38700
|
`http.extraHeader=Authorization: Basic ${Buffer.from(`letta:${token}`).toString("base64")}`
|
|
38629
|
-
]
|
|
38630
|
-
|
|
38701
|
+
];
|
|
38702
|
+
}
|
|
38703
|
+
function isMemfsGitNetworkCommand(args) {
|
|
38704
|
+
return ["clone", "fetch", "pull", "push"].includes(args[0] ?? "");
|
|
38705
|
+
}
|
|
38706
|
+
function buildMemfsGitProxyArgs(args, env3 = process.env) {
|
|
38707
|
+
if (!isMemfsGitNetworkCommand(args)) {
|
|
38708
|
+
return [];
|
|
38709
|
+
}
|
|
38710
|
+
const rewrite = getMemfsGitProxyRewriteConfig(env3);
|
|
38711
|
+
if (!rewrite) {
|
|
38712
|
+
return [];
|
|
38713
|
+
}
|
|
38714
|
+
return ["-c", `${rewrite.configKey}=${rewrite.configValue}`];
|
|
38715
|
+
}
|
|
38716
|
+
function shouldConfigurePersistentMemfsCredentialHelper(env3 = process.env) {
|
|
38717
|
+
return getMemfsGitProxyRewriteConfig(env3) === null;
|
|
38718
|
+
}
|
|
38719
|
+
function buildNonInteractiveGitEnv(env3 = process.env) {
|
|
38720
|
+
return {
|
|
38721
|
+
...env3,
|
|
38722
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
38723
|
+
GCM_INTERACTIVE: "never",
|
|
38724
|
+
GIT_ASKPASS: "",
|
|
38725
|
+
SSH_ASKPASS: ""
|
|
38726
|
+
};
|
|
38727
|
+
}
|
|
38728
|
+
async function runGit(cwd2, args, token) {
|
|
38729
|
+
const authArgs = token ? buildGitAuthArgs(token) : [];
|
|
38730
|
+
const allArgs = [...buildMemfsGitProxyArgs(args), ...authArgs, ...args];
|
|
38631
38731
|
let loggableArgs = args;
|
|
38632
38732
|
if (args[0] === "config" && typeof args[1] === "string" && args[1].includes("credential") && args[1].includes(".helper")) {
|
|
38633
38733
|
loggableArgs = [args[0], args[1], "<redacted>"];
|
|
@@ -38637,6 +38737,7 @@ async function runGit(cwd2, args, token) {
|
|
|
38637
38737
|
debugLog("memfs-git", `git ${loggableArgs.join(" ")} (in ${cwd2})`);
|
|
38638
38738
|
const result = await execFile("git", allArgs, {
|
|
38639
38739
|
cwd: cwd2,
|
|
38740
|
+
env: buildNonInteractiveGitEnv(),
|
|
38640
38741
|
maxBuffer: 10 * 1024 * 1024,
|
|
38641
38742
|
timeout: 60000
|
|
38642
38743
|
});
|
|
@@ -38690,6 +38791,11 @@ async function runGitWithRetry(cwd2, args, token, options) {
|
|
|
38690
38791
|
async function configureLocalCredentialHelper(dir, token) {
|
|
38691
38792
|
const rawBaseUrl = getMemfsServerUrl();
|
|
38692
38793
|
const normalizedBaseUrl = normalizeCredentialBaseUrl(rawBaseUrl);
|
|
38794
|
+
if (!shouldConfigurePersistentMemfsCredentialHelper()) {
|
|
38795
|
+
await clearLocalCredentialHelper(dir, rawBaseUrl, normalizedBaseUrl);
|
|
38796
|
+
debugLog("memfs-git", `Skipped persistent credential helper for ${normalizedBaseUrl}; using transient MemFS git proxy transport`);
|
|
38797
|
+
return;
|
|
38798
|
+
}
|
|
38693
38799
|
let helper;
|
|
38694
38800
|
if (platform2() === "win32") {
|
|
38695
38801
|
const helperScriptPath = join7(dir, ".git", "letta-credential-helper.cmd");
|
|
@@ -38713,6 +38819,17 @@ echo password=${token}
|
|
|
38713
38819
|
}
|
|
38714
38820
|
debugLog("memfs-git", `Configured local credential helper for ${normalizedBaseUrl}${rawBaseUrl !== normalizedBaseUrl ? ` (and raw ${rawBaseUrl})` : ""}`);
|
|
38715
38821
|
}
|
|
38822
|
+
async function clearLocalCredentialHelper(dir, rawBaseUrl, normalizedBaseUrl) {
|
|
38823
|
+
const keys = new Set([
|
|
38824
|
+
`credential.${normalizedBaseUrl}.helper`,
|
|
38825
|
+
`credential.${rawBaseUrl}.helper`
|
|
38826
|
+
]);
|
|
38827
|
+
for (const key of keys) {
|
|
38828
|
+
try {
|
|
38829
|
+
await runGit(dir, ["config", "--local", "--unset-all", key]);
|
|
38830
|
+
} catch {}
|
|
38831
|
+
}
|
|
38832
|
+
}
|
|
38716
38833
|
function installPreCommitHook(dir) {
|
|
38717
38834
|
const hooksDir = join7(dir, ".git", "hooks");
|
|
38718
38835
|
const hookPath = join7(hooksDir, "pre-commit");
|
|
@@ -38963,6 +39080,32 @@ async function fetchMemoryRemote(memoryDir, token) {
|
|
|
38963
39080
|
operation: "fetch origin"
|
|
38964
39081
|
});
|
|
38965
39082
|
}
|
|
39083
|
+
async function getMemoryAheadBehind(memoryDir) {
|
|
39084
|
+
try {
|
|
39085
|
+
const { stdout } = await runGit(memoryDir, [
|
|
39086
|
+
"rev-list",
|
|
39087
|
+
"--left-right",
|
|
39088
|
+
"--count",
|
|
39089
|
+
"HEAD...@{u}"
|
|
39090
|
+
]);
|
|
39091
|
+
const [aheadRaw, behindRaw] = stdout.trim().split(/\s+/);
|
|
39092
|
+
return {
|
|
39093
|
+
ahead: Number.parseInt(aheadRaw ?? "0", 10) || 0,
|
|
39094
|
+
behind: Number.parseInt(behindRaw ?? "0", 10) || 0
|
|
39095
|
+
};
|
|
39096
|
+
} catch {
|
|
39097
|
+
return null;
|
|
39098
|
+
}
|
|
39099
|
+
}
|
|
39100
|
+
async function pushCleanPendingMemoryCommitsForWrite(memoryDir, agentId, token) {
|
|
39101
|
+
await prepareMemoryRepoForGitOps(memoryDir, agentId, token);
|
|
39102
|
+
const divergence = await getMemoryAheadBehind(memoryDir);
|
|
39103
|
+
if (divergence && divergence.ahead > 0) {
|
|
39104
|
+
await runGitWithRetry(memoryDir, ["push"], token, {
|
|
39105
|
+
operation: "push pending memory commits"
|
|
39106
|
+
});
|
|
39107
|
+
}
|
|
39108
|
+
}
|
|
38966
39109
|
async function resetMemoryToUpstream(memoryDir, token) {
|
|
38967
39110
|
await runGit(memoryDir, ["reset", "--hard", "@{u}"], token);
|
|
38968
39111
|
}
|
|
@@ -39028,19 +39171,18 @@ async function recoverMemoryPushConflict(params, token, initialSha) {
|
|
|
39028
39171
|
rescueRef
|
|
39029
39172
|
};
|
|
39030
39173
|
}
|
|
39031
|
-
async function assertMemoryRepoReadyForWrite(memoryDir) {
|
|
39174
|
+
async function assertMemoryRepoReadyForWrite(memoryDir, agentId) {
|
|
39032
39175
|
const status = await runGit(memoryDir, ["status", "--porcelain"]);
|
|
39033
39176
|
if (status.stdout.trim().length > 0) {
|
|
39034
39177
|
throw new Error("Memory repo has uncommitted changes. Commit, discard, or sync them before using memory tools.");
|
|
39035
39178
|
}
|
|
39179
|
+
if (agentId) {
|
|
39180
|
+
const token = await getAuthToken();
|
|
39181
|
+
await pushCleanPendingMemoryCommitsForWrite(memoryDir, agentId, token);
|
|
39182
|
+
}
|
|
39036
39183
|
try {
|
|
39037
|
-
const
|
|
39038
|
-
|
|
39039
|
-
"--count",
|
|
39040
|
-
"@{u}..HEAD"
|
|
39041
|
-
]);
|
|
39042
|
-
const aheadCount = parseInt(stdout.trim(), 10);
|
|
39043
|
-
if (aheadCount > 0) {
|
|
39184
|
+
const divergence = await getMemoryAheadBehind(memoryDir);
|
|
39185
|
+
if (divergence && divergence.ahead > 0) {
|
|
39044
39186
|
throw new Error("Memory repo has local commits that are not pushed to remote. Sync the repo before using memory tools.");
|
|
39045
39187
|
}
|
|
39046
39188
|
} catch (error) {
|
|
@@ -47319,13 +47461,25 @@ function pushUnique(list, seen, entry) {
|
|
|
47319
47461
|
seen.add(key);
|
|
47320
47462
|
list.push(entry);
|
|
47321
47463
|
}
|
|
47464
|
+
function normalizePowerShellCommand(command) {
|
|
47465
|
+
const trimmed = command.trim();
|
|
47466
|
+
if (trimmed.startsWith("&") || trimmed.startsWith('"') || trimmed.startsWith("'")) {
|
|
47467
|
+
return trimmed.startsWith("&") ? trimmed : `& ${trimmed}`;
|
|
47468
|
+
}
|
|
47469
|
+
return trimmed;
|
|
47470
|
+
}
|
|
47471
|
+
function buildPowerShellCommand(command) {
|
|
47472
|
+
const powerShellCommand = normalizePowerShellCommand(command);
|
|
47473
|
+
const aliasPrelude = POWERSHELL_ENV_ALIASES.map((name) => `$${name} = $env:${name}`).join("; ");
|
|
47474
|
+
return `${aliasPrelude}; ${powerShellCommand}`;
|
|
47475
|
+
}
|
|
47322
47476
|
function windowsLaunchers(command) {
|
|
47323
47477
|
const trimmed = command.trim();
|
|
47324
47478
|
if (!trimmed)
|
|
47325
47479
|
return [];
|
|
47326
47480
|
const launchers = [];
|
|
47327
47481
|
const seen = new Set;
|
|
47328
|
-
const powerShellCommand =
|
|
47482
|
+
const powerShellCommand = buildPowerShellCommand(trimmed);
|
|
47329
47483
|
pushUnique(launchers, seen, [
|
|
47330
47484
|
"powershell.exe",
|
|
47331
47485
|
"-NoProfile",
|
|
@@ -47407,7 +47561,19 @@ function buildShellLaunchers(command, options) {
|
|
|
47407
47561
|
const login = options?.login ?? false;
|
|
47408
47562
|
return process.platform === "win32" ? windowsLaunchers(command) : unixLaunchers(command, login);
|
|
47409
47563
|
}
|
|
47410
|
-
var SEP2 = "\x00";
|
|
47564
|
+
var SEP2 = "\x00", POWERSHELL_ENV_ALIASES;
|
|
47565
|
+
var init_shellLaunchers = __esm(() => {
|
|
47566
|
+
POWERSHELL_ENV_ALIASES = [
|
|
47567
|
+
"MEMORY_DIR",
|
|
47568
|
+
"LETTA_MEMORY_DIR",
|
|
47569
|
+
"AGENT_ID",
|
|
47570
|
+
"LETTA_AGENT_ID",
|
|
47571
|
+
"LETTA_PARENT_AGENT_ID",
|
|
47572
|
+
"CONVERSATION_ID",
|
|
47573
|
+
"LETTA_CONVERSATION_ID",
|
|
47574
|
+
"USER_CWD"
|
|
47575
|
+
];
|
|
47576
|
+
});
|
|
47411
47577
|
|
|
47412
47578
|
// src/hooks/types.ts
|
|
47413
47579
|
function supportsPromptHooks(event) {
|
|
@@ -47863,6 +48029,7 @@ async function executeHooksParallel(hooks, input, workingDirectory = process.cwd
|
|
|
47863
48029
|
}
|
|
47864
48030
|
var DEFAULT_TIMEOUT_MS = 60000;
|
|
47865
48031
|
var init_executor = __esm(() => {
|
|
48032
|
+
init_shellLaunchers();
|
|
47866
48033
|
init_prompt_executor();
|
|
47867
48034
|
init_types2();
|
|
47868
48035
|
});
|
|
@@ -48895,6 +49062,7 @@ __export(exports_memoryFilesystem, {
|
|
|
48895
49062
|
renderMemoryFilesystemTree: () => renderMemoryFilesystemTree,
|
|
48896
49063
|
labelFromRelativePath: () => labelFromRelativePath,
|
|
48897
49064
|
isMemfsEnabledOnServer: () => isMemfsEnabledOnServer,
|
|
49065
|
+
isLettaMemfsServer: () => isLettaMemfsServer,
|
|
48898
49066
|
isLettaCloud: () => isLettaCloud,
|
|
48899
49067
|
getMemorySystemDir: () => getMemorySystemDir,
|
|
48900
49068
|
getMemoryFilesystemRoot: () => getMemoryFilesystemRoot,
|
|
@@ -49082,8 +49250,8 @@ function renderMemoryFilesystemTree(systemLabels, detachedLabels, options = {})
|
|
|
49082
49250
|
}
|
|
49083
49251
|
async function applyMemfsFlags(agentId, memfsFlag, noMemfsFlag, options) {
|
|
49084
49252
|
const { settingsManager: settingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
49085
|
-
if (memfsFlag && !await
|
|
49086
|
-
throw new Error(
|
|
49253
|
+
if (memfsFlag && !await isLettaMemfsServer()) {
|
|
49254
|
+
throw new Error(await getMemfsSyncUnavailableMessage());
|
|
49087
49255
|
}
|
|
49088
49256
|
const hasExplicitToggle = Boolean(memfsFlag || noMemfsFlag);
|
|
49089
49257
|
const localMemfsEnabled = settingsManager2.isMemfsEnabled(agentId);
|
|
@@ -49154,6 +49322,24 @@ async function isLettaCloud() {
|
|
|
49154
49322
|
const serverUrl = getServerUrl2();
|
|
49155
49323
|
return serverUrl.includes("api.letta.com") || process.env.LETTA_MEMFS_LOCAL === "1" || process.env.LETTA_API_KEY === "local-desktop";
|
|
49156
49324
|
}
|
|
49325
|
+
function getServerHostLabel(serverUrl) {
|
|
49326
|
+
const trimmed = serverUrl.trim();
|
|
49327
|
+
try {
|
|
49328
|
+
return new URL(trimmed).host || trimmed;
|
|
49329
|
+
} catch {
|
|
49330
|
+
return trimmed.replace(/^https?:\/\//, "").replace(/\/+$/, "") || trimmed;
|
|
49331
|
+
}
|
|
49332
|
+
}
|
|
49333
|
+
async function isLettaMemfsServer() {
|
|
49334
|
+
const { getMemfsServerUrl: getMemfsServerUrl2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
49335
|
+
const memfsServerUrl = getMemfsServerUrl2();
|
|
49336
|
+
return memfsServerUrl.includes("api.letta.com") || process.env.LETTA_MEMFS_LOCAL === "1" || process.env.LETTA_API_KEY === "local-desktop";
|
|
49337
|
+
}
|
|
49338
|
+
async function getMemfsSyncUnavailableMessage() {
|
|
49339
|
+
const { getMemfsServerUrl: getMemfsServerUrl2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
49340
|
+
const memfsServerUrl = getMemfsServerUrl2();
|
|
49341
|
+
return `MemFS sync failed (expected api.letta.com, got ${getServerHostLabel(memfsServerUrl)})`;
|
|
49342
|
+
}
|
|
49157
49343
|
async function enableMemfsIfCloud(agentId) {
|
|
49158
49344
|
if (!await isLettaCloud())
|
|
49159
49345
|
return;
|
|
@@ -54547,6 +54733,24 @@ exec ${commandWithArgs} "$@"
|
|
|
54547
54733
|
});
|
|
54548
54734
|
return shimDir;
|
|
54549
54735
|
}
|
|
54736
|
+
function appendGitConfigEnv(env3, key, value) {
|
|
54737
|
+
const rawCount = env3.GIT_CONFIG_COUNT;
|
|
54738
|
+
const count = rawCount && /^\d+$/.test(rawCount) ? Number(rawCount) : 0;
|
|
54739
|
+
env3[`GIT_CONFIG_KEY_${count}`] = key;
|
|
54740
|
+
env3[`GIT_CONFIG_VALUE_${count}`] = value;
|
|
54741
|
+
env3.GIT_CONFIG_COUNT = String(count + 1);
|
|
54742
|
+
}
|
|
54743
|
+
function applyMemfsGitProxyEnv(env3) {
|
|
54744
|
+
const rewrite = getMemfsGitProxyRewriteConfig(env3);
|
|
54745
|
+
if (!rewrite) {
|
|
54746
|
+
return;
|
|
54747
|
+
}
|
|
54748
|
+
appendGitConfigEnv(env3, rewrite.configKey, rewrite.configValue);
|
|
54749
|
+
env3.GIT_TERMINAL_PROMPT = "0";
|
|
54750
|
+
env3.GCM_INTERACTIVE = "never";
|
|
54751
|
+
env3.GIT_ASKPASS = "";
|
|
54752
|
+
env3.SSH_ASKPASS = "";
|
|
54753
|
+
}
|
|
54550
54754
|
function getShellEnv() {
|
|
54551
54755
|
const env3 = { ...process.env };
|
|
54552
54756
|
const pathKey = Object.keys(env3).find((k) => k.toUpperCase() === "PATH") || "PATH";
|
|
@@ -54634,6 +54838,7 @@ function getShellEnv() {
|
|
|
54634
54838
|
if (!env3.TERM) {
|
|
54635
54839
|
env3.TERM = "xterm-256color";
|
|
54636
54840
|
}
|
|
54841
|
+
applyMemfsGitProxyEnv(env3);
|
|
54637
54842
|
return env3;
|
|
54638
54843
|
}
|
|
54639
54844
|
var LETTA_BIN_ARGS_ENV = "LETTA_CODE_BIN_ARGS_JSON";
|
|
@@ -54922,13 +55127,19 @@ function validateWorktreePath(command, cwd2) {
|
|
|
54922
55127
|
}
|
|
54923
55128
|
return null;
|
|
54924
55129
|
}
|
|
55130
|
+
function rebuildCachedLauncher(command) {
|
|
55131
|
+
if (!cachedWorkingLauncher)
|
|
55132
|
+
return null;
|
|
55133
|
+
const cachedExecutable = cachedWorkingLauncher[0]?.toLowerCase();
|
|
55134
|
+
if (!cachedExecutable)
|
|
55135
|
+
return null;
|
|
55136
|
+
const launchers = buildShellLaunchers(command);
|
|
55137
|
+
return launchers.find((launcher) => launcher[0]?.toLowerCase() === cachedExecutable) ?? null;
|
|
55138
|
+
}
|
|
54925
55139
|
function getBackgroundLauncher(command) {
|
|
54926
|
-
|
|
54927
|
-
|
|
54928
|
-
|
|
54929
|
-
return [executable, ...launcherArgs.slice(0, -1), command];
|
|
54930
|
-
}
|
|
54931
|
-
}
|
|
55140
|
+
const cachedLauncher = rebuildCachedLauncher(command);
|
|
55141
|
+
if (cachedLauncher)
|
|
55142
|
+
return cachedLauncher;
|
|
54932
55143
|
const launchers = buildShellLaunchers(command);
|
|
54933
55144
|
return launchers[0] || [];
|
|
54934
55145
|
}
|
|
@@ -54944,9 +55155,8 @@ async function spawnCommand(command, options) {
|
|
|
54944
55155
|
});
|
|
54945
55156
|
}
|
|
54946
55157
|
if (cachedWorkingLauncher) {
|
|
54947
|
-
const
|
|
54948
|
-
if (
|
|
54949
|
-
const newLauncher = [executable, ...launcherArgs.slice(0, -1), command];
|
|
55158
|
+
const newLauncher = rebuildCachedLauncher(command);
|
|
55159
|
+
if (newLauncher) {
|
|
54950
55160
|
try {
|
|
54951
55161
|
const result = await spawnWithLauncher(newLauncher, {
|
|
54952
55162
|
cwd: options.cwd,
|
|
@@ -55195,6 +55405,7 @@ var init_Bash2 = __esm(() => {
|
|
|
55195
55405
|
init_worktree_ownership();
|
|
55196
55406
|
init_process_manager();
|
|
55197
55407
|
init_shellEnv();
|
|
55408
|
+
init_shellLaunchers();
|
|
55198
55409
|
init_shellRunner();
|
|
55199
55410
|
init_truncation();
|
|
55200
55411
|
});
|
|
@@ -56449,14 +56660,14 @@ async function memory(args) {
|
|
|
56449
56660
|
}
|
|
56450
56661
|
const memoryDir = resolveMemoryDir();
|
|
56451
56662
|
ensureMemoryRepo(memoryDir);
|
|
56452
|
-
await
|
|
56663
|
+
const { agentId, agentName } = await getAgentIdentity();
|
|
56664
|
+
await assertMemoryRepoReadyForWrite(memoryDir, agentId);
|
|
56453
56665
|
const affectedPaths = await applyMemoryCommand(memoryDir, args);
|
|
56454
56666
|
if (affectedPaths.length === 0) {
|
|
56455
56667
|
return {
|
|
56456
56668
|
message: `Memory ${args.command} completed with no changed paths.`
|
|
56457
56669
|
};
|
|
56458
56670
|
}
|
|
56459
|
-
const { agentId, agentName } = await getAgentIdentity();
|
|
56460
56671
|
const commitResult = await commitAndSyncMemoryWrite({
|
|
56461
56672
|
memoryDir,
|
|
56462
56673
|
pathspecs: affectedPaths,
|
|
@@ -56834,12 +57045,12 @@ async function memory_apply_patch(args) {
|
|
|
56834
57045
|
}
|
|
56835
57046
|
const memoryDir = resolveMemoryDir2();
|
|
56836
57047
|
ensureMemoryRepo2(memoryDir);
|
|
56837
|
-
await
|
|
57048
|
+
const { agentId, agentName } = await getAgentIdentity2();
|
|
57049
|
+
await assertMemoryRepoReadyForWrite(memoryDir, agentId);
|
|
56838
57050
|
const pathspecs = await applyMemoryPatch(memoryDir, input);
|
|
56839
57051
|
if (pathspecs.length === 0) {
|
|
56840
57052
|
return { message: "memory_apply_patch completed with no changed paths." };
|
|
56841
57053
|
}
|
|
56842
|
-
const { agentId, agentName } = await getAgentIdentity2();
|
|
56843
57054
|
const commitResult = await commitAndSyncMemoryWrite({
|
|
56844
57055
|
memoryDir,
|
|
56845
57056
|
pathspecs,
|
|
@@ -71382,6 +71593,7 @@ var DEFAULT_TIMEOUT = 120000;
|
|
|
71382
71593
|
var init_Shell2 = __esm(() => {
|
|
71383
71594
|
init_runtime_context();
|
|
71384
71595
|
init_shellEnv();
|
|
71596
|
+
init_shellLaunchers();
|
|
71385
71597
|
init_shellRunner();
|
|
71386
71598
|
});
|
|
71387
71599
|
|
|
@@ -71527,6 +71739,7 @@ var init_ShellCommand2 = __esm(() => {
|
|
|
71527
71739
|
init_context();
|
|
71528
71740
|
init_readOnlyShell();
|
|
71529
71741
|
init_Shell2();
|
|
71742
|
+
init_shellLaunchers();
|
|
71530
71743
|
init_shellRunner();
|
|
71531
71744
|
init_truncation();
|
|
71532
71745
|
});
|
|
@@ -147623,7 +147836,9 @@ function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory,
|
|
|
147623
147836
|
});
|
|
147624
147837
|
}
|
|
147625
147838
|
var MAX_STDOUT_BYTES = 4096;
|
|
147626
|
-
var init_statusLineRuntime = () => {
|
|
147839
|
+
var init_statusLineRuntime = __esm(() => {
|
|
147840
|
+
init_shellLaunchers();
|
|
147841
|
+
});
|
|
147627
147842
|
|
|
147628
147843
|
// src/cli/helpers/subagentAggregation.ts
|
|
147629
147844
|
function hasInProgressTaskToolCalls(order, byId, _emittedIds) {
|
|
@@ -159132,6 +159347,7 @@ __export(exports_memoryFilesystem2, {
|
|
|
159132
159347
|
renderMemoryFilesystemTree: () => renderMemoryFilesystemTree2,
|
|
159133
159348
|
labelFromRelativePath: () => labelFromRelativePath2,
|
|
159134
159349
|
isMemfsEnabledOnServer: () => isMemfsEnabledOnServer2,
|
|
159350
|
+
isLettaMemfsServer: () => isLettaMemfsServer2,
|
|
159135
159351
|
isLettaCloud: () => isLettaCloud2,
|
|
159136
159352
|
getMemorySystemDir: () => getMemorySystemDir2,
|
|
159137
159353
|
getMemoryFilesystemRoot: () => getMemoryFilesystemRoot2,
|
|
@@ -159319,8 +159535,8 @@ function renderMemoryFilesystemTree2(systemLabels, detachedLabels, options = {})
|
|
|
159319
159535
|
}
|
|
159320
159536
|
async function applyMemfsFlags2(agentId, memfsFlag, noMemfsFlag, options) {
|
|
159321
159537
|
const { settingsManager: settingsManager3 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
159322
|
-
if (memfsFlag && !await
|
|
159323
|
-
throw new Error(
|
|
159538
|
+
if (memfsFlag && !await isLettaMemfsServer2()) {
|
|
159539
|
+
throw new Error(await getMemfsSyncUnavailableMessage2());
|
|
159324
159540
|
}
|
|
159325
159541
|
const hasExplicitToggle = Boolean(memfsFlag || noMemfsFlag);
|
|
159326
159542
|
const localMemfsEnabled = settingsManager3.isMemfsEnabled(agentId);
|
|
@@ -159391,6 +159607,24 @@ async function isLettaCloud2() {
|
|
|
159391
159607
|
const serverUrl = getServerUrl2();
|
|
159392
159608
|
return serverUrl.includes("api.letta.com") || process.env.LETTA_MEMFS_LOCAL === "1" || process.env.LETTA_API_KEY === "local-desktop";
|
|
159393
159609
|
}
|
|
159610
|
+
function getServerHostLabel2(serverUrl) {
|
|
159611
|
+
const trimmed = serverUrl.trim();
|
|
159612
|
+
try {
|
|
159613
|
+
return new URL(trimmed).host || trimmed;
|
|
159614
|
+
} catch {
|
|
159615
|
+
return trimmed.replace(/^https?:\/\//, "").replace(/\/+$/, "") || trimmed;
|
|
159616
|
+
}
|
|
159617
|
+
}
|
|
159618
|
+
async function isLettaMemfsServer2() {
|
|
159619
|
+
const { getMemfsServerUrl: getMemfsServerUrl2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
159620
|
+
const memfsServerUrl = getMemfsServerUrl2();
|
|
159621
|
+
return memfsServerUrl.includes("api.letta.com") || process.env.LETTA_MEMFS_LOCAL === "1" || process.env.LETTA_API_KEY === "local-desktop";
|
|
159622
|
+
}
|
|
159623
|
+
async function getMemfsSyncUnavailableMessage2() {
|
|
159624
|
+
const { getMemfsServerUrl: getMemfsServerUrl2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
159625
|
+
const memfsServerUrl = getMemfsServerUrl2();
|
|
159626
|
+
return `MemFS sync failed (expected api.letta.com, got ${getServerHostLabel2(memfsServerUrl)})`;
|
|
159627
|
+
}
|
|
159394
159628
|
async function enableMemfsIfCloud2(agentId) {
|
|
159395
159629
|
if (!await isLettaCloud2())
|
|
159396
159630
|
return;
|
|
@@ -167844,6 +168078,12 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
167844
168078
|
}
|
|
167845
168079
|
const apiKey = process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY;
|
|
167846
168080
|
const baseURL = process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL2;
|
|
168081
|
+
if (isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !process.env.LETTA_API_KEY) {
|
|
168082
|
+
console.error("Missing LETTA_API_KEY");
|
|
168083
|
+
console.error("Headless mode requires an API key set via the LETTA_API_KEY environment variable.");
|
|
168084
|
+
console.error("Get an API key at https://app.letta.com/api-keys");
|
|
168085
|
+
process.exit(1);
|
|
168086
|
+
}
|
|
167847
168087
|
if (!isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !settings.refreshToken && !apiKey) {
|
|
167848
168088
|
const { runSetup: runSetup2 } = await init_setup4().then(() => exports_setup);
|
|
167849
168089
|
await runSetup2();
|
|
@@ -167859,11 +168099,6 @@ Error: ${message}`);
|
|
|
167859
168099
|
});
|
|
167860
168100
|
}
|
|
167861
168101
|
if (!apiKey && baseURL === LETTA_CLOUD_API_URL2) {
|
|
167862
|
-
if (isHeadless) {
|
|
167863
|
-
console.error("Missing LETTA_API_KEY");
|
|
167864
|
-
console.error("Run 'letta' in interactive mode to authenticate or export the missing environment variable");
|
|
167865
|
-
process.exit(1);
|
|
167866
|
-
}
|
|
167867
168102
|
console.log(`No credentials found. Let's get you set up!
|
|
167868
168103
|
`);
|
|
167869
168104
|
const { runSetup: runSetup2 } = await init_setup4().then(() => exports_setup);
|
|
@@ -168712,4 +168947,4 @@ Error during initialization: ${message}`);
|
|
|
168712
168947
|
}
|
|
168713
168948
|
main();
|
|
168714
168949
|
|
|
168715
|
-
//# debugId=
|
|
168950
|
+
//# debugId=00A382B05A86170664756E2164756E21
|
package/package.json
CHANGED
|
@@ -24,11 +24,12 @@ Below are additional common issues with context and how they can be resolved:
|
|
|
24
24
|
#### System prompt bloat
|
|
25
25
|
Memories compiled into the system prompt (contained in `system/`) should take up about 10% of the total context size (usually ~15-20K tokens). This is a soft target, not a hard requirement.
|
|
26
26
|
|
|
27
|
-
Use the
|
|
27
|
+
Use the built-in CLI to evaluate token usage of the system prompt:
|
|
28
28
|
```bash
|
|
29
|
-
|
|
29
|
+
letta memory tokens --format json --quiet
|
|
30
30
|
```
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
The command reports `total_tokens` and per-file estimates for `system/`. It is only a measurement tool; decide whether to intervene based on the actual context and the guidance below.
|
|
32
33
|
|
|
33
34
|
**Why detail is load-bearing (read this before cutting anything)**: In-context detail does more than carry information. It does at least four things, and byte-counting sweeps only see the first:
|
|
34
35
|
1. **Information** — the literal facts stated
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
/**
|
|
3
|
-
* Estimate token usage of system prompt memory files.
|
|
4
|
-
*
|
|
5
|
-
* Self-contained — no imports from the letta-code source tree.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* npx tsx estimate_system_tokens.ts --memory-dir "$MEMORY_DIR"
|
|
9
|
-
* npx tsx estimate_system_tokens.ts --memory-dir ~/.letta/agents/<id>/memory
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
13
|
-
import { join } from "node:path";
|
|
14
|
-
|
|
15
|
-
// Codex heuristic: ~4 bytes per token (codex-rs/core/src/truncate.rs APPROX_BYTES_PER_TOKEN = 4)
|
|
16
|
-
const BYTES_PER_TOKEN = 4;
|
|
17
|
-
|
|
18
|
-
function estimateTokens(text: string): number {
|
|
19
|
-
return Math.ceil(Buffer.byteLength(text, "utf8") / BYTES_PER_TOKEN);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
type FileEstimate = {
|
|
23
|
-
path: string;
|
|
24
|
-
tokens: number;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type ParsedArgs = {
|
|
28
|
-
memoryDir?: string;
|
|
29
|
-
top: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
function parseArgs(argv: string[]): ParsedArgs {
|
|
33
|
-
const parsed: ParsedArgs = { top: 20 };
|
|
34
|
-
|
|
35
|
-
for (let i = 0; i < argv.length; i++) {
|
|
36
|
-
const arg = argv[i];
|
|
37
|
-
if (arg === "--memory-dir") {
|
|
38
|
-
parsed.memoryDir = argv[i + 1];
|
|
39
|
-
i++;
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (arg === "--top") {
|
|
43
|
-
const raw = argv[i + 1];
|
|
44
|
-
const value = Number.parseInt(raw ?? "", 10);
|
|
45
|
-
if (!Number.isNaN(value) && value >= 0) {
|
|
46
|
-
parsed.top = value;
|
|
47
|
-
}
|
|
48
|
-
i++;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return parsed;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function normalizePath(value: string): string {
|
|
56
|
-
return value.replaceAll("\\", "/");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function walkMarkdownFiles(dir: string): string[] {
|
|
60
|
-
if (!existsSync(dir)) {
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const out: string[] = [];
|
|
65
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
66
|
-
|
|
67
|
-
for (const entry of entries) {
|
|
68
|
-
if (entry.name.startsWith(".")) {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
const full = join(dir, entry.name);
|
|
72
|
-
if (entry.isDirectory()) {
|
|
73
|
-
out.push(...walkMarkdownFiles(full));
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
77
|
-
out.push(full);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return out;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function formatNumber(value: number): string {
|
|
85
|
-
return value.toLocaleString("en-US");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function main(): number {
|
|
89
|
-
const args = parseArgs(process.argv.slice(2));
|
|
90
|
-
const memoryDir = args.memoryDir || process.env.MEMORY_DIR;
|
|
91
|
-
|
|
92
|
-
if (!memoryDir) {
|
|
93
|
-
console.error("Missing memory dir. Pass --memory-dir or set MEMORY_DIR.");
|
|
94
|
-
return 1;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const systemDir = join(memoryDir, "system");
|
|
98
|
-
if (!existsSync(systemDir)) {
|
|
99
|
-
console.error(`Missing system directory: ${systemDir}`);
|
|
100
|
-
return 1;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const files = walkMarkdownFiles(systemDir).sort();
|
|
104
|
-
const rows: FileEstimate[] = [];
|
|
105
|
-
|
|
106
|
-
for (const filePath of files) {
|
|
107
|
-
const text = readFileSync(filePath, "utf8");
|
|
108
|
-
const rel = normalizePath(filePath.slice(memoryDir.length + 1));
|
|
109
|
-
rows.push({ path: rel, tokens: estimateTokens(text) });
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const estimatedTotalTokens = rows.reduce((sum, row) => sum + row.tokens, 0);
|
|
113
|
-
|
|
114
|
-
console.log("Estimated total tokens");
|
|
115
|
-
console.log(` ${formatNumber(estimatedTotalTokens)}`);
|
|
116
|
-
|
|
117
|
-
console.log("\nPer-file token estimates");
|
|
118
|
-
console.log(` ${"tokens".padStart(8)} path`);
|
|
119
|
-
|
|
120
|
-
const sortedRows = [...rows].sort((a, b) => b.tokens - a.tokens);
|
|
121
|
-
for (const row of sortedRows.slice(0, Math.max(0, args.top))) {
|
|
122
|
-
console.log(` ${formatNumber(row.tokens).padStart(8)} ${row.path}`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return 0;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
process.exit(main());
|