@letta-ai/letta-code 0.27.23 → 0.27.25

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
@@ -4672,7 +4672,7 @@ var package_default;
4672
4672
  var init_package = __esm(() => {
4673
4673
  package_default = {
4674
4674
  name: "@letta-ai/letta-code",
4675
- version: "0.27.23",
4675
+ version: "0.27.25",
4676
4676
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
4677
4677
  type: "module",
4678
4678
  packageManager: "bun@1.3.0",
@@ -4769,6 +4769,7 @@ var init_package = __esm(() => {
4769
4769
  "check:filename-casing": "node scripts/check-filename-casing.js",
4770
4770
  "check:test-mock-isolation": "bun run scripts/check-test-mock-isolation.js",
4771
4771
  "check:test-coverage": "node scripts/check-test-coverage.cjs",
4772
+ "check:skill-frontmatter": "node scripts/check-skill-frontmatter.js",
4772
4773
  "check:bundled-skill-scripts": "node scripts/check-bundled-skill-scripts.js",
4773
4774
  check: "bun run scripts/check.js",
4774
4775
  dev: "node scripts/dev.cjs",
@@ -4909,7 +4910,7 @@ async function forkConversation(conversationId, options = {}) {
4909
4910
  ...options.agentId ? { agent_id: options.agentId } : {},
4910
4911
  ...options.hidden !== undefined ? { hidden: options.hidden } : {}
4911
4912
  };
4912
- return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/fork`, undefined, { query });
4913
+ return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/fork`, undefined, { query, ...options.headers ? { headers: options.headers } : {} });
4913
4914
  }
4914
4915
  async function updateConversationDescription(conversationId, body) {
4915
4916
  return apiRequest("PATCH", `/v1/conversations/${encodeURIComponent(conversationId)}`, body);
@@ -6533,11 +6534,13 @@ var init_skill_sources = __esm(() => {
6533
6534
  // src/agent/context.ts
6534
6535
  var exports_context = {};
6535
6536
  __export(exports_context, {
6537
+ setCurrentAgentName: () => setCurrentAgentName,
6536
6538
  setCurrentAgentId: () => setCurrentAgentId,
6537
6539
  setConversationId: () => setConversationId,
6538
6540
  setAgentContext: () => setAgentContext,
6539
6541
  getSkillsDirectory: () => getSkillsDirectory,
6540
6542
  getSkillSources: () => getSkillSources,
6543
+ getCurrentAgentName: () => getCurrentAgentName,
6541
6544
  getCurrentAgentId: () => getCurrentAgentId,
6542
6545
  getConversationId: () => getConversationId
6543
6546
  });
@@ -6546,6 +6549,7 @@ function getContext() {
6546
6549
  if (!global2[CONTEXT_KEY]) {
6547
6550
  global2[CONTEXT_KEY] = {
6548
6551
  agentId: null,
6552
+ agentName: null,
6549
6553
  skillsDirectory: null,
6550
6554
  skillSources: [...ALL_SKILL_SOURCES],
6551
6555
  conversationId: null
@@ -6553,24 +6557,43 @@ function getContext() {
6553
6557
  }
6554
6558
  return global2[CONTEXT_KEY];
6555
6559
  }
6556
- function setAgentContext(agentId, skillsDirectory, skillSources) {
6560
+ function setAgentContext(agentId, skillsDirectory, skillSources, agentName) {
6557
6561
  context.agentId = agentId;
6562
+ context.agentName = normalizeAgentName(agentName);
6558
6563
  context.skillsDirectory = skillsDirectory || null;
6559
6564
  context.skillSources = skillSources !== undefined ? [...skillSources] : [...ALL_SKILL_SOURCES];
6560
6565
  if (getRuntimeContext()) {
6561
6566
  updateRuntimeContext({
6562
6567
  agentId,
6568
+ agentName: context.agentName,
6563
6569
  skillsDirectory: skillsDirectory || null,
6564
6570
  skillSources: skillSources !== undefined ? [...skillSources] : [...ALL_SKILL_SOURCES]
6565
6571
  });
6566
6572
  }
6567
6573
  }
6568
6574
  function setCurrentAgentId(agentId) {
6575
+ const agentChanged = context.agentId !== agentId;
6569
6576
  context.agentId = agentId;
6577
+ if (agentId === null || agentChanged) {
6578
+ context.agentName = null;
6579
+ }
6570
6580
  if (getRuntimeContext()) {
6571
- updateRuntimeContext({ agentId });
6581
+ updateRuntimeContext({
6582
+ agentId,
6583
+ ...agentId === null || agentChanged ? { agentName: null } : {}
6584
+ });
6572
6585
  }
6573
6586
  }
6587
+ function setCurrentAgentName(agentName) {
6588
+ context.agentName = normalizeAgentName(agentName);
6589
+ if (getRuntimeContext()) {
6590
+ updateRuntimeContext({ agentName: context.agentName });
6591
+ }
6592
+ }
6593
+ function normalizeAgentName(agentName) {
6594
+ const trimmed = typeof agentName === "string" ? agentName.trim() : "";
6595
+ return trimmed || null;
6596
+ }
6574
6597
  function getCurrentAgentId() {
6575
6598
  const runtimeContext = getRuntimeContext();
6576
6599
  if (runtimeContext && "agentId" in runtimeContext) {
@@ -6584,6 +6607,14 @@ function getCurrentAgentId() {
6584
6607
  }
6585
6608
  return context.agentId;
6586
6609
  }
6610
+ function getCurrentAgentName() {
6611
+ const runtimeContext = getRuntimeContext();
6612
+ if (runtimeContext && "agentName" in runtimeContext) {
6613
+ const trimmed = runtimeContext.agentName?.trim();
6614
+ return trimmed || null;
6615
+ }
6616
+ return context.agentName;
6617
+ }
6587
6618
  function getSkillsDirectory() {
6588
6619
  const runtimeContext = getRuntimeContext();
6589
6620
  if (runtimeContext && "skillsDirectory" in runtimeContext) {
@@ -141240,6 +141271,10 @@ There are two ways to change memory:
141240
141271
  - **The \`memory\` tool (shorthand).** Use it for small, targeted edits. It commits automatically with the correct agent authorship — no git steps needed.
141241
141272
  - **Direct file edits (full control).** For larger changes — restructuring directories, rewriting several blocks — edit the projected files directly, then commit:
141242
141273
 
141274
+ Memory markdown files must start with YAML frontmatter containing a non-empty \`description:\` field. The \`memory\` and \`memory_apply_patch\` tools add and preserve this automatically; when using raw file edits, preserve existing frontmatter or add it before committing. The MemFS pre-commit hook enforces this requirement, rejects unknown keys, and prevents changes to protected \`read_only\` files. Skill \`SKILL.md\` files use their own skill frontmatter format.
141275
+
141276
+ \`$AGENT_NAME\` is normally populated when the runtime knows the current agent name, but direct shell environments can still miss it. Use a non-empty author name fallback when committing directly.
141277
+
141243
141278
  \`\`\`bash
141244
141279
  cd "$MEMORY_DIR"
141245
141280
 
@@ -141247,8 +141282,9 @@ cd "$MEMORY_DIR"
141247
141282
  git status
141248
141283
 
141249
141284
  # Commit your changes
141250
- git add .
141251
- git commit --author="$AGENT_NAME <$AGENT_ID@letta.com>" -m "<type>: <what changed>"
141285
+ git add <specific files>
141286
+ author_name="\${AGENT_NAME:-$AGENT_ID}"
141287
+ git commit --author="$author_name <$AGENT_ID@letta.com>" -m "<type>: <what changed>"
141252
141288
  \`\`\`
141253
141289
 
141254
141290
  Your context is git-tracked, so you can always inspect or revert past changes:
@@ -144697,7 +144733,8 @@ var init_models7 = __esm(() => {
144697
144733
  context_window: 140000,
144698
144734
  max_output_tokens: 28000,
144699
144735
  parallel_tool_calls: true
144700
- }
144736
+ },
144737
+ isFeatured: true
144701
144738
  },
144702
144739
  {
144703
144740
  id: "auto-chat",
@@ -144722,7 +144759,8 @@ var init_models7 = __esm(() => {
144722
144759
  context_window: 200000,
144723
144760
  max_output_tokens: 28000,
144724
144761
  parallel_tool_calls: true
144725
- }
144762
+ },
144763
+ isFeatured: true
144726
144764
  },
144727
144765
  {
144728
144766
  id: "fable",
@@ -144731,7 +144769,7 @@ var init_models7 = __esm(() => {
144731
144769
  description: "Fable 5 (high reasoning)",
144732
144770
  isFeatured: true,
144733
144771
  updateArgs: {
144734
- context_window: 1e6,
144772
+ context_window: 200000,
144735
144773
  max_output_tokens: 128000,
144736
144774
  enable_reasoner: true,
144737
144775
  reasoning_effort: "high",
@@ -144744,7 +144782,7 @@ var init_models7 = __esm(() => {
144744
144782
  label: "Fable 5",
144745
144783
  description: "Fable 5 (low reasoning)",
144746
144784
  updateArgs: {
144747
- context_window: 1e6,
144785
+ context_window: 200000,
144748
144786
  max_output_tokens: 128000,
144749
144787
  enable_reasoner: true,
144750
144788
  reasoning_effort: "low",
@@ -144758,7 +144796,7 @@ var init_models7 = __esm(() => {
144758
144796
  label: "Fable 5",
144759
144797
  description: "Fable 5 (med reasoning)",
144760
144798
  updateArgs: {
144761
- context_window: 1e6,
144799
+ context_window: 200000,
144762
144800
  max_output_tokens: 128000,
144763
144801
  enable_reasoner: true,
144764
144802
  reasoning_effort: "medium",
@@ -144772,7 +144810,7 @@ var init_models7 = __esm(() => {
144772
144810
  label: "Fable 5",
144773
144811
  description: "Fable 5 (extra-high reasoning)",
144774
144812
  updateArgs: {
144775
- context_window: 1e6,
144813
+ context_window: 200000,
144776
144814
  max_output_tokens: 128000,
144777
144815
  enable_reasoner: true,
144778
144816
  reasoning_effort: "xhigh",
@@ -144785,7 +144823,74 @@ var init_models7 = __esm(() => {
144785
144823
  label: "Fable 5",
144786
144824
  description: "Fable 5 (max reasoning)",
144787
144825
  updateArgs: {
144788
- context_window: 1e6,
144826
+ context_window: 200000,
144827
+ max_output_tokens: 128000,
144828
+ enable_reasoner: true,
144829
+ reasoning_effort: "max",
144830
+ parallel_tool_calls: true
144831
+ }
144832
+ },
144833
+ {
144834
+ id: "fable-1m",
144835
+ handle: "anthropic/claude-fable-5",
144836
+ label: "Fable 5 1M",
144837
+ description: "Claude Fable 5 with 1M token context window (high reasoning)",
144838
+ updateArgs: {
144839
+ context_window: 950000,
144840
+ max_output_tokens: 128000,
144841
+ enable_reasoner: true,
144842
+ reasoning_effort: "high",
144843
+ parallel_tool_calls: true
144844
+ }
144845
+ },
144846
+ {
144847
+ id: "fable-1m-low",
144848
+ handle: "anthropic/claude-fable-5",
144849
+ label: "Fable 5 1M",
144850
+ description: "Fable 5 1M (low reasoning)",
144851
+ updateArgs: {
144852
+ context_window: 950000,
144853
+ max_output_tokens: 128000,
144854
+ enable_reasoner: true,
144855
+ reasoning_effort: "low",
144856
+ max_reasoning_tokens: 4000,
144857
+ parallel_tool_calls: true
144858
+ }
144859
+ },
144860
+ {
144861
+ id: "fable-1m-medium",
144862
+ handle: "anthropic/claude-fable-5",
144863
+ label: "Fable 5 1M",
144864
+ description: "Fable 5 1M (med reasoning)",
144865
+ updateArgs: {
144866
+ context_window: 950000,
144867
+ max_output_tokens: 128000,
144868
+ enable_reasoner: true,
144869
+ reasoning_effort: "medium",
144870
+ max_reasoning_tokens: 12000,
144871
+ parallel_tool_calls: true
144872
+ }
144873
+ },
144874
+ {
144875
+ id: "fable-1m-xhigh",
144876
+ handle: "anthropic/claude-fable-5",
144877
+ label: "Fable 5 1M",
144878
+ description: "Fable 5 1M (extra-high reasoning)",
144879
+ updateArgs: {
144880
+ context_window: 950000,
144881
+ max_output_tokens: 128000,
144882
+ enable_reasoner: true,
144883
+ reasoning_effort: "xhigh",
144884
+ parallel_tool_calls: true
144885
+ }
144886
+ },
144887
+ {
144888
+ id: "fable-1m-max",
144889
+ handle: "anthropic/claude-fable-5",
144890
+ label: "Fable 5 1M",
144891
+ description: "Fable 5 1M (max reasoning)",
144892
+ updateArgs: {
144893
+ context_window: 950000,
144789
144894
  max_output_tokens: 128000,
144790
144895
  enable_reasoner: true,
144791
144896
  reasoning_effort: "max",
@@ -144884,8 +144989,7 @@ var init_models7 = __esm(() => {
144884
144989
  reasoning_effort: "high",
144885
144990
  enable_reasoner: true,
144886
144991
  parallel_tool_calls: true
144887
- },
144888
- isFeatured: true
144992
+ }
144889
144993
  },
144890
144994
  {
144891
144995
  id: "opus-4.8-1m-no-reasoning",
@@ -145148,7 +145252,6 @@ var init_models7 = __esm(() => {
145148
145252
  handle: "anthropic/claude-sonnet-4-6",
145149
145253
  label: "Sonnet 4.6 1M",
145150
145254
  description: "Claude Sonnet 4.6 with 1M token context window (high reasoning)",
145151
- isFeatured: true,
145152
145255
  updateArgs: {
145153
145256
  context_window: 9500000,
145154
145257
  max_output_tokens: 128000,
@@ -146030,7 +146133,6 @@ var init_models7 = __esm(() => {
146030
146133
  handle: "openai/gpt-5.4",
146031
146134
  label: "GPT-5.4",
146032
146135
  description: "OpenAI's most capable model (high reasoning)",
146033
- isFeatured: true,
146034
146136
  updateArgs: {
146035
146137
  reasoning_effort: "high",
146036
146138
  verbosity: "medium",
@@ -146187,7 +146289,6 @@ var init_models7 = __esm(() => {
146187
146289
  handle: "openai/gpt-5.4-mini",
146188
146290
  label: "GPT-5.4 Mini",
146189
146291
  description: "Fast, efficient GPT-5.4 variant (med reasoning)",
146190
- isFeatured: true,
146191
146292
  updateArgs: {
146192
146293
  reasoning_effort: "medium",
146193
146294
  verbosity: "low",
@@ -146400,7 +146501,8 @@ var init_models7 = __esm(() => {
146400
146501
  context_window: 1048576,
146401
146502
  max_output_tokens: 384000,
146402
146503
  parallel_tool_calls: true
146403
- }
146504
+ },
146505
+ isFeatured: true
146404
146506
  },
146405
146507
  {
146406
146508
  id: "glm-5.2",
@@ -146444,7 +146546,6 @@ var init_models7 = __esm(() => {
146444
146546
  handle: "minimax/MiniMax-M2.7",
146445
146547
  label: "MiniMax 2.7",
146446
146548
  description: "MiniMax's M2.7 coding model",
146447
- isFeatured: true,
146448
146549
  free: true,
146449
146550
  updateArgs: {
146450
146551
  context_window: 160000,
@@ -151819,12 +151920,14 @@ var init_commands = __esm(() => {
151819
151920
  import { randomUUID as randomUUID8 } from "node:crypto";
151820
151921
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile6 } from "node:fs/promises";
151821
151922
  import { basename as basename6, extname as extname3, join as join12 } from "node:path";
151822
- function mapSlackThreadMessage(message) {
151923
+ async function mapSlackThreadMessage(message, attachmentOptions) {
151924
+ const attachments = await resolveSlackMessageAttachments(message, attachmentOptions);
151823
151925
  return {
151824
151926
  text: resolveSlackThreadMessageText(message),
151825
151927
  userId: isNonEmptyString2(message.user) ? message.user : undefined,
151826
151928
  botId: isNonEmptyString2(message.bot_id) ? message.bot_id : undefined,
151827
- ts: isNonEmptyString2(message.ts) ? message.ts : undefined
151929
+ ts: isNonEmptyString2(message.ts) ? message.ts : undefined,
151930
+ ...attachments.length > 0 ? { attachments } : {}
151828
151931
  };
151829
151932
  }
151830
151933
  function asRecord(value) {
@@ -152128,12 +152231,11 @@ function collectSlackFiles(rawEvent) {
152128
152231
  }
152129
152232
  return Array.from(deduped.values()).slice(0, MAX_SLACK_ATTACHMENTS);
152130
152233
  }
152131
- async function resolveSlackInboundAttachments(params) {
152132
- const files = collectSlackFiles(params.rawEvent);
152133
- if (files.length === 0) {
152234
+ async function resolveSlackFilesAsAttachments(params) {
152235
+ if (params.files.length === 0) {
152134
152236
  return [];
152135
152237
  }
152136
- const resolved = await Promise.all(files.map((file3) => downloadSlackAttachment({
152238
+ const resolved = await Promise.all(params.files.map((file3) => downloadSlackAttachment({
152137
152239
  accountId: params.accountId,
152138
152240
  token: params.token,
152139
152241
  file: file3,
@@ -152141,6 +152243,44 @@ async function resolveSlackInboundAttachments(params) {
152141
152243
  }).catch(() => null)));
152142
152244
  return resolved.filter((attachment) => Boolean(attachment));
152143
152245
  }
152246
+ function resolveSlackThreadAttachmentOptions(params) {
152247
+ if (!isNonEmptyString2(params.accountId) || !isNonEmptyString2(params.token)) {
152248
+ return;
152249
+ }
152250
+ return {
152251
+ accountId: params.accountId,
152252
+ token: params.token,
152253
+ transcribeVoice: params.transcribeVoice
152254
+ };
152255
+ }
152256
+ function hasSlackThreadMessageContent(message, attachmentOptions) {
152257
+ if (resolveSlackThreadMessageText(message)) {
152258
+ return true;
152259
+ }
152260
+ return Boolean(attachmentOptions && collectSlackFiles(message).length > 0);
152261
+ }
152262
+ function hasHydratedSlackThreadMessageContent(message) {
152263
+ return message.text.length > 0 || Boolean(message.attachments?.length);
152264
+ }
152265
+ async function resolveSlackMessageAttachments(message, attachmentOptions) {
152266
+ if (!attachmentOptions) {
152267
+ return [];
152268
+ }
152269
+ return resolveSlackFilesAsAttachments({
152270
+ accountId: attachmentOptions.accountId,
152271
+ token: attachmentOptions.token,
152272
+ files: collectSlackFiles(message),
152273
+ transcribeVoice: attachmentOptions.transcribeVoice
152274
+ });
152275
+ }
152276
+ async function resolveSlackInboundAttachments(params) {
152277
+ return resolveSlackFilesAsAttachments({
152278
+ accountId: params.accountId,
152279
+ token: params.token,
152280
+ files: collectSlackFiles(params.rawEvent),
152281
+ transcribeVoice: params.transcribeVoice
152282
+ });
152283
+ }
152144
152284
  async function resolveSlackThreadStarter(params) {
152145
152285
  try {
152146
152286
  const response = await params.client.conversations.replies({
@@ -152153,16 +152293,12 @@ async function resolveSlackThreadStarter(params) {
152153
152293
  if (!message) {
152154
152294
  return null;
152155
152295
  }
152156
- const text = resolveSlackThreadMessageText(message);
152157
- if (!text) {
152296
+ const attachmentOptions = resolveSlackThreadAttachmentOptions(params);
152297
+ if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
152158
152298
  return null;
152159
152299
  }
152160
- return {
152161
- text,
152162
- userId: isNonEmptyString2(message.user) ? message.user : undefined,
152163
- botId: isNonEmptyString2(message.bot_id) ? message.bot_id : undefined,
152164
- ts: isNonEmptyString2(message.ts) ? message.ts : undefined
152165
- };
152300
+ const mapped3 = await mapSlackThreadMessage(message, attachmentOptions);
152301
+ return hasHydratedSlackThreadMessageContent(mapped3) ? mapped3 : null;
152166
152302
  } catch {
152167
152303
  return null;
152168
152304
  }
@@ -152174,6 +152310,7 @@ async function resolveSlackThreadHistory(params) {
152174
152310
  }
152175
152311
  const fetchLimit = 200;
152176
152312
  const retained = [];
152313
+ const attachmentOptions = resolveSlackThreadAttachmentOptions(params);
152177
152314
  let cursor;
152178
152315
  try {
152179
152316
  do {
@@ -152185,8 +152322,7 @@ async function resolveSlackThreadHistory(params) {
152185
152322
  ...cursor ? { cursor } : {}
152186
152323
  });
152187
152324
  for (const message of response.messages ?? []) {
152188
- const text = resolveSlackThreadMessageText(message);
152189
- if (!text) {
152325
+ if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
152190
152326
  continue;
152191
152327
  }
152192
152328
  if (params.currentMessageTs && message.ts === params.currentMessageTs) {
@@ -152203,7 +152339,8 @@ async function resolveSlackThreadHistory(params) {
152203
152339
  const nextCursor = response.response_metadata?.next_cursor;
152204
152340
  cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
152205
152341
  } while (cursor);
152206
- return retained.map(mapSlackThreadMessage);
152342
+ const mapped3 = await Promise.all(retained.map((message) => mapSlackThreadMessage(message, attachmentOptions)));
152343
+ return mapped3.filter(hasHydratedSlackThreadMessageContent);
152207
152344
  } catch {
152208
152345
  return [];
152209
152346
  }
@@ -152214,6 +152351,7 @@ async function resolveSlackChannelHistory(params) {
152214
152351
  return [];
152215
152352
  }
152216
152353
  const fetchLimit = Math.min(Math.max(maxMessages * 3, maxMessages), 100);
152354
+ const attachmentOptions = resolveSlackThreadAttachmentOptions(params);
152217
152355
  try {
152218
152356
  const response = await params.client.conversations.history({
152219
152357
  channel: params.channelId,
@@ -152225,9 +152363,10 @@ async function resolveSlackChannelHistory(params) {
152225
152363
  if (message.ts === params.beforeTs) {
152226
152364
  return false;
152227
152365
  }
152228
- return Boolean(resolveSlackThreadMessageText(message));
152366
+ return hasSlackThreadMessageContent(message, attachmentOptions);
152229
152367
  }).slice(0, fetchLimit).reverse();
152230
- return retained.slice(-maxMessages).map(mapSlackThreadMessage);
152368
+ const mapped3 = await Promise.all(retained.slice(-maxMessages).map((message) => mapSlackThreadMessage(message, attachmentOptions)));
152369
+ return mapped3.filter(hasHydratedSlackThreadMessageContent);
152231
152370
  } catch {
152232
152371
  return [];
152233
152372
  }
@@ -153193,22 +153332,30 @@ function createSlackAdapter(config3) {
153193
153332
  return msg;
153194
153333
  }
153195
153334
  const slackApp = await ensureApp();
153335
+ const threadAttachmentParams = {
153336
+ accountId: config3.accountId,
153337
+ token: config3.botToken,
153338
+ transcribeVoice: config3.transcribeVoice === true
153339
+ };
153196
153340
  const starter = shouldHydrateExistingThreadContext && isFirstRouteTurn ? await resolveSlackThreadStarter({
153197
153341
  channelId: msg.chatId,
153198
153342
  threadTs: msg.threadId,
153199
- client: slackApp.client
153343
+ client: slackApp.client,
153344
+ ...threadAttachmentParams
153200
153345
  }) : null;
153201
153346
  const resolvedHistory = shouldHydrateExistingThreadContext ? await resolveSlackThreadHistory({
153202
153347
  channelId: msg.chatId,
153203
153348
  threadTs: msg.threadId,
153204
153349
  client: slackApp.client,
153205
153350
  currentMessageTs: msg.messageId,
153206
- limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT
153351
+ limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT,
153352
+ ...threadAttachmentParams
153207
153353
  }) : await resolveSlackChannelHistory({
153208
153354
  channelId: msg.chatId,
153209
153355
  beforeTs: msg.messageId,
153210
153356
  client: slackApp.client,
153211
- limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT
153357
+ limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT,
153358
+ ...threadAttachmentParams
153212
153359
  });
153213
153360
  const history = shouldHydrateExistingThreadContext && !isFirstRouteTurn ? resolvedHistory.filter((entry) => isNonEmptyString3(entry.botId)) : resolvedHistory;
153214
153361
  if (!starter && history.length === 0) {
@@ -153244,7 +153391,8 @@ function createSlackAdapter(config3) {
153244
153391
  messageId: starter.ts,
153245
153392
  senderId: starter.userId ?? starter.botId,
153246
153393
  senderName: resolveThreadSenderName(starter.userId, starter.botId),
153247
- text: starter.text
153394
+ text: starter.text,
153395
+ ...starter.attachments?.length ? { attachments: starter.attachments } : {}
153248
153396
  }
153249
153397
  } : {},
153250
153398
  ...history.length > 0 ? {
@@ -153252,7 +153400,8 @@ function createSlackAdapter(config3) {
153252
153400
  messageId: entry.ts,
153253
153401
  senderId: entry.userId ?? entry.botId,
153254
153402
  senderName: resolveThreadSenderName(entry.userId, entry.botId),
153255
- text: entry.text
153403
+ text: entry.text,
153404
+ ...entry.attachments?.length ? { attachments: entry.attachments } : {}
153256
153405
  }))
153257
153406
  } : {}
153258
153407
  }
@@ -159822,6 +159971,15 @@ function escapeXmlText(text) {
159822
159971
  function escapeXmlAttribute(text) {
159823
159972
  return escapeXmlText(text).replace(/"/g, "&quot;").replace(/'/g, "&apos;");
159824
159973
  }
159974
+ function hasNotificationAttachmentPaths(msg) {
159975
+ if (msg.attachments?.length) {
159976
+ return true;
159977
+ }
159978
+ if (msg.threadContext?.starter?.attachments?.length) {
159979
+ return true;
159980
+ }
159981
+ return Boolean(msg.threadContext?.history?.some((entry) => entry.attachments?.length));
159982
+ }
159825
159983
  function buildChannelReminderText(msg) {
159826
159984
  const localTime = escapeXmlText(getLocalTime());
159827
159985
  const escapedChannel = escapeXmlText(msg.channel);
@@ -159857,7 +160015,7 @@ function buildChannelReminderText(msg) {
159857
160015
  if (msg.channel === "signal") {
159858
160016
  lines.splice(lines.length - 2, 0, 'On Signal, MessageChannel also supports action="react" with emoji + messageId, and action="upload-file" with media. Replies are sent as the linked Signal account through signal-cli-rest-api.');
159859
160017
  }
159860
- if (msg.attachments?.length) {
160018
+ if (hasNotificationAttachmentPaths(msg)) {
159861
160019
  lines.splice(lines.length - 2, 0, "If this notification includes attachment local_path values, you may be able to inspect those files using local file or image tools available in your current toolset (for example Read or ViewImage), using the local_path.");
159862
160020
  }
159863
160021
  return lines.join(`
@@ -159948,8 +160106,13 @@ function buildThreadContextEntryXml(tagName, entry) {
159948
160106
  attrs.push(`message_id="${escapeXmlAttribute(entry.messageId)}"`);
159949
160107
  }
159950
160108
  const attrString = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
160109
+ const body = [
160110
+ ...entry.text ? [escapeXmlText(entry.text)] : [],
160111
+ ...(entry.attachments ?? []).map(buildAttachmentXml)
160112
+ ].join(`
160113
+ `);
159951
160114
  return `<${tagName}${attrString}>
159952
- ${escapeXmlText(entry.text)}
160115
+ ${body}
159953
160116
  </${tagName}>`;
159954
160117
  }
159955
160118
  function buildThreadContextXml(msg) {
@@ -167949,6 +168112,10 @@ function getShellEnv() {
167949
168112
  if (agentId) {
167950
168113
  env3.LETTA_AGENT_ID = agentId;
167951
168114
  env3.AGENT_ID = agentId;
168115
+ const agentName = getCurrentAgentName()?.trim() || env3.AGENT_NAME?.trim();
168116
+ if (agentName) {
168117
+ env3.AGENT_NAME = agentName;
168118
+ }
167952
168119
  try {
167953
168120
  const localBackendNoMemfs = isLocalBackendMemfsDisabledForProcess();
167954
168121
  const localBackendEnabled = process.env.LETTA_LOCAL_BACKEND_EXPERIMENTAL === "1" || process.env.LETTA_LOCAL_BACKEND_EXPERIMENTAL?.toLowerCase() === "true";
@@ -363661,7 +363828,7 @@ function getMemoryGitIdentityEnvOverrides(command, workdir) {
363661
363828
  if (!scopedToMemoryDir) {
363662
363829
  return;
363663
363830
  }
363664
- const agentName = (process.env.AGENT_NAME || "").trim() || agentId;
363831
+ const agentName = getCurrentAgentNameOrEnv() || agentId;
363665
363832
  const agentEmail = `${agentId}@letta.com`;
363666
363833
  return {
363667
363834
  GIT_AUTHOR_NAME: agentName,
@@ -363679,6 +363846,14 @@ function getCurrentAgentIdOrEnv() {
363679
363846
  } catch {}
363680
363847
  return (process.env.LETTA_AGENT_ID || process.env.AGENT_ID || "").trim();
363681
363848
  }
363849
+ function getCurrentAgentNameOrEnv() {
363850
+ const scopedName = getCurrentAgentName()?.trim();
363851
+ if (scopedName) {
363852
+ return scopedName;
363853
+ }
363854
+ const envName = process.env.AGENT_NAME?.trim();
363855
+ return envName || null;
363856
+ }
363682
363857
  function containsGitCommitInvocation(command) {
363683
363858
  const segments = command.split(/&&|\|\||;|\|/).map((segment) => segment.trim()).filter(Boolean);
363684
363859
  for (const segment of segments) {
@@ -373739,6 +373914,7 @@ async function prepareToolExecutionContextForScope(params) {
373739
373914
  agent: agent2,
373740
373915
  runtimeContext: {
373741
373916
  agentId,
373917
+ agentName: agent2.name ?? null,
373742
373918
  conversationId: scopedConversationId,
373743
373919
  workingDirectory,
373744
373920
  ...channelToolScope.channels.length > 0 ? { channelToolScope } : {},
@@ -438900,6 +439076,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
438900
439076
  conversationId
438901
439077
  });
438902
439078
  setCurrentAgentId(agentId);
439079
+ setCurrentAgentName(listenAgentMetadata?.name ?? null);
438903
439080
  setConversationId(conversationId);
438904
439081
  if (isDebugEnabled()) {
438905
439082
  console.log(`[Listen] Handling message: agentId=${agentId}, requestedConversationId=${requestedConversationId}, conversationId=${conversationId}`);
@@ -438959,6 +439136,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
438959
439136
  lastRunAt: cachedAgent.last_run_completion ?? null
438960
439137
  };
438961
439138
  }
439139
+ setCurrentAgentName(listenAgentMetadata?.name ?? cachedAgent?.name ?? null);
438962
439140
  const { parts: reminderParts } = await buildSharedReminderParts(buildListenReminderContext({
438963
439141
  agentId: agentId || "",
438964
439142
  conversationId,
@@ -440884,6 +441062,15 @@ var init_file_commands = __esm(async () => {
440884
441062
  ignoreConfigCache = new Map;
440885
441063
  });
440886
441064
 
441065
+ // src/agent/acting-user.ts
441066
+ function actingUserRequestOptions(actingUserId) {
441067
+ if (!actingUserId) {
441068
+ return;
441069
+ }
441070
+ return { headers: { [ACTING_USER_ID_HEADER]: actingUserId } };
441071
+ }
441072
+ var ACTING_USER_ID_HEADER = "X-Letta-Acting-User-Id";
441073
+
440887
441074
  // src/agent/max-context.ts
440888
441075
  function buildModelHandleFromConfig4(config3) {
440889
441076
  if (!config3)
@@ -441286,10 +441473,15 @@ function buildDoctorMessage(args) {
441286
441473
  ## Memory filesystem
441287
441474
 
441288
441475
  Memory filesystem is enabled. Memory directory: \`${args.memoryDir}\`
441476
+ ` : "";
441477
+ const skillRepairSection = args.skillNameFrontmatterRepairReport ? `
441478
+ ## Automatic skill metadata repair
441479
+
441480
+ ${args.skillNameFrontmatterRepairReport}
441289
441481
  ` : "";
441290
441482
  return `${SYSTEM_REMINDER_OPEN}
441291
441483
  The user has requested a memory structure check via /doctor.
441292
- ${memfsSection}
441484
+ ${memfsSection}${skillRepairSection}
441293
441485
  ## 1. Invoke the context-doctor skill
441294
441486
 
441295
441487
  Use the \`Skill\` tool with \`skill: "context-doctor"\` to load guidance for memory structure refinement.
@@ -441307,6 +441499,150 @@ var init_init_command = __esm(() => {
441307
441499
  init_git_context();
441308
441500
  });
441309
441501
 
441502
+ // src/cli/helpers/skill-name-frontmatter-repair.ts
441503
+ import { readdir as readdir11, readFile as readFile18, stat as stat13, writeFile as writeFile14 } from "node:fs/promises";
441504
+ import { basename as basename23, dirname as dirname24, join as join48, relative as relative10 } from "node:path";
441505
+ async function pathExists(path36) {
441506
+ try {
441507
+ await stat13(path36);
441508
+ return true;
441509
+ } catch {
441510
+ return false;
441511
+ }
441512
+ }
441513
+ async function findSkillMarkdownFiles(root2) {
441514
+ const entries = await readdir11(root2, { withFileTypes: true });
441515
+ const files = [];
441516
+ for (const entry of entries) {
441517
+ if (entry.name === ".git" || entry.name === "node_modules") {
441518
+ continue;
441519
+ }
441520
+ const fullPath = join48(root2, entry.name);
441521
+ if (entry.isSymbolicLink()) {
441522
+ continue;
441523
+ }
441524
+ if (entry.isDirectory()) {
441525
+ files.push(...await findSkillMarkdownFiles(fullPath));
441526
+ continue;
441527
+ }
441528
+ if (entry.isFile() && entry.name === "SKILL.md") {
441529
+ files.push(fullPath);
441530
+ }
441531
+ }
441532
+ return files;
441533
+ }
441534
+ function formatYamlScalar(value) {
441535
+ if (/^[A-Za-z0-9_-]+$/.test(value)) {
441536
+ return value;
441537
+ }
441538
+ return JSON.stringify(value);
441539
+ }
441540
+ function isNonEmptyNameLine(line) {
441541
+ const match4 = line.match(/^\s*name\s*:\s*(.*?)\s*$/);
441542
+ return !!match4?.[1]?.trim();
441543
+ }
441544
+ function repairSkillNameFrontmatterContent(content, skillName) {
441545
+ if (!skillName.trim()) {
441546
+ return {
441547
+ content,
441548
+ changed: false,
441549
+ reason: "skill directory name is empty"
441550
+ };
441551
+ }
441552
+ const match4 = content.match(FRONTMATTER_REGEX2);
441553
+ if (!match4) {
441554
+ return {
441555
+ content,
441556
+ changed: false,
441557
+ reason: "missing YAML frontmatter"
441558
+ };
441559
+ }
441560
+ const opening2 = match4[1] ?? "";
441561
+ const frontmatter = match4[2] ?? "";
441562
+ const closing2 = match4[3] ?? "";
441563
+ const newline = opening2.includes(`\r
441564
+ `) ? `\r
441565
+ ` : `
441566
+ `;
441567
+ const lines = frontmatter.replace(/\r\n/g, `
441568
+ `).split(`
441569
+ `);
441570
+ const nameLineIndex = lines.findIndex((line) => /^\s*name\s*:/.test(line));
441571
+ if (nameLineIndex >= 0 && isNonEmptyNameLine(lines[nameLineIndex] ?? "")) {
441572
+ return { content, changed: false };
441573
+ }
441574
+ const nameLine = `name: ${formatYamlScalar(skillName.trim())}`;
441575
+ if (nameLineIndex >= 0) {
441576
+ lines[nameLineIndex] = nameLine;
441577
+ } else {
441578
+ lines.unshift(nameLine);
441579
+ }
441580
+ const nextContent = `${opening2}${lines.join(newline)}${closing2}${content.slice(match4[0].length)}`;
441581
+ return { content: nextContent, changed: true };
441582
+ }
441583
+ async function repairMissingSkillNameFrontmatter(memoryDir) {
441584
+ const result = {
441585
+ scanned: 0,
441586
+ repaired: [],
441587
+ skipped: []
441588
+ };
441589
+ if (!memoryDir) {
441590
+ return result;
441591
+ }
441592
+ const skillsDir = join48(memoryDir, "skills");
441593
+ if (!await pathExists(skillsDir)) {
441594
+ return result;
441595
+ }
441596
+ let skillFiles;
441597
+ try {
441598
+ skillFiles = await findSkillMarkdownFiles(skillsDir);
441599
+ } catch (error54) {
441600
+ result.skipped.push({
441601
+ path: "skills/",
441602
+ reason: `failed to scan skills directory: ${error54 instanceof Error ? error54.message : String(error54)}`
441603
+ });
441604
+ return result;
441605
+ }
441606
+ for (const skillFile of skillFiles.sort()) {
441607
+ const displayPath = relative10(memoryDir, skillFile).replace(/\\/g, "/");
441608
+ result.scanned++;
441609
+ try {
441610
+ const content = await readFile18(skillFile, "utf8");
441611
+ const repair3 = repairSkillNameFrontmatterContent(content, basename23(dirname24(skillFile)));
441612
+ if (repair3.reason) {
441613
+ result.skipped.push({ path: displayPath, reason: repair3.reason });
441614
+ continue;
441615
+ }
441616
+ if (!repair3.changed) {
441617
+ continue;
441618
+ }
441619
+ await writeFile14(skillFile, repair3.content, "utf8");
441620
+ result.repaired.push(displayPath);
441621
+ } catch (error54) {
441622
+ result.skipped.push({
441623
+ path: displayPath,
441624
+ reason: error54 instanceof Error ? error54.message : String(error54)
441625
+ });
441626
+ }
441627
+ }
441628
+ return result;
441629
+ }
441630
+ function formatSkillNameFrontmatterRepairReport(result) {
441631
+ const sections = [];
441632
+ if (result.repaired.length > 0) {
441633
+ sections.push(`- Added missing \`name:\` frontmatter to ${result.repaired.length} skill${result.repaired.length === 1 ? "" : "s"}: ${result.repaired.map((path36) => `\`${path36}\``).join(", ")}`);
441634
+ }
441635
+ if (result.skipped.length > 0) {
441636
+ sections.push(`- Could not automatically repair ${result.skipped.length} skill${result.skipped.length === 1 ? "" : "s"}: ${result.skipped.map((item) => `\`${item.path}\` (${item.reason})`).join(", ")}`);
441637
+ }
441638
+ return sections.join(`
441639
+ `);
441640
+ }
441641
+ var FRONTMATTER_REGEX2;
441642
+ var init_skill_name_frontmatter_repair = __esm(() => {
441643
+ FRONTMATTER_REGEX2 = /^(---\r?\n)([\s\S]*?)(\r?\n---(?:\r?\n|$))/;
441644
+ });
441645
+
441310
441646
  // src/websocket/listener/commands/secrets.ts
441311
441647
  function markSecretsReminderRefreshPending(runtime, agentId) {
441312
441648
  const prefix = `agent:${agentId}::conversation:`;
@@ -441411,7 +441747,10 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
441411
441747
  let output;
441412
441748
  switch (command.command_id) {
441413
441749
  case "clear":
441414
- output = await handleClearCommand(socket, conversationRuntime, opts);
441750
+ output = await handleClearCommand(socket, conversationRuntime, {
441751
+ ...opts,
441752
+ actingUserId: command.runtime.acting_user_id
441753
+ });
441415
441754
  break;
441416
441755
  case "doctor":
441417
441756
  output = await handleDoctorCommand(socket, conversationRuntime, opts);
@@ -441698,7 +442037,7 @@ async function handleClearCommand(_socket, conversationRuntime, opts) {
441698
442037
  }
441699
442038
  const conversation = await backend4.createConversation({
441700
442039
  agent_id: agentId
441701
- });
442040
+ }, actingUserRequestOptions(opts.actingUserId));
441702
442041
  clearConversationRuntimeState(conversationRuntime);
441703
442042
  conversationRuntime.conversationId = conversation.id;
441704
442043
  emitListenerStatus(conversationRuntime.listener, opts.onStatusChange, opts.connectionId);
@@ -441711,7 +442050,13 @@ async function handleDoctorCommand(socket, conversationRuntime, opts) {
441711
442050
  }
441712
442051
  const { context: gitContext } = gatherInitGitContext();
441713
442052
  const memoryDir = settingsManager.isMemfsEnabled(agentId) ? getScopedMemoryFilesystemRoot(agentId) : undefined;
441714
- const doctorMessage = buildDoctorMessage({ gitContext, memoryDir });
442053
+ const skillNameFrontmatterRepair = await repairMissingSkillNameFrontmatter(memoryDir);
442054
+ const skillNameFrontmatterRepairReport = formatSkillNameFrontmatterRepairReport(skillNameFrontmatterRepair);
442055
+ const doctorMessage = buildDoctorMessage({
442056
+ gitContext,
442057
+ memoryDir,
442058
+ skillNameFrontmatterRepairReport
442059
+ });
441715
442060
  await handleIncomingMessage({
441716
442061
  type: "message",
441717
442062
  agentId,
@@ -441898,6 +442243,7 @@ var init_commands2 = __esm(async () => {
441898
442243
  init_error_formatter();
441899
442244
  init_init_command();
441900
442245
  init_memory_reminder();
442246
+ init_skill_name_frontmatter_repair();
441901
442247
  init_command_runtime();
441902
442248
  init_constants();
441903
442249
  init_hooks2();
@@ -442088,7 +442434,7 @@ async function handleAgentConversationManagementCommand(parsed, socket, safeSock
442088
442434
  }
442089
442435
  if (parsed.type === "conversation_create") {
442090
442436
  try {
442091
- const conversation = await backend4.createConversation(parsed.body);
442437
+ const conversation = await backend4.createConversation(parsed.body, actingUserRequestOptions(parsed.acting_user_id));
442092
442438
  safeSocketSend(socket, {
442093
442439
  type: "conversation_create_response",
442094
442440
  request_id: parsed.request_id,
@@ -442150,7 +442496,8 @@ async function handleAgentConversationManagementCommand(parsed, socket, safeSock
442150
442496
  try {
442151
442497
  const conversation = await backend4.forkConversation(parsed.conversation_id, {
442152
442498
  ...typeof parsed.body?.agent_id === "string" ? { agentId: parsed.body.agent_id } : {},
442153
- ...typeof parsed.body?.hidden === "boolean" ? { hidden: parsed.body.hidden } : {}
442499
+ ...typeof parsed.body?.hidden === "boolean" ? { hidden: parsed.body.hidden } : {},
442500
+ ...actingUserRequestOptions(parsed.acting_user_id) ?? {}
442154
442501
  });
442155
442502
  safeSocketSend(socket, {
442156
442503
  type: "conversation_fork_response",
@@ -443606,7 +443953,7 @@ __export(exports_memory_scanner, {
443606
443953
  getFileNodes: () => getFileNodes
443607
443954
  });
443608
443955
  import { readdirSync as readdirSync15, readFileSync as readFileSync31, statSync as statSync16 } from "node:fs";
443609
- import { join as join48, relative as relative10 } from "node:path";
443956
+ import { join as join49, relative as relative11 } from "node:path";
443610
443957
  function scanMemoryFilesystem(memoryRoot) {
443611
443958
  const nodes = [];
443612
443959
  const scanDir = (dir, depth, parentIsLast) => {
@@ -443618,8 +443965,8 @@ function scanMemoryFilesystem(memoryRoot) {
443618
443965
  }
443619
443966
  const filtered = entries.filter((name) => !name.startsWith("."));
443620
443967
  const sorted = filtered.sort((a2, b3) => {
443621
- const aPath = join48(dir, a2);
443622
- const bPath = join48(dir, b3);
443968
+ const aPath = join49(dir, a2);
443969
+ const bPath = join49(dir, b3);
443623
443970
  let aIsDir = false;
443624
443971
  let bIsDir = false;
443625
443972
  try {
@@ -443639,14 +443986,14 @@ function scanMemoryFilesystem(memoryRoot) {
443639
443986
  return a2.localeCompare(b3);
443640
443987
  });
443641
443988
  sorted.forEach((name, index) => {
443642
- const fullPath = join48(dir, name);
443989
+ const fullPath = join49(dir, name);
443643
443990
  let isDir = false;
443644
443991
  try {
443645
443992
  isDir = statSync16(fullPath).isDirectory();
443646
443993
  } catch {
443647
443994
  return;
443648
443995
  }
443649
- const relativePath = relative10(memoryRoot, fullPath).replace(/\\/g, "/");
443996
+ const relativePath = relative11(memoryRoot, fullPath).replace(/\\/g, "/");
443650
443997
  const isLast = index === sorted.length - 1;
443651
443998
  nodes.push({
443652
443999
  name: isDir ? `${name}/` : name,
@@ -443711,9 +444058,9 @@ async function handleListMemoryCommand(parsed, socket, safeSocketSend, overrides
443711
444058
  const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memory_scanner(), exports_memory_scanner));
443712
444059
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
443713
444060
  const { existsSync: existsSync46, statSync: statSync17 } = await import("node:fs");
443714
- const { join: join49, posix: posix4 } = await import("node:path");
444061
+ const { join: join50, posix: posix4 } = await import("node:path");
443715
444062
  const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
443716
- let memfsInitialized = existsSync46(join49(memoryRoot, ".git"));
444063
+ let memfsInitialized = existsSync46(join50(memoryRoot, ".git"));
443717
444064
  const memfsEnabled = memfsInitialized ? true : await isMemfsEnabledOnServer2(parsed.agent_id);
443718
444065
  if (!memfsEnabled) {
443719
444066
  safeSocketSend(socket, {
@@ -443731,7 +444078,7 @@ async function handleListMemoryCommand(parsed, socket, safeSocketSend, overrides
443731
444078
  await ensureLocalMemfsCheckout2(parsed.agent_id, {
443732
444079
  pullOnExistingRepo: true
443733
444080
  });
443734
- memfsInitialized = existsSync46(join49(memoryRoot, ".git"));
444081
+ memfsInitialized = existsSync46(join50(memoryRoot, ".git"));
443735
444082
  if (!memfsInitialized) {
443736
444083
  throw new Error("MemFS is enabled, but the local memory checkout could not be initialized.");
443737
444084
  }
@@ -444030,33 +444377,33 @@ function handleMemoryProtocolCommand(parsed, context3) {
444030
444377
  ensureLocalMemfsCheckout: ensureLocalMemfsCheckout2,
444031
444378
  isMemfsEnabledOnServer: isMemfsEnabledOnServer2
444032
444379
  } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
444033
- const { readFile: readFile18 } = await import("node:fs/promises");
444380
+ const { readFile: readFile19 } = await import("node:fs/promises");
444034
444381
  const { existsSync: existsSync46 } = await import("node:fs");
444035
- const { isAbsolute: isAbsolute23, join: join49, normalize: normalize5, relative: relative11, sep: sep5 } = await import("node:path");
444382
+ const { isAbsolute: isAbsolute23, join: join50, normalize: normalize5, relative: relative12, sep: sep5 } = await import("node:path");
444036
444383
  if (isAbsolute23(parsed.path) || parsed.path.length === 0) {
444037
444384
  sendFailure("path must be a non-empty relative path");
444038
444385
  return;
444039
444386
  }
444040
444387
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
444041
- const absolutePath = normalize5(join49(memoryRoot, parsed.path));
444042
- const rel = relative11(memoryRoot, absolutePath);
444388
+ const absolutePath = normalize5(join50(memoryRoot, parsed.path));
444389
+ const rel = relative12(memoryRoot, absolutePath);
444043
444390
  if (rel.startsWith("..") || rel === "" || isAbsolute23(rel) || rel.split(sep5).includes("..")) {
444044
444391
  sendFailure("path must resolve inside the memory root");
444045
444392
  return;
444046
444393
  }
444047
- if (!existsSync46(join49(memoryRoot, ".git"))) {
444394
+ if (!existsSync46(join50(memoryRoot, ".git"))) {
444048
444395
  const enabled = await isMemfsEnabledOnServer2(parsed.agent_id);
444049
444396
  if (!enabled) {
444050
444397
  sendFailure("memfs is not enabled for this agent");
444051
444398
  return;
444052
444399
  }
444053
444400
  await ensureLocalMemfsCheckout2(parsed.agent_id);
444054
- if (!existsSync46(join49(memoryRoot, ".git"))) {
444401
+ if (!existsSync46(join50(memoryRoot, ".git"))) {
444055
444402
  sendFailure("failed to initialize local memory checkout");
444056
444403
  return;
444057
444404
  }
444058
444405
  }
444059
- const buffer = await readFile18(absolutePath);
444406
+ const buffer = await readFile19(absolutePath);
444060
444407
  const content = encoding === "base64" ? buffer.toString("base64") : buffer.toString("utf-8");
444061
444408
  const pathspec = rel.split(sep5).join("/");
444062
444409
  safeSocketSend(socket, {
@@ -444096,35 +444443,35 @@ function handleMemoryProtocolCommand(parsed, context3) {
444096
444443
  isMemfsEnabledOnServer: isMemfsEnabledOnServer2
444097
444444
  } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
444098
444445
  const { commitMemoryWrite: commitMemoryWrite2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
444099
- const { writeFile: writeFile14, mkdir: mkdir12 } = await import("node:fs/promises");
444446
+ const { writeFile: writeFile15, mkdir: mkdir12 } = await import("node:fs/promises");
444100
444447
  const { existsSync: existsSync46 } = await import("node:fs");
444101
- const { dirname: dirname24, isAbsolute: isAbsolute23, join: join49, normalize: normalize5, relative: relative11, sep: sep5 } = await import("node:path");
444448
+ const { dirname: dirname25, isAbsolute: isAbsolute23, join: join50, normalize: normalize5, relative: relative12, sep: sep5 } = await import("node:path");
444102
444449
  if (isAbsolute23(parsed.path) || parsed.path.length === 0) {
444103
444450
  sendFailure("write_memory_file: path must be a non-empty relative path");
444104
444451
  return;
444105
444452
  }
444106
444453
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
444107
- const absolutePath = normalize5(join49(memoryRoot, parsed.path));
444108
- const rel = relative11(memoryRoot, absolutePath);
444454
+ const absolutePath = normalize5(join50(memoryRoot, parsed.path));
444455
+ const rel = relative12(memoryRoot, absolutePath);
444109
444456
  if (rel.startsWith("..") || rel === "" || isAbsolute23(rel) || rel.split(sep5).includes("..")) {
444110
444457
  sendFailure("write_memory_file: path must resolve inside the memory root");
444111
444458
  return;
444112
444459
  }
444113
- if (!existsSync46(join49(memoryRoot, ".git"))) {
444460
+ if (!existsSync46(join50(memoryRoot, ".git"))) {
444114
444461
  const enabled = await isMemfsEnabledOnServer2(parsed.agent_id);
444115
444462
  if (!enabled) {
444116
444463
  sendFailure("write_memory_file: memfs is not enabled for this agent");
444117
444464
  return;
444118
444465
  }
444119
444466
  await ensureLocalMemfsCheckout2(parsed.agent_id);
444120
- if (!existsSync46(join49(memoryRoot, ".git"))) {
444467
+ if (!existsSync46(join50(memoryRoot, ".git"))) {
444121
444468
  sendFailure("write_memory_file: failed to initialize local memory checkout");
444122
444469
  return;
444123
444470
  }
444124
444471
  }
444125
444472
  const buffer = encoding === "base64" ? Buffer.from(parsed.content, "base64") : Buffer.from(parsed.content, "utf-8");
444126
- await mkdir12(dirname24(absolutePath), { recursive: true });
444127
- await writeFile14(absolutePath, buffer);
444473
+ await mkdir12(dirname25(absolutePath), { recursive: true });
444474
+ await writeFile15(absolutePath, buffer);
444128
444475
  const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
444129
444476
  const backend4 = getBackend2();
444130
444477
  const memorySyncMode = backend4.capabilities.localMemfs && !backend4.capabilities.remoteMemfs ? "local" : undefined;
@@ -444201,26 +444548,26 @@ function handleMemoryProtocolCommand(parsed, context3) {
444201
444548
  const { commitMemoryWrite: commitMemoryWrite2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
444202
444549
  const { unlink: unlink5 } = await import("node:fs/promises");
444203
444550
  const { existsSync: existsSync46 } = await import("node:fs");
444204
- const { isAbsolute: isAbsolute23, join: join49, normalize: normalize5, relative: relative11, sep: sep5 } = await import("node:path");
444551
+ const { isAbsolute: isAbsolute23, join: join50, normalize: normalize5, relative: relative12, sep: sep5 } = await import("node:path");
444205
444552
  if (isAbsolute23(parsed.path) || parsed.path.length === 0) {
444206
444553
  sendFailure("delete_memory_file: path must be a non-empty relative path");
444207
444554
  return;
444208
444555
  }
444209
444556
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
444210
- const absolutePath = normalize5(join49(memoryRoot, parsed.path));
444211
- const rel = relative11(memoryRoot, absolutePath);
444557
+ const absolutePath = normalize5(join50(memoryRoot, parsed.path));
444558
+ const rel = relative12(memoryRoot, absolutePath);
444212
444559
  if (rel.startsWith("..") || rel === "" || isAbsolute23(rel) || rel.split(sep5).includes("..")) {
444213
444560
  sendFailure("delete_memory_file: path must resolve inside the memory root");
444214
444561
  return;
444215
444562
  }
444216
- if (!existsSync46(join49(memoryRoot, ".git"))) {
444563
+ if (!existsSync46(join50(memoryRoot, ".git"))) {
444217
444564
  const enabled = await isMemfsEnabledOnServer2(parsed.agent_id);
444218
444565
  if (!enabled) {
444219
444566
  sendFailure("delete_memory_file: memfs is not enabled for this agent");
444220
444567
  return;
444221
444568
  }
444222
444569
  await ensureLocalMemfsCheckout2(parsed.agent_id);
444223
- if (!existsSync46(join49(memoryRoot, ".git"))) {
444570
+ if (!existsSync46(join50(memoryRoot, ".git"))) {
444224
444571
  sendFailure("delete_memory_file: failed to initialize local memory checkout");
444225
444572
  return;
444226
444573
  }
@@ -444640,9 +444987,9 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
444640
444987
  symlinkSync: symlinkSync2,
444641
444988
  unlinkSync: unlinkSync7
444642
444989
  } = await import("node:fs");
444643
- const { basename: basename23, join: join49 } = await import("node:path");
444644
- const lettaHome = process.env.LETTA_HOME || join49(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
444645
- const globalSkillsDir = join49(lettaHome, "skills");
444990
+ const { basename: basename24, join: join50 } = await import("node:path");
444991
+ const lettaHome = process.env.LETTA_HOME || join50(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
444992
+ const globalSkillsDir = join50(lettaHome, "skills");
444646
444993
  if (parsed.type === "skill_enable") {
444647
444994
  try {
444648
444995
  if (!existsSync46(parsed.skill_path)) {
@@ -444654,7 +445001,7 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
444654
445001
  }, "listener_skill_send_failed", "listener_skill_command");
444655
445002
  return true;
444656
445003
  }
444657
- const skillMdPath = join49(parsed.skill_path, "SKILL.md");
445004
+ const skillMdPath = join50(parsed.skill_path, "SKILL.md");
444658
445005
  if (!existsSync46(skillMdPath)) {
444659
445006
  safeSocketSend(socket, {
444660
445007
  type: "skill_enable_response",
@@ -444664,12 +445011,12 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
444664
445011
  }, "listener_skill_send_failed", "listener_skill_command");
444665
445012
  return true;
444666
445013
  }
444667
- const linkName = basename23(parsed.skill_path);
444668
- const linkPath = join49(globalSkillsDir, linkName);
445014
+ const linkName = basename24(parsed.skill_path);
445015
+ const linkPath = join50(globalSkillsDir, linkName);
444669
445016
  mkdirSync31(globalSkillsDir, { recursive: true });
444670
445017
  if (existsSync46(linkPath)) {
444671
- const stat13 = lstatSync3(linkPath);
444672
- if (stat13.isSymbolicLink()) {
445018
+ const stat14 = lstatSync3(linkPath);
445019
+ if (stat14.isSymbolicLink()) {
444673
445020
  if (process.platform === "win32") {
444674
445021
  rmdirSync(linkPath);
444675
445022
  } else {
@@ -444708,7 +445055,7 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
444708
445055
  }
444709
445056
  if (parsed.type === "skill_disable") {
444710
445057
  try {
444711
- const linkPath = join49(globalSkillsDir, parsed.name);
445058
+ const linkPath = join50(globalSkillsDir, parsed.name);
444712
445059
  if (!existsSync46(linkPath)) {
444713
445060
  safeSocketSend(socket, {
444714
445061
  type: "skill_disable_response",
@@ -444718,8 +445065,8 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
444718
445065
  }, "listener_skill_send_failed", "listener_skill_command");
444719
445066
  return true;
444720
445067
  }
444721
- const stat13 = lstatSync3(linkPath);
444722
- if (!stat13.isSymbolicLink()) {
445068
+ const stat14 = lstatSync3(linkPath);
445069
+ if (!stat14.isSymbolicLink()) {
444723
445070
  safeSocketSend(socket, {
444724
445071
  type: "skill_disable_response",
444725
445072
  request_id: parsed.request_id,
@@ -449652,7 +449999,7 @@ var init_listen_client = __esm(async () => {
449652
449999
 
449653
450000
  // src/backend/local/transcript-search.ts
449654
450001
  import { existsSync as existsSync49, readdirSync as readdirSync18, readFileSync as readFileSync33, statSync as statSync18 } from "node:fs";
449655
- import { join as join52 } from "node:path";
450002
+ import { join as join53 } from "node:path";
449656
450003
  function readJsonFile3(path37) {
449657
450004
  if (!existsSync49(path37))
449658
450005
  return;
@@ -449873,11 +450220,11 @@ function collectConversationMessages(input) {
449873
450220
  return [];
449874
450221
  if (input.conversationId && conversation.id !== input.conversationId)
449875
450222
  return [];
449876
- const messagesPath = join52(conversationDir, "messages.jsonl");
450223
+ const messagesPath = join53(conversationDir, "messages.jsonl");
449877
450224
  const rows = readJsonlFile2(messagesPath);
449878
450225
  if (rows.length === 0)
449879
450226
  return [];
449880
- const manifest2 = readJsonFile3(join52(conversationDir, "manifest.json"));
450227
+ const manifest2 = readJsonFile3(join53(conversationDir, "manifest.json"));
449881
450228
  const format5 = transcriptFormat(manifest2, rows);
449882
450229
  if (!format5)
449883
450230
  return [];
@@ -449898,11 +450245,11 @@ function collectConversationMessages(input) {
449898
450245
  });
449899
450246
  }
449900
450247
  function conversationDirectories(storageDir) {
449901
- const conversationsDir = join52(storageDir, "conversations");
450248
+ const conversationsDir = join53(storageDir, "conversations");
449902
450249
  if (!existsSync49(conversationsDir))
449903
450250
  return [];
449904
450251
  try {
449905
- return readdirSync18(conversationsDir).map((entry) => join52(conversationsDir, entry)).filter((entryPath) => statSync18(entryPath).isDirectory());
450252
+ return readdirSync18(conversationsDir).map((entry) => join53(conversationsDir, entry)).filter((entryPath) => statSync18(entryPath).isDirectory());
449906
450253
  } catch {
449907
450254
  return [];
449908
450255
  }
@@ -449926,7 +450273,7 @@ function searchLocalTranscriptMessages(storageDir, body3) {
449926
450273
  const endDate = typeof body3.end_date === "string" ? body3.end_date : undefined;
449927
450274
  const includeHidden = body3.include_hidden === true;
449928
450275
  const records = conversationDirectories(storageDir).flatMap((conversationDir) => {
449929
- const conversation = conversationSearchRecord(readJsonFile3(join52(conversationDir, "conversation.json")));
450276
+ const conversation = conversationSearchRecord(readJsonFile3(join53(conversationDir, "conversation.json")));
449930
450277
  if (!conversation)
449931
450278
  return [];
449932
450279
  if (conversation.hidden && !includeHidden)
@@ -451805,7 +452152,7 @@ import {
451805
452152
  unlinkSync as unlinkSync8
451806
452153
  } from "node:fs";
451807
452154
  import { homedir as homedir32 } from "node:os";
451808
- import { join as join56 } from "node:path";
452155
+ import { join as join57 } from "node:path";
451809
452156
  import { format as format5 } from "node:util";
451810
452157
  function isDebugEnabled2() {
451811
452158
  const lettaDebug = process.env.LETTA_DEBUG;
@@ -451836,8 +452183,8 @@ class DebugLogFile2 {
451836
452183
  const telem = process.env.LETTA_CODE_TELEM;
451837
452184
  if (telem === "0" || telem === "false")
451838
452185
  return;
451839
- this.agentDir = join56(DEBUG_LOG_DIR2, agentId);
451840
- this.logPath = join56(this.agentDir, `${sessionId}.log`);
452186
+ this.agentDir = join57(DEBUG_LOG_DIR2, agentId);
452187
+ this.logPath = join57(this.agentDir, `${sessionId}.log`);
451841
452188
  this.dirCreated = false;
451842
452189
  this.pruneOldSessions();
451843
452190
  }
@@ -451885,7 +452232,7 @@ class DebugLogFile2 {
451885
452232
  const toDelete = files.slice(0, files.length - MAX_SESSION_FILES3 + 1);
451886
452233
  for (const file3 of toDelete) {
451887
452234
  try {
451888
- unlinkSync8(join56(this.agentDir, file3));
452235
+ unlinkSync8(join57(this.agentDir, file3));
451889
452236
  } catch {}
451890
452237
  }
451891
452238
  }
@@ -451910,7 +452257,7 @@ function debugWarn2(prefix, message, ...args) {
451910
452257
  }
451911
452258
  var DEBUG_LOG_DIR2, MAX_SESSION_FILES3 = 5, DEFAULT_TAIL_LINES2 = 50, debugLogFile2;
451912
452259
  var init_debug2 = __esm(() => {
451913
- DEBUG_LOG_DIR2 = join56(homedir32(), ".letta", "logs", "debug");
452260
+ DEBUG_LOG_DIR2 = join57(homedir32(), ".letta", "logs", "debug");
451914
452261
  debugLogFile2 = new DebugLogFile2;
451915
452262
  });
451916
452263
 
@@ -451945,15 +452292,15 @@ __export(exports_skills3, {
451945
452292
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
451946
452293
  });
451947
452294
  import { existsSync as existsSync54 } from "node:fs";
451948
- import { readdir as readdir13, readFile as readFile18, realpath as realpath5, stat as stat13 } from "node:fs/promises";
451949
- import { dirname as dirname27, join as join57 } from "node:path";
452295
+ import { readdir as readdir14, readFile as readFile19, realpath as realpath5, stat as stat14 } from "node:fs/promises";
452296
+ import { dirname as dirname28, join as join58 } from "node:path";
451950
452297
  import { fileURLToPath as fileURLToPath8 } from "node:url";
451951
452298
  function getBundledSkillsPath2() {
451952
- const thisDir = dirname27(fileURLToPath8(import.meta.url));
452299
+ const thisDir = dirname28(fileURLToPath8(import.meta.url));
451953
452300
  if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
451954
- return join57(thisDir, "../skills/builtin");
452301
+ return join58(thisDir, "../skills/builtin");
451955
452302
  }
451956
- return join57(thisDir, "skills");
452303
+ return join58(thisDir, "skills");
451957
452304
  }
451958
452305
  function compareSkills2(a2, b3) {
451959
452306
  return a2.id.localeCompare(b3.id) || a2.source.localeCompare(b3.source) || a2.path.localeCompare(b3.path);
@@ -452000,7 +452347,7 @@ function isSkillAvailableForAgent2(skill2, agentId) {
452000
452347
  return true;
452001
452348
  }
452002
452349
  function getAgentSkillsDir2(agentId) {
452003
- return join57(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "memory/skills");
452350
+ return join58(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "memory/skills");
452004
452351
  }
452005
452352
  async function getBundledSkills2() {
452006
452353
  const bundledPath = getBundledSkillsPath2();
@@ -452023,7 +452370,7 @@ async function discoverSkillsFromDir2(skillsPath, source2) {
452023
452370
  }
452024
452371
  return { skills, errors: errors7 };
452025
452372
  }
452026
- async function discoverSkills2(projectSkillsPath = join57(process.cwd(), SKILLS_DIR2), agentId, options3) {
452373
+ async function discoverSkills2(projectSkillsPath = join58(process.cwd(), SKILLS_DIR2), agentId, options3) {
452027
452374
  const allErrors = [];
452028
452375
  const skillsById = new Map;
452029
452376
  const sourceSet = new Set(options3?.sources ?? ALL_SKILL_SOURCES);
@@ -452076,14 +452423,14 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors7, source2,
452076
452423
  return;
452077
452424
  }
452078
452425
  try {
452079
- const entries = await readdir13(currentPath, { withFileTypes: true });
452426
+ const entries = await readdir14(currentPath, { withFileTypes: true });
452080
452427
  for (const entry of entries) {
452081
- const fullPath = join57(currentPath, entry.name);
452428
+ const fullPath = join58(currentPath, entry.name);
452082
452429
  try {
452083
452430
  let isDirectory = entry.isDirectory();
452084
452431
  let isFile = entry.isFile();
452085
452432
  if (entry.isSymbolicLink()) {
452086
- const entryStat = await stat13(fullPath);
452433
+ const entryStat = await stat14(fullPath);
452087
452434
  isDirectory = entryStat.isDirectory();
452088
452435
  isFile = entryStat.isFile();
452089
452436
  }
@@ -452117,7 +452464,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors7, source2,
452117
452464
  }
452118
452465
  }
452119
452466
  async function parseSkillFile2(filePath, rootPath, source2) {
452120
- const content = await readFile18(filePath, "utf-8");
452467
+ const content = await readFile19(filePath, "utf-8");
452121
452468
  const { frontmatter, body: body3 } = parseFrontmatter(content);
452122
452469
  const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
452123
452470
  const relativePath = filePath.slice(normalizedRoot.length + 1);
@@ -452169,17 +452516,17 @@ var LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS2, PROJECT_SKILLS_DIR2, SKILLS_DIR2 = ".s
452169
452516
  var init_skills4 = __esm(() => {
452170
452517
  init_skill_sources();
452171
452518
  LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS2 = new Set(["image-generation"]);
452172
- PROJECT_SKILLS_DIR2 = join57(".agents", "skills");
452173
- GLOBAL_SKILLS_DIR2 = join57(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
452519
+ PROJECT_SKILLS_DIR2 = join58(".agents", "skills");
452520
+ GLOBAL_SKILLS_DIR2 = join58(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
452174
452521
  });
452175
452522
 
452176
452523
  // src/utils/fs.ts
452177
452524
  var exports_fs = {};
452178
452525
  __export(exports_fs, {
452179
452526
  writeJsonFile: () => writeJsonFile2,
452180
- writeFile: () => writeFile15,
452527
+ writeFile: () => writeFile16,
452181
452528
  readJsonFile: () => readJsonFile4,
452182
- readFile: () => readFile19,
452529
+ readFile: () => readFile20,
452183
452530
  mkdir: () => mkdir13,
452184
452531
  exists: () => exists2
452185
452532
  });
@@ -452189,12 +452536,12 @@ import {
452189
452536
  writeFileSync as fsWriteFileSync2,
452190
452537
  mkdirSync as mkdirSync37
452191
452538
  } from "node:fs";
452192
- import { dirname as dirname28 } from "node:path";
452193
- async function readFile19(path39) {
452539
+ import { dirname as dirname29 } from "node:path";
452540
+ async function readFile20(path39) {
452194
452541
  return fsReadFileSync2(path39, { encoding: "utf-8" });
452195
452542
  }
452196
- async function writeFile15(path39, content) {
452197
- const dir = dirname28(path39);
452543
+ async function writeFile16(path39, content) {
452544
+ const dir = dirname29(path39);
452198
452545
  if (!existsSync55(dir)) {
452199
452546
  mkdirSync37(dir, { recursive: true });
452200
452547
  }
@@ -452207,14 +452554,14 @@ async function mkdir13(path39, options3) {
452207
452554
  mkdirSync37(path39, options3);
452208
452555
  }
452209
452556
  async function readJsonFile4(path39) {
452210
- const text2 = await readFile19(path39);
452557
+ const text2 = await readFile20(path39);
452211
452558
  return JSON.parse(text2);
452212
452559
  }
452213
452560
  async function writeJsonFile2(path39, data, options3) {
452214
452561
  const indent = options3?.indent ?? 2;
452215
452562
  const content = `${JSON.stringify(data, null, indent)}
452216
452563
  `;
452217
- await writeFile15(path39, content);
452564
+ await writeFile16(path39, content);
452218
452565
  }
452219
452566
  var init_fs2 = () => {};
452220
452567
 
@@ -452413,8 +452760,8 @@ import {
452413
452760
  execFile as execFile16
452414
452761
  } from "node:child_process";
452415
452762
  import { accessSync as accessSync2, constants as constants4, realpathSync as realpathSync6 } from "node:fs";
452416
- import { readdir as readdir14, rm as rm5 } from "node:fs/promises";
452417
- import { dirname as dirname29, join as join58 } from "node:path";
452763
+ import { readdir as readdir15, rm as rm5 } from "node:fs/promises";
452764
+ import { dirname as dirname30, join as join59 } from "node:path";
452418
452765
  import { promisify as promisify14 } from "node:util";
452419
452766
  function debugLog4(...args) {
452420
452767
  if (DEBUG2) {
@@ -452489,7 +452836,7 @@ function getResolvedEntrypoint2() {
452489
452836
  }
452490
452837
  }
452491
452838
  function findInstalledPackagePath2(resolvedPath) {
452492
- const marker = `${join58("node_modules", "@letta-ai", "letta-code")}`;
452839
+ const marker = `${join59("node_modules", "@letta-ai", "letta-code")}`;
452493
452840
  const index = resolvedPath.lastIndexOf(marker);
452494
452841
  if (index === -1) {
452495
452842
  return null;
@@ -452528,7 +452875,7 @@ function getSelfUpdateStatus2() {
452528
452875
  manual_command: manualCommand
452529
452876
  };
452530
452877
  }
452531
- const packageParentPath = dirname29(installPath);
452878
+ const packageParentPath = dirname30(installPath);
452532
452879
  const writable = canWritePath2(installPath) && canWritePath2(packageParentPath);
452533
452880
  return {
452534
452881
  supported: true,
@@ -452638,12 +452985,12 @@ async function getNpmGlobalPath2() {
452638
452985
  }
452639
452986
  }
452640
452987
  async function cleanupOrphanedDirs2(globalPath) {
452641
- const lettaAiDir = join58(globalPath, "lib/node_modules/@letta-ai");
452988
+ const lettaAiDir = join59(globalPath, "lib/node_modules/@letta-ai");
452642
452989
  try {
452643
- const entries = await readdir14(lettaAiDir);
452990
+ const entries = await readdir15(lettaAiDir);
452644
452991
  for (const entry of entries) {
452645
452992
  if (entry.startsWith(".letta-code-")) {
452646
- const orphanPath = join58(lettaAiDir, entry);
452993
+ const orphanPath = join59(lettaAiDir, entry);
452647
452994
  debugLog4("Cleaning orphaned temp directory:", orphanPath);
452648
452995
  await rm5(orphanPath, { recursive: true, force: true });
452649
452996
  }
@@ -453175,7 +453522,7 @@ __export(exports_bootstrap_tools, {
453175
453522
  });
453176
453523
  import { existsSync as existsSync57, mkdirSync as mkdirSync39, writeFileSync as writeFileSync28 } from "node:fs";
453177
453524
  import { homedir as homedir34 } from "node:os";
453178
- import { join as join60 } from "node:path";
453525
+ import { join as join61 } from "node:path";
453179
453526
  async function bootstrapBaseToolsIfNeeded() {
453180
453527
  if (existsSync57(MARKER_PATH))
453181
453528
  return;
@@ -453183,7 +453530,7 @@ async function bootstrapBaseToolsIfNeeded() {
453183
453530
  try {
453184
453531
  const success2 = await addBaseToolsToServer();
453185
453532
  if (success2) {
453186
- mkdirSync39(join60(homedir34(), ".letta"), { recursive: true });
453533
+ mkdirSync39(join61(homedir34(), ".letta"), { recursive: true });
453187
453534
  writeFileSync28(MARKER_PATH, new Date().toISOString(), "utf-8");
453188
453535
  }
453189
453536
  } catch (err) {
@@ -453194,7 +453541,7 @@ var MARKER_PATH;
453194
453541
  var init_bootstrap_tools = __esm(() => {
453195
453542
  init_debug();
453196
453543
  init_create6();
453197
- MARKER_PATH = join60(homedir34(), ".letta", ".bootstrapped");
453544
+ MARKER_PATH = join61(homedir34(), ".letta", ".bootstrapped");
453198
453545
  });
453199
453546
 
453200
453547
  // src/tools/filter.ts
@@ -453637,7 +453984,7 @@ function validateRegistryHandleOrThrow2(handle2) {
453637
453984
  }
453638
453985
 
453639
453986
  // src/headless-mod-adapter.ts
453640
- import { join as join61 } from "node:path";
453987
+ import { join as join62 } from "node:path";
453641
453988
  function isHeadlessMemfsEnabled(agentId) {
453642
453989
  try {
453643
453990
  return settingsManager.isMemfsEnabled(agentId);
@@ -453708,7 +454055,7 @@ function createHeadlessModContext(options3) {
453708
454055
  };
453709
454056
  }
453710
454057
  function createHeadlessModAdapter(options3) {
453711
- const agentModsDirectory = isHeadlessMemfsEnabled(options3.agent.id) ? join61(getScopedMemoryFilesystemRoot(options3.agent.id), "mods") : undefined;
454058
+ const agentModsDirectory = isHeadlessMemfsEnabled(options3.agent.id) ? join62(getScopedMemoryFilesystemRoot(options3.agent.id), "mods") : undefined;
453712
454059
  return createModAdapter({
453713
454060
  ...agentModsDirectory ? { agentModsDirectory } : {},
453714
454061
  ...options3.cacheDirectory ? { cacheDirectory: options3.cacheDirectory } : {},
@@ -453793,7 +454140,7 @@ async function writeWireMessageAsync(msg) {
453793
454140
 
453794
454141
  // src/skills/builtin/creating-skills/scripts/validate-skill.ts
453795
454142
  import { existsSync as existsSync58, readFileSync as readFileSync38 } from "node:fs";
453796
- import { basename as basename24, join as join62, resolve as resolve34 } from "node:path";
454143
+ import { basename as basename25, join as join63, resolve as resolve34 } from "node:path";
453797
454144
  import { fileURLToPath as fileURLToPath9 } from "node:url";
453798
454145
  function parseQuotedScalar(value) {
453799
454146
  if (value.startsWith('"')) {
@@ -453890,7 +454237,7 @@ function parseFrontmatter2(source2) {
453890
454237
  return parseFrontmatterFallback(source2);
453891
454238
  }
453892
454239
  function validateSkill(skillPath) {
453893
- const skillMdPath = join62(skillPath, "SKILL.md");
454240
+ const skillMdPath = join63(skillPath, "SKILL.md");
453894
454241
  if (!existsSync58(skillMdPath)) {
453895
454242
  return { valid: false, message: "SKILL.md not found" };
453896
454243
  }
@@ -453953,7 +454300,7 @@ function validateSkill(skillPath) {
453953
454300
  message: `Name is too long (${trimmedName.length} characters). Maximum is ${MAX_SKILL_NAME_LENGTH} characters.`
453954
454301
  };
453955
454302
  }
453956
- const dirName = basename24(skillPath);
454303
+ const dirName = basename25(skillPath);
453957
454304
  if (trimmedName !== dirName) {
453958
454305
  warnings.push(`Name '${trimmedName}' doesn't match directory name '${dirName}'. For portability, these should match.`);
453959
454306
  }
@@ -454057,8 +454404,8 @@ __export(exports_import, {
454057
454404
  extractSkillsFromAf: () => extractSkillsFromAf
454058
454405
  });
454059
454406
  import { createReadStream as createReadStream2 } from "node:fs";
454060
- import { access as access2, chmod, mkdir as mkdir14, readFile as readFile20, writeFile as writeFile16 } from "node:fs/promises";
454061
- import { dirname as dirname30, isAbsolute as isAbsolute24, relative as relative11, resolve as resolve35, sep as sep6, win32 as win325 } from "node:path";
454407
+ import { access as access2, chmod, mkdir as mkdir14, readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
454408
+ import { dirname as dirname31, isAbsolute as isAbsolute24, relative as relative12, resolve as resolve35, sep as sep6, win32 as win325 } from "node:path";
454062
454409
  function validateImportedSkillName(name) {
454063
454410
  const trimmedName = name.trim();
454064
454411
  if (trimmedName !== name || trimmedName.length === 0 || trimmedName.length > MAX_SKILL_NAME_LENGTH || trimmedName === "." || trimmedName === ".." || !IMPORTED_SKILL_NAME_PATTERN.test(trimmedName)) {
@@ -454069,7 +454416,7 @@ function validateImportedSkillName(name) {
454069
454416
  function assertPathInside(parent, child) {
454070
454417
  const parentPath = resolve35(parent);
454071
454418
  const childPath = resolve35(child);
454072
- const relativePath = relative11(parentPath, childPath);
454419
+ const relativePath = relative12(parentPath, childPath);
454073
454420
  if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep6}`) || isAbsolute24(relativePath)) {
454074
454421
  throw new Error(`Imported skill file path escapes skill directory: ${child}`);
454075
454422
  }
@@ -454158,7 +454505,7 @@ async function importAgentFromFile(options3) {
454158
454505
  }
454159
454506
  async function extractSkillsFromAf(afPath, destDir) {
454160
454507
  const extracted = [];
454161
- const content = await readFile20(afPath, "utf-8");
454508
+ const content = await readFile21(afPath, "utf-8");
454162
454509
  const afData = JSON.parse(content);
454163
454510
  if (!afData.skills || !Array.isArray(afData.skills)) {
454164
454511
  return [];
@@ -454186,8 +454533,8 @@ async function writeSkillFiles(skillDir, files) {
454186
454533
  }
454187
454534
  async function writeSkillFile(skillDir, filePath, content) {
454188
454535
  const fullPath = resolveImportedSkillFilePath(skillDir, filePath);
454189
- await mkdir14(dirname30(fullPath), { recursive: true });
454190
- await writeFile16(fullPath, content, "utf-8");
454536
+ await mkdir14(dirname31(fullPath), { recursive: true });
454537
+ await writeFile17(fullPath, content, "utf-8");
454191
454538
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
454192
454539
  if (isScript) {
454193
454540
  try {
@@ -454239,8 +454586,8 @@ function parseRegistryHandle(handle2) {
454239
454586
  }
454240
454587
  async function importAgentFromRegistry(options3) {
454241
454588
  const { tmpdir: tmpdir10 } = await import("node:os");
454242
- const { join: join63 } = await import("node:path");
454243
- const { writeFile: writeFile17, unlink: unlink5 } = await import("node:fs/promises");
454589
+ const { join: join64 } = await import("node:path");
454590
+ const { writeFile: writeFile18, unlink: unlink5 } = await import("node:fs/promises");
454244
454591
  const { author, name } = parseRegistryHandle(options3.handle);
454245
454592
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
454246
454593
  const response = await fetch(rawUrl);
@@ -454251,8 +454598,8 @@ async function importAgentFromRegistry(options3) {
454251
454598
  throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
454252
454599
  }
454253
454600
  const afContent = await response.text();
454254
- const tempPath = join63(tmpdir10(), `letta-import-${author}-${name}-${Date.now()}.af`);
454255
- await writeFile17(tempPath, afContent, "utf-8");
454601
+ const tempPath = join64(tmpdir10(), `letta-import-${author}-${name}-${Date.now()}.af`);
454602
+ await writeFile18(tempPath, afContent, "utf-8");
454256
454603
  try {
454257
454604
  const result = await importAgentFromFile({
454258
454605
  filePath: tempPath,
@@ -454283,6 +454630,7 @@ var exports_defaults = {};
454283
454630
  __export(exports_defaults, {
454284
454631
  selectDefaultAgentModel: () => selectDefaultAgentModel,
454285
454632
  ensureDefaultAgents: () => ensureDefaultAgents,
454633
+ TUTOR_TAG: () => TUTOR_TAG,
454286
454634
  MEMO_TAG: () => MEMO_TAG,
454287
454635
  DEFAULT_AGENT_CONFIGS: () => DEFAULT_AGENT_CONFIGS
454288
454636
  });
@@ -454350,29 +454698,39 @@ async function ensureDefaultAgents(backend4, options3) {
454350
454698
  if (!settingsManager.shouldCreateDefaultAgents()) {
454351
454699
  return null;
454352
454700
  }
454701
+ const personality = options3?.personality ?? "memo";
454353
454702
  try {
454354
454703
  const { isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
454355
454704
  const willAutoEnableMemfs = backend4.capabilities.remoteMemfs && await isLettaCloud2();
454356
454705
  const memoryPromptMode = backend4.capabilities.localMemfs ? "local-memfs" : willAutoEnableMemfs ? "memfs" : undefined;
454357
- const { agent: agent2 } = await createAgent({
454706
+ const model = await resolveDefaultAgentModel(backend4, options3?.preferredModel);
454707
+ const createOptions = personality === "tutorial" ? {
454708
+ ...await buildCreateAgentOptionsForPersonality2({
454709
+ personalityId: "tutorial",
454710
+ model
454711
+ }),
454712
+ memoryPromptMode
454713
+ } : {
454358
454714
  ...DEFAULT_AGENT_CONFIGS.memo,
454359
- model: await resolveDefaultAgentModel(backend4, options3?.preferredModel),
454715
+ model,
454360
454716
  memoryPromptMode
454361
- });
454362
- await addTagToAgent(backend4, agent2.id, MEMO_TAG);
454717
+ };
454718
+ const { agent: agent2 } = await createAgent(createOptions);
454719
+ await addTagToAgent(backend4, agent2.id, personality === "tutorial" ? TUTOR_TAG : MEMO_TAG);
454363
454720
  settingsManager.pinAgent(agent2.id);
454364
454721
  return agent2;
454365
454722
  } catch (err) {
454366
454723
  throw new Error(`Failed to create default agents: ${err instanceof Error ? err.message : String(err)}`);
454367
454724
  }
454368
454725
  }
454369
- var MEMO_TAG = "default:memo", MEMO_PERSONA, MEMO_HUMAN, MEMO_DESCRIPTION = "The default Letta Code agent with persistent memory", DEFAULT_AGENT_CONFIGS;
454726
+ var MEMO_TAG = "default:memo", TUTOR_TAG = "default:tutorial", MEMO_PERSONA, MEMO_HUMAN, MEMO_DESCRIPTION = "The default Letta Code agent with persistent memory", DEFAULT_AGENT_CONFIGS;
454370
454727
  var init_defaults = __esm(() => {
454371
454728
  init_client2();
454372
454729
  init_settings_manager();
454373
454730
  init_create6();
454374
454731
  init_memory5();
454375
454732
  init_model();
454733
+ init_personality();
454376
454734
  init_prompt_assets();
454377
454735
  MEMO_PERSONA = parseMdxFrontmatter(MEMORY_PROMPTS["persona_memo.mdx"] ?? "").body;
454378
454736
  MEMO_HUMAN = parseMdxFrontmatter(MEMORY_PROMPTS["human_memo.mdx"] ?? "").body;
@@ -455269,7 +455627,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
455269
455627
  await settingsManager.loadLocalProjectSettings();
455270
455628
  settingsManager.persistSession(agent2.id, conversationId);
455271
455629
  }
455272
- setAgentContext(agent2.id, skillsDirectory, resolvedSkillSources);
455630
+ setAgentContext(agent2.id, skillsDirectory, resolvedSkillSources, agent2.name ?? null);
455273
455631
  const outputFormat = values2["output-format"] || "text";
455274
455632
  const includePartialMessages = Boolean(values2["include-partial-messages"]);
455275
455633
  if (!["text", "json", "stream-json"].includes(outputFormat)) {
@@ -457863,7 +458221,7 @@ var BYTES_PER_TOKEN = 4;
457863
458221
 
457864
458222
  // src/cli/helpers/window-title-config.ts
457865
458223
  import { homedir as homedir36 } from "node:os";
457866
- import { basename as basename25, resolve as resolve36 } from "node:path";
458224
+ import { basename as basename26, resolve as resolve36 } from "node:path";
457867
458225
  function isWindowTitleField(value) {
457868
458226
  return WINDOW_TITLE_FIELDS.includes(value);
457869
458227
  }
@@ -458022,7 +458380,7 @@ function terminalTitleProjectName(data) {
458022
458380
  if (!directory)
458023
458381
  return null;
458024
458382
  const resolved = resolve36(directory);
458025
- const name = basename25(resolved) || formatDirectoryDisplay(resolved) || resolved;
458383
+ const name = basename26(resolved) || formatDirectoryDisplay(resolved) || resolved;
458026
458384
  return truncateTerminalTitlePart(name, 24);
458027
458385
  }
458028
458386
  function titleDirectory(data) {
@@ -459297,7 +459655,7 @@ import {
459297
459655
  writeFileSync as writeFileSync30
459298
459656
  } from "node:fs";
459299
459657
  import { homedir as homedir37, platform as platform9 } from "node:os";
459300
- import { dirname as dirname31, join as join64 } from "node:path";
459658
+ import { dirname as dirname32, join as join65 } from "node:path";
459301
459659
  function detectTerminalType() {
459302
459660
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
459303
459661
  return "cursor";
@@ -459329,16 +459687,16 @@ function getKeybindingsPath(terminal) {
459329
459687
  }[terminal];
459330
459688
  const os9 = platform9();
459331
459689
  if (os9 === "darwin") {
459332
- return join64(homedir37(), "Library", "Application Support", appName, "User", "keybindings.json");
459690
+ return join65(homedir37(), "Library", "Application Support", appName, "User", "keybindings.json");
459333
459691
  }
459334
459692
  if (os9 === "win32") {
459335
459693
  const appData = process.env.APPDATA;
459336
459694
  if (!appData)
459337
459695
  return null;
459338
- return join64(appData, appName, "User", "keybindings.json");
459696
+ return join65(appData, appName, "User", "keybindings.json");
459339
459697
  }
459340
459698
  if (os9 === "linux") {
459341
- return join64(homedir37(), ".config", appName, "User", "keybindings.json");
459699
+ return join65(homedir37(), ".config", appName, "User", "keybindings.json");
459342
459700
  }
459343
459701
  return null;
459344
459702
  }
@@ -459388,7 +459746,7 @@ function installKeybinding(keybindingsPath) {
459388
459746
  if (keybindingExists(keybindingsPath)) {
459389
459747
  return { success: true, alreadyExists: true };
459390
459748
  }
459391
- const parentDir = dirname31(keybindingsPath);
459749
+ const parentDir = dirname32(keybindingsPath);
459392
459750
  if (!existsSync60(parentDir)) {
459393
459751
  mkdirSync41(parentDir, { recursive: true });
459394
459752
  }
@@ -459491,14 +459849,14 @@ function getWezTermConfigPath() {
459491
459849
  }
459492
459850
  const xdgConfig = process.env.XDG_CONFIG_HOME;
459493
459851
  if (xdgConfig) {
459494
- const xdgPath = join64(xdgConfig, "wezterm", "wezterm.lua");
459852
+ const xdgPath = join65(xdgConfig, "wezterm", "wezterm.lua");
459495
459853
  if (existsSync60(xdgPath))
459496
459854
  return xdgPath;
459497
459855
  }
459498
- const configPath = join64(homedir37(), ".config", "wezterm", "wezterm.lua");
459856
+ const configPath = join65(homedir37(), ".config", "wezterm", "wezterm.lua");
459499
459857
  if (existsSync60(configPath))
459500
459858
  return configPath;
459501
- return join64(homedir37(), ".wezterm.lua");
459859
+ return join65(homedir37(), ".wezterm.lua");
459502
459860
  }
459503
459861
  function stripLuaCommentsFromLine(line, blockCommentEnd) {
459504
459862
  let code2 = "";
@@ -459624,7 +459982,7 @@ function installWezTermDeleteFix() {
459624
459982
  content = readFileSync40(configPath, { encoding: "utf-8" });
459625
459983
  }
459626
459984
  content = injectWezTermDeleteFix(content);
459627
- const parentDir = dirname31(configPath);
459985
+ const parentDir = dirname32(configPath);
459628
459986
  if (!existsSync60(parentDir)) {
459629
459987
  mkdirSync41(parentDir, { recursive: true });
459630
459988
  }
@@ -459677,9 +460035,9 @@ __export(exports_settings2, {
459677
460035
  getSetting: () => getSetting
459678
460036
  });
459679
460037
  import { homedir as homedir38 } from "node:os";
459680
- import { join as join65 } from "node:path";
460038
+ import { join as join66 } from "node:path";
459681
460039
  function getSettingsPath() {
459682
- return join65(homedir38(), ".letta", "settings.json");
460040
+ return join66(homedir38(), ".letta", "settings.json");
459683
460041
  }
459684
460042
  async function loadSettings() {
459685
460043
  const settingsPath = getSettingsPath();
@@ -459716,7 +460074,7 @@ async function getSetting(key2) {
459716
460074
  return settings3[key2];
459717
460075
  }
459718
460076
  function getProjectSettingsPath() {
459719
- return join65(process.cwd(), ".letta", "settings.local.json");
460077
+ return join66(process.cwd(), ".letta", "settings.local.json");
459720
460078
  }
459721
460079
  async function loadProjectSettings() {
459722
460080
  const settingsPath = getProjectSettingsPath();
@@ -459734,7 +460092,7 @@ async function loadProjectSettings() {
459734
460092
  }
459735
460093
  async function saveProjectSettings(settings3) {
459736
460094
  const settingsPath = getProjectSettingsPath();
459737
- const dirPath = join65(process.cwd(), ".letta");
460095
+ const dirPath = join66(process.cwd(), ".letta");
459738
460096
  try {
459739
460097
  if (!exists(dirPath)) {
459740
460098
  await mkdir(dirPath, { recursive: true });
@@ -460765,10 +461123,10 @@ var init_InlineBashApproval = __esm(async () => {
460765
461123
  });
460766
461124
 
460767
461125
  // src/cli/components/DiffRenderer.tsx
460768
- import { relative as relative12 } from "node:path";
461126
+ import { relative as relative13 } from "node:path";
460769
461127
  function formatDisplayPath4(filePath) {
460770
461128
  const cwd2 = process.cwd();
460771
- const relativePath = relative12(cwd2, filePath);
461129
+ const relativePath = relative13(cwd2, filePath);
460772
461130
  if (relativePath.startsWith("..")) {
460773
461131
  return filePath;
460774
461132
  }
@@ -461127,10 +461485,10 @@ var init_DiffRenderer = __esm(async () => {
461127
461485
  });
461128
461486
 
461129
461487
  // src/cli/components/AdvancedDiffRenderer.tsx
461130
- import { relative as relative13 } from "node:path";
461488
+ import { relative as relative14 } from "node:path";
461131
461489
  function formatRelativePath(filePath) {
461132
461490
  const cwd2 = process.cwd();
461133
- const relativePath = relative13(cwd2, filePath);
461491
+ const relativePath = relative14(cwd2, filePath);
461134
461492
  return relativePath.startsWith("..") ? relativePath : `./${relativePath}`;
461135
461493
  }
461136
461494
  function padLeft(n, width) {
@@ -461412,7 +461770,7 @@ function AdvancedDiffRenderer(props) {
461412
461770
  }
461413
461771
  const { hunks } = result;
461414
461772
  const filePath = props.filePath;
461415
- const relative14 = formatRelativePath(filePath);
461773
+ const relative15 = formatRelativePath(filePath);
461416
461774
  const lang41 = languageFromPath(filePath);
461417
461775
  const shouldHighlight = lang41 && !exceedsAdvancedDiffHighlightLimits(hunks);
461418
461776
  const hunkSyntaxLines = [];
@@ -461435,7 +461793,7 @@ function AdvancedDiffRenderer(props) {
461435
461793
  const rows = buildAdvancedDiffRows(hunks, hunkSyntaxLines);
461436
461794
  const maxDisplayNo = rows.reduce((m4, r5) => Math.max(m4, r5.displayNo), 1);
461437
461795
  const gutterWidth = String(maxDisplayNo).length;
461438
- const header = props.kind === "write" ? `Wrote changes to ${relative14}` : `Updated ${relative14}`;
461796
+ const header = props.kind === "write" ? `Wrote changes to ${relative15}` : `Updated ${relative15}`;
461439
461797
  if (rows.length === 0) {
461440
461798
  const noChangesGutter = 4;
461441
461799
  return /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
@@ -461486,7 +461844,7 @@ function AdvancedDiffRenderer(props) {
461486
461844
  "No changes to ",
461487
461845
  /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text2, {
461488
461846
  bold: true,
461489
- children: relative14
461847
+ children: relative15
461490
461848
  }, undefined, false, undefined, this),
461491
461849
  " (file content identical)"
461492
461850
  ]
@@ -461592,9 +461950,9 @@ function getHeaderText(fileEdit) {
461592
461950
  } else if (operations.length === 1) {
461593
461951
  const op = operations[0];
461594
461952
  if (op) {
461595
- const { relative: relative15 } = __require("node:path");
461953
+ const { relative: relative16 } = __require("node:path");
461596
461954
  const cwd3 = process.cwd();
461597
- const relPath2 = relative15(cwd3, op.path);
461955
+ const relPath2 = relative16(cwd3, op.path);
461598
461956
  const displayPath2 = relPath2.startsWith("..") ? op.path : relPath2;
461599
461957
  if (op.kind === "add") {
461600
461958
  return `Write to ${displayPath2}?`;
@@ -461608,9 +461966,9 @@ function getHeaderText(fileEdit) {
461608
461966
  }
461609
461967
  return "Apply patch?";
461610
461968
  }
461611
- const { relative: relative14 } = __require("node:path");
461969
+ const { relative: relative15 } = __require("node:path");
461612
461970
  const cwd2 = process.cwd();
461613
- const relPath = relative14(cwd2, fileEdit.filePath);
461971
+ const relPath = relative15(cwd2, fileEdit.filePath);
461614
461972
  const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
461615
461973
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
461616
461974
  const { existsSync: existsSync61 } = __require("node:fs");
@@ -461793,9 +462151,9 @@ var init_InlineFileEditApproval = __esm(async () => {
461793
462151
  children: fileEdit.patchInput ? /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
461794
462152
  flexDirection: "column",
461795
462153
  children: parsePatchOperations2(fileEdit.patchInput).map((op, idx) => {
461796
- const { relative: relative14 } = __require("node:path");
462154
+ const { relative: relative15 } = __require("node:path");
461797
462155
  const cwd2 = process.cwd();
461798
- const relPath = relative14(cwd2, op.path);
462156
+ const relPath = relative15(cwd2, op.path);
461799
462157
  const displayPath = relPath.startsWith("..") ? op.path : relPath;
461800
462158
  const diffKey = fileEdit.toolCallId ? `${fileEdit.toolCallId}:${op.path}` : undefined;
461801
462159
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -469128,7 +469486,7 @@ import {
469128
469486
  statSync as statSync21
469129
469487
  } from "node:fs";
469130
469488
  import { arch as arch4, homedir as homedir40, platform as platform10 } from "node:os";
469131
- import { basename as basename26, join as join66 } from "node:path";
469489
+ import { basename as basename27, join as join67 } from "node:path";
469132
469490
  function toDisplayPath(value) {
469133
469491
  return value.replace(/\\/g, "/");
469134
469492
  }
@@ -469370,7 +469728,7 @@ class FileAutocompleteProvider {
469370
469728
  }
469371
469729
  expandHomePath(path42) {
469372
469730
  if (path42.startsWith("~/")) {
469373
- const expandedPath = join66(homedir40(), path42.slice(2));
469731
+ const expandedPath = join67(homedir40(), path42.slice(2));
469374
469732
  return path42.endsWith("/") && !expandedPath.endsWith("/") ? `${expandedPath}/` : expandedPath;
469375
469733
  } else if (path42 === "~") {
469376
469734
  return homedir40();
@@ -469391,7 +469749,7 @@ class FileAutocompleteProvider {
469391
469749
  } else if (displayBase.startsWith("/")) {
469392
469750
  baseDir = displayBase;
469393
469751
  } else {
469394
- baseDir = join66(this.basePath, displayBase);
469752
+ baseDir = join67(this.basePath, displayBase);
469395
469753
  }
469396
469754
  try {
469397
469755
  if (!statSync21(baseDir).isDirectory()) {
@@ -469410,7 +469768,7 @@ class FileAutocompleteProvider {
469410
469768
  return `${toDisplayPath(displayBase)}${normalizedRelativePath}`;
469411
469769
  }
469412
469770
  scoreEntry(filePath, query2, isDirectory) {
469413
- const fileName = basename26(filePath);
469771
+ const fileName = basename27(filePath);
469414
469772
  const lowerFileName = fileName.toLowerCase();
469415
469773
  const lowerQuery = query2.toLowerCase();
469416
469774
  let score = 0;
@@ -469448,7 +469806,7 @@ class FileAutocompleteProvider {
469448
469806
  for (const { path: entryPath, isDirectory } of topEntries) {
469449
469807
  const pathWithoutSlash = isDirectory ? entryPath.slice(0, -1) : entryPath;
469450
469808
  const displayPath2 = scopedQuery ? this.scopedPathForDisplay(scopedQuery.displayBase, pathWithoutSlash) : pathWithoutSlash;
469451
- const entryName = basename26(pathWithoutSlash);
469809
+ const entryName = basename27(pathWithoutSlash);
469452
469810
  const completionPath = isDirectory ? `${displayPath2}/` : displayPath2;
469453
469811
  const value = buildCompletionValue(completionPath, {
469454
469812
  isDirectory,
@@ -469470,9 +469828,9 @@ class FileAutocompleteProvider {
469470
469828
  var PATH_DELIMITERS2, FD_TOOLS_DIR2, FD_BINARY_NAME2, FD_LOCAL_PATH2;
469471
469829
  var init_file_autocomplete = __esm(() => {
469472
469830
  PATH_DELIMITERS2 = new Set([" ", "\t", '"', "'", "="]);
469473
- FD_TOOLS_DIR2 = join66(homedir40(), ".letta", "bin");
469831
+ FD_TOOLS_DIR2 = join67(homedir40(), ".letta", "bin");
469474
469832
  FD_BINARY_NAME2 = platform10() === "win32" ? "fd.exe" : "fd";
469475
- FD_LOCAL_PATH2 = join66(FD_TOOLS_DIR2, FD_BINARY_NAME2);
469833
+ FD_LOCAL_PATH2 = join67(FD_TOOLS_DIR2, FD_BINARY_NAME2);
469476
469834
  });
469477
469835
 
469478
469836
  // src/cli/hooks/use-autocomplete-navigation.ts
@@ -472299,7 +472657,7 @@ import {
472299
472657
  writeFileSync as writeFileSync31
472300
472658
  } from "node:fs";
472301
472659
  import { tmpdir as tmpdir10 } from "node:os";
472302
- import { dirname as dirname32, join as join67 } from "node:path";
472660
+ import { dirname as dirname33, join as join68 } from "node:path";
472303
472661
  function runCommand(command, args, cwd2, input) {
472304
472662
  try {
472305
472663
  return execFileSync7(command, args, {
@@ -472520,8 +472878,8 @@ async function createLettaAgent(apiKey, name) {
472520
472878
  return createMinimalAgent(apiKey, name);
472521
472879
  }
472522
472880
  function cloneRepoToTemp(repo) {
472523
- const tempDir = mkdtempSync5(join67(tmpdir10(), "letta-install-github-app-"));
472524
- const repoDir = join67(tempDir, "repo");
472881
+ const tempDir = mkdtempSync5(join68(tmpdir10(), "letta-install-github-app-"));
472882
+ const repoDir = join68(tempDir, "repo");
472525
472883
  runCommand("gh", ["repo", "clone", repo, repoDir, "--", "--depth=1"]);
472526
472884
  return { tempDir, repoDir };
472527
472885
  }
@@ -472532,9 +472890,9 @@ function runGit5(args, cwd2) {
472532
472890
  return runCommand("git", args, cwd2);
472533
472891
  }
472534
472892
  function writeWorkflow(repoDir, workflowPath, content) {
472535
- const absolutePath = join67(repoDir, workflowPath);
472536
- if (!existsSync62(dirname32(absolutePath))) {
472537
- mkdirSync43(dirname32(absolutePath), { recursive: true });
472893
+ const absolutePath = join68(repoDir, workflowPath);
472894
+ if (!existsSync62(dirname33(absolutePath))) {
472895
+ mkdirSync43(dirname33(absolutePath), { recursive: true });
472538
472896
  }
472539
472897
  const next = `${content.trimEnd()}
472540
472898
  `;
@@ -476963,7 +477321,7 @@ __export(exports_generate_memory_viewer, {
476963
477321
  import { execFile as execFileCb4 } from "node:child_process";
476964
477322
  import { chmodSync as chmodSync8, existsSync as existsSync63, mkdirSync as mkdirSync44, writeFileSync as writeFileSync32 } from "node:fs";
476965
477323
  import { homedir as homedir41 } from "node:os";
476966
- import { join as join68 } from "node:path";
477324
+ import { join as join69 } from "node:path";
476967
477325
  import { promisify as promisify15 } from "node:util";
476968
477326
  function messagesFromOverview(overview) {
476969
477327
  return overview.messages?.map((message) => ({
@@ -477272,7 +477630,7 @@ ${m4.body}` : m4.subject;
477272
477630
  async function generateAndOpenMemoryViewer(agentId, options3) {
477273
477631
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
477274
477632
  const repoDir = memoryRoot;
477275
- if (!existsSync63(join68(repoDir, ".git"))) {
477633
+ if (!existsSync63(join69(repoDir, ".git"))) {
477276
477634
  throw new Error("Memory viewer requires memfs. Run /memfs enable first.");
477277
477635
  }
477278
477636
  const data = await collectMemoryData(agentId, repoDir, memoryRoot, options3?.conversationId);
@@ -477288,7 +477646,7 @@ async function generateAndOpenMemoryViewer(agentId, options3) {
477288
477646
  try {
477289
477647
  chmodSync8(VIEWERS_DIR, 448);
477290
477648
  } catch {}
477291
- const filePath = join68(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
477649
+ const filePath = join69(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
477292
477650
  writeFileSync32(filePath, html5);
477293
477651
  chmodSync8(filePath, 384);
477294
477652
  const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
@@ -477313,13 +477671,13 @@ var init_generate_memory_viewer = __esm(() => {
477313
477671
  init_local_memory_context();
477314
477672
  init_memory_viewer_template();
477315
477673
  execFile17 = promisify15(execFileCb4);
477316
- VIEWERS_DIR = join68(homedir41(), ".letta", "viewers");
477674
+ VIEWERS_DIR = join69(homedir41(), ".letta", "viewers");
477317
477675
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
477318
477676
  });
477319
477677
 
477320
477678
  // src/cli/components/MemfsTreeViewer.tsx
477321
477679
  import { existsSync as existsSync64 } from "node:fs";
477322
- import { join as join69 } from "node:path";
477680
+ import { join as join70 } from "node:path";
477323
477681
  function renderTreePrefix(node) {
477324
477682
  let prefix = "";
477325
477683
  for (let i4 = 0;i4 < node.depth; i4++) {
@@ -477348,7 +477706,7 @@ function MemfsTreeViewer({
477348
477706
  const statusTimerRef = import_react90.useRef(null);
477349
477707
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
477350
477708
  const memoryExists = existsSync64(memoryRoot);
477351
- const hasGitRepo = import_react90.useMemo(() => existsSync64(join69(memoryRoot, ".git")), [memoryRoot]);
477709
+ const hasGitRepo = import_react90.useMemo(() => existsSync64(join70(memoryRoot, ".git")), [memoryRoot]);
477352
477710
  function showStatus(msg, durationMs) {
477353
477711
  if (statusTimerRef.current)
477354
477712
  clearTimeout(statusTimerRef.current);
@@ -479769,19 +480127,19 @@ var init_PersonalitySelector = __esm(async () => {
479769
480127
  });
479770
480128
 
479771
480129
  // src/utils/aws-credentials.ts
479772
- import { readFile as readFile21 } from "node:fs/promises";
480130
+ import { readFile as readFile22 } from "node:fs/promises";
479773
480131
  import { homedir as homedir42 } from "node:os";
479774
- import { join as join70 } from "node:path";
480132
+ import { join as join71 } from "node:path";
479775
480133
  async function parseAwsCredentials() {
479776
- const credentialsPath = join70(homedir42(), ".aws", "credentials");
479777
- const configPath = join70(homedir42(), ".aws", "config");
480134
+ const credentialsPath = join71(homedir42(), ".aws", "credentials");
480135
+ const configPath = join71(homedir42(), ".aws", "config");
479778
480136
  const profiles = new Map;
479779
480137
  try {
479780
- const content = await readFile21(credentialsPath, "utf-8");
480138
+ const content = await readFile22(credentialsPath, "utf-8");
479781
480139
  parseIniFile(content, profiles, false);
479782
480140
  } catch {}
479783
480141
  try {
479784
- const content = await readFile21(configPath, "utf-8");
480142
+ const content = await readFile22(configPath, "utf-8");
479785
480143
  parseIniFile(content, profiles, true);
479786
480144
  } catch {}
479787
480145
  return Array.from(profiles.values());
@@ -481350,8 +481708,8 @@ function SkillsDialog({ onClose, agentId }) {
481350
481708
  try {
481351
481709
  const { discoverSkills: discoverSkills3, SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills3(), exports_skills2));
481352
481710
  const { getSkillsDirectory: getSkillsDirectory2, getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
481353
- const { join: join71 } = await import("node:path");
481354
- const skillsDir = getSkillsDirectory2() || join71(process.cwd(), SKILLS_DIR3);
481711
+ const { join: join72 } = await import("node:path");
481712
+ const skillsDir = getSkillsDirectory2() || join72(process.cwd(), SKILLS_DIR3);
481355
481713
  const result = await discoverSkills3(skillsDir, agentId, {
481356
481714
  sources: getSkillSources2()
481357
481715
  });
@@ -485255,9 +485613,9 @@ function getFileEditHeader(toolName, toolArgs) {
485255
485613
  } else if (operations.length === 1) {
485256
485614
  const op = operations[0];
485257
485615
  if (op) {
485258
- const { relative: relative15 } = __require("node:path");
485616
+ const { relative: relative16 } = __require("node:path");
485259
485617
  const cwd3 = process.cwd();
485260
- const relPath2 = relative15(cwd3, op.path);
485618
+ const relPath2 = relative16(cwd3, op.path);
485261
485619
  const displayPath3 = relPath2.startsWith("..") ? op.path : relPath2;
485262
485620
  if (op.kind === "add")
485263
485621
  return `Write to ${displayPath3}?`;
@@ -485271,9 +485629,9 @@ function getFileEditHeader(toolName, toolArgs) {
485271
485629
  return "Apply patch?";
485272
485630
  }
485273
485631
  const filePath = args.file_path || "";
485274
- const { relative: relative14 } = __require("node:path");
485632
+ const { relative: relative15 } = __require("node:path");
485275
485633
  const cwd2 = process.cwd();
485276
- const relPath = relative14(cwd2, filePath);
485634
+ const relPath = relative15(cwd2, filePath);
485277
485635
  const displayPath2 = relPath.startsWith("..") ? filePath : relPath;
485278
485636
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
485279
485637
  const { existsSync: existsSync65 } = __require("node:fs");
@@ -485361,9 +485719,9 @@ var init_ApprovalPreview = __esm(async () => {
485361
485719
  /* @__PURE__ */ jsx_dev_runtime89.jsxDEV(Box_default, {
485362
485720
  flexDirection: "column",
485363
485721
  children: operations.map((op, idx) => {
485364
- const { relative: relative14 } = __require("node:path");
485722
+ const { relative: relative15 } = __require("node:path");
485365
485723
  const cwd2 = process.cwd();
485366
- const relPath = relative14(cwd2, op.path);
485724
+ const relPath = relative15(cwd2, op.path);
485367
485725
  const displayPath2 = relPath.startsWith("..") ? op.path : relPath;
485368
485726
  const diffKey = toolCallId ? `${toolCallId}:${op.path}` : undefined;
485369
485727
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -500620,7 +500978,7 @@ __export(exports_generate_diff_viewer, {
500620
500978
  import { execFile as execFileCb5 } from "node:child_process";
500621
500979
  import { chmodSync as chmodSync9, existsSync as existsSync65, mkdirSync as mkdirSync45, writeFileSync as writeFileSync33 } from "node:fs";
500622
500980
  import { homedir as homedir43 } from "node:os";
500623
- import { isAbsolute as isAbsolute25, join as join71, resolve as resolve38 } from "node:path";
500981
+ import { isAbsolute as isAbsolute25, join as join72, resolve as resolve38 } from "node:path";
500624
500982
  import { promisify as promisify16 } from "node:util";
500625
500983
  async function runGit6(cwd2, args) {
500626
500984
  try {
@@ -500845,7 +501203,7 @@ async function generateAndOpenDiffViewer(targetPath) {
500845
501203
  try {
500846
501204
  chmodSync9(VIEWERS_DIR2, 448);
500847
501205
  } catch {}
500848
- const filePath = join71(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
501206
+ const filePath = join72(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
500849
501207
  writeFileSync33(filePath, html5);
500850
501208
  chmodSync9(filePath, 384);
500851
501209
  const skipOpen = shouldSkipOpen();
@@ -500916,7 +501274,7 @@ var init_generate_diff_viewer = __esm(() => {
500916
501274
  init_ssr();
500917
501275
  init_diff_viewer_template();
500918
501276
  execFile18 = promisify16(execFileCb5);
500919
- VIEWERS_DIR2 = join71(homedir43(), ".letta", "viewers");
501277
+ VIEWERS_DIR2 = join72(homedir43(), ".letta", "viewers");
500920
501278
  GIT_MAX_BUFFER = 50 * 1024 * 1024;
500921
501279
  });
500922
501280
 
@@ -502902,7 +503260,7 @@ __export(exports_shell_aliases, {
502902
503260
  });
502903
503261
  import { existsSync as existsSync66, readFileSync as readFileSync42 } from "node:fs";
502904
503262
  import { homedir as homedir44 } from "node:os";
502905
- import { join as join72 } from "node:path";
503263
+ import { join as join73 } from "node:path";
502906
503264
  function parseAliasesFromFile(filePath) {
502907
503265
  const aliases = new Map;
502908
503266
  if (!existsSync66(filePath)) {
@@ -502974,7 +503332,7 @@ function loadAliases(forceReload = false) {
502974
503332
  const home = homedir44();
502975
503333
  const allAliases = new Map;
502976
503334
  for (const file3 of ALIAS_FILES) {
502977
- const filePath = join72(home, file3);
503335
+ const filePath = join73(home, file3);
502978
503336
  const fileAliases = parseAliasesFromFile(filePath);
502979
503337
  for (const [name, value] of fileAliases) {
502980
503338
  allAliases.set(name, value);
@@ -507157,7 +507515,7 @@ The deployment target for this project is CITATION-DOGFOOD-OK.
507157
507515
 
507158
507516
  // src/mods/learning-harness.ts
507159
507517
  import { spawn as spawn13 } from "node:child_process";
507160
- import { access as access3, copyFile as copyFile2, mkdir as mkdir15, readFile as readFile22, writeFile as writeFile17 } from "node:fs/promises";
507518
+ import { access as access3, copyFile as copyFile2, mkdir as mkdir15, readFile as readFile23, writeFile as writeFile18 } from "node:fs/promises";
507161
507519
  import path42 from "node:path";
507162
507520
  function slugify2(value) {
507163
507521
  const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -507405,14 +507763,14 @@ async function existingPath(filePath) {
507405
507763
  return await fileExists(filePath) ? filePath : undefined;
507406
507764
  }
507407
507765
  async function writeJsonArtifact(filePath, value) {
507408
- await writeFile17(filePath, `${JSON.stringify(value, null, 2)}
507766
+ await writeFile18(filePath, `${JSON.stringify(value, null, 2)}
507409
507767
  `, "utf8");
507410
507768
  }
507411
507769
  async function writeCommandArtifacts(prefix, command, args, result) {
507412
- await writeFile17(`${prefix}.command.txt`, `${renderCommand(command, args)}
507770
+ await writeFile18(`${prefix}.command.txt`, `${renderCommand(command, args)}
507413
507771
  `, "utf8");
507414
- await writeFile17(`${prefix}.stdout`, result.stdout, "utf8");
507415
- await writeFile17(`${prefix}.stderr`, result.stderr, "utf8");
507772
+ await writeFile18(`${prefix}.stdout`, result.stdout, "utf8");
507773
+ await writeFile18(`${prefix}.stderr`, result.stderr, "utf8");
507416
507774
  await writeJsonArtifact(`${prefix}.result.json`, result);
507417
507775
  }
507418
507776
  async function prepareMemoryFiles(memoryDir, memoryFiles) {
@@ -507420,7 +507778,7 @@ async function prepareMemoryFiles(memoryDir, memoryFiles) {
507420
507778
  for (const [relativePath, content] of Object.entries(memoryFiles ?? {})) {
507421
507779
  const filePath = safeJoin(memoryDir, relativePath);
507422
507780
  await mkdir15(path42.dirname(filePath), { recursive: true });
507423
- await writeFile17(filePath, content, "utf8");
507781
+ await writeFile18(filePath, content, "utf8");
507424
507782
  }
507425
507783
  }
507426
507784
  function renderEvaluationPrompt(prompt, memoryDir) {
@@ -508083,7 +508441,7 @@ function renderProposerGuide(params) {
508083
508441
  `;
508084
508442
  }
508085
508443
  async function writeHistoryArtifacts(params) {
508086
- await writeFile17(params.historyPath, renderHistoryIndex({
508444
+ await writeFile18(params.historyPath, renderHistoryIndex({
508087
508445
  attempts: params.attempts,
508088
508446
  historyManifestPath: params.historyManifestPath,
508089
508447
  proposerGuidePath: params.proposerGuidePath,
@@ -508091,7 +508449,7 @@ async function writeHistoryArtifacts(params) {
508091
508449
  spec: params.spec
508092
508450
  }), "utf8");
508093
508451
  await writeJsonArtifact(params.historyManifestPath, buildHistoryManifest(params));
508094
- await writeFile17(params.proposerGuidePath, renderProposerGuide(params), "utf8");
508452
+ await writeFile18(params.proposerGuidePath, renderProposerGuide(params), "utf8");
508095
508453
  }
508096
508454
  async function defaultCommandRunner(command, args, options3) {
508097
508455
  const startedAt = Date.now();
@@ -508182,7 +508540,7 @@ function createScenarioSuiteEvaluator(params) {
508182
508540
  outputFormat
508183
508541
  })
508184
508542
  ];
508185
- await writeFile17(hasConfiguredScenarios ? path42.join(scenarioDir, "prompt.md") : path42.join(context3.runDir, "eval-prompt.md"), evalPrompt, "utf8");
508543
+ await writeFile18(hasConfiguredScenarios ? path42.join(scenarioDir, "prompt.md") : path42.join(context3.runDir, "eval-prompt.md"), evalPrompt, "utf8");
508186
508544
  const scenarioEvalResult = await context3.runner(context3.cliCommand, evalArgs, {
508187
508545
  cwd: context3.repoRoot,
508188
508546
  env: {
@@ -508374,7 +508732,7 @@ async function runModLearningCandidate(params) {
508374
508732
  outputFormat: "json"
508375
508733
  })
508376
508734
  ];
508377
- await writeFile17(path42.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
508735
+ await writeFile18(path42.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
508378
508736
  generationResult = await params.runner(params.cliCommand, generationArgs, {
508379
508737
  cwd: repoRoot,
508380
508738
  env: {
@@ -508453,7 +508811,7 @@ async function runModLearningCandidate(params) {
508453
508811
  spec: options3.spec
508454
508812
  };
508455
508813
  await writeJsonArtifact(path42.join(runDir, "report.json"), report);
508456
- await writeFile17(reportPath, renderMarkdownReport(report), "utf8");
508814
+ await writeFile18(reportPath, renderMarkdownReport(report), "utf8");
508457
508815
  await writeCandidateManifest(report);
508458
508816
  emitProgress("done", params.candidateCount > 1 ? `Optimization iteration ${params.candidateIndex}/${params.candidateCount} complete` : "mod optimization complete", {
508459
508817
  attempts: [...params.previousAttempts, summarizeAttempt(report)],
@@ -508631,7 +508989,7 @@ async function runModLearning(options3) {
508631
508989
  spec: normalizedOptions.spec
508632
508990
  });
508633
508991
  await writeJsonArtifact(path42.join(runDir, "report.json"), report);
508634
- await writeFile17(reportPath, renderMarkdownReport(report), "utf8");
508992
+ await writeFile18(reportPath, renderMarkdownReport(report), "utf8");
508635
508993
  normalizedOptions.onProgress?.({
508636
508994
  candidateCount,
508637
508995
  candidateIndex: selectedCandidateIndex,
@@ -508649,7 +509007,7 @@ async function runModLearning(options3) {
508649
509007
  return report;
508650
509008
  }
508651
509009
  async function readModLearningEnv(envPath) {
508652
- return JSON.parse(await readFile22(envPath, "utf8"));
509010
+ return JSON.parse(await readFile23(envPath, "utf8"));
508653
509011
  }
508654
509012
  var init_learning_harness = __esm(async () => {
508655
509013
  await init_mod_engine();
@@ -509217,7 +509575,7 @@ var init_mods = __esm(async () => {
509217
509575
  });
509218
509576
 
509219
509577
  // src/cli/helpers/chdir-command.ts
509220
- import { realpath as realpath6, stat as stat14 } from "node:fs/promises";
509578
+ import { realpath as realpath6, stat as stat15 } from "node:fs/promises";
509221
509579
  import { homedir as homedir45 } from "node:os";
509222
509580
  import path44 from "node:path";
509223
509581
  function parseChdirCommand(input) {
@@ -509256,7 +509614,7 @@ async function resolveChdirTarget(pathArg, currentWorkingDirectory) {
509256
509614
  const expanded = expandHome(pathArg);
509257
509615
  const resolved = path44.isAbsolute(expanded) ? expanded : path44.resolve(currentWorkingDirectory, expanded);
509258
509616
  const normalized = await realpath6(resolved);
509259
- const stats = await stat14(normalized);
509617
+ const stats = await stat15(normalized);
509260
509618
  if (!stats.isDirectory()) {
509261
509619
  throw new Error(`Not a directory: ${normalized}`);
509262
509620
  }
@@ -510897,7 +511255,7 @@ __export(exports_worktree_diff_list, {
510897
511255
  listWorktreeDiffOptions: () => listWorktreeDiffOptions
510898
511256
  });
510899
511257
  import { execFile as execFileCb6 } from "node:child_process";
510900
- import { basename as basename27 } from "node:path";
511258
+ import { basename as basename28 } from "node:path";
510901
511259
  import { promisify as promisify17 } from "node:util";
510902
511260
  async function runGit7(cwd2, args) {
510903
511261
  try {
@@ -510946,7 +511304,7 @@ function parseWorktreeList(output, currentPath) {
510946
511304
  if (current?.path) {
510947
511305
  worktrees.push({
510948
511306
  path: current.path,
510949
- name: basename27(current.path),
511307
+ name: basename28(current.path),
510950
511308
  branch: current.branch ?? "detached",
510951
511309
  head: current.head ?? "",
510952
511310
  isCurrent: current.path === currentPath,
@@ -510972,7 +511330,7 @@ function parseWorktreeList(output, currentPath) {
510972
511330
  if (current?.path) {
510973
511331
  worktrees.push({
510974
511332
  path: current.path,
510975
- name: basename27(current.path),
511333
+ name: basename28(current.path),
510976
511334
  branch: current.branch ?? "detached",
510977
511335
  head: current.head ?? "",
510978
511336
  isCurrent: current.path === currentPath,
@@ -511041,8 +511399,8 @@ var exports_export = {};
511041
511399
  __export(exports_export, {
511042
511400
  packageSkills: () => packageSkills
511043
511401
  });
511044
- import { readdir as readdir15, readFile as readFile23 } from "node:fs/promises";
511045
- import { relative as relative14, resolve as resolve39 } from "node:path";
511402
+ import { readdir as readdir16, readFile as readFile24 } from "node:fs/promises";
511403
+ import { relative as relative15, resolve as resolve39 } from "node:path";
511046
511404
  async function packageSkills(agentId, skillsDir) {
511047
511405
  const skills = [];
511048
511406
  const skillNames = new Set;
@@ -511053,7 +511411,7 @@ async function packageSkills(agentId, skillsDir) {
511053
511411
  ].filter((dir) => Boolean(dir));
511054
511412
  for (const baseDir of dirsToCheck) {
511055
511413
  try {
511056
- const entries = await readdir15(baseDir, { withFileTypes: true });
511414
+ const entries = await readdir16(baseDir, { withFileTypes: true });
511057
511415
  for (const entry of entries) {
511058
511416
  if (!entry.isDirectory())
511059
511417
  continue;
@@ -511062,7 +511420,7 @@ async function packageSkills(agentId, skillsDir) {
511062
511420
  const skillDir = resolve39(baseDir, entry.name);
511063
511421
  const skillMdPath = resolve39(skillDir, "SKILL.md");
511064
511422
  try {
511065
- await readFile23(skillMdPath, "utf-8");
511423
+ await readFile24(skillMdPath, "utf-8");
511066
511424
  } catch {
511067
511425
  console.warn(`Skipping invalid skill ${entry.name}: missing SKILL.md`);
511068
511426
  continue;
@@ -511088,14 +511446,14 @@ async function packageSkills(agentId, skillsDir) {
511088
511446
  async function readSkillFiles(skillDir) {
511089
511447
  const files = {};
511090
511448
  async function walk(dir) {
511091
- const entries = await readdir15(dir, { withFileTypes: true });
511449
+ const entries = await readdir16(dir, { withFileTypes: true });
511092
511450
  for (const entry of entries) {
511093
511451
  const fullPath = resolve39(dir, entry.name);
511094
511452
  if (entry.isDirectory()) {
511095
511453
  await walk(fullPath);
511096
511454
  } else {
511097
- const content = await readFile23(fullPath, "utf-8");
511098
- const relativePath = relative14(skillDir, fullPath).replace(/\\/g, "/");
511455
+ const content = await readFile24(fullPath, "utf-8");
511456
+ const relativePath = relative15(skillDir, fullPath).replace(/\\/g, "/");
511099
511457
  files[relativePath] = content;
511100
511458
  }
511101
511459
  }
@@ -511232,7 +511590,7 @@ var init_conversation_switch_alert = __esm(() => {
511232
511590
  import { randomUUID as randomUUID33 } from "node:crypto";
511233
511591
  import { existsSync as existsSync67, readFileSync as readFileSync43, renameSync as renameSync7, writeFileSync as writeFileSync34 } from "node:fs";
511234
511592
  import { tmpdir as tmpdir11 } from "node:os";
511235
- import { join as join73 } from "node:path";
511593
+ import { join as join74 } from "node:path";
511236
511594
  async function findCustomCommandByName(commandName) {
511237
511595
  const { findCustomCommand: findCustomCommand2 } = await Promise.resolve().then(() => (init_custom(), exports_custom));
511238
511596
  return findCustomCommand2(commandName);
@@ -511833,8 +512191,8 @@ ${SYSTEM_REMINDER_CLOSE}`),
511833
512191
  try {
511834
512192
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
511835
512193
  const personaCandidates = [
511836
- join73(memoryRoot, "system", "persona.md"),
511837
- join73(memoryRoot, "memory", "system", "persona.md")
512194
+ join74(memoryRoot, "system", "persona.md"),
512195
+ join74(memoryRoot, "memory", "system", "persona.md")
511838
512196
  ];
511839
512197
  const personaPath = personaCandidates.find((candidate) => existsSync67(candidate));
511840
512198
  if (personaPath) {
@@ -512693,7 +513051,7 @@ Path: ${memoryDir}`, true);
512693
513051
  updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
512694
513052
  return { submitted: true };
512695
513053
  }
512696
- const backupDir = join73(tmpdir11(), `letta-memfs-reset-${agentId}-${Date.now()}`);
513054
+ const backupDir = join74(tmpdir11(), `letta-memfs-reset-${agentId}-${Date.now()}`);
512697
513055
  renameSync7(memoryDir, backupDir);
512698
513056
  if (getBackend().capabilities.localMemfs) {
512699
513057
  const { initializeLocalMemoryRepo: initializeLocalMemoryRepo2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
@@ -513132,9 +513490,12 @@ ${SYSTEM_REMINDER_CLOSE}`;
513132
513490
  cmd.finish("Running memory doctor... I'll ask a few questions to refine memory structure.", true);
513133
513491
  const { context: gitContext } = gatherInitGitContext();
513134
513492
  const memoryDir = getActiveMemoryDirectory(agentId);
513493
+ const skillNameFrontmatterRepair = await repairMissingSkillNameFrontmatter(memoryDir);
513494
+ const skillNameFrontmatterRepairReport = formatSkillNameFrontmatterRepairReport(skillNameFrontmatterRepair);
513135
513495
  const doctorMessage = buildDoctorMessage({
513136
513496
  gitContext,
513137
- memoryDir
513497
+ memoryDir,
513498
+ skillNameFrontmatterRepairReport
513138
513499
  });
513139
513500
  await processConversationWithQueuedApprovals([
513140
513501
  {
@@ -513511,6 +513872,7 @@ var init_use_submit_handler = __esm(async () => {
513511
513872
  init_reasoning_tab_toggle();
513512
513873
  init_reflection_launcher();
513513
513874
  init_reflection_transcript();
513875
+ init_skill_name_frontmatter_repair();
513514
513876
  init_system_prompt_warning();
513515
513877
  init_thinking_messages();
513516
513878
  init_command_runtime();
@@ -513543,7 +513905,7 @@ var init_use_submit_handler = __esm(async () => {
513543
513905
  });
513544
513906
 
513545
513907
  // src/cli/app/AppCoordinator.tsx
513546
- import { join as join74 } from "node:path";
513908
+ import { join as join75 } from "node:path";
513547
513909
  function buildStartupCommandHints(options3) {
513548
513910
  const {
513549
513911
  isResumingConversation,
@@ -514848,7 +515210,7 @@ function App2({
514848
515210
  agentId: a2.agentId ?? null
514849
515211
  }))
514850
515212
  });
514851
- const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join74(modContext.memfs.memoryDir, "mods") : null;
515213
+ const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join75(modContext.memfs.memoryDir, "mods") : null;
514852
515214
  const modAdapter = useLocalModAdapter(modContext, {
514853
515215
  agentModsDirectory,
514854
515216
  disabled: modsDisabled
@@ -516875,7 +517237,7 @@ import {
516875
517237
  writeFileSync as writeFileSync35
516876
517238
  } from "node:fs";
516877
517239
  import { homedir as homedir46, platform as platform11 } from "node:os";
516878
- import { dirname as dirname33, join as join75 } from "node:path";
517240
+ import { dirname as dirname34, join as join76 } from "node:path";
516879
517241
  function detectTerminalType2() {
516880
517242
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
516881
517243
  return "cursor";
@@ -516907,16 +517269,16 @@ function getKeybindingsPath2(terminal) {
516907
517269
  }[terminal];
516908
517270
  const os10 = platform11();
516909
517271
  if (os10 === "darwin") {
516910
- return join75(homedir46(), "Library", "Application Support", appName, "User", "keybindings.json");
517272
+ return join76(homedir46(), "Library", "Application Support", appName, "User", "keybindings.json");
516911
517273
  }
516912
517274
  if (os10 === "win32") {
516913
517275
  const appData = process.env.APPDATA;
516914
517276
  if (!appData)
516915
517277
  return null;
516916
- return join75(appData, appName, "User", "keybindings.json");
517278
+ return join76(appData, appName, "User", "keybindings.json");
516917
517279
  }
516918
517280
  if (os10 === "linux") {
516919
- return join75(homedir46(), ".config", appName, "User", "keybindings.json");
517281
+ return join76(homedir46(), ".config", appName, "User", "keybindings.json");
516920
517282
  }
516921
517283
  return null;
516922
517284
  }
@@ -516966,7 +517328,7 @@ function installKeybinding2(keybindingsPath) {
516966
517328
  if (keybindingExists2(keybindingsPath)) {
516967
517329
  return { success: true, alreadyExists: true };
516968
517330
  }
516969
- const parentDir = dirname33(keybindingsPath);
517331
+ const parentDir = dirname34(keybindingsPath);
516970
517332
  if (!existsSync68(parentDir)) {
516971
517333
  mkdirSync46(parentDir, { recursive: true });
516972
517334
  }
@@ -517069,14 +517431,14 @@ function getWezTermConfigPath2() {
517069
517431
  }
517070
517432
  const xdgConfig = process.env.XDG_CONFIG_HOME;
517071
517433
  if (xdgConfig) {
517072
- const xdgPath = join75(xdgConfig, "wezterm", "wezterm.lua");
517434
+ const xdgPath = join76(xdgConfig, "wezterm", "wezterm.lua");
517073
517435
  if (existsSync68(xdgPath))
517074
517436
  return xdgPath;
517075
517437
  }
517076
- const configPath = join75(homedir46(), ".config", "wezterm", "wezterm.lua");
517438
+ const configPath = join76(homedir46(), ".config", "wezterm", "wezterm.lua");
517077
517439
  if (existsSync68(configPath))
517078
517440
  return configPath;
517079
- return join75(homedir46(), ".wezterm.lua");
517441
+ return join76(homedir46(), ".wezterm.lua");
517080
517442
  }
517081
517443
  function stripLuaCommentsFromLine2(line, blockCommentEnd) {
517082
517444
  let code2 = "";
@@ -517202,7 +517564,7 @@ function installWezTermDeleteFix2() {
517202
517564
  content = readFileSync44(configPath, { encoding: "utf-8" });
517203
517565
  }
517204
517566
  content = injectWezTermDeleteFix2(content);
517205
- const parentDir = dirname33(configPath);
517567
+ const parentDir = dirname34(configPath);
517206
517568
  if (!existsSync68(parentDir)) {
517207
517569
  mkdirSync46(parentDir, { recursive: true });
517208
517570
  }
@@ -517255,9 +517617,9 @@ __export(exports_settings3, {
517255
517617
  getSetting: () => getSetting2
517256
517618
  });
517257
517619
  import { homedir as homedir47 } from "node:os";
517258
- import { join as join76 } from "node:path";
517620
+ import { join as join77 } from "node:path";
517259
517621
  function getSettingsPath2() {
517260
- return join76(homedir47(), ".letta", "settings.json");
517622
+ return join77(homedir47(), ".letta", "settings.json");
517261
517623
  }
517262
517624
  async function loadSettings2() {
517263
517625
  const settingsPath = getSettingsPath2();
@@ -517294,7 +517656,7 @@ async function getSetting2(key2) {
517294
517656
  return settings3[key2];
517295
517657
  }
517296
517658
  function getProjectSettingsPath2() {
517297
- return join76(process.cwd(), ".letta", "settings.local.json");
517659
+ return join77(process.cwd(), ".letta", "settings.local.json");
517298
517660
  }
517299
517661
  async function loadProjectSettings2() {
517300
517662
  const settingsPath = getProjectSettingsPath2();
@@ -517312,7 +517674,7 @@ async function loadProjectSettings2() {
517312
517674
  }
517313
517675
  async function saveProjectSettings2(settings3) {
517314
517676
  const settingsPath = getProjectSettingsPath2();
517315
- const dirPath = join76(process.cwd(), ".letta");
517677
+ const dirPath = join77(process.cwd(), ".letta");
517316
517678
  try {
517317
517679
  if (!exists(dirPath)) {
517318
517680
  await mkdir(dirPath, { recursive: true });
@@ -517431,7 +517793,7 @@ __export(exports_resolve_startup_agent, {
517431
517793
  });
517432
517794
  function resolveStartupTarget(input) {
517433
517795
  if (input.forceNew) {
517434
- return { action: "create" };
517796
+ return { action: "create", trigger: "force-new" };
517435
517797
  }
517436
517798
  if (input.pinnedAgentId && input.pinnedAgentExists) {
517437
517799
  const conversationId = input.pinnedAgentId === input.localAgentId ? input.localConversationId ?? undefined : undefined;
@@ -517470,7 +517832,7 @@ function resolveStartupTarget(input) {
517470
517832
  if (input.pinnedCount > 0) {
517471
517833
  return { action: "select" };
517472
517834
  }
517473
- return { action: "create" };
517835
+ return { action: "create", trigger: "fresh-start" };
517474
517836
  }
517475
517837
 
517476
517838
  // src/agent/defaults.ts
@@ -517478,6 +517840,7 @@ var exports_defaults2 = {};
517478
517840
  __export(exports_defaults2, {
517479
517841
  selectDefaultAgentModel: () => selectDefaultAgentModel2,
517480
517842
  ensureDefaultAgents: () => ensureDefaultAgents2,
517843
+ TUTOR_TAG: () => TUTOR_TAG2,
517481
517844
  MEMO_TAG: () => MEMO_TAG2,
517482
517845
  DEFAULT_AGENT_CONFIGS: () => DEFAULT_AGENT_CONFIGS2
517483
517846
  });
@@ -517545,29 +517908,39 @@ async function ensureDefaultAgents2(backend4, options3) {
517545
517908
  if (!settingsManager.shouldCreateDefaultAgents()) {
517546
517909
  return null;
517547
517910
  }
517911
+ const personality = options3?.personality ?? "memo";
517548
517912
  try {
517549
517913
  const { isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
517550
517914
  const willAutoEnableMemfs = backend4.capabilities.remoteMemfs && await isLettaCloud2();
517551
517915
  const memoryPromptMode = backend4.capabilities.localMemfs ? "local-memfs" : willAutoEnableMemfs ? "memfs" : undefined;
517552
- const { agent: agent2 } = await createAgent({
517916
+ const model = await resolveDefaultAgentModel2(backend4, options3?.preferredModel);
517917
+ const createOptions = personality === "tutorial" ? {
517918
+ ...await buildCreateAgentOptionsForPersonality2({
517919
+ personalityId: "tutorial",
517920
+ model
517921
+ }),
517922
+ memoryPromptMode
517923
+ } : {
517553
517924
  ...DEFAULT_AGENT_CONFIGS2.memo,
517554
- model: await resolveDefaultAgentModel2(backend4, options3?.preferredModel),
517925
+ model,
517555
517926
  memoryPromptMode
517556
- });
517557
- await addTagToAgent2(backend4, agent2.id, MEMO_TAG2);
517927
+ };
517928
+ const { agent: agent2 } = await createAgent(createOptions);
517929
+ await addTagToAgent2(backend4, agent2.id, personality === "tutorial" ? TUTOR_TAG2 : MEMO_TAG2);
517558
517930
  settingsManager.pinAgent(agent2.id);
517559
517931
  return agent2;
517560
517932
  } catch (err) {
517561
517933
  throw new Error(`Failed to create default agents: ${err instanceof Error ? err.message : String(err)}`);
517562
517934
  }
517563
517935
  }
517564
- var MEMO_TAG2 = "default:memo", MEMO_PERSONA2, MEMO_HUMAN2, MEMO_DESCRIPTION2 = "The default Letta Code agent with persistent memory", DEFAULT_AGENT_CONFIGS2;
517936
+ var MEMO_TAG2 = "default:memo", TUTOR_TAG2 = "default:tutorial", MEMO_PERSONA2, MEMO_HUMAN2, MEMO_DESCRIPTION2 = "The default Letta Code agent with persistent memory", DEFAULT_AGENT_CONFIGS2;
517565
517937
  var init_defaults2 = __esm(() => {
517566
517938
  init_client2();
517567
517939
  init_settings_manager();
517568
517940
  init_create6();
517569
517941
  init_memory5();
517570
517942
  init_model();
517943
+ init_personality();
517571
517944
  init_prompt_assets();
517572
517945
  MEMO_PERSONA2 = parseMdxFrontmatter(MEMORY_PROMPTS["persona_memo.mdx"] ?? "").body;
517573
517946
  MEMO_HUMAN2 = parseMdxFrontmatter(MEMORY_PROMPTS["human_memo.mdx"] ?? "").body;
@@ -517792,8 +518165,8 @@ __export(exports_import2, {
517792
518165
  extractSkillsFromAf: () => extractSkillsFromAf2
517793
518166
  });
517794
518167
  import { createReadStream as createReadStream3 } from "node:fs";
517795
- import { access as access4, chmod as chmod2, mkdir as mkdir16, readFile as readFile24, writeFile as writeFile18 } from "node:fs/promises";
517796
- import { dirname as dirname34, isAbsolute as isAbsolute26, relative as relative15, resolve as resolve40, sep as sep7, win32 as win326 } from "node:path";
518168
+ import { access as access4, chmod as chmod2, mkdir as mkdir16, readFile as readFile25, writeFile as writeFile19 } from "node:fs/promises";
518169
+ import { dirname as dirname35, isAbsolute as isAbsolute26, relative as relative16, resolve as resolve40, sep as sep7, win32 as win326 } from "node:path";
517797
518170
  function validateImportedSkillName2(name) {
517798
518171
  const trimmedName = name.trim();
517799
518172
  if (trimmedName !== name || trimmedName.length === 0 || trimmedName.length > MAX_SKILL_NAME_LENGTH || trimmedName === "." || trimmedName === ".." || !IMPORTED_SKILL_NAME_PATTERN2.test(trimmedName)) {
@@ -517804,7 +518177,7 @@ function validateImportedSkillName2(name) {
517804
518177
  function assertPathInside2(parent, child) {
517805
518178
  const parentPath = resolve40(parent);
517806
518179
  const childPath = resolve40(child);
517807
- const relativePath = relative15(parentPath, childPath);
518180
+ const relativePath = relative16(parentPath, childPath);
517808
518181
  if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep7}`) || isAbsolute26(relativePath)) {
517809
518182
  throw new Error(`Imported skill file path escapes skill directory: ${child}`);
517810
518183
  }
@@ -517893,7 +518266,7 @@ async function importAgentFromFile2(options3) {
517893
518266
  }
517894
518267
  async function extractSkillsFromAf2(afPath, destDir) {
517895
518268
  const extracted = [];
517896
- const content = await readFile24(afPath, "utf-8");
518269
+ const content = await readFile25(afPath, "utf-8");
517897
518270
  const afData = JSON.parse(content);
517898
518271
  if (!afData.skills || !Array.isArray(afData.skills)) {
517899
518272
  return [];
@@ -517921,8 +518294,8 @@ async function writeSkillFiles2(skillDir, files) {
517921
518294
  }
517922
518295
  async function writeSkillFile2(skillDir, filePath, content) {
517923
518296
  const fullPath = resolveImportedSkillFilePath2(skillDir, filePath);
517924
- await mkdir16(dirname34(fullPath), { recursive: true });
517925
- await writeFile18(fullPath, content, "utf-8");
518297
+ await mkdir16(dirname35(fullPath), { recursive: true });
518298
+ await writeFile19(fullPath, content, "utf-8");
517926
518299
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
517927
518300
  if (isScript) {
517928
518301
  try {
@@ -517974,8 +518347,8 @@ function parseRegistryHandle2(handle2) {
517974
518347
  }
517975
518348
  async function importAgentFromRegistry2(options3) {
517976
518349
  const { tmpdir: tmpdir12 } = await import("node:os");
517977
- const { join: join77 } = await import("node:path");
517978
- const { writeFile: writeFile19, unlink: unlink5 } = await import("node:fs/promises");
518350
+ const { join: join78 } = await import("node:path");
518351
+ const { writeFile: writeFile20, unlink: unlink5 } = await import("node:fs/promises");
517979
518352
  const { author, name } = parseRegistryHandle2(options3.handle);
517980
518353
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
517981
518354
  const response = await fetch(rawUrl);
@@ -517986,8 +518359,8 @@ async function importAgentFromRegistry2(options3) {
517986
518359
  throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
517987
518360
  }
517988
518361
  const afContent = await response.text();
517989
- const tempPath = join77(tmpdir12(), `letta-import-${author}-${name}-${Date.now()}.af`);
517990
- await writeFile19(tempPath, afContent, "utf-8");
518362
+ const tempPath = join78(tmpdir12(), `letta-import-${author}-${name}-${Date.now()}.af`);
518363
+ await writeFile20(tempPath, afContent, "utf-8");
517991
518364
  try {
517992
518365
  const result = await importAgentFromFile2({
517993
518366
  filePath: tempPath,
@@ -518042,12 +518415,12 @@ __export(exports_memory_filesystem2, {
518042
518415
  });
518043
518416
  import { existsSync as existsSync69, mkdirSync as mkdirSync47 } from "node:fs";
518044
518417
  import { homedir as homedir48 } from "node:os";
518045
- import { join as join77, resolve as resolve41 } from "node:path";
518418
+ import { join as join78, resolve as resolve41 } from "node:path";
518046
518419
  function getMemoryFilesystemRoot2(agentId, homeDir = homedir48()) {
518047
- return join77(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
518420
+ return join78(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
518048
518421
  }
518049
518422
  function getMemorySystemDir2(agentId, homeDir = homedir48()) {
518050
- return join77(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
518423
+ return join78(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
518051
518424
  }
518052
518425
  function getScopedMemoryFilesystemRoot2(agentId, options3 = {}) {
518053
518426
  const env6 = options3.env ?? process.env;
@@ -518393,7 +518766,7 @@ __export(exports_secrets_store2, {
518393
518766
  __testOverrideLocalSecretStorage: () => __testOverrideLocalSecretStorage2
518394
518767
  });
518395
518768
  import { existsSync as existsSync70, mkdirSync as mkdirSync48, readFileSync as readFileSync45, writeFileSync as writeFileSync36 } from "node:fs";
518396
- import { dirname as dirname35, join as join78 } from "node:path";
518769
+ import { dirname as dirname36, join as join79 } from "node:path";
518397
518770
  function __testOverrideSecretsBackend2(backend4) {
518398
518771
  testBackendOverride2 = backend4;
518399
518772
  }
@@ -518404,7 +518777,7 @@ function getSecretsBackend2() {
518404
518777
  return testBackendOverride2 ?? getBackend();
518405
518778
  }
518406
518779
  function getFileBackedLocalSecretsPath2() {
518407
- return join78(getLocalBackendStorageDir(), FILE_BACKED_LOCAL_SECRETS_PATH2);
518780
+ return join79(getLocalBackendStorageDir(), FILE_BACKED_LOCAL_SECRETS_PATH2);
518408
518781
  }
518409
518782
  function readFileBackedLocalSecrets2() {
518410
518783
  const filePath = getFileBackedLocalSecretsPath2();
@@ -518421,7 +518794,7 @@ function readFileBackedLocalSecrets2() {
518421
518794
  }
518422
518795
  function writeFileBackedLocalSecrets2(secrets2) {
518423
518796
  const filePath = getFileBackedLocalSecretsPath2();
518424
- mkdirSync48(dirname35(filePath), { mode: 448, recursive: true });
518797
+ mkdirSync48(dirname36(filePath), { mode: 448, recursive: true });
518425
518798
  writeFileSync36(filePath, `${JSON.stringify({ secrets: secrets2 }, null, 2)}
518426
518799
  `, {
518427
518800
  encoding: "utf8",
@@ -518717,7 +519090,7 @@ var init_secrets_store2 = __esm(() => {
518717
519090
  init_backend2();
518718
519091
  init_paths();
518719
519092
  init_secrets();
518720
- FILE_BACKED_LOCAL_SECRETS_PATH2 = join78("secrets", "local-agent-secrets.json");
519093
+ FILE_BACKED_LOCAL_SECRETS_PATH2 = join79("secrets", "local-agent-secrets.json");
518721
519094
  SECRETS_CACHE_KEY2 = Symbol.for("@letta/secretsCache");
518722
519095
  LOCAL_SECRET_NAME_PATTERN2 = /^[A-Z_][A-Z0-9_]*$/;
518723
519096
  });
@@ -519791,6 +520164,7 @@ function getContext2() {
519791
520164
  if (!global2[CONTEXT_KEY2]) {
519792
520165
  global2[CONTEXT_KEY2] = {
519793
520166
  agentId: null,
520167
+ agentName: null,
519794
520168
  skillsDirectory: null,
519795
520169
  skillSources: [...ALL_SKILL_SOURCES],
519796
520170
  conversationId: null
@@ -519799,18 +520173,24 @@ function getContext2() {
519799
520173
  return global2[CONTEXT_KEY2];
519800
520174
  }
519801
520175
  var context2 = getContext2();
519802
- function setAgentContext2(agentId, skillsDirectory, skillSources) {
520176
+ function setAgentContext2(agentId, skillsDirectory, skillSources, agentName) {
519803
520177
  context2.agentId = agentId;
520178
+ context2.agentName = normalizeAgentName2(agentName);
519804
520179
  context2.skillsDirectory = skillsDirectory || null;
519805
520180
  context2.skillSources = skillSources !== undefined ? [...skillSources] : [...ALL_SKILL_SOURCES];
519806
520181
  if (getRuntimeContext()) {
519807
520182
  updateRuntimeContext({
519808
520183
  agentId,
520184
+ agentName: context2.agentName,
519809
520185
  skillsDirectory: skillsDirectory || null,
519810
520186
  skillSources: skillSources !== undefined ? [...skillSources] : [...ALL_SKILL_SOURCES]
519811
520187
  });
519812
520188
  }
519813
520189
  }
520190
+ function normalizeAgentName2(agentName) {
520191
+ const trimmed = typeof agentName === "string" ? agentName.trim() : "";
520192
+ return trimmed || null;
520193
+ }
519814
520194
  function setConversationId2(conversationId) {
519815
520195
  context2.conversationId = conversationId;
519816
520196
  if (getRuntimeContext()) {
@@ -525224,8 +525604,8 @@ import {
525224
525604
  unlinkSync as unlinkSync7
525225
525605
  } from "node:fs";
525226
525606
  import { homedir as homedir30 } from "node:os";
525227
- import { join as join49 } from "node:path";
525228
- var REMOTE_LOG_DIR = join49(homedir30(), ".letta", "logs", "remote");
525607
+ import { join as join50 } from "node:path";
525608
+ var REMOTE_LOG_DIR = join50(homedir30(), ".letta", "logs", "remote");
525229
525609
  var MAX_LOG_FILES = 10;
525230
525610
  function formatTimestamp2() {
525231
525611
  const now = new Date;
@@ -525244,7 +525624,7 @@ function pruneOldLogs() {
525244
525624
  const toDelete = files.slice(0, files.length - MAX_LOG_FILES + 1);
525245
525625
  for (const file3 of toDelete) {
525246
525626
  try {
525247
- unlinkSync7(join49(REMOTE_LOG_DIR, file3));
525627
+ unlinkSync7(join50(REMOTE_LOG_DIR, file3));
525248
525628
  } catch {}
525249
525629
  }
525250
525630
  }
@@ -525257,7 +525637,7 @@ class RemoteSessionLog {
525257
525637
  constructor() {
525258
525638
  const now = new Date;
525259
525639
  const stamp = now.toISOString().replace(/[:.]/g, "-");
525260
- this.path = join49(REMOTE_LOG_DIR, `${stamp}.log`);
525640
+ this.path = join50(REMOTE_LOG_DIR, `${stamp}.log`);
525261
525641
  }
525262
525642
  init() {
525263
525643
  this.ensureDir();
@@ -525886,7 +526266,7 @@ import {
525886
526266
  readFileSync as readFileSync32,
525887
526267
  writeFileSync as writeFileSync23
525888
526268
  } from "node:fs";
525889
- import { join as join50 } from "node:path";
526269
+ import { join as join51 } from "node:path";
525890
526270
  function readJsonl(path37) {
525891
526271
  if (!existsSync47(path37))
525892
526272
  return [];
@@ -526169,7 +526549,7 @@ function convertMessages4(messages, mode, nextId2) {
526169
526549
  }
526170
526550
  function migrateLocalBackendTranscripts(input) {
526171
526551
  const storageDir = input.storageDir;
526172
- const conversationsDir = join50(storageDir, "conversations");
526552
+ const conversationsDir = join51(storageDir, "conversations");
526173
526553
  const result = {
526174
526554
  storageDir,
526175
526555
  converted: [],
@@ -526179,9 +526559,9 @@ function migrateLocalBackendTranscripts(input) {
526179
526559
  if (!existsSync47(conversationsDir))
526180
526560
  return result;
526181
526561
  for (const name of readdirSync17(conversationsDir)) {
526182
- const conversationDir = join50(conversationsDir, name);
526183
- const messagesPath = join50(conversationDir, "messages.jsonl");
526184
- const manifestPath = join50(conversationDir, "manifest.json");
526562
+ const conversationDir = join51(conversationsDir, name);
526563
+ const messagesPath = join51(conversationDir, "messages.jsonl");
526564
+ const manifestPath = join51(conversationDir, "manifest.json");
526185
526565
  const hasManifest = existsSync47(manifestPath);
526186
526566
  const existingManifest = hasManifest ? (() => {
526187
526567
  try {
@@ -526224,7 +526604,7 @@ function migrateLocalBackendTranscripts(input) {
526224
526604
  const backupPath = `${messagesPath}.pre-pi-backup-${timestampSuffix()}`;
526225
526605
  if (!input.dryRun) {
526226
526606
  copyFileSync2(messagesPath, backupPath);
526227
- const conversationPath = join50(conversationDir, "conversation.json");
526607
+ const conversationPath = join51(conversationDir, "conversation.json");
526228
526608
  let conversation;
526229
526609
  if (existsSync47(conversationPath)) {
526230
526610
  try {
@@ -526337,8 +526717,8 @@ init_memory_filesystem2();
526337
526717
  init_memory_git();
526338
526718
  init_paths();
526339
526719
  import { cpSync, existsSync as existsSync48, mkdirSync as mkdirSync33, rmSync as rmSync10, statSync as statSync17 } from "node:fs";
526340
- import { readdir as readdir11 } from "node:fs/promises";
526341
- import { dirname as dirname24, join as join51 } from "node:path";
526720
+ import { readdir as readdir12 } from "node:fs/promises";
526721
+ import { dirname as dirname25, join as join52 } from "node:path";
526342
526722
  import { parseArgs as parseArgs9 } from "node:util";
526343
526723
 
526344
526724
  // src/cli/subcommands/memory-tokens.ts
@@ -526476,7 +526856,7 @@ function getMemoryRoot(agentId) {
526476
526856
  return getScopedMemoryFilesystemRoot(agentId);
526477
526857
  }
526478
526858
  function getAgentRoot(agentId) {
526479
- return dirname24(getMemoryRoot(agentId));
526859
+ return dirname25(getMemoryRoot(agentId));
526480
526860
  }
526481
526861
  function formatBackupTimestamp(date6 = new Date) {
526482
526862
  const pad = (value) => String(value).padStart(2, "0");
@@ -526493,18 +526873,18 @@ async function listBackups(agentId) {
526493
526873
  if (!existsSync48(agentRoot)) {
526494
526874
  return [];
526495
526875
  }
526496
- const entries = await readdir11(agentRoot, { withFileTypes: true });
526876
+ const entries = await readdir12(agentRoot, { withFileTypes: true });
526497
526877
  const backups = [];
526498
526878
  for (const entry of entries) {
526499
526879
  if (!entry.isDirectory())
526500
526880
  continue;
526501
526881
  if (!entry.name.startsWith("memory-backup-"))
526502
526882
  continue;
526503
- const path37 = join51(agentRoot, entry.name);
526883
+ const path37 = join52(agentRoot, entry.name);
526504
526884
  let createdAt = null;
526505
526885
  try {
526506
- const stat13 = statSync17(path37);
526507
- createdAt = stat13.mtime.toISOString();
526886
+ const stat14 = statSync17(path37);
526887
+ createdAt = stat14.mtime.toISOString();
526508
526888
  } catch {
526509
526889
  createdAt = null;
526510
526890
  }
@@ -526517,7 +526897,7 @@ function resolveBackupPath(agentId, from) {
526517
526897
  if (from.startsWith("/") || /^[A-Za-z]:[/\\]/.test(from)) {
526518
526898
  return from;
526519
526899
  }
526520
- return join51(getAgentRoot(agentId), from);
526900
+ return join52(getAgentRoot(agentId), from);
526521
526901
  }
526522
526902
  async function runMemorySubcommand(argv) {
526523
526903
  let parsed;
@@ -526599,7 +526979,7 @@ async function runMemorySubcommand(argv) {
526599
526979
  }
526600
526980
  const agentRoot = getAgentRoot(agentId);
526601
526981
  const backupName = `memory-backup-${formatBackupTimestamp()}`;
526602
- const backupPath = join51(agentRoot, backupName);
526982
+ const backupPath = join52(agentRoot, backupName);
526603
526983
  if (existsSync48(backupPath)) {
526604
526984
  console.error(`Backup already exists at ${backupPath}`);
526605
526985
  return 1;
@@ -526628,8 +527008,8 @@ async function runMemorySubcommand(argv) {
526628
527008
  console.error(`Backup not found: ${backupPath}`);
526629
527009
  return 1;
526630
527010
  }
526631
- const stat13 = statSync17(backupPath);
526632
- if (!stat13.isDirectory()) {
527011
+ const stat14 = statSync17(backupPath);
527012
+ if (!stat14.isDirectory()) {
526633
527013
  console.error(`Backup path is not a directory: ${backupPath}`);
526634
527014
  return 1;
526635
527015
  }
@@ -526651,9 +527031,9 @@ async function runMemorySubcommand(argv) {
526651
527031
  return 1;
526652
527032
  }
526653
527033
  if (existsSync48(out)) {
526654
- const stat13 = statSync17(out);
526655
- if (stat13.isDirectory()) {
526656
- const contents = await readdir11(out);
527034
+ const stat14 = statSync17(out);
527035
+ if (stat14.isDirectory()) {
527036
+ const contents = await readdir12(out);
526657
527037
  if (contents.length > 0) {
526658
527038
  console.error(`Export directory not empty: ${out}`);
526659
527039
  return 1;
@@ -526682,7 +527062,7 @@ async function runMemorySubcommand(argv) {
526682
527062
  init_backend2();
526683
527063
  init_message_search();
526684
527064
  init_settings_manager();
526685
- import { writeFile as writeFile14 } from "node:fs/promises";
527065
+ import { writeFile as writeFile15 } from "node:fs/promises";
526686
527066
  import { resolve as resolve30 } from "node:path";
526687
527067
  import { parseArgs as parseArgs10 } from "node:util";
526688
527068
  function printUsage7() {
@@ -527027,7 +527407,7 @@ async function runMessagesSubcommand(argv, deps = {}) {
527027
527407
  `).trim();
527028
527408
  if (outputPathRaw && typeof outputPathRaw === "string") {
527029
527409
  const outputPath = resolve30(process.cwd(), outputPathRaw);
527030
- await writeFile14(outputPath, `${transcript}
527410
+ await writeFile15(outputPath, `${transcript}
527031
527411
  `, "utf-8");
527032
527412
  console.log(JSON.stringify({
527033
527413
  conversation_id: conversationId,
@@ -527057,7 +527437,7 @@ async function runMessagesSubcommand(argv, deps = {}) {
527057
527437
  // src/cli/subcommands/mods.ts
527058
527438
  init_memory_filesystem2();
527059
527439
  await init_mod_engine();
527060
- import { dirname as dirname25, join as join53 } from "node:path";
527440
+ import { dirname as dirname26, join as join54 } from "node:path";
527061
527441
  import { parseArgs as parseArgs11 } from "node:util";
527062
527442
 
527063
527443
  // src/mods/package-installer.ts
@@ -527091,8 +527471,8 @@ function isRecord10(value) {
527091
527471
  function isPathInsideOrEqual2(childPath, parentPath) {
527092
527472
  const child = path37.resolve(childPath);
527093
527473
  const parent = path37.resolve(parentPath);
527094
- const relative11 = path37.relative(parent, child);
527095
- return relative11 === "" || !!relative11 && !relative11.startsWith("..") && !path37.isAbsolute(relative11);
527474
+ const relative12 = path37.relative(parent, child);
527475
+ return relative12 === "" || !!relative12 && !relative12.startsWith("..") && !path37.isAbsolute(relative12);
527096
527476
  }
527097
527477
  function readPackageJson(packageJsonPath) {
527098
527478
  let parsed;
@@ -528110,10 +528490,10 @@ function getExplicitAgentId(values2) {
528110
528490
  return typeof explicitAgent === "string" && explicitAgent.trim() ? explicitAgent.trim() : null;
528111
528491
  }
528112
528492
  function getAgentModsDirectory(agentId) {
528113
- return join53(getScopedMemoryFilesystemRoot(agentId), "mods");
528493
+ return join54(getScopedMemoryFilesystemRoot(agentId), "mods");
528114
528494
  }
528115
528495
  function directFilesForSource(source2) {
528116
- return source2.files.filter((file3) => dirname25(file3) === source2.root);
528496
+ return source2.files.filter((file3) => dirname26(file3) === source2.root);
528117
528497
  }
528118
528498
  function toSection(source2) {
528119
528499
  return {
@@ -528446,9 +528826,9 @@ import {
528446
528826
  statSync as statSync19,
528447
528827
  writeFileSync as writeFileSync26
528448
528828
  } from "node:fs";
528449
- import { mkdir as mkdir12, readdir as readdir12 } from "node:fs/promises";
528829
+ import { mkdir as mkdir12, readdir as readdir13 } from "node:fs/promises";
528450
528830
  import { tmpdir as tmpdir9 } from "node:os";
528451
- import { basename as basename23, dirname as dirname26, join as join54, normalize as normalize5, resolve as resolve31, sep as sep5 } from "node:path";
528831
+ import { basename as basename24, dirname as dirname27, join as join55, normalize as normalize5, resolve as resolve31, sep as sep5 } from "node:path";
528452
528832
  import { parseArgs as parseArgs12, TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
528453
528833
  init_paths2();
528454
528834
  var HERMES_REPO_URL = "https://github.com/NousResearch/hermes-agent.git";
@@ -528623,7 +529003,7 @@ function parseGitHubSpecifier(input) {
528623
529003
  return {
528624
529004
  repoUrl,
528625
529005
  branch: null,
528626
- subdir: marker === "blob" ? dirname26(treePath) : treePath
529006
+ subdir: marker === "blob" ? dirname27(treePath) : treePath
528627
529007
  };
528628
529008
  }
528629
529009
  return { repoUrl, branch: null, subdir: null };
@@ -528656,7 +529036,7 @@ function parseDirectSkillFileUrlSpecifier(input) {
528656
529036
  if (url2.protocol !== "https:" && !(url2.protocol === "http:" && isLocalhostHostname(url2.hostname))) {
528657
529037
  return null;
528658
529038
  }
528659
- if (basename23(url2.pathname).toLowerCase() !== "skill.md")
529039
+ if (basename24(url2.pathname).toLowerCase() !== "skill.md")
528660
529040
  return null;
528661
529041
  return { url: url2.toString() };
528662
529042
  }
@@ -528753,14 +529133,14 @@ async function resolveBranchAndSubdir(location) {
528753
529133
  }
528754
529134
  async function cloneSkillSource(location) {
528755
529135
  const resolvedLocation = await resolveBranchAndSubdir(location);
528756
- const tmpDir = mkdtempSync4(join54(tmpdir9(), "letta-skill-install-"));
529136
+ const tmpDir = mkdtempSync4(join55(tmpdir9(), "letta-skill-install-"));
528757
529137
  const args = ["clone", "--depth", "1"];
528758
529138
  if (resolvedLocation.branch) {
528759
529139
  args.push("--branch", resolvedLocation.branch);
528760
529140
  }
528761
529141
  args.push(resolvedLocation.repoUrl, tmpDir);
528762
529142
  await execFile15("git", args, { timeout: 120000 });
528763
- const sourceDir = resolvedLocation.subdir ? join54(tmpDir, resolvedLocation.subdir) : tmpDir;
529143
+ const sourceDir = resolvedLocation.subdir ? join55(tmpDir, resolvedLocation.subdir) : tmpDir;
528764
529144
  return { tmpDir, sourceDir };
528765
529145
  }
528766
529146
  function assertDirectSkillFileSize(receivedBytes, maxBytes) {
@@ -528815,11 +529195,11 @@ async function downloadDirectSkillFileSource(location, options3 = {}) {
528815
529195
  throw new Error(`Direct skill file download failed for ${location.url}: ${response.status}`);
528816
529196
  }
528817
529197
  const skillText = await readResponseTextWithLimit(response, MAX_DIRECT_SKILL_FILE_BYTES);
528818
- const tmpDir = mkdtempSync4(join54(tmpdir9(), "letta-direct-skill-"));
529198
+ const tmpDir = mkdtempSync4(join55(tmpdir9(), "letta-direct-skill-"));
528819
529199
  try {
528820
- const sourceDir = join54(tmpDir, "skill");
529200
+ const sourceDir = join55(tmpDir, "skill");
528821
529201
  await mkdir12(sourceDir, { recursive: true });
528822
- writeFileSync26(join54(sourceDir, "SKILL.md"), skillText, "utf8");
529202
+ writeFileSync26(join55(sourceDir, "SKILL.md"), skillText, "utf8");
528823
529203
  return { tmpDir, sourceDir };
528824
529204
  } catch (error54) {
528825
529205
  rmSync13(tmpDir, { recursive: true, force: true });
@@ -528860,9 +529240,9 @@ function assertSafeZipMember(name) {
528860
529240
  }
528861
529241
  async function downloadClawHubSkillSource(location) {
528862
529242
  const version2 = await resolveClawHubVersion(location);
528863
- const tmpDir = mkdtempSync4(join54(tmpdir9(), "letta-clawhub-skill-"));
528864
- const zipPath = join54(tmpDir, "skill.zip");
528865
- const sourceDir = join54(tmpDir, "skill");
529243
+ const tmpDir = mkdtempSync4(join55(tmpdir9(), "letta-clawhub-skill-"));
529244
+ const zipPath = join55(tmpDir, "skill.zip");
529245
+ const sourceDir = join55(tmpDir, "skill");
528866
529246
  await mkdir12(sourceDir, { recursive: true });
528867
529247
  const url2 = new URL(`${CLAWHUB_API_BASE_URL}/download`);
528868
529248
  url2.searchParams.set("slug", location.slug);
@@ -528901,16 +529281,16 @@ function sanitizeSkillName(name) {
528901
529281
  return trimmed;
528902
529282
  }
528903
529283
  function getSkillName(sourceDir) {
528904
- const skillMd = readFileSync35(join54(sourceDir, "SKILL.md"), "utf8");
529284
+ const skillMd = readFileSync35(join55(sourceDir, "SKILL.md"), "utf8");
528905
529285
  const { frontmatter } = parseFrontmatter(skillMd);
528906
529286
  const frontmatterName = frontmatter.name;
528907
- const name = typeof frontmatterName === "string" && frontmatterName.trim() ? frontmatterName : basename23(sourceDir);
529287
+ const name = typeof frontmatterName === "string" && frontmatterName.trim() ? frontmatterName : basename24(sourceDir);
528908
529288
  return sanitizeSkillName(name);
528909
529289
  }
528910
529290
  async function installSkillDirectory(params) {
528911
529291
  const sourceDir = resolve31(params.sourceDir);
528912
529292
  const memoryDir = resolve31(params.memoryDir);
528913
- const skillMdPath = join54(sourceDir, "SKILL.md");
529293
+ const skillMdPath = join55(sourceDir, "SKILL.md");
528914
529294
  if (!existsSync52(skillMdPath)) {
528915
529295
  throw new Error("No SKILL.md found in the skill directory.");
528916
529296
  }
@@ -528918,8 +529298,8 @@ async function installSkillDirectory(params) {
528918
529298
  throw new Error(`Skill source is not a directory: ${sourceDir}`);
528919
529299
  }
528920
529300
  const name = getSkillName(sourceDir);
528921
- const skillsDir = join54(memoryDir, "skills");
528922
- const targetPath = join54(skillsDir, name);
529301
+ const skillsDir = join55(memoryDir, "skills");
529302
+ const targetPath = join55(skillsDir, name);
528923
529303
  assertInside(skillsDir, targetPath);
528924
529304
  if (existsSync52(targetPath)) {
528925
529305
  if (!params.force) {
@@ -528930,22 +529310,22 @@ async function installSkillDirectory(params) {
528930
529310
  await mkdir12(skillsDir, { recursive: true });
528931
529311
  cpSync2(sourceDir, targetPath, {
528932
529312
  recursive: true,
528933
- filter: (source2) => basename23(source2) !== ".git"
529313
+ filter: (source2) => basename24(source2) !== ".git"
528934
529314
  });
528935
529315
  return { name, path: normalize5(targetPath) };
528936
529316
  }
528937
529317
  async function listSkillDirectories(params) {
528938
529318
  const memoryDir = resolve31(params.memoryDir);
528939
- const skillsDir = join54(memoryDir, "skills");
529319
+ const skillsDir = join55(memoryDir, "skills");
528940
529320
  if (!existsSync52(skillsDir))
528941
529321
  return [];
528942
- const entries = await readdir12(skillsDir, { withFileTypes: true });
529322
+ const entries = await readdir13(skillsDir, { withFileTypes: true });
528943
529323
  const skills = [];
528944
529324
  for (const entry of entries) {
528945
529325
  if (!entry.isDirectory())
528946
529326
  continue;
528947
- const skillDir = join54(skillsDir, entry.name);
528948
- const skillMdPath = join54(skillDir, "SKILL.md");
529327
+ const skillDir = join55(skillsDir, entry.name);
529328
+ const skillMdPath = join55(skillDir, "SKILL.md");
528949
529329
  if (!existsSync52(skillMdPath))
528950
529330
  continue;
528951
529331
  let name = entry.name;
@@ -528966,9 +529346,9 @@ async function listSkillDirectories(params) {
528966
529346
  }
528967
529347
  async function deleteSkillDirectory(params) {
528968
529348
  const memoryDir = resolve31(params.memoryDir);
528969
- const skillsDir = join54(memoryDir, "skills");
529349
+ const skillsDir = join55(memoryDir, "skills");
528970
529350
  const name = sanitizeSkillName(params.name);
528971
- const targetPath = join54(skillsDir, name);
529351
+ const targetPath = join55(skillsDir, name);
528972
529352
  assertInside(skillsDir, targetPath);
528973
529353
  if (!existsSync52(targetPath)) {
528974
529354
  throw new Error(`Skill "${name}" is not installed at ${targetPath}.`);
@@ -528979,6 +529359,27 @@ async function deleteSkillDirectory(params) {
528979
529359
  rmSync13(targetPath, { recursive: true, force: true });
528980
529360
  return { name, path: normalize5(targetPath) };
528981
529361
  }
529362
+ async function loadSkillMemorySyncFn() {
529363
+ const { syncPendingMemoryCommitsAfterTurn: syncPendingMemoryCommitsAfterTurn2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
529364
+ return syncPendingMemoryCommitsAfterTurn2;
529365
+ }
529366
+ async function syncCommittedRemoteSkillMemoryChange(params) {
529367
+ if (!params.committed || isLocalAgentId(params.agentId)) {
529368
+ return;
529369
+ }
529370
+ try {
529371
+ const syncFn = params.syncFn ?? await loadSkillMemorySyncFn();
529372
+ const result = await syncFn(params.agentId, {
529373
+ memoryDir: params.memoryDir
529374
+ });
529375
+ return { status: result.status, summary: result.summary };
529376
+ } catch (error54) {
529377
+ return {
529378
+ status: "push_failed",
529379
+ summary: error54 instanceof Error ? error54.message : String(error54)
529380
+ };
529381
+ }
529382
+ }
528982
529383
  async function installSkill(specifier, agentId, force) {
528983
529384
  const source2 = resolveSkillSourceSpecifier(specifier);
528984
529385
  if (!source2) {
@@ -529014,7 +529415,8 @@ async function installSkill(specifier, agentId, force) {
529014
529415
  source: specifier,
529015
529416
  ...result,
529016
529417
  committed: commit.committed,
529017
- commitSha: commit.sha
529418
+ commitSha: commit.sha,
529419
+ memorySync: commit.memorySync
529018
529420
  };
529019
529421
  } finally {
529020
529422
  if (tmpDir)
@@ -529054,7 +529456,12 @@ async function commitSkillMemoryChange(params) {
529054
529456
  },
529055
529457
  syncMode: isLocalAgentId(params.agentId) ? "local" : "remote"
529056
529458
  });
529057
- return { committed: result.committed, sha: result.sha };
529459
+ const memorySync = await syncCommittedRemoteSkillMemoryChange({
529460
+ agentId: params.agentId,
529461
+ memoryDir: params.memoryDir,
529462
+ committed: result.committed
529463
+ });
529464
+ return { committed: result.committed, sha: result.sha, memorySync };
529058
529465
  }
529059
529466
  async function listSkills(agentId) {
529060
529467
  const memoryDir = await getAgentMemoryDir(agentId);
@@ -529075,7 +529482,8 @@ async function deleteSkill(skillName, agentId) {
529075
529482
  deleted: true,
529076
529483
  ...result,
529077
529484
  committed: commit.committed,
529078
- commitSha: commit.sha
529485
+ commitSha: commit.sha,
529486
+ memorySync: commit.memorySync
529079
529487
  };
529080
529488
  }
529081
529489
  async function initializeAndResolveAgent(values2, promptStatusMessage) {
@@ -529437,7 +529845,7 @@ init_secrets();
529437
529845
  import { randomUUID as randomUUID24 } from "node:crypto";
529438
529846
  import { readFileSync as readFileSync36 } from "node:fs";
529439
529847
  import { homedir as homedir31 } from "node:os";
529440
- import { join as join55, resolve as resolve32 } from "node:path";
529848
+ import { join as join56, resolve as resolve32 } from "node:path";
529441
529849
  var OBSOLETE_SETTINGS_KEYS2 = [
529442
529850
  "reflectionBehavior",
529443
529851
  "enableSleeptime",
@@ -529880,7 +530288,7 @@ class SettingsManager2 {
529880
530288
  return;
529881
530289
  const settingsPath = this.getSettingsPath();
529882
530290
  const home = process.env.HOME || homedir31();
529883
- const dirPath = join55(home, ".letta");
530291
+ const dirPath = join56(home, ".letta");
529884
530292
  try {
529885
530293
  if (!exists(dirPath)) {
529886
530294
  await mkdir(dirPath, { recursive: true });
@@ -529921,7 +530329,7 @@ class SettingsManager2 {
529921
530329
  if (!settings3)
529922
530330
  return;
529923
530331
  const settingsPath = this.getProjectSettingsPath(workingDirectory);
529924
- const dirPath = join55(workingDirectory, ".letta");
530332
+ const dirPath = join56(workingDirectory, ".letta");
529925
530333
  try {
529926
530334
  let existingSettings = {};
529927
530335
  if (exists(settingsPath)) {
@@ -529943,16 +530351,16 @@ class SettingsManager2 {
529943
530351
  }
529944
530352
  getSettingsPath() {
529945
530353
  const home = process.env.HOME || homedir31();
529946
- return join55(home, ".letta", "settings.json");
530354
+ return join56(home, ".letta", "settings.json");
529947
530355
  }
529948
530356
  getProjectSettingsPath(workingDirectory) {
529949
- return join55(workingDirectory, ".letta", "settings.json");
530357
+ return join56(workingDirectory, ".letta", "settings.json");
529950
530358
  }
529951
530359
  isProjectSettingsPathCollidingWithGlobal(workingDirectory) {
529952
530360
  return resolve32(this.getProjectSettingsPath(workingDirectory)) === resolve32(this.getSettingsPath());
529953
530361
  }
529954
530362
  getLocalProjectSettingsPath(workingDirectory) {
529955
- return join55(workingDirectory, ".letta", "settings.local.json");
530363
+ return join56(workingDirectory, ".letta", "settings.local.json");
529956
530364
  }
529957
530365
  async loadLocalProjectSettings(workingDirectory = process.cwd()) {
529958
530366
  const cached3 = this.localProjectSettings.get(workingDirectory);
@@ -530013,7 +530421,7 @@ class SettingsManager2 {
530013
530421
  if (!settings3)
530014
530422
  return;
530015
530423
  const settingsPath = this.getLocalProjectSettingsPath(workingDirectory);
530016
- const dirPath = join55(workingDirectory, ".letta");
530424
+ const dirPath = join56(workingDirectory, ".letta");
530017
530425
  try {
530018
530426
  if (!exists(dirPath)) {
530019
530427
  await mkdir(dirPath, { recursive: true });
@@ -530362,7 +530770,7 @@ class SettingsManager2 {
530362
530770
  });
530363
530771
  }
530364
530772
  hasLocalLettaDir(workingDirectory = process.cwd()) {
530365
- const dirPath = join55(workingDirectory, ".letta");
530773
+ const dirPath = join56(workingDirectory, ".letta");
530366
530774
  return exists(dirPath);
530367
530775
  }
530368
530776
  storeOAuthState(state, codeVerifier, redirectUri, provider) {
@@ -530995,8 +531403,8 @@ function markMilestone2(name) {
530995
531403
  firstMilestoneTime2 = now;
530996
531404
  }
530997
531405
  if (isTimingsEnabled2()) {
530998
- const relative11 = now - firstMilestoneTime2;
530999
- console.error(`[timing] MILESTONE ${name} at +${formatDuration3(relative11)} (${formatTimestamp4(new Date)})`);
531406
+ const relative12 = now - firstMilestoneTime2;
531407
+ console.error(`[timing] MILESTONE ${name} at +${formatDuration3(relative12)} (${formatTimestamp4(new Date)})`);
531000
531408
  }
531001
531409
  }
531002
531410
 
@@ -531133,12 +531541,12 @@ EXAMPLES
531133
531541
  console.log(usage);
531134
531542
  }
531135
531543
  async function printInfo() {
531136
- const { join: join79 } = await import("path");
531544
+ const { join: join80 } = await import("path");
531137
531545
  const { getVersion: getVersion3 } = await Promise.resolve().then(() => (init_version2(), exports_version2));
531138
531546
  const { SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills4(), exports_skills3));
531139
531547
  const { exists: exists3 } = await Promise.resolve().then(() => (init_fs2(), exports_fs));
531140
531548
  const cwd2 = process.cwd();
531141
- const skillsDir = join79(cwd2, SKILLS_DIR3);
531549
+ const skillsDir = join80(cwd2, SKILLS_DIR3);
531142
531550
  const skillsExist = exists3(skillsDir);
531143
531551
  await settingsManager2.loadLocalProjectSettings(cwd2);
531144
531552
  const pinned = settingsManager2.getPinnedAgents();
@@ -532205,7 +532613,8 @@ Error: ${message}`);
532205
532613
  const { ensureDefaultAgents: ensureDefaultAgents3 } = await Promise.resolve().then(() => (init_defaults2(), exports_defaults2));
532206
532614
  try {
532207
532615
  const defaultAgent = await ensureDefaultAgents3(getBackend(), {
532208
- preferredModel: model
532616
+ preferredModel: model,
532617
+ personality: target2.trigger === "fresh-start" ? "tutorial" : "memo"
532209
532618
  });
532210
532619
  if (defaultAgent) {
532211
532620
  startupCreatedAgentRef.current = defaultAgent;
@@ -532415,7 +532824,7 @@ Error: ${message}`);
532415
532824
  } catch {
532416
532825
  await settingsManager2.loadLocalProjectSettings();
532417
532826
  }
532418
- setAgentContext2(agent2.id, skillsDirectory2, resolvedSkillSources);
532827
+ setAgentContext2(agent2.id, skillsDirectory2, resolvedSkillSources, agent2.name ?? null);
532419
532828
  let startupMemfsFlag = autoEnableMemfsForFreshAgent ? true : memfsFlag;
532420
532829
  if (backend4.capabilities.remoteMemfs && !autoEnableMemfsForFreshAgent) {
532421
532830
  const { hydrateMemfsSettingFromAgent: hydrateMemfsSettingFromAgent3, isLettaCloud: isLettaCloud3 } = await Promise.resolve().then(() => (init_memory_filesystem3(), exports_memory_filesystem2));
@@ -532743,4 +533152,4 @@ Error during initialization: ${message}`);
532743
533152
  }
532744
533153
  main2();
532745
533154
 
532746
- //# debugId=E2E63DE64562692D64756E2164756E21
533155
+ //# debugId=CD2C04A4505B2DC064756E2164756E21