@letta-ai/letta-code 0.30.4 → 0.30.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/agent-presets.js +125 -19
  2. package/dist/agent-presets.js.map +3 -3
  3. package/dist/mcp-client.js +2 -2
  4. package/dist/mcp-client.js.map +1 -1
  5. package/dist/types/agent/create-agent-request.d.ts +55 -25
  6. package/dist/types/agent/create-agent-request.d.ts.map +1 -1
  7. package/dist/types/agent/modify.d.ts.map +1 -1
  8. package/dist/types/agent/subagents/index.d.ts +1 -0
  9. package/dist/types/agent/subagents/index.d.ts.map +1 -1
  10. package/dist/types/agent/subagents/manager.d.ts +1 -0
  11. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  12. package/dist/types/agent/subagents/subagent-launcher.d.ts.map +1 -1
  13. package/dist/types/agent-presets.d.ts +1 -1
  14. package/dist/types/agent-presets.d.ts.map +1 -1
  15. package/dist/types/cli/helpers/memory-reminder.d.ts +9 -3
  16. package/dist/types/cli/helpers/memory-reminder.d.ts.map +1 -1
  17. package/dist/types/reflection-settings.d.ts +9 -0
  18. package/dist/types/reflection-settings.d.ts.map +1 -0
  19. package/dist/types/settings-manager.d.ts +9 -10
  20. package/dist/types/settings-manager.d.ts.map +1 -1
  21. package/dist/types/telemetry/index.d.ts +15 -1
  22. package/dist/types/telemetry/index.d.ts.map +1 -1
  23. package/dist/types/tools/impl/process_manager.d.ts +1 -0
  24. package/dist/types/tools/impl/process_manager.d.ts.map +1 -1
  25. package/dist/types/tools/impl/task.d.ts +4 -0
  26. package/dist/types/tools/impl/task.d.ts.map +1 -1
  27. package/dist/types/types/protocol_v2.d.ts +5 -0
  28. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  29. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  30. package/letta.js +1493 -807
  31. package/package.json +1 -1
  32. package/scripts/isolated-unit-tests.json +11 -0
  33. package/scripts/source-file-size-baseline.json +4 -4
  34. package/skills/managing-shared-memory/SKILL.md +47 -81
package/letta.js CHANGED
@@ -5359,7 +5359,9 @@ var init_settings_manager = __esm(() => {
5359
5359
  recentModels: [],
5360
5360
  memoryReminderInterval: 25,
5361
5361
  reflectionTrigger: "step-count",
5362
- reflectionStepCount: 25
5362
+ reflectionStepCount: 25,
5363
+ reflectionMerge: "auto",
5364
+ reflectionMergeInstructions: ""
5363
5365
  };
5364
5366
  DEFAULT_PROJECT_SETTINGS = {};
5365
5367
  DEFAULT_LOCAL_PROJECT_SETTINGS = {
@@ -5462,7 +5464,7 @@ var package_default;
5462
5464
  var init_package = __esm(() => {
5463
5465
  package_default = {
5464
5466
  name: "@letta-ai/letta-code",
5465
- version: "0.30.4",
5467
+ version: "0.30.5",
5466
5468
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5467
5469
  type: "module",
5468
5470
  packageManager: "bun@1.3.0",
@@ -6486,6 +6488,14 @@ class TelemetryManager {
6486
6488
  };
6487
6489
  this.track("reflection_end", data);
6488
6490
  }
6491
+ trackReflectionWorktreeCleanup(options) {
6492
+ const data = {
6493
+ ...options,
6494
+ version: getVersion(),
6495
+ platform: process.platform
6496
+ };
6497
+ this.track("reflection_worktree_cleanup", data);
6498
+ }
6489
6499
  trackReflectionArenaVote(vote) {
6490
6500
  this.track("reflection_arena_vote", {
6491
6501
  ...vote,
@@ -141415,6 +141425,73 @@ var init_models7 = __esm(() => {
141415
141425
  parallel_tool_calls: true
141416
141426
  }
141417
141427
  },
141428
+ {
141429
+ id: "opus-5",
141430
+ handle: "anthropic/claude-opus-5",
141431
+ label: "Opus 5",
141432
+ description: "Opus 5 (high reasoning)",
141433
+ updateArgs: {
141434
+ context_window: 200000,
141435
+ max_output_tokens: 128000,
141436
+ enable_reasoner: true,
141437
+ reasoning_effort: "high",
141438
+ parallel_tool_calls: true
141439
+ }
141440
+ },
141441
+ {
141442
+ id: "opus-5-low",
141443
+ handle: "anthropic/claude-opus-5",
141444
+ label: "Opus 5",
141445
+ description: "Opus 5 (low reasoning)",
141446
+ updateArgs: {
141447
+ context_window: 200000,
141448
+ max_output_tokens: 128000,
141449
+ enable_reasoner: true,
141450
+ reasoning_effort: "low",
141451
+ max_reasoning_tokens: 4000,
141452
+ parallel_tool_calls: true
141453
+ }
141454
+ },
141455
+ {
141456
+ id: "opus-5-medium",
141457
+ handle: "anthropic/claude-opus-5",
141458
+ label: "Opus 5",
141459
+ description: "Opus 5 (med reasoning)",
141460
+ updateArgs: {
141461
+ context_window: 200000,
141462
+ max_output_tokens: 128000,
141463
+ enable_reasoner: true,
141464
+ reasoning_effort: "medium",
141465
+ max_reasoning_tokens: 12000,
141466
+ parallel_tool_calls: true
141467
+ }
141468
+ },
141469
+ {
141470
+ id: "opus-5-xhigh",
141471
+ handle: "anthropic/claude-opus-5",
141472
+ label: "Opus 5",
141473
+ description: "Opus 5 (extra-high reasoning)",
141474
+ updateArgs: {
141475
+ context_window: 200000,
141476
+ max_output_tokens: 128000,
141477
+ enable_reasoner: true,
141478
+ reasoning_effort: "xhigh",
141479
+ parallel_tool_calls: true
141480
+ }
141481
+ },
141482
+ {
141483
+ id: "opus-5-max",
141484
+ handle: "anthropic/claude-opus-5",
141485
+ label: "Opus 5",
141486
+ description: "Opus 5 (max reasoning)",
141487
+ updateArgs: {
141488
+ context_window: 200000,
141489
+ max_output_tokens: 128000,
141490
+ enable_reasoner: true,
141491
+ reasoning_effort: "max",
141492
+ parallel_tool_calls: true
141493
+ }
141494
+ },
141418
141495
  {
141419
141496
  id: "opus",
141420
141497
  handle: "anthropic/claude-opus-4-8",
@@ -141689,7 +141766,7 @@ var init_models7 = __esm(() => {
141689
141766
  id: "sonnet-5-xhigh",
141690
141767
  handle: "anthropic/claude-sonnet-5",
141691
141768
  label: "Sonnet 5",
141692
- description: "Sonnet 5 (max reasoning)",
141769
+ description: "Sonnet 5 (extra-high reasoning)",
141693
141770
  updateArgs: {
141694
141771
  context_window: 1e6,
141695
141772
  max_output_tokens: 128000,
@@ -141698,6 +141775,19 @@ var init_models7 = __esm(() => {
141698
141775
  parallel_tool_calls: true
141699
141776
  }
141700
141777
  },
141778
+ {
141779
+ id: "sonnet-5-max",
141780
+ handle: "anthropic/claude-sonnet-5",
141781
+ label: "Sonnet 5",
141782
+ description: "Sonnet 5 (max reasoning)",
141783
+ updateArgs: {
141784
+ context_window: 1e6,
141785
+ max_output_tokens: 128000,
141786
+ reasoning_effort: "max",
141787
+ enable_reasoner: true,
141788
+ parallel_tool_calls: true
141789
+ }
141790
+ },
141701
141791
  {
141702
141792
  id: "sonnet-4.6",
141703
141793
  handle: "anthropic/claude-sonnet-4-6",
@@ -145321,7 +145411,7 @@ __export(exports_modify, {
145321
145411
  __modifyTestUtils: () => __modifyTestUtils
145322
145412
  });
145323
145413
  function supportsDistinctAnthropicXHighEffort(modelHandle) {
145324
- return modelHandle.includes("claude-fable-5") || modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
145414
+ return modelHandle.includes("claude-fable-5") || modelHandle.includes("claude-opus-5") || modelHandle.includes("claude-sonnet-5") || modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
145325
145415
  }
145326
145416
  function buildModelSettings(modelHandle, updateArgs) {
145327
145417
  const explicitProviderType = typeof updateArgs?.provider_type === "string" ? updateArgs.provider_type : undefined;
@@ -175417,10 +175507,18 @@ function normalizeTrigger(value, fallback) {
175417
175507
  }
175418
175508
  return fallback;
175419
175509
  }
175510
+ function normalizeMerge(value, fallback) {
175511
+ return value === "auto" || value === "explicit" ? value : fallback;
175512
+ }
175513
+ function normalizeMergeInstructions(value, fallback) {
175514
+ return typeof value === "string" ? value.trim() : fallback;
175515
+ }
175420
175516
  function applyExplicitReflectionOverrides(base2, raw) {
175421
175517
  return {
175422
175518
  trigger: normalizeTrigger(raw.reflectionTrigger, base2.trigger),
175423
- stepCount: normalizeStepCount(raw.reflectionStepCount, base2.stepCount)
175519
+ stepCount: normalizeStepCount(raw.reflectionStepCount, base2.stepCount),
175520
+ merge: normalizeMerge(raw.reflectionMerge, base2.merge),
175521
+ mergeInstructions: normalizeMergeInstructions(raw.reflectionMergeInstructions, base2.mergeInstructions)
175424
175522
  };
175425
175523
  }
175426
175524
  function applyPersistedAgentScopedSettings(base2, raw) {
@@ -175429,32 +175527,42 @@ function applyPersistedAgentScopedSettings(base2, raw) {
175429
175527
  }
175430
175528
  return {
175431
175529
  trigger: normalizeTrigger(raw.trigger, base2.trigger),
175432
- stepCount: normalizeStepCount(raw.stepCount, base2.stepCount)
175530
+ stepCount: normalizeStepCount(raw.stepCount, base2.stepCount),
175531
+ merge: normalizeMerge(raw.merge, base2.merge),
175532
+ mergeInstructions: normalizeMergeInstructions(raw.mergeInstructions, base2.mergeInstructions)
175433
175533
  };
175434
175534
  }
175435
175535
  function legacyModeToReflectionSettings(mode) {
175436
175536
  if (typeof mode === "number") {
175437
175537
  return {
175438
175538
  trigger: "step-count",
175439
- stepCount: normalizeStepCount(mode, DEFAULT_STEP_COUNT)
175539
+ stepCount: normalizeStepCount(mode, DEFAULT_STEP_COUNT),
175540
+ merge: DEFAULT_REFLECTION_SETTINGS.merge,
175541
+ mergeInstructions: DEFAULT_REFLECTION_SETTINGS.mergeInstructions
175440
175542
  };
175441
175543
  }
175442
175544
  if (mode === null) {
175443
175545
  return {
175444
175546
  trigger: "off",
175445
- stepCount: DEFAULT_REFLECTION_SETTINGS.stepCount
175547
+ stepCount: DEFAULT_REFLECTION_SETTINGS.stepCount,
175548
+ merge: DEFAULT_REFLECTION_SETTINGS.merge,
175549
+ mergeInstructions: DEFAULT_REFLECTION_SETTINGS.mergeInstructions
175446
175550
  };
175447
175551
  }
175448
175552
  if (mode === "compaction") {
175449
175553
  return {
175450
175554
  trigger: "compaction-event",
175451
- stepCount: DEFAULT_REFLECTION_SETTINGS.stepCount
175555
+ stepCount: DEFAULT_REFLECTION_SETTINGS.stepCount,
175556
+ merge: DEFAULT_REFLECTION_SETTINGS.merge,
175557
+ mergeInstructions: DEFAULT_REFLECTION_SETTINGS.mergeInstructions
175452
175558
  };
175453
175559
  }
175454
175560
  if (mode === "auto-compaction") {
175455
175561
  return {
175456
175562
  trigger: "compaction-event",
175457
- stepCount: DEFAULT_REFLECTION_SETTINGS.stepCount
175563
+ stepCount: DEFAULT_REFLECTION_SETTINGS.stepCount,
175564
+ merge: DEFAULT_REFLECTION_SETTINGS.merge,
175565
+ mergeInstructions: DEFAULT_REFLECTION_SETTINGS.mergeInstructions
175458
175566
  };
175459
175567
  }
175460
175568
  return { ...DEFAULT_REFLECTION_SETTINGS };
@@ -175476,16 +175584,6 @@ function getReflectionSettings(agentId, workingDirectory = process.cwd()) {
175476
175584
  } catch {
175477
175585
  localSettings = null;
175478
175586
  }
175479
- if (agentId) {
175480
- const localScoped = localSettings?.reflectionSettingsByAgent?.[agentId];
175481
- if (localScoped) {
175482
- return applyPersistedAgentScopedSettings(DEFAULT_REFLECTION_SETTINGS, localScoped);
175483
- }
175484
- const globalScoped = globalSettings.reflectionSettingsByAgent?.[agentId];
175485
- if (globalScoped) {
175486
- return applyPersistedAgentScopedSettings(DEFAULT_REFLECTION_SETTINGS, globalScoped);
175487
- }
175488
- }
175489
175587
  let resolved = legacyModeToReflectionSettings(globalSettings.memoryReminderInterval);
175490
175588
  resolved = applyExplicitReflectionOverrides(resolved, globalSettings);
175491
175589
  if (localSettings) {
@@ -175494,6 +175592,10 @@ function getReflectionSettings(agentId, workingDirectory = process.cwd()) {
175494
175592
  }
175495
175593
  resolved = applyExplicitReflectionOverrides(resolved, localSettings);
175496
175594
  }
175595
+ if (agentId) {
175596
+ resolved = applyPersistedAgentScopedSettings(resolved, globalSettings.reflectionSettingsByAgent?.[agentId]);
175597
+ resolved = applyPersistedAgentScopedSettings(resolved, localSettings?.reflectionSettingsByAgent?.[agentId]);
175598
+ }
175497
175599
  return resolved;
175498
175600
  }
175499
175601
  function shouldFireStepCountTrigger(stepsSinceLastSuccessfulReflection, settings3 = getReflectionSettings()) {
@@ -175509,6 +175611,8 @@ async function persistReflectionSettingsForAgent(agentId, settings3, options3 =
175509
175611
  persistLocalProject = true,
175510
175612
  persistGlobal = true
175511
175613
  } = options3;
175614
+ const merge2 = normalizeMerge(settings3.merge, DEFAULT_REFLECTION_SETTINGS.merge);
175615
+ const mergeInstructions = normalizeMergeInstructions(settings3.mergeInstructions, DEFAULT_REFLECTION_SETTINGS.mergeInstructions);
175512
175616
  const legacyMode = reflectionSettingsToLegacyMode(settings3);
175513
175617
  if (persistLocalProject) {
175514
175618
  try {
@@ -175521,11 +175625,15 @@ async function persistReflectionSettingsForAgent(agentId, settings3, options3 =
175521
175625
  memoryReminderInterval: legacyMode,
175522
175626
  reflectionTrigger: settings3.trigger,
175523
175627
  reflectionStepCount: settings3.stepCount,
175628
+ reflectionMerge: merge2,
175629
+ reflectionMergeInstructions: mergeInstructions,
175524
175630
  reflectionSettingsByAgent: {
175525
175631
  ...localSettings.reflectionSettingsByAgent ?? {},
175526
175632
  [agentId]: {
175527
175633
  trigger: settings3.trigger,
175528
- stepCount: settings3.stepCount
175634
+ stepCount: settings3.stepCount,
175635
+ merge: merge2,
175636
+ mergeInstructions
175529
175637
  }
175530
175638
  }
175531
175639
  }, workingDirectory);
@@ -175536,11 +175644,15 @@ async function persistReflectionSettingsForAgent(agentId, settings3, options3 =
175536
175644
  memoryReminderInterval: legacyMode,
175537
175645
  reflectionTrigger: settings3.trigger,
175538
175646
  reflectionStepCount: settings3.stepCount,
175647
+ reflectionMerge: merge2,
175648
+ reflectionMergeInstructions: mergeInstructions,
175539
175649
  reflectionSettingsByAgent: {
175540
175650
  ...globalSettings.reflectionSettingsByAgent ?? {},
175541
175651
  [agentId]: {
175542
175652
  trigger: settings3.trigger,
175543
- stepCount: settings3.stepCount
175653
+ stepCount: settings3.stepCount,
175654
+ merge: merge2,
175655
+ mergeInstructions
175544
175656
  }
175545
175657
  }
175546
175658
  });
@@ -175551,7 +175663,9 @@ var init_memory_reminder = __esm(() => {
175551
175663
  init_settings_manager();
175552
175664
  DEFAULT_REFLECTION_SETTINGS = {
175553
175665
  trigger: "compaction-event",
175554
- stepCount: DEFAULT_STEP_COUNT
175666
+ stepCount: DEFAULT_STEP_COUNT,
175667
+ merge: "auto",
175668
+ mergeInstructions: ""
175555
175669
  };
175556
175670
  });
175557
175671
 
@@ -175694,7 +175808,7 @@ function buildBackgroundProcessSnapshot(agentId, conversationId = "default") {
175694
175808
  const taskProcesses = Array.from(backgroundTasks.entries()).filter(([, task]) => task.status === "running" && (!runtimeScope || belongsToRuntime(task, runtimeScope))).map(([processId, task]) => ({
175695
175809
  process_id: processId,
175696
175810
  kind: "agent_task",
175697
- task_type: task.subagentType,
175811
+ task_type: task.displayType ?? task.subagentType,
175698
175812
  description: task.description,
175699
175813
  started_at_ms: task.startTime.getTime(),
175700
175814
  status: task.status,
@@ -349572,7 +349686,9 @@ function buildDeviceStatus(runtime, params) {
349572
349686
  reflection_settings: scopedAgentId ? {
349573
349687
  agent_id: scopedAgentId,
349574
349688
  trigger: reflectionSettings?.trigger ?? "compaction-event",
349575
- step_count: reflectionSettings?.stepCount ?? 25
349689
+ step_count: reflectionSettings?.stepCount ?? 25,
349690
+ merge: reflectionSettings?.merge ?? "auto",
349691
+ merge_instructions: reflectionSettings?.mergeInstructions ?? ""
349576
349692
  } : null
349577
349693
  };
349578
349694
  }
@@ -364685,6 +364801,9 @@ function resolveSubagentWorkingDirectory(env3 = process.env, fallbackCwd = getCu
364685
364801
  if (options3.subagentType === "reflection" && options3.launchProfile === "memory-subagent" && options3.memoryScope) {
364686
364802
  return env3.USER_CWD || fallbackCwd;
364687
364803
  }
364804
+ if (options3.subagentType !== "reflection" && options3.launchProfile === "memory-subagent" && options3.memoryScope?.primaryRoot) {
364805
+ return options3.memoryScope.primaryRoot;
364806
+ }
364688
364807
  const primaryRoot = options3.memoryScope?.primaryRoot ?? options3.inheritedPrimaryRoot;
364689
364808
  if (options3.subagentType === "reflection" && options3.launchProfile === "memory-subagent" && primaryRoot) {
364690
364809
  return primaryRoot;
@@ -365231,13 +365350,14 @@ function buildSubagentArgs(type3, config3, model, userPrompt, existingAgentId, e
365231
365350
  return args;
365232
365351
  }
365233
365352
  async function executeSubagent(type3, config3, model, userPrompt, subagentId, isRetry = false, signal, existingAgentId, existingConversationId, maxTurns, parentAgentIdOverride, transcriptPath, memoryScope, systemPromptOverride) {
365353
+ const withModel = (result) => model ? { ...result, model } : result;
365234
365354
  if (signal?.aborted) {
365235
- return {
365355
+ return withModel({
365236
365356
  agentId: "",
365237
365357
  report: "",
365238
365358
  success: false,
365239
365359
  error: INTERRUPTED_BY_USER
365240
- };
365360
+ });
365241
365361
  }
365242
365362
  if (model) {
365243
365363
  updateSubagent(subagentId, { model });
@@ -365268,6 +365388,7 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365268
365388
  const inheritedMemoryRoots = resolveAllowedMemoryRoots({
365269
365389
  currentAgentId: parentAgentId ?? null
365270
365390
  });
365391
+ const effectiveLaunchProfile = memoryScope ? "memory-subagent" : config3.launchProfile;
365271
365392
  const localBackendStorageDir = backendMode === "local" ? getLocalBackendStorageDir2() : null;
365272
365393
  const inheritedPrimaryRoot = resolveSubagentInheritedPrimaryRoot({
365273
365394
  backendMode,
@@ -365277,7 +365398,7 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365277
365398
  });
365278
365399
  const subagentWorkingDirectory = resolveSubagentWorkingDirectory(process.env, getCurrentWorkingDirectory(), {
365279
365400
  subagentType: type3,
365280
- launchProfile: config3.launchProfile,
365401
+ launchProfile: effectiveLaunchProfile,
365281
365402
  inheritedPrimaryRoot,
365282
365403
  memoryScope
365283
365404
  });
@@ -365289,7 +365410,7 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365289
365410
  backendMode,
365290
365411
  localBackendStorageDir,
365291
365412
  parentAgentId,
365292
- launchProfile: config3.launchProfile,
365413
+ launchProfile: effectiveLaunchProfile,
365293
365414
  inheritedPrimaryRoot,
365294
365415
  memoryScope,
365295
365416
  inheritedApiKey,
@@ -365299,7 +365420,7 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365299
365420
  });
365300
365421
  const sandbox = wrapSubagentLauncher({
365301
365422
  launcher,
365302
- launchProfile: config3.launchProfile,
365423
+ launchProfile: effectiveLaunchProfile,
365303
365424
  backendMode,
365304
365425
  memoryRoots: inheritedMemoryRoots.roots,
365305
365426
  inheritedPrimaryRoot,
@@ -365359,13 +365480,13 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365359
365480
  }
365360
365481
  signal?.removeEventListener("abort", abortHandler);
365361
365482
  if (wasAborted) {
365362
- return {
365483
+ return withModel({
365363
365484
  agentId: state.agentId || "",
365364
365485
  conversationId: state.conversationId || undefined,
365365
365486
  report: "",
365366
365487
  success: false,
365367
365488
  error: INTERRUPTED_BY_USER
365368
- };
365489
+ });
365369
365490
  }
365370
365491
  const stderr = Buffer.concat(stderrChunks).toString("utf-8").trim();
365371
365492
  if (exitCode !== 0) {
@@ -365383,16 +365504,16 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365383
365504
  }
365384
365505
  const propagatedError = state.finalError?.trim();
365385
365506
  const fallbackError = stderr || `Subagent exited with code ${exitCode}`;
365386
- return {
365507
+ return withModel({
365387
365508
  agentId: state.agentId || "",
365388
365509
  conversationId: state.conversationId || undefined,
365389
365510
  report: "",
365390
365511
  success: false,
365391
365512
  error: propagatedError || fallbackError
365392
- };
365513
+ });
365393
365514
  }
365394
365515
  if (state.finalResult !== null) {
365395
- return {
365516
+ return withModel({
365396
365517
  agentId: state.agentId || "",
365397
365518
  conversationId: state.conversationId || undefined,
365398
365519
  report: state.finalResult,
@@ -365401,11 +365522,11 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365401
365522
  totalTokens: state.resultStats?.totalTokens,
365402
365523
  stepCount: state.resultStats?.stepCount,
365403
365524
  durationMs: state.resultStats?.durationMs
365404
- };
365525
+ });
365405
365526
  }
365406
365527
  if (state.finalError) {
365407
365528
  debugWarn("subagent", `Subagent ${subagentId} (agentId=${state.agentId}) exited with captured error: ${state.finalError}. ` + `exitCode=${exitCode}, stderr=${stderr.length} bytes`);
365408
- return {
365529
+ return withModel({
365409
365530
  agentId: state.agentId || "",
365410
365531
  conversationId: state.conversationId || undefined,
365411
365532
  report: "",
@@ -365414,7 +365535,7 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365414
365535
  totalTokens: state.resultStats?.totalTokens,
365415
365536
  stepCount: state.resultStats?.stepCount,
365416
365537
  durationMs: state.resultStats?.durationMs
365417
- };
365538
+ });
365418
365539
  }
365419
365540
  debugWarn("subagent", `Subagent ${subagentId} (agentId=${state.agentId}) exited cleanly (exitCode=${exitCode}) ` + `but no result event was captured during streaming. ` + `stdout=${Buffer.concat(stdoutChunks).length} bytes, stderr=${stderr.length} bytes`);
365420
365541
  const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
@@ -365427,14 +365548,14 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
365427
365548
  return executeSubagent(type3, config3, model, userPrompt, subagentId, true, signal, existingAgentId, existingConversationId, maxTurns, parentAgentIdOverride, transcriptPath, memoryScope, systemPromptOverride);
365428
365549
  }
365429
365550
  }
365430
- return result;
365551
+ return withModel(result);
365431
365552
  } catch (error54) {
365432
- return {
365553
+ return withModel({
365433
365554
  agentId: "",
365434
365555
  report: "",
365435
365556
  success: false,
365436
365557
  error: getErrorMessage2(error54)
365437
- };
365558
+ });
365438
365559
  }
365439
365560
  }
365440
365561
  function buildDeploySystemReminder(senderAgentName, senderAgentId) {
@@ -365446,6 +365567,9 @@ ${SYSTEM_REMINDER_CLOSE}
365446
365567
 
365447
365568
  `;
365448
365569
  }
365570
+ function shouldPrependDeploySystemReminder(existingAgentId, parentAgentId) {
365571
+ return !existingAgentId || existingAgentId !== parentAgentId;
365572
+ }
365449
365573
  function recallPromptForBackend(backendMode) {
365450
365574
  return backendMode === "local" ? recall_subagent_local_default : recall_subagent_default;
365451
365575
  }
@@ -365527,7 +365651,7 @@ async function spawnSubagent(type3, prompt, userModel, subagentId, signal, exist
365527
365651
  if (forkedContext) {
365528
365652
  const systemReminder = buildForkSystemReminder(type3, backendMode);
365529
365653
  finalPrompt = systemReminder + prompt;
365530
- } else {
365654
+ } else if (shouldPrependDeploySystemReminder(existingAgentId, resolvedParentAgentId)) {
365531
365655
  const systemReminder = buildDeploySystemReminder(cachedParent.name ?? "", resolvedParentAgentId);
365532
365656
  finalPrompt = systemReminder + prompt;
365533
365657
  }
@@ -365687,6 +365811,7 @@ var init_task_notifications = __esm(() => {
365687
365811
  var exports_task = {};
365688
365812
  __export(exports_task, {
365689
365813
  waitForBackgroundSubagentLink: () => waitForBackgroundSubagentLink,
365814
+ waitForBackgroundSubagentConversationId: () => waitForBackgroundSubagentConversationId,
365690
365815
  waitForBackgroundSubagentAgentId: () => waitForBackgroundSubagentAgentId,
365691
365816
  task: () => task,
365692
365817
  spawnBackgroundSubagentTask: () => spawnBackgroundSubagentTask
@@ -365791,10 +365916,33 @@ async function waitForBackgroundSubagentAgentId(subagentId, timeoutMs = null, si
365791
365916
  await sleep8(BACKGROUND_STARTUP_POLL_MS);
365792
365917
  }
365793
365918
  }
365919
+ async function waitForBackgroundSubagentConversationId(subagentId, timeoutMs = null, signal) {
365920
+ const deadline = timeoutMs !== null && timeoutMs > 0 ? Date.now() + timeoutMs : null;
365921
+ while (true) {
365922
+ if (signal?.aborted) {
365923
+ return null;
365924
+ }
365925
+ const agent2 = getSnapshot().agents.find((a) => a.id === subagentId);
365926
+ if (!agent2) {
365927
+ return null;
365928
+ }
365929
+ if (agent2.conversationId) {
365930
+ return agent2.conversationId;
365931
+ }
365932
+ if (agent2.status === "error" || agent2.status === "completed") {
365933
+ return agent2.conversationId ?? null;
365934
+ }
365935
+ if (deadline !== null && Date.now() >= deadline) {
365936
+ return agent2.conversationId ?? null;
365937
+ }
365938
+ await sleep8(BACKGROUND_STARTUP_POLL_MS);
365939
+ }
365940
+ }
365794
365941
  function spawnBackgroundSubagentTask(args) {
365795
365942
  assertBackgroundTaskCapacity();
365796
365943
  const {
365797
365944
  subagentType,
365945
+ displayType,
365798
365946
  prompt,
365799
365947
  description,
365800
365948
  model,
@@ -365824,13 +365972,14 @@ function spawnBackgroundSubagentTask(args) {
365824
365972
  const completeSubagentFn = deps?.completeSubagentImpl ?? completeSubagent;
365825
365973
  const getSubagentSnapshotFn = deps?.getSubagentSnapshotImpl ?? getSnapshot;
365826
365974
  const subagentId = generateSubagentIdFn();
365827
- registerSubagentFn(subagentId, subagentType, description, toolCallId, true, silentCompletion, resolvedParentScope, prompt);
365975
+ registerSubagentFn(subagentId, displayType ?? subagentType, description, toolCallId, true, silentCompletion, resolvedParentScope, prompt);
365828
365976
  const taskId = getNextTaskId();
365829
365977
  const outputFile = createBackgroundOutputFile(taskId);
365830
365978
  const abortController = new AbortController;
365831
365979
  const bgTask = {
365832
365980
  description,
365833
365981
  subagentType,
365982
+ displayType,
365834
365983
  subagentId,
365835
365984
  status: "running",
365836
365985
  output: [],
@@ -365864,6 +366013,7 @@ function spawnBackgroundSubagentTask(args) {
365864
366013
  error: result.error,
365865
366014
  agentId: result.agentId,
365866
366015
  conversationId: result.conversationId,
366016
+ model: result.model,
365867
366017
  stepCount: result.stepCount,
365868
366018
  durationMs: result.durationMs,
365869
366019
  report: result.report
@@ -384829,6 +384979,59 @@ var init_check_approval = __esm(() => {
384829
384979
  });
384830
384980
 
384831
384981
  // src/agent/create-agent-request.ts
384982
+ function mergeMemoryBlocks(base2, overrides) {
384983
+ const blocks = base2.map((block) => ({ ...block }));
384984
+ for (const override of overrides ?? []) {
384985
+ const index = blocks.findIndex((block) => block.label === override.label);
384986
+ if (index >= 0) {
384987
+ blocks[index] = { ...override };
384988
+ } else {
384989
+ blocks.push({ ...override });
384990
+ }
384991
+ }
384992
+ return blocks;
384993
+ }
384994
+ async function buildCreateAgentRequest(options3 = {}) {
384995
+ const personality = options3.personalityId ? getPersonalityOption(options3.personalityId) : undefined;
384996
+ const modelIdentifier = options3.model ?? personality?.defaultModel;
384997
+ const modelHandle = modelIdentifier ? resolveModel(modelIdentifier) : getDefaultModel();
384998
+ if (!modelHandle) {
384999
+ throw new Error(`Unknown model: ${modelIdentifier}`);
385000
+ }
385001
+ if (!options3.isSubagent && options3.enableMemfs !== undefined && options3.memoryPromptMode !== undefined && options3.enableMemfs !== (options3.memoryPromptMode !== "standard")) {
385002
+ throw new Error("enableMemfs and memoryPromptMode must describe the same memory mode");
385003
+ }
385004
+ const enableMemfs = options3.isSubagent ? false : options3.enableMemfs ?? options3.memoryPromptMode !== "standard";
385005
+ const memoryPromptMode = options3.isSubagent ? "standard" : options3.memoryPromptMode ?? (enableMemfs ? "memfs" : "standard");
385006
+ const personalityTags = options3.personalityId ? getPersonalityCreationTags(options3.personalityId) : [];
385007
+ const personalityBlocks = options3.personalityId ? buildPersonalityMemoryBlocks(options3.personalityId, await getDefaultMemoryBlocks()) : [];
385008
+ const memoryBlocks = options3.isSubagent ? undefined : options3.personalityId || options3.memoryBlocks !== undefined ? mergeMemoryBlocks(personalityBlocks, options3.memoryBlocks) : undefined;
385009
+ const blockIds = options3.isSubagent ? undefined : options3.blockIds;
385010
+ return {
385011
+ agent_type: LETTA_CODE_AGENT_TYPE,
385012
+ ...options3.name !== undefined || personality ? { name: options3.name ?? personality?.label } : {},
385013
+ ...options3.description !== undefined || personality ? { description: options3.description ?? personality?.description } : {},
385014
+ model: modelHandle,
385015
+ system: options3.system ?? buildSystemPrompt("default", memoryPromptMode),
385016
+ ...memoryBlocks !== undefined ? { memory_blocks: memoryBlocks } : {},
385017
+ ...blockIds && blockIds.length > 0 ? { block_ids: blockIds } : {},
385018
+ tags: buildCreatedAgentTags({
385019
+ enableMemfs,
385020
+ isSubagent: options3.isSubagent,
385021
+ tags: [...personalityTags, ...options3.extraTags ?? []]
385022
+ }),
385023
+ tools: [...options3.baseTools ?? DEFAULT_CREATED_AGENT_BASE_TOOLS],
385024
+ include_base_tools: false,
385025
+ include_base_tool_rules: false,
385026
+ initial_message_sequence: [],
385027
+ parallel_tool_calls: options3.parallelToolCalls ?? true,
385028
+ compaction_settings: {
385029
+ model: options3.compactionModel ?? DEFAULT_SUMMARIZATION_MODEL
385030
+ },
385031
+ ...options3.embedding !== undefined ? { embedding: options3.embedding } : {},
385032
+ ...options3.isSubagent ? { hidden: true } : options3.hidden !== undefined ? { hidden: options3.hidden } : {}
385033
+ };
385034
+ }
384832
385035
  var LETTA_CODE_AGENT_TYPE = "letta_v1_agent", DEFAULT_CREATED_AGENT_BASE_TOOLS;
384833
385036
  var init_create_agent_request = __esm(() => {
384834
385037
  init_constants2();
@@ -384932,8 +385135,7 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
384932
385135
  isLettaCloud: isLettaCloud2,
384933
385136
  isSubagent
384934
385137
  });
384935
- const defaultBaseTools = options3.baseTools ?? DEFAULT_CREATED_AGENT_BASE_TOOLS;
384936
- const toolNames = [...defaultBaseTools];
385138
+ const toolNames = options3.baseTools;
384937
385139
  const referencedBlockIds = [];
384938
385140
  let filteredMemoryBlocks;
384939
385141
  if (options3.memoryBlocks !== undefined) {
@@ -384971,37 +385173,28 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
384971
385173
  const contextWindow = modelUpdateArgs?.context_window ?? await getModelContextWindow(modelHandle);
384972
385174
  const memMode = memfsConfig.memoryPromptMode;
384973
385175
  const systemPromptContent = options3.systemPromptCustom ? options3.systemPromptCustom : await resolveAndBuildSystemPrompt(options3.systemPromptPreset, memMode);
384974
- const tags = buildCreatedAgentTags({
384975
- tags: options3.tags,
384976
- isSubagent,
384977
- enableMemfs: memfsConfig.enableMemfs
384978
- });
384979
385176
  const agentDescription = options3.description ?? `Letta Code agent created in ${process.cwd()}`;
384980
- const createAgentRequestBase = {
384981
- agent_type: LETTA_CODE_AGENT_TYPE,
384982
- system: systemPromptContent,
385177
+ const createAgentRequestBase = await buildCreateAgentRequest({
384983
385178
  name,
384984
385179
  description: agentDescription,
384985
- embedding: embeddingModelVal || undefined,
384986
385180
  model: modelHandle,
384987
- ...contextWindow && { context_window_limit: contextWindow },
384988
- memory_blocks: filteredMemoryBlocks.length > 0 ? filteredMemoryBlocks : undefined,
384989
- block_ids: referencedBlockIds.length > 0 ? referencedBlockIds : undefined,
384990
- tags,
384991
- ...isSubagent && { hidden: true },
384992
- include_base_tools: false,
384993
- include_base_tool_rules: false,
384994
- initial_message_sequence: [],
384995
- parallel_tool_calls: parallelToolCallsVal,
384996
- compaction_settings: {
384997
- model: DEFAULT_SUMMARIZATION_MODEL
384998
- }
384999
- };
385181
+ system: systemPromptContent,
385182
+ memoryPromptMode: memMode,
385183
+ memoryBlocks: filteredMemoryBlocks.length > 0 ? filteredMemoryBlocks : undefined,
385184
+ blockIds: referencedBlockIds,
385185
+ extraTags: options3.tags,
385186
+ enableMemfs: memfsConfig.enableMemfs,
385187
+ isSubagent,
385188
+ baseTools: toolNames,
385189
+ embedding: embeddingModelVal || undefined,
385190
+ parallelToolCalls: parallelToolCallsVal
385191
+ });
385000
385192
  const createWithTools = (tools) => backend3.createAgent({
385001
385193
  ...createAgentRequestBase,
385194
+ ...contextWindow && { context_window_limit: contextWindow },
385002
385195
  tools
385003
385196
  });
385004
- const agent2 = await createAgentWithBaseToolsRecovery(createWithTools, toolNames, addBaseToolsToServer);
385197
+ const agent2 = await createAgentWithBaseToolsRecovery(createWithTools, createAgentRequestBase.tools, addBaseToolsToServer);
385005
385198
  const mergedUpdateArgs = {
385006
385199
  ...modelUpdateArgs ?? {},
385007
385200
  ...options3.updateArgs ?? {}
@@ -385575,6 +385768,13 @@ var init_args = __esm(() => {
385575
385768
  mode: "both",
385576
385769
  help: { description: "Enable memory filesystem for this agent" }
385577
385770
  },
385771
+ stateless: {
385772
+ parser: { type: "boolean" },
385773
+ mode: "headless",
385774
+ help: {
385775
+ description: "Run an existing agent without MemFS enablement or sync"
385776
+ }
385777
+ },
385578
385778
  "no-memfs": {
385579
385779
  parser: { type: "boolean" },
385580
385780
  mode: "both"
@@ -425742,6 +425942,74 @@ function validateConversationDefaultRequiresAgent(options3) {
425742
425942
  throw new Error("--conv default requires --agent <agent-id>");
425743
425943
  }
425744
425944
  }
425945
+ function validateStatelessStartupOptions(options3) {
425946
+ if (!options3.stateless) {
425947
+ return;
425948
+ }
425949
+ if (!options3.isHeadless) {
425950
+ throw new Error("--stateless is only supported in headless mode");
425951
+ }
425952
+ if (options3.memfs) {
425953
+ throw new Error("--stateless cannot be used with --memfs");
425954
+ }
425955
+ if (options3.memfsStartup) {
425956
+ throw new Error("--stateless cannot be used with --memfs-startup");
425957
+ }
425958
+ if (options3.forceNewAgent) {
425959
+ throw new Error("--stateless is for existing agents and cannot be used with --new-agent");
425960
+ }
425961
+ if (!options3.hasExistingAgentSelector) {
425962
+ throw new Error("--stateless requires --agent, --name, or --conversation");
425963
+ }
425964
+ }
425965
+ function validatePrimaryStartupFlagConflicts(options3) {
425966
+ validateStatelessStartupOptions({
425967
+ stateless: options3.stateless,
425968
+ isHeadless: options3.isHeadless,
425969
+ memfs: options3.memfs,
425970
+ memfsStartup: options3.memfsStartup,
425971
+ forceNewAgent: options3.forceNewAgent,
425972
+ hasExistingAgentSelector: Boolean(options3.specifiedAgentId || options3.specifiedAgentName || options3.specifiedConversationId)
425973
+ });
425974
+ validateFlagConflicts({
425975
+ guard: options3.specifiedConversationId && options3.specifiedConversationId !== "default",
425976
+ checks: [
425977
+ {
425978
+ when: options3.specifiedAgentId,
425979
+ message: "--conversation cannot be used with --agent"
425980
+ },
425981
+ {
425982
+ when: options3.specifiedAgentName,
425983
+ message: "--conversation cannot be used with --name"
425984
+ },
425985
+ {
425986
+ when: options3.forceNewAgent,
425987
+ message: "--conversation cannot be used with --new-agent"
425988
+ },
425989
+ {
425990
+ when: options3.importFile,
425991
+ message: "--conversation cannot be used with --import"
425992
+ },
425993
+ {
425994
+ when: options3.shouldResume,
425995
+ message: "--conversation cannot be used with --resume"
425996
+ }
425997
+ ]
425998
+ });
425999
+ validateFlagConflicts({
426000
+ guard: options3.forceNewConversation,
426001
+ checks: [
426002
+ {
426003
+ when: options3.specifiedConversationId,
426004
+ message: "--new cannot be used with --conversation"
426005
+ },
426006
+ {
426007
+ when: options3.shouldResume,
426008
+ message: "--new cannot be used with --resume"
426009
+ }
426010
+ ]
426011
+ });
426012
+ }
425745
426013
  function validateRegistryHandleOrThrow(handle2) {
425746
426014
  const normalized = handle2.startsWith("@") ? handle2.slice(1) : handle2;
425747
426015
  const parts = normalized.split("/");
@@ -437758,7 +438026,8 @@ function buildQueuedTurnMessage(runtime, batch) {
437758
438026
  messages: [
437759
438027
  {
437760
438028
  role: "user",
437761
- content: mergedContent2
438029
+ content: mergedContent2,
438030
+ otid: crypto.randomUUID()
437762
438031
  }
437763
438032
  ]
437764
438033
  };
@@ -443817,8 +444086,8 @@ var init_dream_targets = __esm(() => {
443817
444086
  import { execFile as execFileCb4 } from "node:child_process";
443818
444087
  import { randomUUID as randomUUID24 } from "node:crypto";
443819
444088
  import { existsSync as existsSync46 } from "node:fs";
443820
- import { mkdir as mkdir13, realpath as realpath4 } from "node:fs/promises";
443821
- import { dirname as dirname26, isAbsolute as isAbsolute25, join as join61, relative as relative9, resolve as resolve31 } from "node:path";
444089
+ import { mkdir as mkdir13 } from "node:fs/promises";
444090
+ import { dirname as dirname26, isAbsolute as isAbsolute25, join as join61, resolve as resolve31 } from "node:path";
443822
444091
  import { promisify as promisify13 } from "node:util";
443823
444092
  async function runGit4(cwd2, args) {
443824
444093
  try {
@@ -443922,23 +444191,19 @@ function buildReflectionMemoryScope(worktree) {
443922
444191
  readonlyRoots: [dirname26(worktree.parentMemoryDir)]
443923
444192
  };
443924
444193
  }
443925
- function buildPendingResultFromPending(pending, status, summary, error54) {
444194
+ function buildReflectionIntegrationMemoryScope(worktree) {
443926
444195
  return {
443927
- status,
443928
- parentMemoryDir: pending.parentMemoryDir,
443929
- reflectionWorktreeDir: pending.reflectionWorktreeDir,
443930
- reflectionBranch: pending.reflectionBranch,
443931
- commitCount: pending.commitCount,
443932
- head: pending.head,
443933
- summary,
443934
- error: error54
444196
+ primaryRoot: worktree.worktreeDir,
444197
+ writableRoots: [
444198
+ worktree.worktreeDir,
444199
+ worktree.parentMemoryDir,
444200
+ worktree.gitCommonDir
444201
+ ],
444202
+ readonlyRoots: []
443935
444203
  };
443936
444204
  }
443937
444205
  function reflectionIntegrationConsumesTranscript(result) {
443938
- return result.status === "merged" || result.status === "no_changes" || result.status === "pending_conflict" || result.status === "pending_manual_merge";
443939
- }
443940
- function reflectionIntegrationNeedsReminder(result) {
443941
- return result.status === "pending_conflict" || result.status === "pending_manual_merge";
444206
+ return result.status === "merged" || result.status === "no_changes";
443942
444207
  }
443943
444208
  function reflectionIntegrationShouldRecompile(result) {
443944
444209
  return result.status === "merged";
@@ -443947,6 +444212,9 @@ async function getStatusPorcelain(cwd2) {
443947
444212
  const { stdout } = await runGit4(cwd2, ["status", "--porcelain"]);
443948
444213
  return stdout.trim();
443949
444214
  }
444215
+ async function reflectionMemoryParentHasChanges(parentMemoryDir) {
444216
+ return (await getStatusPorcelain(resolve31(parentMemoryDir))).length > 0;
444217
+ }
443950
444218
  async function getCommitCount(worktree) {
443951
444219
  const { stdout } = await runGit4(worktree.worktreeDir, [
443952
444220
  "rev-list",
@@ -443960,131 +444228,12 @@ async function getHead(cwd2) {
443960
444228
  const head2 = result?.stdout.trim();
443961
444229
  return head2 || undefined;
443962
444230
  }
443963
- async function getBranchCommitCount(parentMemoryDir, branchName) {
443964
- const result = await tryRunGit(parentMemoryDir, [
443965
- "rev-list",
443966
- "--count",
443967
- `HEAD..${branchName}`
443968
- ]);
443969
- return Number.parseInt(result?.stdout.trim() ?? "", 10) || 0;
443970
- }
443971
- function parseWorktreeListPorcelain(output) {
443972
- const entries = [];
443973
- for (const block of output.split(/\n\s*\n/)) {
443974
- const entry = {};
443975
- for (const line of block.split(`
443976
- `)) {
443977
- const separatorIndex = line.indexOf(" ");
443978
- const key2 = separatorIndex === -1 ? line : line.slice(0, separatorIndex);
443979
- const value = separatorIndex === -1 ? "" : line.slice(separatorIndex + 1);
443980
- if (key2 === "worktree")
443981
- entry.path = value;
443982
- if (key2 === "HEAD")
443983
- entry.head = value;
443984
- if (key2 === "branch")
443985
- entry.branch = value;
443986
- }
443987
- if (!entry.path)
443988
- continue;
443989
- entries.push({
443990
- path: entry.path,
443991
- ...entry.head ? { head: entry.head } : {},
443992
- ...entry.branch ? { branch: entry.branch } : {}
443993
- });
443994
- }
443995
- return entries;
443996
- }
443997
- async function listPendingReflectionMemoryWorktrees(parentMemoryDir) {
443998
- const resolvedParent = await realpath4(resolve31(parentMemoryDir));
443999
- const worktreeBaseDir = join61(dirname26(resolvedParent), "memory-worktrees");
444000
- const worktreeList = await tryRunGit(resolvedParent, [
444001
- "worktree",
444002
- "list",
444003
- "--porcelain"
444004
- ]);
444005
- if (!worktreeList)
444006
- return [];
444007
- const pending = [];
444008
- for (const entry of parseWorktreeListPorcelain(worktreeList.stdout)) {
444009
- const worktreeDir = normalizeGitPath(entry.path, resolvedParent);
444010
- const relativeWorktreeDir = relative9(worktreeBaseDir, worktreeDir);
444011
- if (relativeWorktreeDir.startsWith("..") || isAbsolute25(relativeWorktreeDir))
444012
- continue;
444013
- const branchName = entry.branch?.startsWith("refs/heads/") ? entry.branch.slice("refs/heads/".length) : undefined;
444014
- if (!branchName?.startsWith("letta/reflection/"))
444015
- continue;
444016
- const isMerged = await tryRunGit(resolvedParent, [
444017
- "merge-base",
444018
- "--is-ancestor",
444019
- branchName,
444020
- "HEAD"
444021
- ]);
444022
- if (isMerged) {
444023
- await cleanupWorktreeAndBranch(resolvedParent, worktreeDir, branchName, {
444024
- force: true
444025
- });
444026
- debugLog("memfs-git", "reflection pending scan cleaned already-merged branch=%s worktree=%s", branchName, worktreeDir);
444027
- continue;
444028
- }
444029
- pending.push({
444030
- id: branchName.slice("letta/reflection/".length),
444031
- parentMemoryDir: resolvedParent,
444032
- reflectionWorktreeDir: worktreeDir,
444033
- reflectionBranch: branchName,
444034
- commitCount: await getBranchCommitCount(resolvedParent, branchName),
444035
- head: entry.head
444036
- });
444037
- }
444038
- if (pending.length > 0) {
444039
- debugLog("memfs-git", "reflection pending scan found=%d parent=%s branches=%s", pending.length, resolvedParent, pending.map((entry) => entry.reflectionBranch).join(","));
444040
- }
444041
- return pending;
444042
- }
444043
- async function integratePendingReflectionMemoryWorktrees(parentMemoryDir) {
444044
- const pendingWorktrees = await listPendingReflectionMemoryWorktrees(parentMemoryDir);
444045
- const unresolved = [];
444046
- for (const pending of pendingWorktrees) {
444047
- const isMerged = await tryRunGit(pending.parentMemoryDir, [
444048
- "merge-base",
444049
- "--is-ancestor",
444050
- pending.reflectionBranch,
444051
- "HEAD"
444052
- ]);
444053
- if (isMerged) {
444054
- await cleanupWorktreeAndBranch(pending.parentMemoryDir, pending.reflectionWorktreeDir, pending.reflectionBranch, { force: true });
444055
- debugLog("memfs-git", "reflection pending integration cleaned already-merged branch=%s worktree=%s", pending.reflectionBranch, pending.reflectionWorktreeDir);
444056
- continue;
444057
- }
444058
- const worktreeStatus = await getStatusPorcelain(pending.reflectionWorktreeDir);
444059
- if (worktreeStatus.length > 0) {
444060
- unresolved.push(buildPendingResultFromPending(pending, "pending_manual_merge", "A previously unresolved reflection memory worktree has uncommitted changes. Background merge was deferred."));
444061
- debugLog("memfs-git", "reflection pending integration deferred branch=%s reason=worktree_dirty worktree=%s", pending.reflectionBranch, pending.reflectionWorktreeDir);
444062
- continue;
444063
- }
444064
- const parentStatus = await getStatusPorcelain(pending.parentMemoryDir);
444065
- if (parentStatus.length > 0) {
444066
- unresolved.push(buildPendingResultFromPending(pending, "pending_manual_merge", "A previously unresolved reflection memory worktree is still unmerged, and the parent memory repo has uncommitted changes. Background merge was deferred."));
444067
- debugLog("memfs-git", "reflection pending integration deferred branch=%s reason=parent_dirty", pending.reflectionBranch);
444068
- continue;
444069
- }
444070
- const mergeMessage = await buildReflectionMergeMessage(pending.parentMemoryDir, pending.reflectionBranch);
444071
- const mergeResult = await tryRunGit(pending.parentMemoryDir, [
444072
- "merge",
444073
- pending.reflectionBranch,
444074
- "-m",
444075
- mergeMessage
444076
- ]);
444077
- if (!mergeResult) {
444078
- await tryRunGit(pending.parentMemoryDir, ["merge", "--abort"]);
444079
- unresolved.push(buildPendingResultFromPending(pending, "pending_conflict", "A previously unresolved reflection memory worktree still has conflicts. The parent merge was aborted and the reflection worktree was preserved."));
444080
- debugLog("memfs-git", "reflection pending integration conflicted branch=%s mergeAbort=true preservedWorktree=%s", pending.reflectionBranch, pending.reflectionWorktreeDir);
444081
- continue;
444082
- }
444083
- const mergedHead = await getHead(pending.parentMemoryDir);
444084
- await cleanupWorktreeAndBranch(pending.parentMemoryDir, pending.reflectionWorktreeDir, pending.reflectionBranch, { force: true });
444085
- debugLog("memfs-git", "reflection pending integration merged branch=%s commitCount=%d parentHead=%s cleanedUp=true", pending.reflectionBranch, pending.commitCount, mergedHead ?? "<none>");
444086
- }
444087
- return unresolved;
444231
+ async function inspectReflectionMemoryWorktree(worktree) {
444232
+ return {
444233
+ commitCount: await getCommitCount(worktree),
444234
+ dirty: (await getStatusPorcelain(worktree.worktreeDir)).length > 0,
444235
+ head: await getHead(worktree.worktreeDir)
444236
+ };
444088
444237
  }
444089
444238
  async function cleanupWorktreeAndBranch(parentMemoryDir, worktreeDir, branchName, options3 = {}) {
444090
444239
  const removedWorktree = existsSync46(worktreeDir);
@@ -444102,19 +444251,28 @@ async function cleanupWorktreeAndBranch(parentMemoryDir, worktreeDir, branchName
444102
444251
  branchName
444103
444252
  ]);
444104
444253
  }
444105
- function buildPendingManualResult(worktree, commitCount, summary, options3 = {}) {
444106
- return {
444107
- status: "pending_manual_merge",
444108
- parentMemoryDir: worktree.parentMemoryDir,
444109
- reflectionWorktreeDir: worktree.worktreeDir,
444110
- reflectionBranch: worktree.branchName,
444111
- commitCount,
444112
- head: options3.head,
444113
- summary,
444114
- error: options3.error
444115
- };
444116
- }
444117
- async function finalizeReflectionMemoryWorktree(worktree, options3) {
444254
+ async function finalizeReflectionMemoryWorktreeImpl(worktree, options3) {
444255
+ if (!existsSync46(worktree.worktreeDir) && options3.knownNoChanges) {
444256
+ const branchHead = (await tryRunGit(worktree.parentMemoryDir, [
444257
+ "rev-parse",
444258
+ "--verify",
444259
+ worktree.branchName
444260
+ ]))?.stdout.trim();
444261
+ if (branchHead && branchHead !== worktree.baseHead) {
444262
+ throw new Error(`Cannot finalize missing reflection worktree ${worktree.worktreeDir} as no-op: ${worktree.branchName} advanced from ${worktree.baseHead} to ${branchHead}`);
444263
+ }
444264
+ await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName, { force: true });
444265
+ debugLog("memfs-git", "reflection finalized id=%s status=no_changes worktreeMissing=true cleanedUp=true", worktree.id);
444266
+ return {
444267
+ status: "no_changes",
444268
+ parentMemoryDir: worktree.parentMemoryDir,
444269
+ reflectionWorktreeDir: worktree.worktreeDir,
444270
+ reflectionBranch: worktree.branchName,
444271
+ commitCount: 0,
444272
+ head: worktree.baseHead,
444273
+ summary: "Reflection made no memory commits."
444274
+ };
444275
+ }
444118
444276
  const commitCount = await getCommitCount(worktree);
444119
444277
  const status = await getStatusPorcelain(worktree.worktreeDir);
444120
444278
  const head2 = await getHead(worktree.worktreeDir);
@@ -444131,6 +444289,19 @@ async function finalizeReflectionMemoryWorktree(worktree, options3) {
444131
444289
  summary: "Reflection memory worktree had uncommitted changes; it was cleaned up so the transcript can be retried."
444132
444290
  };
444133
444291
  }
444292
+ if (!options3.shouldMerge) {
444293
+ await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName, { force: true });
444294
+ debugLog("memfs-git", "reflection finalized id=%s status=failed commitCount=%d cleanedUp=true retryable=true", worktree.id, commitCount);
444295
+ return {
444296
+ status: "failed",
444297
+ parentMemoryDir: worktree.parentMemoryDir,
444298
+ reflectionWorktreeDir: worktree.worktreeDir,
444299
+ reflectionBranch: worktree.branchName,
444300
+ commitCount,
444301
+ head: head2,
444302
+ summary: "Reflection subagent did not complete successfully; the worktree was cleaned up so the transcript can be retried."
444303
+ };
444304
+ }
444134
444305
  if (commitCount === 0) {
444135
444306
  await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName);
444136
444307
  debugLog("memfs-git", "reflection finalized id=%s status=no_changes cleanedUp=true", worktree.id);
@@ -444144,23 +444315,52 @@ async function finalizeReflectionMemoryWorktree(worktree, options3) {
444144
444315
  summary: "Reflection made no memory commits."
444145
444316
  };
444146
444317
  }
444147
- if (!options3.shouldMerge) {
444318
+ const parentStatus = await getStatusPorcelain(worktree.parentMemoryDir);
444319
+ if (parentStatus.length > 0) {
444148
444320
  await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName, { force: true });
444149
- debugLog("memfs-git", "reflection finalized id=%s status=failed commitCount=%d cleanedUp=true retryable=true", worktree.id, commitCount);
444321
+ debugLog("memfs-git", "reflection finalized id=%s status=parent_dirty commitCount=%d cleanedUp=true retryable=true", worktree.id, commitCount);
444150
444322
  return {
444151
- status: "failed",
444323
+ status: "parent_dirty",
444152
444324
  parentMemoryDir: worktree.parentMemoryDir,
444153
444325
  reflectionWorktreeDir: worktree.worktreeDir,
444154
444326
  reflectionBranch: worktree.branchName,
444155
444327
  commitCount,
444156
444328
  head: head2,
444157
- summary: "Reflection produced committed memory updates, but the subagent did not complete successfully; the worktree was cleaned up so the transcript can be retried."
444329
+ summary: "Reflection produced memory updates, but the parent memory repo had uncommitted changes; the worktree was cleaned up so the transcript can be retried."
444158
444330
  };
444159
444331
  }
444160
- const parentStatus = await getStatusPorcelain(worktree.parentMemoryDir);
444161
- if (parentStatus.length > 0) {
444162
- debugLog("memfs-git", "reflection finalized id=%s status=pending_manual_merge reason=parent_dirty branch=%s preservedWorktree=%s", worktree.id, worktree.branchName, worktree.worktreeDir);
444163
- return buildPendingManualResult(worktree, commitCount, "Reflection produced memory updates, but the parent memory repo has uncommitted changes. Merge was deferred.", { head: head2 });
444332
+ if (options3.requireAlreadyMerged) {
444333
+ const alreadyMerged = await tryRunGit(worktree.parentMemoryDir, [
444334
+ "merge-base",
444335
+ "--is-ancestor",
444336
+ worktree.branchName,
444337
+ "HEAD"
444338
+ ]);
444339
+ if (!alreadyMerged) {
444340
+ await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName, { force: true });
444341
+ return {
444342
+ status: "failed",
444343
+ parentMemoryDir: worktree.parentMemoryDir,
444344
+ reflectionWorktreeDir: worktree.worktreeDir,
444345
+ reflectionBranch: worktree.branchName,
444346
+ commitCount,
444347
+ head: head2,
444348
+ failurePhase: "integration",
444349
+ summary: options3.failureSummary ?? "The primary-agent integration conversation did not merge the reflection branch; the worktree was cleaned up so the transcript can be retried."
444350
+ };
444351
+ }
444352
+ const mergedHead2 = await getHead(worktree.parentMemoryDir);
444353
+ await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName);
444354
+ debugLog("memfs-git", "reflection finalized id=%s status=merged integration=primary_agent commitCount=%d parentHead=%s cleanedUp=true", worktree.id, commitCount, mergedHead2 ?? "<none>");
444355
+ return {
444356
+ status: "merged",
444357
+ parentMemoryDir: worktree.parentMemoryDir,
444358
+ reflectionWorktreeDir: worktree.worktreeDir,
444359
+ reflectionBranch: worktree.branchName,
444360
+ commitCount,
444361
+ head: mergedHead2,
444362
+ summary: `Primary agent integrated ${commitCount} reflection memory commit(s).`
444363
+ };
444164
444364
  }
444165
444365
  debugLog("memfs-git", "reflection merge attempt id=%s branch=%s parent=%s commitCount=%d", worktree.id, worktree.branchName, worktree.parentMemoryDir, commitCount);
444166
444366
  const mergeMessage = await buildReflectionMergeMessage(worktree.parentMemoryDir, worktree.branchName);
@@ -444172,15 +444372,16 @@ async function finalizeReflectionMemoryWorktree(worktree, options3) {
444172
444372
  ]);
444173
444373
  if (!mergeResult) {
444174
444374
  await tryRunGit(worktree.parentMemoryDir, ["merge", "--abort"]);
444175
- debugLog("memfs-git", "reflection finalized id=%s status=pending_conflict branch=%s mergeAbort=true preservedWorktree=%s", worktree.id, worktree.branchName, worktree.worktreeDir);
444375
+ await cleanupWorktreeAndBranch(worktree.parentMemoryDir, worktree.worktreeDir, worktree.branchName, { force: true });
444376
+ debugLog("memfs-git", "reflection finalized id=%s status=merge_conflict commitCount=%d mergeAbort=true cleanedUp=true retryable=true", worktree.id, commitCount);
444176
444377
  return {
444177
- status: "pending_conflict",
444378
+ status: "merge_conflict",
444178
444379
  parentMemoryDir: worktree.parentMemoryDir,
444179
444380
  reflectionWorktreeDir: worktree.worktreeDir,
444180
444381
  reflectionBranch: worktree.branchName,
444181
444382
  commitCount,
444182
444383
  head: head2,
444183
- summary: "Reflection produced memory updates, but merging them into the parent memory repo has conflicts. The parent merge was aborted and the reflection worktree was preserved for manual merge."
444384
+ summary: "Reflection produced memory updates, but merging them into the parent memory repo conflicted; the worktree was cleaned up so the transcript can be retried."
444184
444385
  };
444185
444386
  }
444186
444387
  const mergedHead = await getHead(worktree.parentMemoryDir);
@@ -444196,6 +444397,9 @@ async function finalizeReflectionMemoryWorktree(worktree, options3) {
444196
444397
  summary: `Merged ${commitCount} reflection memory commit(s) into parent memory main.`
444197
444398
  };
444198
444399
  }
444400
+ async function finalizeReflectionMemoryWorktree(worktree, options3) {
444401
+ return await finalizeReflectionMemoryWorktreeImpl(worktree, options3);
444402
+ }
444199
444403
  var execFile13, GIT_TIMEOUT_MS = 30000, HARNESS_GIT_ENV;
444200
444404
  var init_memory_worktree = __esm(() => {
444201
444405
  init_memory_git_signing();
@@ -444268,6 +444472,43 @@ var init_memory_subagent_completion = __esm(() => {
444268
444472
  init_system_prompt_warning();
444269
444473
  });
444270
444474
 
444475
+ // src/cli/helpers/reflection-integration.ts
444476
+ function buildReflectionIntegrationConversationTitle(reflectionSubagentId) {
444477
+ return reflectionSubagentId ? `Reflection integration (reflection ${reflectionSubagentId})` : "Reflection integration";
444478
+ }
444479
+ function buildReflectionIntegrationPrompt(params) {
444480
+ const instructions = params.instructions?.trim();
444481
+ return `Integrate proposed reflection changes into your memory.
444482
+
444483
+ The user configured explicit handling for reflection merges. You are responsible for the entire integration. Work autonomously in this separate conversation; do not interrupt or add messages to the original conversation.
444484
+
444485
+ Reflection worktree: ${params.worktree.worktreeDir}
444486
+ Your memory repository: ${params.worktree.parentMemoryDir}
444487
+ Reflection branch: ${params.worktree.branchName}
444488
+ Reflection base commit: ${params.worktree.baseHead}
444489
+ Original reflection subagent ID: ${params.reflectionSubagentId ?? "unavailable"}
444490
+
444491
+ Work in the reflection worktree while refining the proposal. Start directly by checking both repository states and the proposed diff in one combined shell call; do not create a task plan or spend turns narrating routine Git checks.
444492
+
444493
+ Review the proposal for accuracy, placement, precision, and consistency with existing memory, then make any needed edits. If no edits are needed, do not create another commit. If you edit the proposal, stage only those files and create one follow-up commit on top of the reflection commit; do not amend. Use the subject \`merge(reflection): <concise summary>\`.${params.reflectionSubagentId ? ` Include the trailer \`Reflection-Subagent-ID: ${params.reflectionSubagentId}\`.` : ""}
444494
+
444495
+ Before merging, incorporate the latest committed memory repository HEAD into the reflection branch and resolve conflicts yourself while preserving the intended memory state. If the memory repository has pre-existing uncommitted changes, leave them completely untouched—do not modify, stash, commit, or discard them—and stop the integration.
444496
+
444497
+ Merge the completed reflection branch into your memory repository without pushing, then verify both repositories are clean. Do not remove the worktree or branch; the harness performs final verification and cleanup.
444498
+
444499
+ Do not ask the user questions or wait for input. Handle the integration as far as you safely can and explain any remaining blocker in your final response. If integration remains incomplete, the harness will clean up this proposal without consuming the source transcript so reflection can retry later.
444500
+
444501
+ ${instructions ? `## IMPORTANT: Additional reflection merge instructions from the user
444502
+
444503
+ The user explicitly configured the following instructions for this integration. Follow them carefully:
444504
+
444505
+ <reflection-merge-instructions>
444506
+ ${instructions}
444507
+ </reflection-merge-instructions>
444508
+
444509
+ ` : ""}When finished, provide a concise normal summary of what you reviewed, changed, and merged.`;
444510
+ }
444511
+
444271
444512
  // src/telemetry/reflection-threshold-feedback.ts
444272
444513
  import { randomUUID as randomUUID25 } from "node:crypto";
444273
444514
  async function resolveFeedbackApiKey() {
@@ -444283,6 +444524,18 @@ function getFeedbackDeviceId() {
444283
444524
  } catch {}
444284
444525
  return randomUUID25();
444285
444526
  }
444527
+ function getAlertDeviceType() {
444528
+ switch (process.platform) {
444529
+ case "darwin":
444530
+ return "macOS";
444531
+ case "win32":
444532
+ return "Windows";
444533
+ case "linux":
444534
+ return "Linux";
444535
+ default:
444536
+ return process.platform;
444537
+ }
444538
+ }
444286
444539
  function getAlertReasonDescriptions(alertReasons) {
444287
444540
  return alertReasons.map((reason) => {
444288
444541
  switch (reason) {
@@ -444323,6 +444576,10 @@ function maybeSendReflectionThresholdFeedback(options3) {
444323
444576
  feature: "letta-code",
444324
444577
  agent_id: agentId,
444325
444578
  session_id: telemetry.getSessionId(),
444579
+ version: getVersion(),
444580
+ platform: process.platform,
444581
+ device_type: getAlertDeviceType(),
444582
+ node_version: process.version,
444326
444583
  total_wall_ms: options3.durationMs,
444327
444584
  step_count: options3.stepCount,
444328
444585
  agent_name: options3.parentAgentName ?? undefined,
@@ -444350,6 +444607,7 @@ var init_reflection_threshold_feedback = __esm(() => {
444350
444607
  init_metadata();
444351
444608
  init_settings_manager();
444352
444609
  init_telemetry();
444610
+ init_version();
444353
444611
  REFLECTION_DURATION_THRESHOLD_MS = 10 * 60 * 1000;
444354
444612
  });
444355
444613
 
@@ -444359,10 +444617,11 @@ __export(exports_reflection_launcher, {
444359
444617
  tryReserveReflectionLaunch: () => tryReserveReflectionLaunch,
444360
444618
  shouldRunQueuedReflectionLaunch: () => shouldRunQueuedReflectionLaunch,
444361
444619
  releaseReflectionLaunch: () => releaseReflectionLaunch,
444362
- queuePendingReflectionWorktreeReminders: () => queuePendingReflectionWorktreeReminders,
444363
444620
  prepareReflectionMemoryWorktreeLaunch: () => prepareReflectionMemoryWorktreeLaunch,
444364
444621
  launchReflectionSubagent: () => launchReflectionSubagent,
444365
- formatReflectionIntegrationReminder: () => formatReflectionIntegrationReminder,
444622
+ getReflectionMergeLaunchOptions: () => getReflectionMergeLaunchOptions,
444623
+ getReflectionLaunchSkippedMessage: () => getReflectionLaunchSkippedMessage,
444624
+ getReflectionFinalizationContext: () => getReflectionFinalizationContext,
444366
444625
  finalizeReflectionMemoryWorktreeLaunch: () => finalizeReflectionMemoryWorktreeLaunch,
444367
444626
  emitReflectionRunStart: () => emitReflectionRunStart,
444368
444627
  emitReflectionRunEnd: () => emitReflectionRunEnd,
@@ -444370,11 +444629,56 @@ __export(exports_reflection_launcher, {
444370
444629
  REFLECTION_AGENT_ID_WAIT_MS: () => REFLECTION_AGENT_ID_WAIT_MS,
444371
444630
  AUTO_REFLECTION_DESCRIPTION: () => AUTO_REFLECTION_DESCRIPTION
444372
444631
  });
444632
+ function getReflectionMergeLaunchOptions(agentId) {
444633
+ const settings3 = getReflectionSettings(agentId);
444634
+ return {
444635
+ mergePolicy: settings3.merge ?? "auto",
444636
+ mergeInstructions: settings3.mergeInstructions
444637
+ };
444638
+ }
444639
+ function getReflectionFinalizationContext(agentId) {
444640
+ return {
444641
+ agentId,
444642
+ ...getReflectionMergeLaunchOptions(agentId)
444643
+ };
444644
+ }
444645
+ function getReflectionLaunchSkippedMessage(reason, surface = "cli") {
444646
+ switch (reason) {
444647
+ case "already_active":
444648
+ return surface === "listener" ? "A reflection agent is already running for this conversation." : "A reflection agent is already running in the background.";
444649
+ case "memfs_disabled":
444650
+ return surface === "listener" ? "Reflection needs the memory filesystem to be enabled for this agent. Use /remember for a lightweight memory update instead." : "Memory filesystem is not enabled. Use /remember instead.";
444651
+ case "no_payload":
444652
+ return surface === "listener" ? "No new transcript content to reflect on for this conversation." : "No new transcript content to reflect on.";
444653
+ case "parent_dirty":
444654
+ return "Parent memory has uncommitted changes; commit or discard them before reflecting.";
444655
+ case "error":
444656
+ return;
444657
+ }
444658
+ }
444373
444659
  function drainReflectionTelemetry() {
444374
444660
  telemetry.drain().catch((error54) => {
444375
444661
  debugWarn("telemetry", `Failed to flush reflection telemetry: ${error54 instanceof Error ? error54.message : String(error54)}`);
444376
444662
  });
444377
444663
  }
444664
+ function getReflectionWorktreeCleanupOutcome(integration) {
444665
+ switch (integration.status) {
444666
+ case "parent_dirty":
444667
+ return { outcome: "parent_dirty", integrationStatus: "parent_dirty" };
444668
+ case "merge_conflict":
444669
+ return { outcome: "merge_conflict", integrationStatus: "merge_conflict" };
444670
+ case "dirty_uncommitted":
444671
+ return {
444672
+ outcome: "reflection_worktree_dirty",
444673
+ integrationStatus: "dirty_uncommitted"
444674
+ };
444675
+ case "failed":
444676
+ return { outcome: "subagent_failed", integrationStatus: "failed" };
444677
+ case "merged":
444678
+ case "no_changes":
444679
+ return;
444680
+ }
444681
+ }
444378
444682
  function emitReflectionRunStart(params) {
444379
444683
  telemetry.trackReflectionStart(params.triggerSource, {
444380
444684
  subagentId: params.subagentId,
@@ -444392,7 +444696,7 @@ function emitReflectionRunEnd(params) {
444392
444696
  error: params.error,
444393
444697
  stepCount: params.stepCount,
444394
444698
  durationMs: params.durationMs,
444395
- model: params.feedbackContext?.model
444699
+ model: params.model
444396
444700
  });
444397
444701
  drainReflectionTelemetry();
444398
444702
  maybeSendReflectionThresholdFeedback({
@@ -444407,7 +444711,7 @@ function emitReflectionRunEnd(params) {
444407
444711
  stepCount: params.stepCount,
444408
444712
  durationMs: params.durationMs,
444409
444713
  surface: params.feedbackContext?.surface,
444410
- model: params.feedbackContext?.model
444714
+ model: params.model
444411
444715
  });
444412
444716
  }
444413
444717
  function isReflectionSubagentActiveForAgent(agentId) {
@@ -444480,84 +444784,64 @@ function getReflectionCompletionMessage(integration) {
444480
444784
  return;
444481
444785
  case "no_changes":
444482
444786
  return ({ action: action3 }) => `${action3}; no durable memory changes were needed.`;
444483
- case "pending_conflict":
444484
- return ({ action: action3 }) => `${action3}; memory merge will finish after conflicts are resolved.`;
444485
- case "pending_manual_merge":
444486
- return ({ action: action3 }) => `${action3}; memory merge will finish after pending memory changes are resolved.`;
444787
+ case "parent_dirty":
444788
+ return "Tried to reflect, but parent memory had uncommitted changes; will retry later.";
444789
+ case "merge_conflict":
444790
+ return "Tried to reflect, but memory updates conflicted with newer changes; will retry later.";
444487
444791
  case "dirty_uncommitted":
444488
444792
  return "Tried to reflect, but memory changes were not committed cleanly; will retry later.";
444489
444793
  case "failed":
444490
- return "Tried to reflect, but memory updates were not completed cleanly; will retry later.";
444794
+ return integration.failurePhase === "integration" ? `${integration.summary} Will retry later.` : "Tried to reflect, but memory updates were not completed cleanly; will retry later.";
444491
444795
  }
444492
444796
  }
444493
- function escapeTaskNotificationSummary(summary) {
444494
- return summary.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
444495
- }
444496
- function formatReflectionIntegrationNotification(reminder) {
444497
- return `<task-notification>
444498
- <summary>${escapeTaskNotificationSummary("Memory reflection merge is pending.")}</summary>
444499
- <result>
444500
- ${reminder}
444501
- </result>
444502
- </task-notification>`;
444503
- }
444504
- function formatReflectionIntegrationReminder(integration) {
444505
- const resolveCommands = `cd ${JSON.stringify(integration.parentMemoryDir)}
444506
- git status
444507
- reflection_branch=${JSON.stringify(integration.reflectionBranch)}
444508
- reflection_subject=$(git log -1 --pretty=%s "$reflection_branch")
444509
- reflection_summary=$(printf '%s' "$reflection_subject" | sed -E 's/^[a-z]+(\\([^)]+\\))?!?:[[:space:]]*//I')
444510
- merge_message="merge(reflection): \${reflection_summary:-reflection memory updates}"
444511
- # If parent MemFS has unrelated changes, inspect changes, then commit or discard them.
444512
- # Then merge the reflection branch and resolve conflicts if prompted:
444513
- git merge "$reflection_branch" -m "$merge_message" || {
444514
- git status
444515
- echo "Resolve conflicted memory files, then stage specific resolved files and run: git commit --no-edit"
444516
- exit 1
444517
- }
444518
-
444519
- git worktree remove ${JSON.stringify(integration.reflectionWorktreeDir)}
444520
- git branch -d "$reflection_branch"`;
444521
- const reminder = `${SYSTEM_REMINDER_OPEN}
444522
- BACKGROUND MEMORY MAINTENANCE: A reflection memory merge is pending.
444523
-
444524
- A background reflection completed and produced committed memory updates, but the harness could not merge them into your main MemFS automatically.
444525
-
444526
- Do not interrupt the user's current request just because of this reminder, and do not invoke a skill solely because this reminder arrived. If you are already responding to the user, finish that response first. Resolve this later when appropriate, or when the user asks you to handle pending memory merges.
444527
-
444528
- Parent memory dir: ${integration.parentMemoryDir}
444529
- Reflection branch: ${integration.reflectionBranch}
444530
- Reflection worktree: ${integration.reflectionWorktreeDir}
444531
- Status: ${integration.summary}
444532
-
444533
- When you decide to resolve it, use standard git commands like:
444534
- \`\`\`bash
444535
- ${resolveCommands}
444536
- \`\`\`
444537
-
444538
- This reminder is one-time. The transcript was already reflected, so do not launch another reflection for the same content just to resolve this merge.
444539
- ${SYSTEM_REMINDER_CLOSE}`;
444540
- return formatReflectionIntegrationNotification(reminder);
444541
- }
444542
- function queueReflectionIntegrationReminder(params) {
444543
- addToMessageQueue({
444544
- kind: "task_notification",
444545
- text: formatReflectionIntegrationReminder(params.integration),
444546
- agentId: params.agentId,
444547
- conversationId: params.conversationId
444797
+ async function runExplicitReflectionIntegration(params) {
444798
+ const {
444799
+ spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2,
444800
+ waitForBackgroundSubagentConversationId: waitForBackgroundSubagentConversationId2
444801
+ } = await Promise.resolve().then(() => (init_task(), exports_task));
444802
+ return await new Promise((resolve32) => {
444803
+ try {
444804
+ const { subagentId } = spawnBackgroundSubagentTask2({
444805
+ subagentType: "general-purpose",
444806
+ displayType: "reflection integration",
444807
+ prompt: buildReflectionIntegrationPrompt({
444808
+ worktree: params.worktree,
444809
+ instructions: params.instructions,
444810
+ reflectionSubagentId: params.reflectionSubagentId
444811
+ }),
444812
+ description: "Integrate reflection memory changes",
444813
+ existingAgentId: params.agentId,
444814
+ memoryScope: buildReflectionIntegrationMemoryScope(params.worktree),
444815
+ parentScope: {
444816
+ agentId: params.agentId,
444817
+ conversationId: params.conversationId
444818
+ },
444819
+ silentCompletion: true,
444820
+ onComplete: (result) => {
444821
+ resolve32({
444822
+ success: result.success,
444823
+ error: result.success ? undefined : result.error ?? "Reflection integration did not complete",
444824
+ conversationId: result.conversationId
444825
+ });
444826
+ }
444827
+ });
444828
+ waitForBackgroundSubagentConversationId2(subagentId, REFLECTION_AGENT_ID_WAIT_MS).then(async (conversationId) => {
444829
+ if (!conversationId)
444830
+ return;
444831
+ await getBackend().updateConversation(conversationId, {
444832
+ summary: buildReflectionIntegrationConversationTitle(params.reflectionSubagentId)
444833
+ });
444834
+ }).catch((error54) => {
444835
+ debugWarn("memory", `Failed to title reflection integration conversation: ${error54 instanceof Error ? error54.message : String(error54)}`);
444836
+ });
444837
+ } catch (error54) {
444838
+ resolve32({
444839
+ success: false,
444840
+ error: error54 instanceof Error ? error54.message : String(error54)
444841
+ });
444842
+ }
444548
444843
  });
444549
444844
  }
444550
- async function queuePendingReflectionWorktreeReminders(params) {
444551
- const memoryDir = getScopedMemoryFilesystemRoot(params.agentId);
444552
- const unresolvedIntegrations = await integratePendingReflectionMemoryWorktrees(memoryDir);
444553
- for (const integration of unresolvedIntegrations) {
444554
- queueReflectionIntegrationReminder({
444555
- agentId: params.agentId,
444556
- conversationId: params.conversationId,
444557
- integration
444558
- });
444559
- }
444560
- }
444561
444845
  async function prepareReflectionMemoryWorktreeLaunch(params) {
444562
444846
  const memoryDir = getScopedMemoryFilesystemRoot(params.agentId);
444563
444847
  const worktree = await createReflectionMemoryWorktree({
@@ -444577,16 +444861,39 @@ async function prepareReflectionMemoryWorktreeLaunch(params) {
444577
444861
  }
444578
444862
  }
444579
444863
  async function finalizeReflectionMemoryWorktreeLaunch(params) {
444864
+ let integrationRun;
444865
+ if (params.subagentSuccess && params.mergePolicy === "explicit") {
444866
+ const state = params.knownNoChanges ? { commitCount: 0, dirty: false } : await inspectReflectionMemoryWorktree(params.worktree);
444867
+ if (state.commitCount > 0 || state.dirty) {
444868
+ integrationRun = await (params.runExplicitIntegration ?? runExplicitReflectionIntegration)({
444869
+ agentId: params.agentId,
444870
+ conversationId: params.conversationId,
444871
+ worktree: params.worktree,
444872
+ instructions: params.mergeInstructions,
444873
+ reflectionSubagentId: params.subagentAgentId
444874
+ });
444875
+ }
444876
+ }
444580
444877
  const integration = await finalizeReflectionMemoryWorktree(params.worktree, {
444581
- shouldMerge: params.subagentSuccess
444878
+ shouldMerge: params.subagentSuccess,
444879
+ knownNoChanges: params.knownNoChanges,
444880
+ requireAlreadyMerged: params.mergePolicy === "explicit" && integrationRun !== undefined,
444881
+ failureSummary: integrationRun?.error ? `Reflection integration did not complete (${integrationRun.error}); the worktree was cleaned up so the transcript can be retried.` : undefined
444582
444882
  });
444583
444883
  const completionSuccess = params.subagentSuccess && reflectionIntegrationConsumesTranscript(integration);
444584
- if (reflectionIntegrationNeedsReminder(integration)) {
444585
- queueReflectionIntegrationReminder({
444586
- agentId: params.agentId,
444587
- conversationId: params.conversationId,
444588
- integration
444884
+ const cleanup = getReflectionWorktreeCleanupOutcome(integration);
444885
+ if (cleanup) {
444886
+ telemetry.trackReflectionWorktreeCleanup({
444887
+ outcome: cleanup.outcome,
444888
+ integration_status: cleanup.integrationStatus,
444889
+ trigger_source: params.telemetryContext?.triggerSource,
444890
+ subagent_id: params.subagentAgentId,
444891
+ conversation_id: params.conversationId,
444892
+ reflection_worktree_id: params.worktree.id,
444893
+ commit_count: integration.commitCount,
444894
+ model: params.model ?? undefined
444589
444895
  });
444896
+ drainReflectionTelemetry();
444590
444897
  }
444591
444898
  const completionMessage = await handleMemorySubagentCompletion({
444592
444899
  agentId: params.agentId,
@@ -444602,7 +444909,27 @@ async function finalizeReflectionMemoryWorktreeLaunch(params) {
444602
444909
  recompileQueuedByConversation: params.recompileQueuedByConversation,
444603
444910
  logRecompileFailure: params.logRecompileFailure
444604
444911
  });
444605
- return { integration, completionSuccess, completionMessage };
444912
+ if (completionSuccess && integrationRun?.conversationId) {
444913
+ try {
444914
+ const body3 = {
444915
+ summary: buildReflectionIntegrationConversationTitle(params.subagentAgentId),
444916
+ archived: true
444917
+ };
444918
+ if (params.updateIntegrationConversation) {
444919
+ await params.updateIntegrationConversation(integrationRun.conversationId, body3);
444920
+ } else {
444921
+ await getBackend().updateConversation(integrationRun.conversationId, body3);
444922
+ }
444923
+ } catch (error54) {
444924
+ debugWarn("memory", `Failed to archive reflection integration conversation: ${error54 instanceof Error ? error54.message : String(error54)}`);
444925
+ }
444926
+ }
444927
+ return {
444928
+ integration,
444929
+ completionSuccess,
444930
+ completionMessage,
444931
+ integrationConversationId: integrationRun?.conversationId
444932
+ };
444606
444933
  }
444607
444934
  async function launchReflectionSubagent(options3) {
444608
444935
  const {
@@ -444615,19 +444942,10 @@ async function launchReflectionSubagent(options3) {
444615
444942
  recompileQueuedByConversation,
444616
444943
  onCompletionMessage
444617
444944
  } = options3;
444945
+ const reflectionSettings = options3.reflectionSettings ?? getReflectionSettings(agentId);
444618
444946
  if (!memfsEnabled) {
444619
444947
  return { launched: false, reason: "memfs_disabled" };
444620
444948
  }
444621
- if (triggerSource === "compaction-event" && !options3.skipPendingWorktreeReminderScan) {
444622
- try {
444623
- await queuePendingReflectionWorktreeReminders({
444624
- agentId,
444625
- conversationId
444626
- });
444627
- } catch (error54) {
444628
- debugWarn("memory", "Failed to queue pending reflection worktree reminders after compaction:", error54 instanceof Error ? error54.message : String(error54));
444629
- }
444630
- }
444631
444949
  if (!tryReserveReflectionLaunch(agentId)) {
444632
444950
  debugLog("memory", `Skipping reflection launch (${triggerSource}) because one is already active`);
444633
444951
  if (reservedReflectionAgentIds.has(agentId)) {
@@ -444638,6 +444956,12 @@ async function launchReflectionSubagent(options3) {
444638
444956
  let releaseOnComplete = false;
444639
444957
  let preparedWorktree;
444640
444958
  try {
444959
+ const memoryDir = getScopedMemoryFilesystemRoot(agentId);
444960
+ if (await reflectionMemoryParentHasChanges(memoryDir)) {
444961
+ debugLog("memory", `Skipping reflection launch (${triggerSource}) because parent memory has uncommitted changes`);
444962
+ releaseReflectionLaunch(agentId);
444963
+ return { launched: false, reason: "parent_dirty" };
444964
+ }
444641
444965
  const autoPayload = await buildAutoReflectionPayload(agentId, conversationId);
444642
444966
  if (!autoPayload) {
444643
444967
  debugLog("memory", `Skipping reflection launch (${triggerSource}) because transcript has no new content`);
@@ -444658,7 +444982,7 @@ async function launchReflectionSubagent(options3) {
444658
444982
  conversationId,
444659
444983
  startMessageId: autoPayload.startMessageId,
444660
444984
  endMessageId: autoPayload.endMessageId,
444661
- model: options3.feedbackContext?.model
444985
+ model: options3.model
444662
444986
  });
444663
444987
  };
444664
444988
  const { subagentId } = spawnBackgroundSubagentTask2({
@@ -444675,6 +444999,7 @@ async function launchReflectionSubagent(options3) {
444675
444999
  success: success2,
444676
445000
  error: error54,
444677
445001
  agentId: reflectionAgentId,
445002
+ model: reflectionModel,
444678
445003
  stepCount,
444679
445004
  durationMs
444680
445005
  }) => {
@@ -444688,16 +445013,25 @@ async function launchReflectionSubagent(options3) {
444688
445013
  error: error54,
444689
445014
  stepCount,
444690
445015
  durationMs,
445016
+ model: reflectionModel,
444691
445017
  feedbackContext: options3.feedbackContext
444692
445018
  });
444693
445019
  const completionConversationId = resolveCompletionConversationId(options3.completionConversationId, conversationId);
444694
- const { completionSuccess, completionMessage } = await finalizeReflectionMemoryWorktreeLaunch({
445020
+ const {
445021
+ completionSuccess,
445022
+ completionMessage,
445023
+ integrationConversationId
445024
+ } = await finalizeReflectionMemoryWorktreeLaunch({
444695
445025
  worktree,
444696
445026
  subagentSuccess: success2,
444697
445027
  subagentError: error54,
444698
445028
  agentId,
444699
445029
  conversationId: completionConversationId,
444700
445030
  subagentAgentId: reflectionAgentId ?? undefined,
445031
+ model: reflectionModel,
445032
+ mergePolicy: reflectionSettings.merge,
445033
+ mergeInstructions: reflectionSettings.mergeInstructions,
445034
+ telemetryContext: { triggerSource },
444701
445035
  recompileByConversation,
444702
445036
  recompileQueuedByConversation,
444703
445037
  logRecompileFailure: (message) => debugWarn("memory", message)
@@ -444706,7 +445040,8 @@ async function launchReflectionSubagent(options3) {
444706
445040
  await onCompletionMessage?.(completionMessage, {
444707
445041
  success: completionSuccess,
444708
445042
  error: error54,
444709
- reflectionAgentId: reflectionAgentId ?? undefined
445043
+ reflectionAgentId: reflectionAgentId ?? undefined,
445044
+ integrationConversationId
444710
445045
  });
444711
445046
  } finally {
444712
445047
  releaseReflectionLaunch(agentId);
@@ -444747,14 +445082,13 @@ var init_reflection_launcher = __esm(() => {
444747
445082
  init_memory_filesystem2();
444748
445083
  init_memory_worktree();
444749
445084
  init_subagent_state();
445085
+ init_backend2();
444750
445086
  init_memory_reminder();
444751
445087
  init_memory_subagent_completion();
444752
445088
  init_reflection_transcript();
444753
- init_constants2();
444754
445089
  init_telemetry();
444755
445090
  init_reflection_threshold_feedback();
444756
445091
  init_debug();
444757
- init_message_queue_bridge();
444758
445092
  reservedReflectionAgentIds = new Set;
444759
445093
  pendingReflectionLaunches = new Map;
444760
445094
  });
@@ -444938,8 +445272,7 @@ ${targetInstruction}` : targetInstruction;
444938
445272
  });
444939
445273
  },
444940
445274
  feedbackContext: {
444941
- surface: "letta_code_cli",
444942
- model: parsed.values.model
445275
+ surface: "letta_code_cli"
444943
445276
  }
444944
445277
  });
444945
445278
  if (!result.launched) {
@@ -444962,6 +445295,9 @@ ${targetInstruction}` : targetInstruction;
444962
445295
  case "memfs_disabled":
444963
445296
  console.error(`Memory filesystem is not enabled for ${agentId}.`);
444964
445297
  return 1;
445298
+ case "parent_dirty":
445299
+ console.error("Parent memory has uncommitted changes; commit or discard them before reflecting.");
445300
+ return 1;
444965
445301
  default: {
444966
445302
  const message = result.error instanceof Error ? result.error.message : String(result.error ?? "Unknown error");
444967
445303
  console.error(`Failed to start reflection pass: ${message}`);
@@ -448563,7 +448899,7 @@ function isSetReflectionSettingsCommand(value) {
448563
448899
  return false;
448564
448900
  }
448565
448901
  const settings3 = c.settings;
448566
- return (settings3.trigger === "off" || settings3.trigger === "step-count" || settings3.trigger === "compaction-event") && typeof settings3.step_count === "number" && Number.isInteger(settings3.step_count) && settings3.step_count > 0 && (c.scope === undefined || c.scope === "local_project" || c.scope === "global" || c.scope === "both");
448902
+ return (settings3.trigger === "off" || settings3.trigger === "step-count" || settings3.trigger === "compaction-event") && typeof settings3.step_count === "number" && Number.isInteger(settings3.step_count) && settings3.step_count > 0 && (settings3.merge === undefined || settings3.merge === "auto" || settings3.merge === "explicit") && (settings3.merge_instructions === undefined || typeof settings3.merge_instructions === "string") && (c.scope === undefined || c.scope === "local_project" || c.scope === "global" || c.scope === "both");
448567
448903
  }
448568
448904
  function isGetExperimentsCommand(value) {
448569
448905
  if (!value || typeof value !== "object")
@@ -449443,7 +449779,7 @@ __export(exports_memory_scanner, {
449443
449779
  getFileNodes: () => getFileNodes
449444
449780
  });
449445
449781
  import { readdirSync as readdirSync18, readFileSync as readFileSync33, statSync as statSync17 } from "node:fs";
449446
- import { join as join63, relative as relative10 } from "node:path";
449782
+ import { join as join63, relative as relative9 } from "node:path";
449447
449783
  function scanMemoryFilesystem(memoryRoot) {
449448
449784
  const nodes = [];
449449
449785
  const scanDir = (dir, depth, parentIsLast) => {
@@ -449483,7 +449819,7 @@ function scanMemoryFilesystem(memoryRoot) {
449483
449819
  } catch {
449484
449820
  return;
449485
449821
  }
449486
- const relativePath = relative10(memoryRoot, fullPath).replace(/\\/g, "/");
449822
+ const relativePath = relative9(memoryRoot, fullPath).replace(/\\/g, "/");
449487
449823
  const isLast = index === sorted.length - 1;
449488
449824
  nodes.push({
449489
449825
  name: isDir ? `${name}/` : name,
@@ -449900,14 +450236,14 @@ function handleMemoryProtocolCommand(parsed, context3) {
449900
450236
  } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
449901
450237
  const { readFile: readFile20 } = await import("node:fs/promises");
449902
450238
  const { existsSync: existsSync48 } = await import("node:fs");
449903
- const { isAbsolute: isAbsolute26, join: join64, normalize: normalize5, relative: relative11, sep: sep7 } = await import("node:path");
450239
+ const { isAbsolute: isAbsolute26, join: join64, normalize: normalize5, relative: relative10, sep: sep7 } = await import("node:path");
449904
450240
  if (isAbsolute26(parsed.path) || parsed.path.length === 0) {
449905
450241
  sendFailure("path must be a non-empty relative path");
449906
450242
  return;
449907
450243
  }
449908
450244
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
449909
450245
  const absolutePath = normalize5(join64(memoryRoot, parsed.path));
449910
- const rel = relative11(memoryRoot, absolutePath);
450246
+ const rel = relative10(memoryRoot, absolutePath);
449911
450247
  if (rel.startsWith("..") || rel === "" || isAbsolute26(rel) || rel.split(sep7).includes("..")) {
449912
450248
  sendFailure("path must resolve inside the memory root");
449913
450249
  return;
@@ -449966,14 +450302,14 @@ function handleMemoryProtocolCommand(parsed, context3) {
449966
450302
  const { commitMemoryWrite: commitMemoryWrite2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
449967
450303
  const { writeFile: writeFile16, mkdir: mkdir15 } = await import("node:fs/promises");
449968
450304
  const { existsSync: existsSync48 } = await import("node:fs");
449969
- const { dirname: dirname27, isAbsolute: isAbsolute26, join: join64, normalize: normalize5, relative: relative11, sep: sep7 } = await import("node:path");
450305
+ const { dirname: dirname27, isAbsolute: isAbsolute26, join: join64, normalize: normalize5, relative: relative10, sep: sep7 } = await import("node:path");
449970
450306
  if (isAbsolute26(parsed.path) || parsed.path.length === 0) {
449971
450307
  sendFailure("write_memory_file: path must be a non-empty relative path");
449972
450308
  return;
449973
450309
  }
449974
450310
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
449975
450311
  const absolutePath = normalize5(join64(memoryRoot, parsed.path));
449976
- const rel = relative11(memoryRoot, absolutePath);
450312
+ const rel = relative10(memoryRoot, absolutePath);
449977
450313
  if (rel.startsWith("..") || rel === "" || isAbsolute26(rel) || rel.split(sep7).includes("..")) {
449978
450314
  sendFailure("write_memory_file: path must resolve inside the memory root");
449979
450315
  return;
@@ -450064,14 +450400,14 @@ function handleMemoryProtocolCommand(parsed, context3) {
450064
450400
  const { commitMemoryWrite: commitMemoryWrite2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
450065
450401
  const { unlink: unlink6 } = await import("node:fs/promises");
450066
450402
  const { existsSync: existsSync48 } = await import("node:fs");
450067
- const { isAbsolute: isAbsolute26, join: join64, normalize: normalize5, relative: relative11, sep: sep7 } = await import("node:path");
450403
+ const { isAbsolute: isAbsolute26, join: join64, normalize: normalize5, relative: relative10, sep: sep7 } = await import("node:path");
450068
450404
  if (isAbsolute26(parsed.path) || parsed.path.length === 0) {
450069
450405
  sendFailure("delete_memory_file: path must be a non-empty relative path");
450070
450406
  return;
450071
450407
  }
450072
450408
  const memoryRoot = getScopedMemoryFilesystemRoot2(parsed.agent_id);
450073
450409
  const absolutePath = normalize5(join64(memoryRoot, parsed.path));
450074
- const rel = relative11(memoryRoot, absolutePath);
450410
+ const rel = relative10(memoryRoot, absolutePath);
450075
450411
  if (rel.startsWith("..") || rel === "" || isAbsolute26(rel) || rel.split(sep7).includes("..")) {
450076
450412
  sendFailure("delete_memory_file: path must resolve inside the memory root");
450077
450413
  return;
@@ -451407,7 +451743,9 @@ function toReflectionSettingsResponse(agentId, workingDirectory) {
451407
451743
  return {
451408
451744
  agent_id: agentId,
451409
451745
  trigger: settings3.trigger,
451410
- step_count: settings3.stepCount
451746
+ step_count: settings3.stepCount,
451747
+ merge: settings3.merge,
451748
+ merge_instructions: settings3.mergeInstructions
451411
451749
  };
451412
451750
  }
451413
451751
  function resolveReflectionSettingsScope(scope) {
@@ -451488,9 +451826,12 @@ async function handleReflectionSettingsCommand(parsed, socket, listener, safeSoc
451488
451826
  }
451489
451827
  const { persistLocalProject, persistGlobal, normalizedScope } = resolveReflectionSettingsScope(parsed.scope);
451490
451828
  try {
451829
+ const currentSettings = getReflectionSettings(agentId, workingDirectory);
451491
451830
  await persistReflectionSettingsForAgent(agentId, {
451492
451831
  trigger: parsed.settings.trigger,
451493
- stepCount: parsed.settings.step_count
451832
+ stepCount: parsed.settings.step_count,
451833
+ merge: parsed.settings.merge ?? currentSettings.merge,
451834
+ mergeInstructions: parsed.settings.merge_instructions ?? currentSettings.mergeInstructions
451494
451835
  }, {
451495
451836
  workingDirectory,
451496
451837
  persistLocalProject,
@@ -456901,7 +457242,7 @@ var init_diff4 = __esm(() => {
456901
457242
  });
456902
457243
 
456903
457244
  // src/cli/helpers/shell-semantic-display.ts
456904
- import { relative as relative11 } from "node:path";
457245
+ import { relative as relative10 } from "node:path";
456905
457246
  function quoteSummaryValue(value) {
456906
457247
  return JSON.stringify(value);
456907
457248
  }
@@ -456968,7 +457309,7 @@ function formatDisplayPath2(filePath) {
456968
457309
  return ".";
456969
457310
  }
456970
457311
  const cwd2 = process.cwd();
456971
- const relativePath = relative11(cwd2, filePath);
457312
+ const relativePath = relative10(cwd2, filePath);
456972
457313
  if (relativePath === "") {
456973
457314
  return ".";
456974
457315
  }
@@ -457593,13 +457934,13 @@ __export(exports_format_args_display, {
457593
457934
  parsePatchInput: () => parsePatchInput,
457594
457935
  formatArgsDisplay: () => formatArgsDisplay
457595
457936
  });
457596
- import { relative as relative12 } from "node:path";
457937
+ import { relative as relative11 } from "node:path";
457597
457938
  function formatItemCount(count) {
457598
457939
  return `${String(count)} item${count === 1 ? "" : "s"}`;
457599
457940
  }
457600
457941
  function formatDisplayPath3(filePath) {
457601
457942
  const cwd2 = process.cwd();
457602
- const relativePath = relative12(cwd2, filePath);
457943
+ const relativePath = relative11(cwd2, filePath);
457603
457944
  if (relativePath.startsWith("..")) {
457604
457945
  return filePath;
457605
457946
  }
@@ -458753,7 +459094,7 @@ var init_post_turn_reflection = __esm(() => {
458753
459094
  });
458754
459095
 
458755
459096
  // src/websocket/listener/turn-events.ts
458756
- function escapeTaskNotificationSummary2(summary) {
459097
+ function escapeTaskNotificationSummary(summary) {
458757
459098
  return summary.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
458758
459099
  }
458759
459100
  function isTurnInputArray(value) {
@@ -458818,7 +459159,6 @@ function buildMaybeLaunchReflectionSubagent(params) {
458818
459159
  conversationId,
458819
459160
  memfsEnabled: settingsManager.isMemfsEnabled(agentId),
458820
459161
  triggerSource,
458821
- skipPendingWorktreeReminderScan: triggerSource === "compaction-event",
458822
459162
  reflectionSettings,
458823
459163
  description: AUTO_REFLECTION_DESCRIPTION,
458824
459164
  recompileByConversation: runtime.listener.systemPromptRecompileByConversation,
@@ -458827,8 +459167,8 @@ function buildMaybeLaunchReflectionSubagent(params) {
458827
459167
  surface: getListenerTelemetrySurface()
458828
459168
  },
458829
459169
  onCompletionMessage: async (completionMessage, reflectionResult) => {
458830
- const reflectionAgentIdTag = reflectionResult.reflectionAgentId ? `<reflection-agent-id>${escapeTaskNotificationSummary2(reflectionResult.reflectionAgentId)}</reflection-agent-id>` : "";
458831
- const notificationXml = `<task-notification><summary>${escapeTaskNotificationSummary2(completionMessage)}</summary>${reflectionAgentIdTag}</task-notification>`;
459170
+ const reflectionAgentIdTag = reflectionResult.reflectionAgentId ? `<reflection-agent-id>${escapeTaskNotificationSummary(reflectionResult.reflectionAgentId)}</reflection-agent-id>` : "";
459171
+ const notificationXml = `<task-notification><summary>${escapeTaskNotificationSummary(completionMessage)}</summary>${reflectionAgentIdTag}</task-notification>`;
458832
459172
  emitCanonicalMessageDelta(socket, runtime, {
458833
459173
  type: "message",
458834
459174
  id: `user-msg-${crypto.randomUUID()}`,
@@ -458898,10 +459238,6 @@ async function completeSuccessfulListenerTurn(params) {
458898
459238
  reflectionSettings,
458899
459239
  reminderState: params.runtime.reminderState,
458900
459240
  contextTracker: params.runtime.contextTracker,
458901
- onCompaction: () => queuePendingReflectionWorktreeReminders({
458902
- agentId: params.agentId,
458903
- conversationId: params.conversationId
458904
- }),
458905
459241
  launch: buildMaybeLaunchReflectionSubagent({
458906
459242
  runtime: params.runtime,
458907
459243
  socket: params.socket,
@@ -458926,7 +459262,6 @@ var init_turn_completion = __esm(async () => {
458926
459262
  init_conversation_description();
458927
459263
  init_memory_reminder();
458928
459264
  init_post_turn_reflection();
458929
- init_reflection_launcher();
458930
459265
  init_reflection_transcript();
458931
459266
  init_settings_manager();
458932
459267
  init_debug();
@@ -460639,7 +460974,7 @@ var init_turn = __esm(async () => {
460639
460974
  });
460640
460975
 
460641
460976
  // src/websocket/listener/control-inputs.ts
460642
- import { realpath as realpath5, stat as stat13 } from "node:fs/promises";
460977
+ import { realpath as realpath4, stat as stat13 } from "node:fs/promises";
460643
460978
  import path38 from "node:path";
460644
460979
  function trackListenerError2(errorType, error54, context3) {
460645
460980
  trackBoundaryError({
@@ -460900,7 +461235,7 @@ async function handleCwdChange(msg, socket, runtime) {
460900
461235
  throw new Error("Working directory cannot be empty");
460901
461236
  }
460902
461237
  const resolvedPath = path38.isAbsolute(requestedPath) ? requestedPath : path38.resolve(currentWorkingDirectory, requestedPath);
460903
- const normalizedPath = await realpath5(resolvedPath);
461238
+ const normalizedPath = await realpath4(resolvedPath);
460904
461239
  const stats = await stat13(normalizedPath);
460905
461240
  if (!stats.isDirectory()) {
460906
461241
  throw new Error(`Not a directory: ${normalizedPath}`);
@@ -461553,8 +461888,8 @@ function normalizeAbsPath(value) {
461553
461888
  return path40.resolve(value);
461554
461889
  }
461555
461890
  function isWithinOrEqual(parent, child) {
461556
- const relative14 = path40.relative(parent, child);
461557
- return relative14 === "" || !relative14.startsWith("..") && !path40.isAbsolute(relative14);
461891
+ const relative13 = path40.relative(parent, child);
461892
+ return relative13 === "" || !relative13.startsWith("..") && !path40.isAbsolute(relative13);
461558
461893
  }
461559
461894
  function getHomeDirectory() {
461560
461895
  return normalizeAbsPath(process.env.HOME || homedir41());
@@ -461567,10 +461902,10 @@ function getProtectedHomeSegment(absPath) {
461567
461902
  const target2 = normalizeAbsPath(absPath);
461568
461903
  if (!isWithinOrEqual(home, target2))
461569
461904
  return null;
461570
- const relative14 = path40.relative(home, target2);
461571
- if (!relative14)
461905
+ const relative13 = path40.relative(home, target2);
461906
+ if (!relative13)
461572
461907
  return null;
461573
- const [firstSegment] = relative14.split(path40.sep);
461908
+ const [firstSegment] = relative13.split(path40.sep);
461574
461909
  const normalized = firstSegment?.toLowerCase();
461575
461910
  return normalized && PROTECTED_HOME_NAMES.has(normalized) ? normalized : null;
461576
461911
  }
@@ -462684,7 +463019,7 @@ var init_init_command = __esm(() => {
462684
463019
 
462685
463020
  // src/cli/helpers/skill-name-frontmatter-repair.ts
462686
463021
  import { readdir as readdir12, readFile as readFile22, stat as stat14, writeFile as writeFile16 } from "node:fs/promises";
462687
- import { basename as basename27, dirname as dirname30, join as join67, relative as relative14 } from "node:path";
463022
+ import { basename as basename27, dirname as dirname30, join as join67, relative as relative13 } from "node:path";
462688
463023
  async function pathExists(path41) {
462689
463024
  try {
462690
463025
  await stat14(path41);
@@ -462787,7 +463122,7 @@ async function repairMissingSkillNameFrontmatter(memoryDir) {
462787
463122
  return result;
462788
463123
  }
462789
463124
  for (const skillFile of skillFiles.sort()) {
462790
- const displayPath = relative14(memoryDir, skillFile).replace(/\\/g, "/");
463125
+ const displayPath = relative13(memoryDir, skillFile).replace(/\\/g, "/");
462791
463126
  result.scanned++;
462792
463127
  try {
462793
463128
  const content = await readFile22(skillFile, "utf8");
@@ -463373,7 +463708,7 @@ async function handleReflectCommand(socket, conversationRuntime) {
463373
463708
  recompileByConversation: listener.systemPromptRecompileByConversation,
463374
463709
  recompileQueuedByConversation: listener.queuedSystemPromptRecompileByConversation,
463375
463710
  onCompletionMessage: async (completionMessage, reflectionResult) => {
463376
- const reflectionAgentIdTag = reflectionResult.reflectionAgentId ? `<reflection-agent-id>${escapeTaskNotificationSummary2(reflectionResult.reflectionAgentId)}</reflection-agent-id>` : "";
463711
+ const reflectionAgentIdTag = reflectionResult.reflectionAgentId ? `<reflection-agent-id>${escapeTaskNotificationSummary(reflectionResult.reflectionAgentId)}</reflection-agent-id>` : "";
463377
463712
  emitCanonicalMessageDelta(socket, conversationRuntime, {
463378
463713
  type: "message",
463379
463714
  id: `user-msg-${crypto.randomUUID()}`,
@@ -463382,7 +463717,7 @@ async function handleReflectCommand(socket, conversationRuntime) {
463382
463717
  content: [
463383
463718
  {
463384
463719
  type: "text",
463385
- text: `<task-notification><summary>${escapeTaskNotificationSummary2(completionMessage)}</summary>${reflectionAgentIdTag}</task-notification>`
463720
+ text: `<task-notification><summary>${escapeTaskNotificationSummary(completionMessage)}</summary>${reflectionAgentIdTag}</task-notification>`
463386
463721
  }
463387
463722
  ]
463388
463723
  }, { agent_id: agentId, conversation_id: conversationId });
@@ -471135,8 +471470,8 @@ function isRecord13(value) {
471135
471470
  function isPathInsideOrEqual2(childPath, parentPath) {
471136
471471
  const child = path41.resolve(childPath);
471137
471472
  const parent = path41.resolve(parentPath);
471138
- const relative15 = path41.relative(parent, child);
471139
- return relative15 === "" || !!relative15 && !relative15.startsWith("..") && !path41.isAbsolute(relative15);
471473
+ const relative14 = path41.relative(parent, child);
471474
+ return relative14 === "" || !!relative14 && !relative14.startsWith("..") && !path41.isAbsolute(relative14);
471140
471475
  }
471141
471476
  function readPackageJson(packageJsonPath) {
471142
471477
  let parsed;
@@ -472658,7 +472993,22 @@ var init_server = __esm(async () => {
472658
472993
 
472659
472994
  // src/auth/LettaLoginView.tsx
472660
472995
  import { hostname as hostname7 } from "node:os";
472996
+ async function completeLettaLogin(tokens, options3) {
472997
+ const settings3 = options3.settings ?? settingsManager;
472998
+ const now = options3.now?.() ?? Date.now();
472999
+ settings3.updateSettings({
473000
+ env: { LETTA_API_KEY: tokens.access_token },
473001
+ refreshToken: tokens.refresh_token,
473002
+ tokenExpiresAt: now + tokens.expires_in * 1000,
473003
+ preferredBackendMode: "api"
473004
+ });
473005
+ await settings3.flush();
473006
+ if (options3.activateCloudBackend) {
473007
+ configureBackendMode("api");
473008
+ }
473009
+ }
472661
473010
  function LettaLoginView({
473011
+ activateCloudBackend,
472662
473012
  onComplete,
472663
473013
  onCancel,
472664
473014
  successMessage = "Signed in with Letta. Switch agents with /agents."
@@ -472703,15 +473053,7 @@ function LettaLoginView({
472703
473053
  return;
472704
473054
  }
472705
473055
  const tokens = await pollForToken2(deviceData.device_code, deviceData.interval, deviceData.expires_in, deviceId, deviceName, controller.signal);
472706
- const now = Date.now();
472707
- settingsManager.updateSettings({
472708
- env: { LETTA_API_KEY: tokens.access_token },
472709
- refreshToken: tokens.refresh_token,
472710
- tokenExpiresAt: now + tokens.expires_in * 1000,
472711
- preferredBackendMode: "api"
472712
- });
472713
- await settingsManager.flush();
472714
- configureBackendMode("api");
473056
+ await completeLettaLogin(tokens, { activateCloudBackend });
472715
473057
  setDoneMessage(successMessage);
472716
473058
  setTimeout(() => onCompleteRef.current?.(), 500);
472717
473059
  } catch (err) {
@@ -472726,7 +473068,7 @@ function LettaLoginView({
472726
473068
  cancelledRef.current = true;
472727
473069
  abortControllerRef.current?.abort();
472728
473070
  };
472729
- }, [successMessage]);
473071
+ }, [activateCloudBackend, successMessage]);
472730
473072
  if (doneMessage) {
472731
473073
  return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
472732
473074
  flexDirection: "column",
@@ -472926,6 +473268,7 @@ function SetupUI({
472926
473268
  children: " "
472927
473269
  }, undefined, false, undefined, this),
472928
473270
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(LettaLoginView, {
473271
+ activateCloudBackend: true,
472929
473272
  onComplete: () => onComplete({ kind: "cloud-login" }),
472930
473273
  onCancel: () => setMode("menu"),
472931
473274
  successMessage: "Signed in with Letta. Starting Letta Code..."
@@ -473094,6 +473437,252 @@ var init_setup7 = __esm(async () => {
473094
473437
  await init_setup6();
473095
473438
  });
473096
473439
 
473440
+ // src/cli/subcommands/shared-memory.ts
473441
+ import { existsSync as existsSync57 } from "node:fs";
473442
+ import { join as join72 } from "node:path";
473443
+ import { parseArgs as parseArgs14 } from "node:util";
473444
+ function printUsage12() {
473445
+ console.log(`
473446
+ Usage:
473447
+ letta shared-memory list [--agent <id>]
473448
+ letta shared-memory create --name <name>
473449
+ letta shared-memory attach <name-or-id> [--agent <id>]
473450
+ letta shared-memory detach <name-or-id> [--agent <id>]
473451
+ letta shared-memory sync [--agent <id>]
473452
+ letta shared-memory history <name-or-id> [--path <file>] [--limit <n>]
473453
+
473454
+ Actions:
473455
+ list List org repositories, marking which are attached to the agent
473456
+ create Create a new shared memory repository
473457
+ attach Attach a repository to the agent, clone its local mount, and
473458
+ recompile the agent's system prompt
473459
+ detach Detach a repository from the agent and recompile
473460
+ sync Clone/pull local mounts for every repository attached to the agent
473461
+ history List commits for a repository (optionally scoped to one path)
473462
+
473463
+ Notes:
473464
+ - Output is JSON only.
473465
+ - Agent id comes from --agent or AGENT_ID/LETTA_AGENT_ID in the env.
473466
+ - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
473467
+ - Attached repositories mount at $MEMORY_DIR/../<name> as normal git
473468
+ checkouts. Edit files and commit/push there like MemFS — no API calls
473469
+ are needed for file content.
473470
+
473471
+ Examples:
473472
+ letta shared-memory list
473473
+ letta shared-memory create --name shared-notes
473474
+ letta shared-memory attach shared-notes
473475
+ letta shared-memory history shared-notes --path docs/plan.md
473476
+ `.trim());
473477
+ }
473478
+ function parseSharedMemoryArgs(argv) {
473479
+ return parseArgs14({
473480
+ args: argv,
473481
+ options: SHARED_MEMORY_OPTIONS,
473482
+ strict: true,
473483
+ allowPositionals: true
473484
+ });
473485
+ }
473486
+ function resolveSharedMemoryAgentId(agent2, agentId, env5 = process.env) {
473487
+ return (agent2 || agentId || env5.LETTA_AGENT_ID || env5.AGENT_ID || "").trim();
473488
+ }
473489
+ function parseLimit4(value, fallback) {
473490
+ if (typeof value !== "string" || value.length === 0)
473491
+ return fallback;
473492
+ const parsed = Number.parseInt(value, 10);
473493
+ return Number.isNaN(parsed) || parsed <= 0 ? fallback : parsed;
473494
+ }
473495
+ async function listOrgRepositories(request) {
473496
+ const repositories = [];
473497
+ const limit3 = 50;
473498
+ let offset = 0;
473499
+ for (;; ) {
473500
+ const page = await request("GET", `/v1/repositories?limit=${limit3}&offset=${offset}`);
473501
+ repositories.push(...page.repositories);
473502
+ if (!page.has_next_page)
473503
+ break;
473504
+ offset += limit3;
473505
+ }
473506
+ return repositories;
473507
+ }
473508
+ async function listAgentRepositories(request, agentId) {
473509
+ const response = await request("GET", `/v1/agents/${encodeURIComponent(agentId)}/repositories`);
473510
+ return response.repositories.filter((repository) => !repository.is_primary && repository.name !== "memory");
473511
+ }
473512
+ function resolveRepositoryReference(repositories, reference) {
473513
+ const trimmed = reference.trim();
473514
+ if (!trimmed)
473515
+ return null;
473516
+ return repositories.find((repository) => repository.id === trimmed) ?? repositories.find((repository) => repository.name === trimmed) ?? null;
473517
+ }
473518
+ async function waitForAttachedRepository(request, agentId, repositoryId, poll) {
473519
+ for (let attempt = 0;attempt < poll.attempts; attempt += 1) {
473520
+ const attached = await listAgentRepositories(request, agentId);
473521
+ if (attached.some((repository) => repository.id === repositoryId)) {
473522
+ return true;
473523
+ }
473524
+ await new Promise((resolvePoll) => setTimeout(resolvePoll, poll.intervalMs));
473525
+ }
473526
+ return false;
473527
+ }
473528
+ async function defaultRecompileAgent(agentId) {
473529
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
473530
+ const client = await getClient2();
473531
+ await client.agents.recompile(agentId, { update_timestamp: false });
473532
+ }
473533
+ async function recompileAndReportFailure(recompileAgent, agentId) {
473534
+ try {
473535
+ await recompileAgent(agentId);
473536
+ return null;
473537
+ } catch (error54) {
473538
+ return error54 instanceof Error ? error54.message : String(error54);
473539
+ }
473540
+ }
473541
+ function requireAgentId(parsed) {
473542
+ const agentId = resolveSharedMemoryAgentId(parsed.values.agent, parsed.values["agent-id"]);
473543
+ if (!agentId) {
473544
+ console.error("Agent id required: pass --agent <id> or set AGENT_ID/LETTA_AGENT_ID.");
473545
+ return null;
473546
+ }
473547
+ return agentId;
473548
+ }
473549
+ async function runSharedMemorySubcommand(argv, deps = {}) {
473550
+ let parsed;
473551
+ try {
473552
+ parsed = parseSharedMemoryArgs(argv);
473553
+ } catch (error54) {
473554
+ console.error(error54 instanceof Error ? error54.message : String(error54));
473555
+ printUsage12();
473556
+ return 1;
473557
+ }
473558
+ const [action3, reference] = parsed.positionals;
473559
+ if (parsed.values.help || !action3 || action3 === "help") {
473560
+ printUsage12();
473561
+ return 0;
473562
+ }
473563
+ if (isLocalBackendEnvEnabled()) {
473564
+ console.error("Shared memory requires a Letta Cloud agent; the local backend does not support it.");
473565
+ return 1;
473566
+ }
473567
+ await (deps.initializeSettings ?? (() => settingsManager.initialize()))();
473568
+ const request = deps.request ?? apiRequest;
473569
+ const syncRepositories = deps.syncRepositories ?? syncAttachedAgentRepositories;
473570
+ const recompileAgent = deps.recompileAgent ?? defaultRecompileAgent;
473571
+ try {
473572
+ if (action3 === "list") {
473573
+ const agentId = resolveSharedMemoryAgentId(parsed.values.agent, parsed.values["agent-id"]);
473574
+ const repositories = await listOrgRepositories(request);
473575
+ let attachedIds = new Set;
473576
+ if (agentId && !isLocalAgentId(agentId)) {
473577
+ const attached = await listAgentRepositories(request, agentId);
473578
+ attachedIds = new Set(attached.map((repository) => repository.id));
473579
+ }
473580
+ console.log(JSON.stringify({
473581
+ repositories: repositories.map((repository) => ({
473582
+ ...repository,
473583
+ ...agentId ? { attached: attachedIds.has(repository.id) } : {}
473584
+ }))
473585
+ }, null, 2));
473586
+ return 0;
473587
+ }
473588
+ if (action3 === "create") {
473589
+ const name = parsed.values.name?.trim();
473590
+ if (!name) {
473591
+ console.error("Usage: letta shared-memory create --name <name>");
473592
+ return 1;
473593
+ }
473594
+ const repository = await request("POST", "/v1/repositories", { name });
473595
+ console.log(JSON.stringify(repository, null, 2));
473596
+ return 0;
473597
+ }
473598
+ if (action3 === "attach" || action3 === "detach" || action3 === "history") {
473599
+ if (!reference) {
473600
+ console.error(`Usage: letta shared-memory ${action3} <name-or-id>`);
473601
+ return 1;
473602
+ }
473603
+ const repositories = await listOrgRepositories(request);
473604
+ const repository = resolveRepositoryReference(repositories, reference);
473605
+ if (!repository) {
473606
+ console.error(`Repository not found: ${reference}. Run \`letta shared-memory list\` to see available repositories.`);
473607
+ return 1;
473608
+ }
473609
+ if (action3 === "history") {
473610
+ const limit3 = parseLimit4(parsed.values.limit, 20);
473611
+ const query2 = new URLSearchParams({ limit: String(limit3) });
473612
+ if (parsed.values.path) {
473613
+ query2.set("path", parsed.values.path);
473614
+ }
473615
+ const versions2 = await request("GET", `/v1/repositories/${encodeURIComponent(repository.id)}/versions?${query2}`);
473616
+ console.log(JSON.stringify({ repository: repository.name, ...versions2 }, null, 2));
473617
+ return 0;
473618
+ }
473619
+ const agentId = requireAgentId(parsed);
473620
+ if (!agentId)
473621
+ return 1;
473622
+ if (action3 === "attach") {
473623
+ await request("POST", `/v1/agents/${encodeURIComponent(agentId)}/repositories`, { repository_id: repository.id });
473624
+ const visible = await waitForAttachedRepository(request, agentId, repository.id, deps.attachPoll ?? DEFAULT_ATTACH_POLL);
473625
+ if (!visible) {
473626
+ console.error(`Attach accepted but ${repository.name} did not appear in the agent's repository list. Retry \`letta shared-memory sync\` shortly.`);
473627
+ return 1;
473628
+ }
473629
+ const sync2 = await syncRepositories(agentId);
473630
+ const recompileError = await recompileAndReportFailure(recompileAgent, agentId);
473631
+ const mountDir = getRepositoryMountDir(agentId, repository.name);
473632
+ const mounted = existsSync57(join72(mountDir, ".git"));
473633
+ console.log(JSON.stringify({
473634
+ attached: true,
473635
+ repository: { id: repository.id, name: repository.name },
473636
+ mount: mounted ? mountDir : null,
473637
+ sync: sync2.summaries,
473638
+ ...recompileError ? { recompile_failed: recompileError } : {},
473639
+ note: mounted ? "Edit files under the mount and commit/push with git, like MemFS." : "The repository is attached but its local mount was not created — see `sync` above. Resolve the reported error, then re-run `letta shared-memory sync`."
473640
+ }, null, 2));
473641
+ return mounted ? 0 : 1;
473642
+ }
473643
+ await request("DELETE", `/v1/agents/${encodeURIComponent(agentId)}/repositories/${encodeURIComponent(repository.id)}`);
473644
+ const detachRecompileError = await recompileAndReportFailure(recompileAgent, agentId);
473645
+ console.log(JSON.stringify({
473646
+ detached: true,
473647
+ repository: { id: repository.id, name: repository.name },
473648
+ ...detachRecompileError ? { recompile_failed: detachRecompileError } : {},
473649
+ note: "The local mount was left in place; delete it manually if no longer needed."
473650
+ }, null, 2));
473651
+ return 0;
473652
+ }
473653
+ if (action3 === "sync") {
473654
+ const agentId = requireAgentId(parsed);
473655
+ if (!agentId)
473656
+ return 1;
473657
+ const result = await syncRepositories(agentId);
473658
+ console.log(JSON.stringify(result, null, 2));
473659
+ return result.failed > 0 ? 1 : 0;
473660
+ }
473661
+ console.error(`Unknown action: ${action3}`);
473662
+ printUsage12();
473663
+ return 1;
473664
+ } catch (error54) {
473665
+ console.error(error54 instanceof Error ? error54.message : String(error54));
473666
+ return 1;
473667
+ }
473668
+ }
473669
+ var SHARED_MEMORY_OPTIONS, DEFAULT_ATTACH_POLL;
473670
+ var init_shared_memory = __esm(() => {
473671
+ init_memory_git();
473672
+ init_request();
473673
+ init_paths();
473674
+ init_settings_manager();
473675
+ SHARED_MEMORY_OPTIONS = {
473676
+ help: { type: "boolean", short: "h" },
473677
+ agent: { type: "string" },
473678
+ "agent-id": { type: "string" },
473679
+ name: { type: "string" },
473680
+ path: { type: "string" },
473681
+ limit: { type: "string" }
473682
+ };
473683
+ DEFAULT_ATTACH_POLL = { intervalMs: 1000, attempts: 15 };
473684
+ });
473685
+
473097
473686
  // src/cli/components/AgentSelectorFooter.tsx
473098
473687
  function buildCloudPageText(params) {
473099
473688
  return `Page ${params.cloudPage + 1}${params.cloudHasMore ? "+" : `/${params.cloudTotalPages || 1}`}${params.cloudLoadingMore ? " (loading...)" : ""}`;
@@ -474567,7 +475156,7 @@ var init_AgentSelector = __esm(async () => {
474567
475156
  // src/cli/subcommands/skills.ts
474568
475157
  import {
474569
475158
  cpSync as cpSync2,
474570
- existsSync as existsSync57,
475159
+ existsSync as existsSync58,
474571
475160
  mkdtempSync as mkdtempSync4,
474572
475161
  readFileSync as readFileSync38,
474573
475162
  rmSync as rmSync14,
@@ -474576,9 +475165,9 @@ import {
474576
475165
  } from "node:fs";
474577
475166
  import { mkdir as mkdir15, readdir as readdir14 } from "node:fs/promises";
474578
475167
  import { tmpdir as tmpdir10 } from "node:os";
474579
- import { basename as basename28, dirname as dirname33, join as join72, normalize as normalize5, resolve as resolve33, sep as sep7 } from "node:path";
474580
- import { parseArgs as parseArgs14, TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
474581
- function printUsage12() {
475168
+ import { basename as basename28, dirname as dirname33, join as join73, normalize as normalize5, resolve as resolve33, sep as sep7 } from "node:path";
475169
+ import { parseArgs as parseArgs15, TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
475170
+ function printUsage13() {
474582
475171
  console.log(`
474583
475172
  Usage:
474584
475173
  letta install <thing> [--agent <id> | -n <agent name>] [--force]
@@ -474605,7 +475194,7 @@ Options:
474605
475194
  `.trim());
474606
475195
  }
474607
475196
  function parseSkillsArgs(argv) {
474608
- return parseArgs14({
475197
+ return parseArgs15({
474609
475198
  args: argv,
474610
475199
  options: SKILLS_OPTIONS,
474611
475200
  strict: true,
@@ -474868,14 +475457,14 @@ async function resolveBranchAndSubdir(location) {
474868
475457
  }
474869
475458
  async function cloneSkillSource(location) {
474870
475459
  const resolvedLocation = await resolveBranchAndSubdir(location);
474871
- const tmpDir = mkdtempSync4(join72(tmpdir10(), "letta-skill-install-"));
475460
+ const tmpDir = mkdtempSync4(join73(tmpdir10(), "letta-skill-install-"));
474872
475461
  const args = ["clone", "--depth", "1"];
474873
475462
  if (resolvedLocation.branch) {
474874
475463
  args.push("--branch", resolvedLocation.branch);
474875
475464
  }
474876
475465
  args.push(resolvedLocation.repoUrl, tmpDir);
474877
475466
  await execFile16("git", args, { timeout: 120000 });
474878
- const sourceDir = resolvedLocation.subdir ? join72(tmpDir, resolvedLocation.subdir) : tmpDir;
475467
+ const sourceDir = resolvedLocation.subdir ? join73(tmpDir, resolvedLocation.subdir) : tmpDir;
474879
475468
  return { tmpDir, sourceDir };
474880
475469
  }
474881
475470
  function assertDirectSkillFileSize(receivedBytes, maxBytes) {
@@ -474930,11 +475519,11 @@ async function downloadDirectSkillFileSource(location, options3 = {}) {
474930
475519
  throw new Error(`Direct skill file download failed for ${location.url}: ${response.status}`);
474931
475520
  }
474932
475521
  const skillText = await readResponseTextWithLimit(response, MAX_DIRECT_SKILL_FILE_BYTES);
474933
- const tmpDir = mkdtempSync4(join72(tmpdir10(), "letta-direct-skill-"));
475522
+ const tmpDir = mkdtempSync4(join73(tmpdir10(), "letta-direct-skill-"));
474934
475523
  try {
474935
- const sourceDir = join72(tmpDir, "skill");
475524
+ const sourceDir = join73(tmpDir, "skill");
474936
475525
  await mkdir15(sourceDir, { recursive: true });
474937
- writeFileSync30(join72(sourceDir, "SKILL.md"), skillText, "utf8");
475526
+ writeFileSync30(join73(sourceDir, "SKILL.md"), skillText, "utf8");
474938
475527
  return { tmpDir, sourceDir };
474939
475528
  } catch (error54) {
474940
475529
  rmSync14(tmpDir, { recursive: true, force: true });
@@ -474975,9 +475564,9 @@ function assertSafeZipMember(name) {
474975
475564
  }
474976
475565
  async function downloadClawHubSkillSource(location) {
474977
475566
  const version2 = await resolveClawHubVersion(location);
474978
- const tmpDir = mkdtempSync4(join72(tmpdir10(), "letta-clawhub-skill-"));
474979
- const zipPath = join72(tmpDir, "skill.zip");
474980
- const sourceDir = join72(tmpDir, "skill");
475567
+ const tmpDir = mkdtempSync4(join73(tmpdir10(), "letta-clawhub-skill-"));
475568
+ const zipPath = join73(tmpDir, "skill.zip");
475569
+ const sourceDir = join73(tmpDir, "skill");
474981
475570
  await mkdir15(sourceDir, { recursive: true });
474982
475571
  const url2 = new URL(`${CLAWHUB_API_BASE_URL}/download`);
474983
475572
  url2.searchParams.set("slug", location.slug);
@@ -475016,7 +475605,7 @@ function sanitizeSkillName(name) {
475016
475605
  return trimmed;
475017
475606
  }
475018
475607
  function getSkillName(sourceDir) {
475019
- const skillMd = readFileSync38(join72(sourceDir, "SKILL.md"), "utf8");
475608
+ const skillMd = readFileSync38(join73(sourceDir, "SKILL.md"), "utf8");
475020
475609
  const { frontmatter } = parseFrontmatter(skillMd);
475021
475610
  const frontmatterName = frontmatter.name;
475022
475611
  const name = typeof frontmatterName === "string" && frontmatterName.trim() ? frontmatterName : basename28(sourceDir);
@@ -475025,18 +475614,18 @@ function getSkillName(sourceDir) {
475025
475614
  async function installSkillDirectory(params) {
475026
475615
  const sourceDir = resolve33(params.sourceDir);
475027
475616
  const memoryDir = resolve33(params.memoryDir);
475028
- const skillMdPath = join72(sourceDir, "SKILL.md");
475029
- if (!existsSync57(skillMdPath)) {
475617
+ const skillMdPath = join73(sourceDir, "SKILL.md");
475618
+ if (!existsSync58(skillMdPath)) {
475030
475619
  throw new Error("No SKILL.md found in the skill directory.");
475031
475620
  }
475032
475621
  if (!statSync20(sourceDir).isDirectory()) {
475033
475622
  throw new Error(`Skill source is not a directory: ${sourceDir}`);
475034
475623
  }
475035
475624
  const name = getSkillName(sourceDir);
475036
- const skillsDir = join72(memoryDir, "skills");
475037
- const targetPath = join72(skillsDir, name);
475625
+ const skillsDir = join73(memoryDir, "skills");
475626
+ const targetPath = join73(skillsDir, name);
475038
475627
  assertInside(skillsDir, targetPath);
475039
- if (existsSync57(targetPath)) {
475628
+ if (existsSync58(targetPath)) {
475040
475629
  if (!params.force) {
475041
475630
  throw new Error(`Skill "${name}" already exists at ${targetPath}. Re-run with --force to replace it.`);
475042
475631
  }
@@ -475051,17 +475640,17 @@ async function installSkillDirectory(params) {
475051
475640
  }
475052
475641
  async function listSkillDirectories(params) {
475053
475642
  const memoryDir = resolve33(params.memoryDir);
475054
- const skillsDir = join72(memoryDir, "skills");
475055
- if (!existsSync57(skillsDir))
475643
+ const skillsDir = join73(memoryDir, "skills");
475644
+ if (!existsSync58(skillsDir))
475056
475645
  return [];
475057
475646
  const entries = await readdir14(skillsDir, { withFileTypes: true });
475058
475647
  const skills = [];
475059
475648
  for (const entry of entries) {
475060
475649
  if (!entry.isDirectory())
475061
475650
  continue;
475062
- const skillDir = join72(skillsDir, entry.name);
475063
- const skillMdPath = join72(skillDir, "SKILL.md");
475064
- if (!existsSync57(skillMdPath))
475651
+ const skillDir = join73(skillsDir, entry.name);
475652
+ const skillMdPath = join73(skillDir, "SKILL.md");
475653
+ if (!existsSync58(skillMdPath))
475065
475654
  continue;
475066
475655
  let name = entry.name;
475067
475656
  let description;
@@ -475081,11 +475670,11 @@ async function listSkillDirectories(params) {
475081
475670
  }
475082
475671
  async function deleteSkillDirectory(params) {
475083
475672
  const memoryDir = resolve33(params.memoryDir);
475084
- const skillsDir = join72(memoryDir, "skills");
475673
+ const skillsDir = join73(memoryDir, "skills");
475085
475674
  const name = sanitizeSkillName(params.name);
475086
- const targetPath = join72(skillsDir, name);
475675
+ const targetPath = join73(skillsDir, name);
475087
475676
  assertInside(skillsDir, targetPath);
475088
- if (!existsSync57(targetPath)) {
475677
+ if (!existsSync58(targetPath)) {
475089
475678
  throw new Error(`Skill "${name}" is not installed at ${targetPath}.`);
475090
475679
  }
475091
475680
  if (!statSync20(targetPath).isDirectory()) {
@@ -475134,7 +475723,7 @@ async function installSkill(specifier, agentId, force) {
475134
475723
  tmpDir = downloaded.tmpDir;
475135
475724
  const sourceDir = resolve33(downloaded.sourceDir);
475136
475725
  assertInside(tmpDir, sourceDir);
475137
- if (!existsSync57(sourceDir)) {
475726
+ if (!existsSync58(sourceDir)) {
475138
475727
  const missingPath = source2.type === "git" ? source2.location.subdir ?? "." : source2.type === "direct-file" ? source2.location.url : source2.location.slug;
475139
475728
  throw new Error(`Skill path not found: ${missingPath}`);
475140
475729
  }
@@ -475253,17 +475842,17 @@ async function runInstall(argv, options3 = {}) {
475253
475842
  parsed = parseSkillsArgs(argv);
475254
475843
  } catch (error54) {
475255
475844
  console.error(`Error: ${error54 instanceof Error ? error54.message : String(error54)}`);
475256
- printUsage12();
475845
+ printUsage13();
475257
475846
  return 1;
475258
475847
  }
475259
475848
  const [specifier] = parsed.positionals;
475260
475849
  if (parsed.values.help || !specifier || specifier === "help") {
475261
- printUsage12();
475850
+ printUsage13();
475262
475851
  return 0;
475263
475852
  }
475264
475853
  if (parsed.positionals.length > 1) {
475265
475854
  console.error(`Unexpected argument: ${parsed.positionals[1]}`);
475266
- printUsage12();
475855
+ printUsage13();
475267
475856
  return 1;
475268
475857
  }
475269
475858
  if (specifier.startsWith("npm:")) {
@@ -475354,16 +475943,16 @@ async function runList2(argv) {
475354
475943
  parsed = parseSkillsArgs(argv);
475355
475944
  } catch (error54) {
475356
475945
  console.error(`Error: ${error54 instanceof Error ? error54.message : String(error54)}`);
475357
- printUsage12();
475946
+ printUsage13();
475358
475947
  return 1;
475359
475948
  }
475360
475949
  if (parsed.values.help) {
475361
- printUsage12();
475950
+ printUsage13();
475362
475951
  return 0;
475363
475952
  }
475364
475953
  if (parsed.positionals.length > 0) {
475365
475954
  console.error(`Unexpected argument: ${parsed.positionals[0]}`);
475366
- printUsage12();
475955
+ printUsage13();
475367
475956
  return 1;
475368
475957
  }
475369
475958
  try {
@@ -475384,17 +475973,17 @@ async function runDelete(argv) {
475384
475973
  parsed = parseSkillsArgs(argv);
475385
475974
  } catch (error54) {
475386
475975
  console.error(`Error: ${error54 instanceof Error ? error54.message : String(error54)}`);
475387
- printUsage12();
475976
+ printUsage13();
475388
475977
  return 1;
475389
475978
  }
475390
475979
  const [skillName] = parsed.positionals;
475391
475980
  if (parsed.values.help || !skillName || skillName === "help") {
475392
- printUsage12();
475981
+ printUsage13();
475393
475982
  return 0;
475394
475983
  }
475395
475984
  if (parsed.positionals.length > 1) {
475396
475985
  console.error(`Unexpected argument: ${parsed.positionals[1]}`);
475397
- printUsage12();
475986
+ printUsage13();
475398
475987
  return 1;
475399
475988
  }
475400
475989
  const agentId = getExplicitAgentId2(parsed.values);
@@ -475434,11 +476023,11 @@ async function runSkillsSubcommand(argv) {
475434
476023
  case "help":
475435
476024
  case "--help":
475436
476025
  case "-h":
475437
- printUsage12();
476026
+ printUsage13();
475438
476027
  return 0;
475439
476028
  default:
475440
476029
  console.error(`Unknown action: ${action3}`);
475441
- printUsage12();
476030
+ printUsage13();
475442
476031
  return 1;
475443
476032
  }
475444
476033
  }
@@ -475458,7 +476047,7 @@ var init_skills4 = __esm(() => {
475458
476047
 
475459
476048
  // src/cli/subcommands/trajectories/readers.ts
475460
476049
  import { readdir as readdir15, readFile as readFile24, stat as stat15 } from "node:fs/promises";
475461
- import { join as join73 } from "node:path";
476050
+ import { join as join74 } from "node:path";
475462
476051
  async function loadSessionTranscript(item) {
475463
476052
  const stats = await stat15(item.path);
475464
476053
  if (stats.isDirectory()) {
@@ -475470,13 +476059,13 @@ async function loadSessionTranscript(item) {
475470
476059
  return readFile24(item.path, "utf-8");
475471
476060
  }
475472
476061
  async function assembleEventDirectory(sessionDir) {
475473
- const eventsSubdir = join73(sessionDir, "events");
476062
+ const eventsSubdir = join74(sessionDir, "events");
475474
476063
  const eventsDir = (await stat15(eventsSubdir).catch(() => null))?.isDirectory() ? eventsSubdir : sessionDir;
475475
476064
  const names = (await readdir15(eventsDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a2, b3) => Number.parseInt(a2, 10) - Number.parseInt(b3, 10) || a2.localeCompare(b3));
475476
476065
  if (names.length === 0) {
475477
476066
  throw new Error(`No event files found in ${eventsDir}`);
475478
476067
  }
475479
- const events = await Promise.all(names.map(async (name) => JSON.parse(await readFile24(join73(eventsDir, name), "utf-8"))));
476068
+ const events = await Promise.all(names.map(async (name) => JSON.parse(await readFile24(join74(eventsDir, name), "utf-8"))));
475480
476069
  return JSON.stringify(events);
475481
476070
  }
475482
476071
  async function openReadOnlyDatabase(path43) {
@@ -475554,7 +476143,7 @@ import {
475554
476143
  stat as stat16,
475555
476144
  writeFile as writeFile18
475556
476145
  } from "node:fs/promises";
475557
- import { basename as basename29, join as join74 } from "node:path";
476146
+ import { basename as basename29, join as join75 } from "node:path";
475558
476147
  function fileTimestamp(startedAt) {
475559
476148
  if (!startedAt)
475560
476149
  return "unknown-date";
@@ -475624,7 +476213,7 @@ async function prepareOutDir(outDir) {
475624
476213
  throw new Error(`--out ${outDir} is not empty and has no ${MANIFEST_NAME}; refusing to overwrite a directory this tool did not create`);
475625
476214
  }
475626
476215
  for (const entry of entries) {
475627
- await rm10(join74(outDir, entry), { recursive: true, force: true });
476216
+ await rm10(join75(outDir, entry), { recursive: true, force: true });
475628
476217
  }
475629
476218
  } catch (error54) {
475630
476219
  if (error54.code !== "ENOENT")
@@ -475667,14 +476256,14 @@ async function runTrajectoryExport(options3) {
475667
476256
  }
475668
476257
  const sessionId = sessionHash(source2, id2);
475669
476258
  const base3 = `${fileTimestamp(stats.startedAt)}_${sessionId}`;
475670
- let file3 = join74(source2, `${base3}.json`);
476259
+ let file3 = join75(source2, `${base3}.json`);
475671
476260
  for (let suffix = 2;usedFiles.has(file3); suffix += 1) {
475672
- file3 = join74(source2, `${base3}-${suffix}.json`);
476261
+ file3 = join75(source2, `${base3}-${suffix}.json`);
475673
476262
  }
475674
476263
  usedFiles.add(file3);
475675
476264
  const body3 = JSON.stringify(records);
475676
- await mkdir16(join74(options3.outDir, source2), { recursive: true });
475677
- await writeFile18(join74(options3.outDir, file3), body3, "utf-8");
476265
+ await mkdir16(join75(options3.outDir, source2), { recursive: true });
476266
+ await writeFile18(join75(options3.outDir, file3), body3, "utf-8");
475678
476267
  counts.exported += 1;
475679
476268
  manifest2.sessions.push({
475680
476269
  source: source2,
@@ -475728,7 +476317,7 @@ async function runTrajectoryExport(options3) {
475728
476317
  await exportCheckpoint(checkpoint2, `${basename29(checkpoint2.path)}-${checkpoint2.threadId}`);
475729
476318
  }
475730
476319
  manifest2.sessions.sort((a2, b3) => (a2.startedAt ?? "").localeCompare(b3.startedAt ?? ""));
475731
- await writeFile18(join74(options3.outDir, MANIFEST_NAME), JSON.stringify(manifest2, null, 2), "utf-8");
476320
+ await writeFile18(join75(options3.outDir, MANIFEST_NAME), JSON.stringify(manifest2, null, 2), "utf-8");
475732
476321
  return manifest2;
475733
476322
  }
475734
476323
  var MANIFEST_NAME = "manifest.json", FIRST_PROMPT_MAX_CHARS = 200, LIST_PAGE_LIMIT = 1000;
@@ -475740,13 +476329,13 @@ var init_export = __esm(() => {
475740
476329
 
475741
476330
  // src/cli/subcommands/trajectories/review.ts
475742
476331
  import { readFile as readFile26 } from "node:fs/promises";
475743
- import { isAbsolute as isAbsolute27, join as join75 } from "node:path";
476332
+ import { isAbsolute as isAbsolute27, join as join76 } from "node:path";
475744
476333
  async function readManifest(dir) {
475745
476334
  let raw2;
475746
476335
  try {
475747
- raw2 = await readFile26(join75(dir, "manifest.json"), "utf-8");
476336
+ raw2 = await readFile26(join76(dir, "manifest.json"), "utf-8");
475748
476337
  } catch {
475749
- throw new Error(`No manifest at ${join75(dir, "manifest.json")}. Run: letta trajectories export --out ${dir}`);
476338
+ throw new Error(`No manifest at ${join76(dir, "manifest.json")}. Run: letta trajectories export --out ${dir}`);
475750
476339
  }
475751
476340
  return JSON.parse(raw2);
475752
476341
  }
@@ -475755,7 +476344,7 @@ function filterSessions(sessions, filter3) {
475755
476344
  }
475756
476345
  async function resolveSessionFile(dir, target2) {
475757
476346
  if (target2.endsWith(".json")) {
475758
- const direct = isAbsolute27(target2) ? target2 : join75(dir, target2);
476347
+ const direct = isAbsolute27(target2) ? target2 : join76(dir, target2);
475759
476348
  try {
475760
476349
  await readFile26(direct, "utf-8");
475761
476350
  return direct;
@@ -475766,7 +476355,7 @@ async function resolveSessionFile(dir, target2) {
475766
476355
  if (!entry) {
475767
476356
  throw new Error(`No session "${target2}" in ${dir} (pass a file path, a manifest-relative file, or a sessionId)`);
475768
476357
  }
475769
- return join75(dir, entry.file);
476358
+ return join76(dir, entry.file);
475770
476359
  }
475771
476360
  function stamp(timestamp) {
475772
476361
  return (timestamp ?? "").slice(0, 19);
@@ -475809,7 +476398,7 @@ async function searchSessions(dir, keyword, options3 = {}) {
475809
476398
  for (const session of filterSessions(manifest2.sessions, options3)) {
475810
476399
  let records;
475811
476400
  try {
475812
- records = JSON.parse(await readFile26(join75(dir, session.file), "utf-8"));
476401
+ records = JSON.parse(await readFile26(join76(dir, session.file), "utf-8"));
475813
476402
  } catch {
475814
476403
  continue;
475815
476404
  }
@@ -475841,8 +476430,8 @@ var init_review = () => {};
475841
476430
 
475842
476431
  // src/cli/subcommands/trajectories.ts
475843
476432
  import { readFile as readFile27 } from "node:fs/promises";
475844
- import { parseArgs as parseArgs15 } from "node:util";
475845
- function printUsage13() {
476433
+ import { parseArgs as parseArgs16 } from "node:util";
476434
+ function printUsage14() {
475846
476435
  console.log(`
475847
476436
  Usage:
475848
476437
  letta trajectories export [options]
@@ -475980,7 +476569,7 @@ ${results.length} session(s) matched "${keyword}"`);
475980
476569
  return 0;
475981
476570
  }
475982
476571
  function parseTrajectoriesArgs(argv) {
475983
- return parseArgs15({
476572
+ return parseArgs16({
475984
476573
  args: argv,
475985
476574
  options: TRAJECTORIES_OPTIONS,
475986
476575
  strict: true,
@@ -475993,12 +476582,12 @@ async function runTrajectoriesSubcommand(argv) {
475993
476582
  parsed = parseTrajectoriesArgs(argv);
475994
476583
  } catch (error54) {
475995
476584
  console.error(`Error: ${error54 instanceof Error ? error54.message : String(error54)}`);
475996
- printUsage13();
476585
+ printUsage14();
475997
476586
  return 1;
475998
476587
  }
475999
476588
  const [action3] = parsed.positionals;
476000
476589
  if (parsed.values.help || action3 === "help" || !action3) {
476001
- printUsage13();
476590
+ printUsage14();
476002
476591
  return parsed.values.help || action3 === "help" ? 0 : 1;
476003
476592
  }
476004
476593
  const asJson = Boolean(parsed.values.json);
@@ -476030,7 +476619,7 @@ async function runTrajectoriesSubcommand(argv) {
476030
476619
  }
476031
476620
  if (action3 !== "export") {
476032
476621
  console.error(`Unknown command: ${action3}`);
476033
- printUsage13();
476622
+ printUsage14();
476034
476623
  return 1;
476035
476624
  }
476036
476625
  const options3 = {
@@ -477763,7 +478352,7 @@ var init_gateway_core = __esm(() => {
477763
478352
  });
477764
478353
 
477765
478354
  // src/channels/custom/scaffolding.ts
477766
- import { existsSync as existsSync58, mkdirSync as mkdirSync42, rmSync as rmSync15, writeFileSync as writeFileSync31 } from "node:fs";
478355
+ import { existsSync as existsSync59, mkdirSync as mkdirSync42, rmSync as rmSync15, writeFileSync as writeFileSync31 } from "node:fs";
477767
478356
  function removeUserPlugin(channelId) {
477768
478357
  if (FIRST_PARTY_SET.has(channelId)) {
477769
478358
  return;
@@ -477772,7 +478361,7 @@ function removeUserPlugin(channelId) {
477772
478361
  return;
477773
478362
  }
477774
478363
  const channelDir = getChannelDir(channelId);
477775
- if (!existsSync58(channelDir)) {
478364
+ if (!existsSync59(channelDir)) {
477776
478365
  return;
477777
478366
  }
477778
478367
  try {
@@ -479037,14 +479626,14 @@ var exports_channel_gateway = {};
479037
479626
  __export(exports_channel_gateway, {
479038
479627
  runChannelGatewaySubcommand: () => runChannelGatewaySubcommand
479039
479628
  });
479040
- import { parseArgs as parseArgs16 } from "node:util";
479629
+ import { parseArgs as parseArgs17 } from "node:util";
479041
479630
  function isGatewayCommandEnvelope(value) {
479042
479631
  return Boolean(value && typeof value === "object" && "type" in value && value.type === "command" && "requestId" in value && typeof value.requestId === "string" && "command" in value && value.command && typeof value.command === "object");
479043
479632
  }
479044
479633
  async function runChannelGatewaySubcommand(argv) {
479045
479634
  let values2;
479046
479635
  try {
479047
- ({ values: values2 } = parseArgs16({
479636
+ ({ values: values2 } = parseArgs17({
479048
479637
  args: argv,
479049
479638
  strict: true,
479050
479639
  allowPositionals: false,
@@ -479181,6 +479770,7 @@ function subcommandNeedsEarlyBackendMode(command) {
479181
479770
  case "mods":
479182
479771
  case "remote":
479183
479772
  case "server":
479773
+ case "shared-memory":
479184
479774
  case "skills":
479185
479775
  return true;
479186
479776
  default:
@@ -479225,6 +479815,8 @@ async function runSubcommand(argv) {
479225
479815
  return runSetupSubcommand(rest3);
479226
479816
  case "install":
479227
479817
  return runInstallSubcommand(rest3);
479818
+ case "shared-memory":
479819
+ return runSharedMemorySubcommand(rest3);
479228
479820
  case "skills":
479229
479821
  return runSkillsSubcommand(rest3);
479230
479822
  case "cron":
@@ -479255,6 +479847,7 @@ var init_router = __esm(async () => {
479255
479847
  init_local_backend2();
479256
479848
  init_memory7();
479257
479849
  init_messages10();
479850
+ init_shared_memory();
479258
479851
  init_skills4();
479259
479852
  init_trajectories();
479260
479853
  await __promiseAll([
@@ -479489,17 +480082,17 @@ var exports_bootstrap_tools = {};
479489
480082
  __export(exports_bootstrap_tools, {
479490
480083
  bootstrapBaseToolsIfNeeded: () => bootstrapBaseToolsIfNeeded
479491
480084
  });
479492
- import { existsSync as existsSync59, mkdirSync as mkdirSync43, writeFileSync as writeFileSync32 } from "node:fs";
480085
+ import { existsSync as existsSync60, mkdirSync as mkdirSync43, writeFileSync as writeFileSync32 } from "node:fs";
479493
480086
  import { homedir as homedir42 } from "node:os";
479494
- import { join as join76 } from "node:path";
480087
+ import { join as join77 } from "node:path";
479495
480088
  async function bootstrapBaseToolsIfNeeded() {
479496
- if (existsSync59(MARKER_PATH))
480089
+ if (existsSync60(MARKER_PATH))
479497
480090
  return;
479498
480091
  debugLog("bootstrap", "No marker found, bootstrapping base tools...");
479499
480092
  try {
479500
480093
  const success2 = await addBaseToolsToServer();
479501
480094
  if (success2) {
479502
- mkdirSync43(join76(homedir42(), ".letta"), { recursive: true });
480095
+ mkdirSync43(join77(homedir42(), ".letta"), { recursive: true });
479503
480096
  writeFileSync32(MARKER_PATH, new Date().toISOString(), "utf-8");
479504
480097
  }
479505
480098
  } catch (err) {
@@ -479510,7 +480103,7 @@ var MARKER_PATH;
479510
480103
  var init_bootstrap_tools = __esm(() => {
479511
480104
  init_debug();
479512
480105
  init_create5();
479513
- MARKER_PATH = join76(homedir42(), ".letta", ".bootstrapped");
480106
+ MARKER_PATH = join77(homedir42(), ".letta", ".bootstrapped");
479514
480107
  });
479515
480108
 
479516
480109
  // src/utils/headless-stdout-guard.ts
@@ -479856,8 +480449,17 @@ var init_local_backend_mod_events = __esm(() => {
479856
480449
  init_local_backend();
479857
480450
  });
479858
480451
 
480452
+ // src/headless-memfs-policy.ts
480453
+ function resolveHeadlessMemfsPolicy(options3) {
480454
+ const isFreshStatelessSubagent = options3.isSubagentRole && options3.newAgentRequested;
480455
+ return {
480456
+ isFreshStatelessSubagent,
480457
+ isStatelessSession: options3.statelessRequested || isFreshStatelessSubagent
480458
+ };
480459
+ }
480460
+
479859
480461
  // src/headless-mod-adapter.ts
479860
- import { join as join77 } from "node:path";
480462
+ import { join as join78 } from "node:path";
479861
480463
  function isHeadlessMemfsEnabled(agentId) {
479862
480464
  try {
479863
480465
  return settingsManager.isMemfsEnabled(agentId);
@@ -479928,7 +480530,7 @@ function createHeadlessModContext(options3) {
479928
480530
  };
479929
480531
  }
479930
480532
  function createHeadlessModAdapter(options3) {
479931
- const agentModsDirectory = isHeadlessMemfsEnabled(options3.agent.id) ? join77(getScopedMemoryFilesystemRoot(options3.agent.id), "mods") : undefined;
480533
+ const agentModsDirectory = isHeadlessMemfsEnabled(options3.agent.id) ? join78(getScopedMemoryFilesystemRoot(options3.agent.id), "mods") : undefined;
479932
480534
  return createModAdapter({
479933
480535
  ...agentModsDirectory ? { agentModsDirectory } : {},
479934
480536
  ...options3.cacheDirectory ? { cacheDirectory: options3.cacheDirectory } : {},
@@ -486215,49 +486817,49 @@ var require_fast_uri = __commonJS((exports, module3) => {
486215
486817
  schemelessOptions.skipEscape = true;
486216
486818
  return serialize(resolved, schemelessOptions);
486217
486819
  }
486218
- function resolveComponent(base3, relative15, options3, skipNormalization) {
486820
+ function resolveComponent(base3, relative14, options3, skipNormalization) {
486219
486821
  const target2 = {};
486220
486822
  if (!skipNormalization) {
486221
486823
  base3 = parse9(serialize(base3, options3), options3);
486222
- relative15 = parse9(serialize(relative15, options3), options3);
486824
+ relative14 = parse9(serialize(relative14, options3), options3);
486223
486825
  }
486224
486826
  options3 = options3 || {};
486225
- if (!options3.tolerant && relative15.scheme) {
486226
- target2.scheme = relative15.scheme;
486227
- target2.userinfo = relative15.userinfo;
486228
- target2.host = relative15.host;
486229
- target2.port = relative15.port;
486230
- target2.path = removeDotSegments(relative15.path || "");
486231
- target2.query = relative15.query;
486827
+ if (!options3.tolerant && relative14.scheme) {
486828
+ target2.scheme = relative14.scheme;
486829
+ target2.userinfo = relative14.userinfo;
486830
+ target2.host = relative14.host;
486831
+ target2.port = relative14.port;
486832
+ target2.path = removeDotSegments(relative14.path || "");
486833
+ target2.query = relative14.query;
486232
486834
  } else {
486233
- if (relative15.userinfo !== undefined || relative15.host !== undefined || relative15.port !== undefined) {
486234
- target2.userinfo = relative15.userinfo;
486235
- target2.host = relative15.host;
486236
- target2.port = relative15.port;
486237
- target2.path = removeDotSegments(relative15.path || "");
486238
- target2.query = relative15.query;
486835
+ if (relative14.userinfo !== undefined || relative14.host !== undefined || relative14.port !== undefined) {
486836
+ target2.userinfo = relative14.userinfo;
486837
+ target2.host = relative14.host;
486838
+ target2.port = relative14.port;
486839
+ target2.path = removeDotSegments(relative14.path || "");
486840
+ target2.query = relative14.query;
486239
486841
  } else {
486240
- if (!relative15.path) {
486842
+ if (!relative14.path) {
486241
486843
  target2.path = base3.path;
486242
- if (relative15.query !== undefined) {
486243
- target2.query = relative15.query;
486844
+ if (relative14.query !== undefined) {
486845
+ target2.query = relative14.query;
486244
486846
  } else {
486245
486847
  target2.query = base3.query;
486246
486848
  }
486247
486849
  } else {
486248
- if (relative15.path[0] === "/") {
486249
- target2.path = removeDotSegments(relative15.path);
486850
+ if (relative14.path[0] === "/") {
486851
+ target2.path = removeDotSegments(relative14.path);
486250
486852
  } else {
486251
486853
  if ((base3.userinfo !== undefined || base3.host !== undefined || base3.port !== undefined) && !base3.path) {
486252
- target2.path = "/" + relative15.path;
486854
+ target2.path = "/" + relative14.path;
486253
486855
  } else if (!base3.path) {
486254
- target2.path = relative15.path;
486856
+ target2.path = relative14.path;
486255
486857
  } else {
486256
- target2.path = base3.path.slice(0, base3.path.lastIndexOf("/") + 1) + relative15.path;
486858
+ target2.path = base3.path.slice(0, base3.path.lastIndexOf("/") + 1) + relative14.path;
486257
486859
  }
486258
486860
  target2.path = removeDotSegments(target2.path);
486259
486861
  }
486260
- target2.query = relative15.query;
486862
+ target2.query = relative14.query;
486261
486863
  }
486262
486864
  target2.userinfo = base3.userinfo;
486263
486865
  target2.host = base3.host;
@@ -486265,7 +486867,7 @@ var require_fast_uri = __commonJS((exports, module3) => {
486265
486867
  }
486266
486868
  target2.scheme = base3.scheme;
486267
486869
  }
486268
- target2.fragment = relative15.fragment;
486870
+ target2.fragment = relative14.fragment;
486269
486871
  return target2;
486270
486872
  }
486271
486873
  function equal3(uriA, uriB, options3) {
@@ -491284,7 +491886,7 @@ var init_mcp_client = __esm(() => {
491284
491886
  init_streamableHttp();
491285
491887
  DEFAULT_CLIENT_INFO = {
491286
491888
  name: "letta-code",
491287
- version: "0.30.4"
491889
+ version: "0.30.5"
491288
491890
  };
491289
491891
  });
491290
491892
 
@@ -491706,8 +492308,8 @@ var init_mcp_runtime = __esm(async () => {
491706
492308
  });
491707
492309
 
491708
492310
  // src/skills/builtin/creating-skills/scripts/validate-skill.ts
491709
- import { existsSync as existsSync60, readFileSync as readFileSync39 } from "node:fs";
491710
- import { basename as basename30, join as join78, resolve as resolve34 } from "node:path";
492311
+ import { existsSync as existsSync61, readFileSync as readFileSync39 } from "node:fs";
492312
+ import { basename as basename30, join as join79, resolve as resolve34 } from "node:path";
491711
492313
  import { fileURLToPath as fileURLToPath11 } from "node:url";
491712
492314
  function parseQuotedScalar(value) {
491713
492315
  if (value.startsWith('"')) {
@@ -491804,8 +492406,8 @@ function parseFrontmatter2(source2) {
491804
492406
  return parseFrontmatterFallback(source2);
491805
492407
  }
491806
492408
  function validateSkill(skillPath) {
491807
- const skillMdPath = join78(skillPath, "SKILL.md");
491808
- if (!existsSync60(skillMdPath)) {
492409
+ const skillMdPath = join79(skillPath, "SKILL.md");
492410
+ if (!existsSync61(skillMdPath)) {
491809
492411
  return { valid: false, message: "SKILL.md not found" };
491810
492412
  }
491811
492413
  const content = readFileSync39(skillMdPath, "utf-8");
@@ -491972,7 +492574,7 @@ __export(exports_import, {
491972
492574
  });
491973
492575
  import { createReadStream as createReadStream2 } from "node:fs";
491974
492576
  import { access as access2, chmod, mkdir as mkdir17, readFile as readFile28, writeFile as writeFile19 } from "node:fs/promises";
491975
- import { dirname as dirname34, isAbsolute as isAbsolute28, relative as relative15, resolve as resolve35, sep as sep8, win32 as win325 } from "node:path";
492577
+ import { dirname as dirname34, isAbsolute as isAbsolute28, relative as relative14, resolve as resolve35, sep as sep8, win32 as win325 } from "node:path";
491976
492578
  function validateImportedSkillName(name) {
491977
492579
  const trimmedName = name.trim();
491978
492580
  if (trimmedName !== name || trimmedName.length === 0 || trimmedName.length > MAX_SKILL_NAME_LENGTH || trimmedName === "." || trimmedName === ".." || !IMPORTED_SKILL_NAME_PATTERN.test(trimmedName)) {
@@ -491983,7 +492585,7 @@ function validateImportedSkillName(name) {
491983
492585
  function assertPathInside(parent, child) {
491984
492586
  const parentPath = resolve35(parent);
491985
492587
  const childPath = resolve35(child);
491986
- const relativePath = relative15(parentPath, childPath);
492588
+ const relativePath = relative14(parentPath, childPath);
491987
492589
  if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep8}`) || isAbsolute28(relativePath)) {
491988
492590
  throw new Error(`Imported skill file path escapes skill directory: ${child}`);
491989
492591
  }
@@ -492153,7 +492755,7 @@ function parseRegistryHandle(handle2) {
492153
492755
  }
492154
492756
  async function importAgentFromRegistry(options3) {
492155
492757
  const { tmpdir: tmpdir11 } = await import("node:os");
492156
- const { join: join79 } = await import("node:path");
492758
+ const { join: join80 } = await import("node:path");
492157
492759
  const { writeFile: writeFile20, unlink: unlink6 } = await import("node:fs/promises");
492158
492760
  const { author, name } = parseRegistryHandle(options3.handle);
492159
492761
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
@@ -492165,7 +492767,7 @@ async function importAgentFromRegistry(options3) {
492165
492767
  throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
492166
492768
  }
492167
492769
  const afContent = await response.text();
492168
- const tempPath = join79(tmpdir11(), `letta-import-${author}-${name}-${Date.now()}.af`);
492770
+ const tempPath = join80(tmpdir11(), `letta-import-${author}-${name}-${Date.now()}.af`);
492169
492771
  await writeFile20(tempPath, afContent, "utf-8");
492170
492772
  try {
492171
492773
  const result = await importAgentFromFile({
@@ -492424,6 +493026,7 @@ function hasReflectionOverrides(overrides) {
492424
493026
  async function applyReflectionOverrides(agentId, overrides) {
492425
493027
  const current = getReflectionSettings(agentId);
492426
493028
  const merged = {
493029
+ ...current,
492427
493030
  trigger: overrides.trigger ?? current.trigger,
492428
493031
  stepCount: overrides.stepCount ?? current.stepCount
492429
493032
  };
@@ -492815,9 +493418,14 @@ In headless mode, use:
492815
493418
  const noBundledSkillsFlag = values2["no-bundled-skills"];
492816
493419
  const skillSourcesRaw = values2["skill-sources"];
492817
493420
  const memfsFlag = values2.memfs;
493421
+ const statelessFlag = values2.stateless;
492818
493422
  const isSubagentRole = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
492819
- const isStatelessSubagent = isSubagentRole && Boolean(values2["new-agent"]);
492820
- if (isStatelessSubagent && backend3.capabilities.localMemfs) {
493423
+ const { isFreshStatelessSubagent, isStatelessSession } = resolveHeadlessMemfsPolicy({
493424
+ statelessRequested: Boolean(statelessFlag),
493425
+ isSubagentRole,
493426
+ newAgentRequested: Boolean(forceNew)
493427
+ });
493428
+ if (isStatelessSession && backend3.capabilities.localMemfs) {
492821
493429
  const { disableLocalBackendMemfsForProcess: disableLocalBackendMemfsForProcess2 } = await Promise.resolve().then(() => (init_paths(), exports_paths));
492822
493430
  disableLocalBackendMemfsForProcess2();
492823
493431
  }
@@ -492829,7 +493437,7 @@ In headless mode, use:
492829
493437
  console.error("Error: --memfs is not supported by this backend yet");
492830
493438
  process.exit(1);
492831
493439
  }
492832
- const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !isStatelessSubagent;
493440
+ const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !isStatelessSession;
492833
493441
  const fromAfFile = resolveImportFlagAlias({
492834
493442
  importFlagValue: values2.import,
492835
493443
  fromAfFlagValue: values2["from-af"]
@@ -492917,35 +493525,17 @@ In headless mode, use:
492917
493525
  }
492918
493526
  }
492919
493527
  try {
492920
- validateFlagConflicts({
492921
- guard: specifiedConversationId && specifiedConversationId !== "default",
492922
- checks: [
492923
- {
492924
- when: specifiedAgentId,
492925
- message: "--conversation cannot be used with --agent"
492926
- },
492927
- {
492928
- when: specifiedAgentName,
492929
- message: "--conversation cannot be used with --name"
492930
- },
492931
- {
492932
- when: forceNew,
492933
- message: "--conversation cannot be used with --new-agent"
492934
- },
492935
- {
492936
- when: fromAfFile,
492937
- message: "--conversation cannot be used with --import"
492938
- }
492939
- ]
492940
- });
492941
- validateFlagConflicts({
492942
- guard: forceNewConversation,
492943
- checks: [
492944
- {
492945
- when: specifiedConversationId,
492946
- message: "--new cannot be used with --conversation"
492947
- }
492948
- ]
493528
+ validatePrimaryStartupFlagConflicts({
493529
+ specifiedConversationId,
493530
+ specifiedAgentId,
493531
+ specifiedAgentName,
493532
+ forceNewAgent: forceNew,
493533
+ forceNewConversation,
493534
+ importFile: fromAfFile,
493535
+ stateless: statelessFlag,
493536
+ isHeadless: true,
493537
+ memfs: memfsFlag,
493538
+ memfsStartup: values2["memfs-startup"]
492949
493539
  });
492950
493540
  } catch (error54) {
492951
493541
  return reportAndExitHeadless("headless_flag_conflict_validation_failed", error54, "headless_startup_flag_conflicts");
@@ -493076,7 +493666,7 @@ In headless mode, use:
493076
493666
  if (!agent2 && forceNew) {
493077
493667
  const { isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
493078
493668
  const willAutoEnableMemfs = backend3.capabilities.remoteMemfs && shouldAutoEnableMemfsForNewAgent && await isLettaCloud2();
493079
- const effectiveMemoryMode = backend3.capabilities.localMemfs ? isStatelessSubagent ? "standard" : "local-memfs" : requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
493669
+ const effectiveMemoryMode = backend3.capabilities.localMemfs ? isFreshStatelessSubagent ? "standard" : "local-memfs" : requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
493080
493670
  const personalityOptions = personality ? await buildCreateAgentOptionsForPersonality({
493081
493671
  personalityId: personality,
493082
493672
  model,
@@ -493178,19 +493768,21 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
493178
493768
  let effectiveReflectionSettings;
493179
493769
  const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
493180
493770
  let startupMemfsFlag = autoEnableMemfsForFreshAgent ? true : memfsFlag;
493181
- if (backend3.capabilities.remoteMemfs && !autoEnableMemfsForFreshAgent) {
493771
+ if (!isStatelessSession && backend3.capabilities.remoteMemfs && !autoEnableMemfsForFreshAgent) {
493182
493772
  const { hydrateMemfsSettingFromAgent: hydrateMemfsSettingFromAgent2, isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
493183
493773
  const memfsEnabled = await hydrateMemfsSettingFromAgent2(agent2);
493184
- if (!memfsEnabled && !isStatelessSubagent && await isLettaCloud2()) {
493774
+ if (!memfsEnabled && await isLettaCloud2()) {
493185
493775
  startupMemfsFlag = true;
493186
493776
  }
493187
493777
  }
493188
493778
  let memfsBgPromise;
493189
493779
  const secretsAgentId = agent2?.id;
493190
493780
  const secretsInitPromise = secretsAgentId ? Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store)).then(({ initSecretsFromServer: initSecretsFromServer2 }) => initSecretsFromServer2(secretsAgentId, agent2 ?? undefined)) : Promise.resolve();
493191
- if (!backend3.capabilities.remoteMemfs) {
493781
+ if (isStatelessSession) {
493782
+ settingsManager.setMemfsEnabled(agent2.id, false);
493783
+ } else if (!backend3.capabilities.remoteMemfs) {
493192
493784
  if (backend3.capabilities.localMemfs) {
493193
- settingsManager.setMemfsEnabled(agent2.id, !isStatelessSubagent);
493785
+ settingsManager.setMemfsEnabled(agent2.id, true);
493194
493786
  }
493195
493787
  } else if (memfsStartupPolicy === "skip") {
493196
493788
  try {
@@ -493281,7 +493873,8 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
493281
493873
  debugWarn("headless startup", `Failed to clear persisted client tool rules for ${startupAgentId}: ${error54 instanceof Error ? error54.message : String(error54)}`);
493282
493874
  });
493283
493875
  try {
493284
- effectiveReflectionSettings = await applyReflectionOverrides(agent2.id, reflectionOverrides);
493876
+ const resolvedReflectionSettings = await applyReflectionOverrides(agent2.id, reflectionOverrides);
493877
+ effectiveReflectionSettings = isStatelessSession ? { ...resolvedReflectionSettings, trigger: "off" } : resolvedReflectionSettings;
493285
493878
  } catch (error54) {
493286
493879
  console.error(`Failed to apply sleeptime settings: ${error54 instanceof Error ? error54.message : String(error54)}`);
493287
493880
  process.exit(1);
@@ -496935,10 +497528,10 @@ var init_queued_message_parts = __esm(() => {
496935
497528
 
496936
497529
  // src/cli/helpers/reflection-arena-hf-upload.ts
496937
497530
  import { execFile as execFileCb5 } from "node:child_process";
496938
- import { existsSync as existsSync62 } from "node:fs";
497531
+ import { existsSync as existsSync63 } from "node:fs";
496939
497532
  import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir18, writeFile as writeFile20 } from "node:fs/promises";
496940
497533
  import { homedir as homedir45 } from "node:os";
496941
- import { join as join80 } from "node:path";
497534
+ import { join as join81 } from "node:path";
496942
497535
  import { promisify as promisify15 } from "node:util";
496943
497536
  function buildGitEnv(token2, askpassPath) {
496944
497537
  return {
@@ -496974,7 +497567,7 @@ async function runGit6(cwd2, args, env5) {
496974
497567
  }
496975
497568
  }
496976
497569
  async function writeGitAskpass(repoRoot) {
496977
- const askpassPath = join80(repoRoot, "hf-askpass.sh");
497570
+ const askpassPath = join81(repoRoot, "hf-askpass.sh");
496978
497571
  await writeFile20(askpassPath, [
496979
497572
  "#!/bin/sh",
496980
497573
  'case "$1" in',
@@ -496989,7 +497582,7 @@ async function writeGitAskpass(repoRoot) {
496989
497582
  }
496990
497583
  async function prepareHfRepo(env5) {
496991
497584
  await mkdir18(HF_CACHE_ROOT, { recursive: true });
496992
- if (!existsSync62(join80(HF_REPO_DIR, ".git"))) {
497585
+ if (!existsSync63(join81(HF_REPO_DIR, ".git"))) {
496993
497586
  await runGit6(HF_CACHE_ROOT, ["clone", "--depth", "1", HF_REPO_URL, HF_REPO_DIR], env5);
496994
497587
  return HF_REPO_DIR;
496995
497588
  }
@@ -497024,8 +497617,8 @@ async function maybeUploadReflectionArenaChoiceToHf(row) {
497024
497617
  const env5 = buildGitEnv(token2, askpassPath);
497025
497618
  try {
497026
497619
  const repoDir = await prepareHfRepo(env5);
497027
- await mkdir18(join80(repoDir, "data"), { recursive: true });
497028
- await appendFile2(join80(repoDir, HF_DATASET_PATH), `${JSON.stringify(row)}
497620
+ await mkdir18(join81(repoDir, "data"), { recursive: true });
497621
+ await appendFile2(join81(repoDir, HF_DATASET_PATH), `${JSON.stringify(row)}
497029
497622
  `, {
497030
497623
  encoding: "utf-8"
497031
497624
  });
@@ -497053,8 +497646,8 @@ var init_reflection_arena_hf_upload = __esm(() => {
497053
497646
  init_version();
497054
497647
  execFile17 = promisify15(execFileCb5);
497055
497648
  HF_REPO_URL = `https://huggingface.co/datasets/${HF_REPO_ID}`;
497056
- HF_CACHE_ROOT = join80(homedir45(), ".letta", "reflection-arena", "hf-upload");
497057
- HF_REPO_DIR = join80(HF_CACHE_ROOT, "repo");
497649
+ HF_CACHE_ROOT = join81(homedir45(), ".letta", "reflection-arena", "hf-upload");
497650
+ HF_REPO_DIR = join81(HF_CACHE_ROOT, "repo");
497058
497651
  });
497059
497652
 
497060
497653
  // src/cli/helpers/reflection-arena.ts
@@ -497062,7 +497655,7 @@ import { execFile as execFileCb6 } from "node:child_process";
497062
497655
  import { randomInt as randomInt2, randomUUID as randomUUID34 } from "node:crypto";
497063
497656
  import { appendFile as appendFile3, mkdir as mkdir19, readFile as readFile29, writeFile as writeFile21 } from "node:fs/promises";
497064
497657
  import { homedir as homedir46 } from "node:os";
497065
- import { join as join81 } from "node:path";
497658
+ import { join as join82 } from "node:path";
497066
497659
  import { promisify as promisify16 } from "node:util";
497067
497660
  function sampleReflectionArenaComparisonModel(excludedModels = []) {
497068
497661
  const excluded = new Set(excludedModels);
@@ -497078,30 +497671,49 @@ function sampleReflectionArenaComparisonModel(excludedModels = []) {
497078
497671
  }
497079
497672
  return candidates2[0]?.model ?? "letta/auto";
497080
497673
  }
497081
- async function getGitHead(cwd2) {
497674
+ async function getGitOutput(cwd2, args) {
497082
497675
  try {
497083
- const { stdout } = await execFile18("git", ["rev-parse", "HEAD"], {
497676
+ const { stdout } = await execFile18("git", args, {
497084
497677
  cwd: cwd2,
497085
497678
  encoding: "utf-8",
497086
497679
  timeout: 30000,
497087
497680
  maxBuffer: 1024 * 1024
497088
497681
  });
497089
- return stdout.trim() || null;
497682
+ return stdout.trim();
497090
497683
  } catch {
497091
497684
  return null;
497092
497685
  }
497093
497686
  }
497687
+ async function getGitHead(cwd2) {
497688
+ return await getGitOutput(cwd2, ["rev-parse", "HEAD"]) || null;
497689
+ }
497690
+ async function reflectionMemoryWorktreeHasNoChanges(worktree) {
497691
+ const [count, status] = await Promise.all([
497692
+ getGitOutput(worktree.worktreeDir, [
497693
+ "rev-list",
497694
+ "--count",
497695
+ `${worktree.baseHead}..HEAD`
497696
+ ]),
497697
+ getGitOutput(worktree.worktreeDir, ["status", "--porcelain"])
497698
+ ]);
497699
+ if (count === null || status === null)
497700
+ return;
497701
+ return count === "0" && status.length === 0;
497702
+ }
497703
+ function candidateIsConfirmedNoOp(candidate) {
497704
+ return candidate.result?.success === true && candidate.result.memoryNoChanges === true && candidate.result.memoryHead === candidate.worktree.baseHead;
497705
+ }
497094
497706
  function getReflectionArenaRoot() {
497095
- return join81(homedir46(), ".letta", "reflection-arena");
497707
+ return join82(homedir46(), ".letta", "reflection-arena");
497096
497708
  }
497097
497709
  function getReflectionArenaRunsDir() {
497098
- return join81(getReflectionArenaRoot(), "runs");
497710
+ return join82(getReflectionArenaRoot(), "runs");
497099
497711
  }
497100
497712
  function getReflectionArenaChoiceLogPath() {
497101
- return join81(getReflectionArenaRoot(), "choices.jsonl");
497713
+ return join82(getReflectionArenaRoot(), "choices.jsonl");
497102
497714
  }
497103
497715
  function getReflectionArenaRunPath(runId) {
497104
- return join81(getReflectionArenaRunsDir(), `${runId}.json`);
497716
+ return join82(getReflectionArenaRunsDir(), `${runId}.json`);
497105
497717
  }
497106
497718
  async function saveReflectionArenaRun(run) {
497107
497719
  await mkdir19(getReflectionArenaRunsDir(), { recursive: true });
@@ -497393,6 +498005,11 @@ async function markCandidateComplete(params) {
497393
498005
  });
497394
498006
  }
497395
498007
  async function launchReflectionArena(options3) {
498008
+ const memoryDir = getScopedMemoryFilesystemRoot(options3.agentId);
498009
+ if (await reflectionMemoryParentHasChanges(memoryDir)) {
498010
+ debugLog("memory", `Skipping reflection arena launch (${options3.triggerSource}) because parent memory has uncommitted changes`);
498011
+ return { launched: false, reason: "parent_dirty" };
498012
+ }
497396
498013
  const payload = await buildAutoReflectionPayload(options3.agentId, options3.conversationId);
497397
498014
  if (!payload) {
497398
498015
  return { launched: false, reason: "no_payload" };
@@ -497439,7 +498056,8 @@ async function startReflectionArenaRun(options3) {
497439
498056
  payloadPath: options3.payload.payloadPath,
497440
498057
  runId,
497441
498058
  startMessageId: options3.payload.startMessageId,
497442
- status: "running"
498059
+ status: "running",
498060
+ triggerSource: options3.triggerSource
497443
498061
  };
497444
498062
  await saveReflectionArenaRun(run);
497445
498063
  const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
@@ -497464,11 +498082,16 @@ async function startReflectionArenaRun(options3) {
497464
498082
  error: error54,
497465
498083
  agentId,
497466
498084
  conversationId,
498085
+ model: resolvedModel,
497467
498086
  stepCount,
497468
498087
  durationMs,
497469
498088
  report
497470
498089
  }) => {
497471
498090
  try {
498091
+ const [memoryHead, memoryNoChanges] = await Promise.all([
498092
+ getGitHead(candidate.worktree.worktreeDir),
498093
+ reflectionMemoryWorktreeHasNoChanges(candidate.worktree)
498094
+ ]);
497472
498095
  emitReflectionRunEnd({
497473
498096
  parentAgentId: options3.agentId,
497474
498097
  triggerSource: options3.triggerSource,
@@ -497478,9 +498101,9 @@ async function startReflectionArenaRun(options3) {
497478
498101
  error: error54,
497479
498102
  stepCount,
497480
498103
  durationMs,
498104
+ model: resolvedModel ?? model,
497481
498105
  feedbackContext: {
497482
- ...options3.feedbackContext,
497483
- model
498106
+ ...options3.feedbackContext
497484
498107
  }
497485
498108
  });
497486
498109
  if (!success2 && model !== REFLECTION_ARENA_MODEL_A_DEFAULT && isRetryableArenaModelError(error54)) {
@@ -497501,9 +498124,12 @@ async function startReflectionArenaRun(options3) {
497501
498124
  error: error54,
497502
498125
  agentId,
497503
498126
  conversationId,
498127
+ model: resolvedModel ?? model,
497504
498128
  stepCount,
497505
498129
  durationMs,
497506
- report
498130
+ report,
498131
+ ...memoryHead ? { memoryHead } : {},
498132
+ ...memoryNoChanges !== undefined ? { memoryNoChanges } : {}
497507
498133
  }
497508
498134
  });
497509
498135
  if (updated.status === "awaiting_choice") {
@@ -497561,14 +498187,19 @@ async function finalizeReflectionArenaChoice(options3) {
497561
498187
  throw new Error(`Unknown reflection arena label: ${options3.choice}`);
497562
498188
  }
497563
498189
  memoryBaseCommit = chosen.worktree.baseHead;
497564
- memoryCandidateCommit = await getGitHead(chosen.worktree.worktreeDir);
498190
+ memoryCandidateCommit = await getGitHead(chosen.worktree.worktreeDir) ?? chosen.result?.memoryHead ?? null;
497565
498191
  const finalized = await finalizeReflectionMemoryWorktreeLaunch({
497566
498192
  worktree: chosen.worktree,
497567
498193
  subagentSuccess: chosen.result?.success ?? false,
497568
498194
  subagentError: chosen.result?.error,
497569
- agentId: run.agentId,
498195
+ knownNoChanges: candidateIsConfirmedNoOp(chosen),
498196
+ ...getReflectionFinalizationContext(run.agentId),
497570
498197
  conversationId: run.conversationId,
497571
498198
  subagentAgentId: chosen.result?.agentId,
498199
+ model: chosen.result?.model ?? chosen.model,
498200
+ telemetryContext: {
498201
+ triggerSource: run.triggerSource ?? "compaction-event"
498202
+ },
497572
498203
  recompileByConversation: options3.recompileByConversation,
497573
498204
  recompileQueuedByConversation: options3.recompileQueuedByConversation,
497574
498205
  logRecompileFailure: (message) => debugWarn("memory", message)
@@ -497581,7 +498212,8 @@ async function finalizeReflectionArenaChoice(options3) {
497581
498212
  }
497582
498213
  discarded.push(candidate.label);
497583
498214
  await finalizeReflectionMemoryWorktree(candidate.worktree, {
497584
- shouldMerge: false
498215
+ shouldMerge: false,
498216
+ knownNoChanges: candidateIsConfirmedNoOp(candidate)
497585
498217
  });
497586
498218
  }
497587
498219
  await finalizeAutoReflectionPayload(run.agentId, run.conversationId, run.payloadPath, run.endSnapshotLine, integration ? reflectionIntegrationConsumesTranscript(integration) : false);
@@ -497621,6 +498253,7 @@ async function finalizeReflectionArenaChoice(options3) {
497621
498253
  }
497622
498254
  var execFile18, REFLECTION_ARENA_TELEMETRY_TRANSCRIPT_MAX_CHARS = 1e6, REFLECTION_ARENA_MODEL_A_DEFAULT = "letta/auto-memory", REFLECTION_ARENA_COMPARISON_MODEL_POOL, ANSI_BOLD = "\x1B[1m", ANSI_CYAN = "\x1B[36m", ANSI_MAGENTA = "\x1B[35m", ANSI_RESET_BOLD = "\x1B[22m", ANSI_RESET_FOREGROUND = "\x1B[39m", REFLECTION_ARENA_CANDIDATE_COUNT = 2, REFLECTION_ARENA_CHOICE_QUESTION = "Which reflection should be merged?", REFLECTION_ARENA_NOTES_QUESTION = "Optional feedback for this choice?", updateLocks;
497623
498255
  var init_reflection_arena = __esm(() => {
498256
+ init_memory_filesystem2();
497624
498257
  init_memory_worktree();
497625
498258
  init_app_urls();
497626
498259
  init_reflection_arena_hf_upload();
@@ -498192,13 +498825,13 @@ __export(exports_terminal_keybinding_installer, {
498192
498825
  });
498193
498826
  import {
498194
498827
  copyFileSync as copyFileSync6,
498195
- existsSync as existsSync63,
498828
+ existsSync as existsSync64,
498196
498829
  mkdirSync as mkdirSync45,
498197
498830
  readFileSync as readFileSync41,
498198
498831
  writeFileSync as writeFileSync34
498199
498832
  } from "node:fs";
498200
498833
  import { homedir as homedir47, platform as platform10 } from "node:os";
498201
- import { dirname as dirname35, join as join82 } from "node:path";
498834
+ import { dirname as dirname35, join as join83 } from "node:path";
498202
498835
  function detectTerminalType() {
498203
498836
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
498204
498837
  return "cursor";
@@ -498230,16 +498863,16 @@ function getKeybindingsPath(terminal) {
498230
498863
  }[terminal];
498231
498864
  const os8 = platform10();
498232
498865
  if (os8 === "darwin") {
498233
- return join82(homedir47(), "Library", "Application Support", appName, "User", "keybindings.json");
498866
+ return join83(homedir47(), "Library", "Application Support", appName, "User", "keybindings.json");
498234
498867
  }
498235
498868
  if (os8 === "win32") {
498236
498869
  const appData = process.env.APPDATA;
498237
498870
  if (!appData)
498238
498871
  return null;
498239
- return join82(appData, appName, "User", "keybindings.json");
498872
+ return join83(appData, appName, "User", "keybindings.json");
498240
498873
  }
498241
498874
  if (os8 === "linux") {
498242
- return join82(homedir47(), ".config", appName, "User", "keybindings.json");
498875
+ return join83(homedir47(), ".config", appName, "User", "keybindings.json");
498243
498876
  }
498244
498877
  return null;
498245
498878
  }
@@ -498261,7 +498894,7 @@ function parseKeybindings(content) {
498261
498894
  }
498262
498895
  }
498263
498896
  function keybindingExists(keybindingsPath) {
498264
- if (!existsSync63(keybindingsPath))
498897
+ if (!existsSync64(keybindingsPath))
498265
498898
  return false;
498266
498899
  try {
498267
498900
  const content = readFileSync41(keybindingsPath, { encoding: "utf-8" });
@@ -498274,7 +498907,7 @@ function keybindingExists(keybindingsPath) {
498274
498907
  }
498275
498908
  }
498276
498909
  function createBackup(keybindingsPath) {
498277
- if (!existsSync63(keybindingsPath))
498910
+ if (!existsSync64(keybindingsPath))
498278
498911
  return null;
498279
498912
  const backupPath = `${keybindingsPath}.letta-backup`;
498280
498913
  try {
@@ -498290,12 +498923,12 @@ function installKeybinding(keybindingsPath) {
498290
498923
  return { success: true, alreadyExists: true };
498291
498924
  }
498292
498925
  const parentDir = dirname35(keybindingsPath);
498293
- if (!existsSync63(parentDir)) {
498926
+ if (!existsSync64(parentDir)) {
498294
498927
  mkdirSync45(parentDir, { recursive: true });
498295
498928
  }
498296
498929
  let keybindings = [];
498297
498930
  let backupPath = null;
498298
- if (existsSync63(keybindingsPath)) {
498931
+ if (existsSync64(keybindingsPath)) {
498299
498932
  backupPath = createBackup(keybindingsPath);
498300
498933
  const content = readFileSync41(keybindingsPath, { encoding: "utf-8" });
498301
498934
  const parsed = parseKeybindings(content);
@@ -498325,7 +498958,7 @@ function installKeybinding(keybindingsPath) {
498325
498958
  }
498326
498959
  function removeKeybinding(keybindingsPath) {
498327
498960
  try {
498328
- if (!existsSync63(keybindingsPath)) {
498961
+ if (!existsSync64(keybindingsPath)) {
498329
498962
  return { success: true };
498330
498963
  }
498331
498964
  const content = readFileSync41(keybindingsPath, { encoding: "utf-8" });
@@ -498392,14 +499025,14 @@ function getWezTermConfigPath() {
498392
499025
  }
498393
499026
  const xdgConfig = process.env.XDG_CONFIG_HOME;
498394
499027
  if (xdgConfig) {
498395
- const xdgPath = join82(xdgConfig, "wezterm", "wezterm.lua");
498396
- if (existsSync63(xdgPath))
499028
+ const xdgPath = join83(xdgConfig, "wezterm", "wezterm.lua");
499029
+ if (existsSync64(xdgPath))
498397
499030
  return xdgPath;
498398
499031
  }
498399
- const configPath = join82(homedir47(), ".config", "wezterm", "wezterm.lua");
498400
- if (existsSync63(configPath))
499032
+ const configPath = join83(homedir47(), ".config", "wezterm", "wezterm.lua");
499033
+ if (existsSync64(configPath))
498401
499034
  return configPath;
498402
- return join82(homedir47(), ".wezterm.lua");
499035
+ return join83(homedir47(), ".wezterm.lua");
498403
499036
  }
498404
499037
  function stripLuaCommentsFromLine(line, blockCommentEnd) {
498405
499038
  let code2 = "";
@@ -498502,7 +499135,7 @@ ${WEZTERM_DELETE_FIX}
498502
499135
  `;
498503
499136
  }
498504
499137
  function wezTermDeleteFixExists(configPath) {
498505
- if (!existsSync63(configPath))
499138
+ if (!existsSync64(configPath))
498506
499139
  return false;
498507
499140
  try {
498508
499141
  const content = readFileSync41(configPath, { encoding: "utf-8" });
@@ -498519,14 +499152,14 @@ function installWezTermDeleteFix() {
498519
499152
  }
498520
499153
  let content = "";
498521
499154
  let backupPath = null;
498522
- if (existsSync63(configPath)) {
499155
+ if (existsSync64(configPath)) {
498523
499156
  backupPath = `${configPath}.letta-backup`;
498524
499157
  copyFileSync6(configPath, backupPath);
498525
499158
  content = readFileSync41(configPath, { encoding: "utf-8" });
498526
499159
  }
498527
499160
  content = injectWezTermDeleteFix(content);
498528
499161
  const parentDir = dirname35(configPath);
498529
- if (!existsSync63(parentDir)) {
499162
+ if (!existsSync64(parentDir)) {
498530
499163
  mkdirSync45(parentDir, { recursive: true });
498531
499164
  }
498532
499165
  writeFileSync34(configPath, content, { encoding: "utf-8" });
@@ -498578,9 +499211,9 @@ __export(exports_settings2, {
498578
499211
  getSetting: () => getSetting
498579
499212
  });
498580
499213
  import { homedir as homedir48 } from "node:os";
498581
- import { join as join83 } from "node:path";
499214
+ import { join as join84 } from "node:path";
498582
499215
  function getSettingsPath() {
498583
- return join83(homedir48(), ".letta", "settings.json");
499216
+ return join84(homedir48(), ".letta", "settings.json");
498584
499217
  }
498585
499218
  async function loadSettings() {
498586
499219
  const settingsPath = getSettingsPath();
@@ -498617,7 +499250,7 @@ async function getSetting(key2) {
498617
499250
  return settings3[key2];
498618
499251
  }
498619
499252
  function getProjectSettingsPath() {
498620
- return join83(process.cwd(), ".letta", "settings.local.json");
499253
+ return join84(process.cwd(), ".letta", "settings.local.json");
498621
499254
  }
498622
499255
  async function loadProjectSettings() {
498623
499256
  const settingsPath = getProjectSettingsPath();
@@ -498635,7 +499268,7 @@ async function loadProjectSettings() {
498635
499268
  }
498636
499269
  async function saveProjectSettings(settings3) {
498637
499270
  const settingsPath = getProjectSettingsPath();
498638
- const dirPath = join83(process.cwd(), ".letta");
499271
+ const dirPath = join84(process.cwd(), ".letta");
498639
499272
  try {
498640
499273
  if (!exists(dirPath)) {
498641
499274
  await mkdir(dirPath, { recursive: true });
@@ -498806,7 +499439,7 @@ var init_registry2 = __esm(() => {
498806
499439
  }
498807
499440
  },
498808
499441
  "/sleeptime": {
498809
- desc: "Configure sleep-time reflection trigger settings",
499442
+ desc: "Configure sleep-time reflection trigger and merge settings",
498810
499443
  order: 15.5,
498811
499444
  noArgs: true,
498812
499445
  handler: () => {
@@ -499674,10 +500307,10 @@ var init_InlineBashApproval = __esm(async () => {
499674
500307
  });
499675
500308
 
499676
500309
  // src/cli/components/DiffRenderer.tsx
499677
- import { relative as relative16 } from "node:path";
500310
+ import { relative as relative15 } from "node:path";
499678
500311
  function formatDisplayPath4(filePath) {
499679
500312
  const cwd2 = process.cwd();
499680
- const relativePath = relative16(cwd2, filePath);
500313
+ const relativePath = relative15(cwd2, filePath);
499681
500314
  if (relativePath.startsWith("..")) {
499682
500315
  return filePath;
499683
500316
  }
@@ -500036,10 +500669,10 @@ var init_DiffRenderer = __esm(async () => {
500036
500669
  });
500037
500670
 
500038
500671
  // src/cli/components/AdvancedDiffRenderer.tsx
500039
- import { relative as relative17 } from "node:path";
500672
+ import { relative as relative16 } from "node:path";
500040
500673
  function formatRelativePath(filePath) {
500041
500674
  const cwd2 = process.cwd();
500042
- const relativePath = relative17(cwd2, filePath);
500675
+ const relativePath = relative16(cwd2, filePath);
500043
500676
  return relativePath.startsWith("..") ? relativePath : `./${relativePath}`;
500044
500677
  }
500045
500678
  function padLeft(n, width) {
@@ -500321,7 +500954,7 @@ function AdvancedDiffRenderer(props) {
500321
500954
  }
500322
500955
  const { hunks } = result;
500323
500956
  const filePath = props.filePath;
500324
- const relative18 = formatRelativePath(filePath);
500957
+ const relative17 = formatRelativePath(filePath);
500325
500958
  const lang41 = languageFromPath(filePath);
500326
500959
  const shouldHighlight = lang41 && !exceedsAdvancedDiffHighlightLimits(hunks);
500327
500960
  const hunkSyntaxLines = [];
@@ -500344,7 +500977,7 @@ function AdvancedDiffRenderer(props) {
500344
500977
  const rows = buildAdvancedDiffRows(hunks, hunkSyntaxLines);
500345
500978
  const maxDisplayNo = rows.reduce((m4, r5) => Math.max(m4, r5.displayNo), 1);
500346
500979
  const gutterWidth = String(maxDisplayNo).length;
500347
- const header = props.kind === "write" ? `Wrote changes to ${relative18}` : `Updated ${relative18}`;
500980
+ const header = props.kind === "write" ? `Wrote changes to ${relative17}` : `Updated ${relative17}`;
500348
500981
  if (rows.length === 0) {
500349
500982
  const noChangesGutter = 4;
500350
500983
  return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
@@ -500395,7 +501028,7 @@ function AdvancedDiffRenderer(props) {
500395
501028
  "No changes to ",
500396
501029
  /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text2, {
500397
501030
  bold: true,
500398
- children: relative18
501031
+ children: relative17
500399
501032
  }, undefined, false, undefined, this),
500400
501033
  " (file content identical)"
500401
501034
  ]
@@ -500501,9 +501134,9 @@ function getHeaderText(fileEdit) {
500501
501134
  } else if (operations.length === 1) {
500502
501135
  const op = operations[0];
500503
501136
  if (op) {
500504
- const { relative: relative19 } = __require("node:path");
501137
+ const { relative: relative18 } = __require("node:path");
500505
501138
  const cwd3 = process.cwd();
500506
- const relPath2 = relative19(cwd3, op.path);
501139
+ const relPath2 = relative18(cwd3, op.path);
500507
501140
  const displayPath2 = relPath2.startsWith("..") ? op.path : relPath2;
500508
501141
  if (op.kind === "add") {
500509
501142
  return `Write to ${displayPath2}?`;
@@ -500517,14 +501150,14 @@ function getHeaderText(fileEdit) {
500517
501150
  }
500518
501151
  return "Apply patch?";
500519
501152
  }
500520
- const { relative: relative18 } = __require("node:path");
501153
+ const { relative: relative17 } = __require("node:path");
500521
501154
  const cwd2 = process.cwd();
500522
- const relPath = relative18(cwd2, fileEdit.filePath);
501155
+ const relPath = relative17(cwd2, fileEdit.filePath);
500523
501156
  const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
500524
501157
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
500525
- const { existsSync: existsSync64 } = __require("node:fs");
501158
+ const { existsSync: existsSync65 } = __require("node:fs");
500526
501159
  try {
500527
- if (existsSync64(fileEdit.filePath)) {
501160
+ if (existsSync65(fileEdit.filePath)) {
500528
501161
  return `Overwrite ${displayPath}?`;
500529
501162
  }
500530
501163
  } catch {}
@@ -500702,9 +501335,9 @@ var init_InlineFileEditApproval = __esm(async () => {
500702
501335
  children: fileEdit.patchInput ? /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
500703
501336
  flexDirection: "column",
500704
501337
  children: parsePatchOperations2(fileEdit.patchInput).map((op, idx) => {
500705
- const { relative: relative18 } = __require("node:path");
501338
+ const { relative: relative17 } = __require("node:path");
500706
501339
  const cwd2 = process.cwd();
500707
- const relPath = relative18(cwd2, op.path);
501340
+ const relPath = relative17(cwd2, op.path);
500708
501341
  const displayPath = relPath.startsWith("..") ? op.path : relPath;
500709
501342
  const diffKey = fileEdit.toolCallId ? `${fileEdit.toolCallId}:${op.path}` : undefined;
500710
501343
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -510019,7 +510652,7 @@ var init_agents8 = __esm(() => {
510019
510652
  // src/cli/commands/install-github-app.ts
510020
510653
  import { execFileSync as execFileSync8 } from "node:child_process";
510021
510654
  import {
510022
- existsSync as existsSync64,
510655
+ existsSync as existsSync65,
510023
510656
  mkdirSync as mkdirSync46,
510024
510657
  mkdtempSync as mkdtempSync5,
510025
510658
  readFileSync as readFileSync42,
@@ -510027,7 +510660,7 @@ import {
510027
510660
  writeFileSync as writeFileSync35
510028
510661
  } from "node:fs";
510029
510662
  import { tmpdir as tmpdir11 } from "node:os";
510030
- import { dirname as dirname36, join as join84 } from "node:path";
510663
+ import { dirname as dirname36, join as join85 } from "node:path";
510031
510664
  function runCommand(command, args, cwd2, input) {
510032
510665
  try {
510033
510666
  return execFileSync8(command, args, {
@@ -510248,8 +510881,8 @@ async function createLettaAgent(apiKey, name) {
510248
510881
  return createMinimalAgent(apiKey, name);
510249
510882
  }
510250
510883
  function cloneRepoToTemp(repo) {
510251
- const tempDir = mkdtempSync5(join84(tmpdir11(), "letta-install-github-app-"));
510252
- const repoDir = join84(tempDir, "repo");
510884
+ const tempDir = mkdtempSync5(join85(tmpdir11(), "letta-install-github-app-"));
510885
+ const repoDir = join85(tempDir, "repo");
510253
510886
  runCommand("gh", ["repo", "clone", repo, repoDir, "--", "--depth=1"]);
510254
510887
  return { tempDir, repoDir };
510255
510888
  }
@@ -510260,13 +510893,13 @@ function runGit7(args, cwd2) {
510260
510893
  return runCommand("git", args, cwd2);
510261
510894
  }
510262
510895
  function writeWorkflow(repoDir, workflowPath, content) {
510263
- const absolutePath = join84(repoDir, workflowPath);
510264
- if (!existsSync64(dirname36(absolutePath))) {
510896
+ const absolutePath = join85(repoDir, workflowPath);
510897
+ if (!existsSync65(dirname36(absolutePath))) {
510265
510898
  mkdirSync46(dirname36(absolutePath), { recursive: true });
510266
510899
  }
510267
510900
  const next = `${content.trimEnd()}
510268
510901
  `;
510269
- if (existsSync64(absolutePath)) {
510902
+ if (existsSync65(absolutePath)) {
510270
510903
  const previous = readFileSync42(absolutePath, "utf8");
510271
510904
  if (previous === next) {
510272
510905
  return false;
@@ -511223,6 +511856,7 @@ function LettaLoginOverlay({
511223
511856
  command: "/login",
511224
511857
  title: "Sign in with Letta",
511225
511858
  children: /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(LettaLoginView, {
511859
+ activateCloudBackend: false,
511226
511860
  onComplete,
511227
511861
  onCancel
511228
511862
  }, undefined, false, undefined, this)
@@ -514155,9 +514789,9 @@ __export(exports_generate_memory_viewer, {
514155
514789
  generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
514156
514790
  });
514157
514791
  import { execFile as execFileCb7 } from "node:child_process";
514158
- import { chmodSync as chmodSync7, existsSync as existsSync65, mkdirSync as mkdirSync47, writeFileSync as writeFileSync36 } from "node:fs";
514792
+ import { chmodSync as chmodSync7, existsSync as existsSync66, mkdirSync as mkdirSync47, writeFileSync as writeFileSync36 } from "node:fs";
514159
514793
  import { homedir as homedir50 } from "node:os";
514160
- import { join as join85 } from "node:path";
514794
+ import { join as join86 } from "node:path";
514161
514795
  import { promisify as promisify17 } from "node:util";
514162
514796
  function messagesFromOverview(overview) {
514163
514797
  return overview.messages?.map((message) => ({
@@ -514466,7 +515100,7 @@ ${m4.body}` : m4.subject;
514466
515100
  async function generateAndOpenMemoryViewer(agentId, options3) {
514467
515101
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
514468
515102
  const repoDir = memoryRoot;
514469
- if (!existsSync65(join85(repoDir, ".git"))) {
515103
+ if (!existsSync66(join86(repoDir, ".git"))) {
514470
515104
  throw new Error("Memory viewer requires memfs. Run /memfs enable first.");
514471
515105
  }
514472
515106
  const data = await collectMemoryData(agentId, repoDir, memoryRoot, options3?.conversationId);
@@ -514476,13 +515110,13 @@ async function generateAndOpenMemoryViewer(agentId, options3) {
514476
515110
  data.context = applyContextUsageSnapshot(data.context, options3?.contextUsage);
514477
515111
  const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
514478
515112
  const html5 = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
514479
- if (!existsSync65(VIEWERS_DIR)) {
515113
+ if (!existsSync66(VIEWERS_DIR)) {
514480
515114
  mkdirSync47(VIEWERS_DIR, { recursive: true, mode: 448 });
514481
515115
  }
514482
515116
  try {
514483
515117
  chmodSync7(VIEWERS_DIR, 448);
514484
515118
  } catch {}
514485
- const filePath = join85(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
515119
+ const filePath = join86(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
514486
515120
  writeFileSync36(filePath, html5);
514487
515121
  chmodSync7(filePath, 384);
514488
515122
  const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
@@ -514507,13 +515141,13 @@ var init_generate_memory_viewer = __esm(() => {
514507
515141
  init_local_memory_context();
514508
515142
  init_memory_viewer_template();
514509
515143
  execFile19 = promisify17(execFileCb7);
514510
- VIEWERS_DIR = join85(homedir50(), ".letta", "viewers");
515144
+ VIEWERS_DIR = join86(homedir50(), ".letta", "viewers");
514511
515145
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
514512
515146
  });
514513
515147
 
514514
515148
  // src/cli/components/MemfsTreeViewer.tsx
514515
- import { existsSync as existsSync66 } from "node:fs";
514516
- import { join as join86 } from "node:path";
515149
+ import { existsSync as existsSync67 } from "node:fs";
515150
+ import { join as join87 } from "node:path";
514517
515151
  function renderTreePrefix(node) {
514518
515152
  let prefix = "";
514519
515153
  for (let i4 = 0;i4 < node.depth; i4++) {
@@ -514541,8 +515175,8 @@ function MemfsTreeViewer({
514541
515175
  const [status, setStatus] = import_react87.useState(null);
514542
515176
  const statusTimerRef = import_react87.useRef(null);
514543
515177
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
514544
- const memoryExists = existsSync66(memoryRoot);
514545
- const hasGitRepo = import_react87.useMemo(() => existsSync66(join86(memoryRoot, ".git")), [memoryRoot]);
515178
+ const memoryExists = existsSync67(memoryRoot);
515179
+ const hasGitRepo = import_react87.useMemo(() => existsSync67(join87(memoryRoot, ".git")), [memoryRoot]);
514546
515180
  function showStatus(msg, durationMs) {
514547
515181
  if (statusTimerRef.current)
514548
515182
  clearTimeout(statusTimerRef.current);
@@ -516919,10 +517553,10 @@ var init_PersonalitySelector = __esm(async () => {
516919
517553
  // src/utils/aws-credentials.ts
516920
517554
  import { readFile as readFile30 } from "node:fs/promises";
516921
517555
  import { homedir as homedir51 } from "node:os";
516922
- import { join as join87 } from "node:path";
517556
+ import { join as join88 } from "node:path";
516923
517557
  async function parseAwsCredentials() {
516924
- const credentialsPath = join87(homedir51(), ".aws", "credentials");
516925
- const configPath = join87(homedir51(), ".aws", "config");
517558
+ const credentialsPath = join88(homedir51(), ".aws", "credentials");
517559
+ const configPath = join88(homedir51(), ".aws", "config");
516926
517560
  const profiles = new Map;
516927
517561
  try {
516928
517562
  const content = await readFile30(credentialsPath, "utf-8");
@@ -518501,8 +519135,8 @@ function SkillsDialog({ onClose, agentId }) {
518501
519135
  try {
518502
519136
  const { discoverSkills: discoverSkills2, SKILLS_DIR: SKILLS_DIR2 } = await Promise.resolve().then(() => (init_skills3(), exports_skills2));
518503
519137
  const { getSkillsDirectory: getSkillsDirectory2, getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
518504
- const { join: join88 } = await import("node:path");
518505
- const skillsDir = getSkillsDirectory2() || join88(process.cwd(), SKILLS_DIR2);
519138
+ const { join: join89 } = await import("node:path");
519139
+ const skillsDir = getSkillsDirectory2() || join89(process.cwd(), SKILLS_DIR2);
518506
519140
  const result = await discoverSkills2(skillsDir, agentId, {
518507
519141
  sources: getSkillSources2()
518508
519142
  });
@@ -518717,6 +519351,36 @@ var init_SkillsDialog = __esm(async () => {
518717
519351
  });
518718
519352
 
518719
519353
  // src/cli/components/SleeptimeSelector.tsx
519354
+ function triggerFocusRow(trigger) {
519355
+ switch (trigger) {
519356
+ case "off":
519357
+ return "trigger-off";
519358
+ case "step-count":
519359
+ return "trigger-step-count";
519360
+ case "compaction-event":
519361
+ return "trigger-compaction";
519362
+ }
519363
+ }
519364
+ function mergeFocusRow(merge3) {
519365
+ return merge3 === "explicit" ? "merge-explicit" : "merge-auto";
519366
+ }
519367
+ function ChoiceRow(props) {
519368
+ const { focused, selected, children } = props;
519369
+ return /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
519370
+ flexDirection: "row",
519371
+ children: [
519372
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
519373
+ children: focused ? "> " : " "
519374
+ }, undefined, false, undefined, this),
519375
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
519376
+ backgroundColor: selected ? colors.selector.itemHighlighted : undefined,
519377
+ color: selected ? "black" : undefined,
519378
+ bold: selected,
519379
+ children
519380
+ }, undefined, false, undefined, this)
519381
+ ]
519382
+ }, undefined, true, undefined, this);
519383
+ }
518720
519384
  function cycleOption(options3, current, direction) {
518721
519385
  if (options3.length === 0) {
518722
519386
  return current;
@@ -518729,7 +519393,9 @@ function cycleOption(options3, current, direction) {
518729
519393
  function parseInitialState(initialSettings) {
518730
519394
  return {
518731
519395
  trigger: initialSettings.trigger === "off" || initialSettings.trigger === "step-count" || initialSettings.trigger === "compaction-event" ? initialSettings.trigger : "step-count",
518732
- stepCount: String(Number.isInteger(initialSettings.stepCount) && initialSettings.stepCount > 0 ? initialSettings.stepCount : Number(DEFAULT_STEP_COUNT2))
519396
+ stepCount: String(Number.isInteger(initialSettings.stepCount) && initialSettings.stepCount > 0 ? initialSettings.stepCount : Number(DEFAULT_STEP_COUNT2)),
519397
+ merge: initialSettings.merge === "explicit" ? "explicit" : "auto",
519398
+ mergeInstructions: initialSettings.mergeInstructions ?? ""
518733
519399
  };
518734
519400
  }
518735
519401
  function parseStepCount(raw2) {
@@ -518752,19 +519418,28 @@ function SleeptimeSelector({
518752
519418
  const initialState = import_react96.useMemo(() => parseInitialState(initialSettings), [initialSettings]);
518753
519419
  const [trigger, setTrigger] = import_react96.useState(initialState.trigger);
518754
519420
  const [stepCountInput, setStepCountInput] = import_react96.useState(initialState.stepCount);
518755
- const [focusRow, setFocusRow] = import_react96.useState("trigger");
519421
+ const [merge3, setMerge] = import_react96.useState(initialState.merge);
519422
+ const [mergeInstructions, setMergeInstructions] = import_react96.useState(initialState.mergeInstructions);
519423
+ const [focusRow, setFocusRow] = import_react96.useState(() => triggerFocusRow(initialState.trigger));
518756
519424
  const [validationError, setValidationError] = import_react96.useState(null);
518757
519425
  const visibleRows = import_react96.useMemo(() => {
518758
- const rows = ["trigger"];
518759
- if (trigger === "step-count") {
518760
- rows.push("step-count");
519426
+ const rows = [
519427
+ "trigger-off",
519428
+ "trigger-step-count",
519429
+ "trigger-compaction",
519430
+ "merge-auto",
519431
+ "merge-explicit"
519432
+ ];
519433
+ if (merge3 === "explicit") {
519434
+ rows.push("merge-instructions");
518761
519435
  }
518762
519436
  return rows;
518763
- }, [trigger]);
518764
- const isEditingStepCount = focusRow === "step-count" && trigger === "step-count";
519437
+ }, [merge3]);
519438
+ const isEditingStepCount = focusRow === "trigger-step-count";
519439
+ const isEditingMergeInstructions = focusRow === "merge-instructions" && merge3 === "explicit";
518765
519440
  import_react96.useEffect(() => {
518766
519441
  if (!visibleRows.includes(focusRow)) {
518767
- setFocusRow(visibleRows[visibleRows.length - 1] ?? "trigger");
519442
+ setFocusRow(visibleRows[visibleRows.length - 1] ?? "trigger-off");
518768
519443
  }
518769
519444
  }, [focusRow, visibleRows]);
518770
519445
  const saveSelection = () => {
@@ -518776,16 +519451,42 @@ function SleeptimeSelector({
518776
519451
  }
518777
519452
  onSave({
518778
519453
  trigger,
518779
- stepCount
519454
+ stepCount,
519455
+ merge: merge3,
519456
+ mergeInstructions
518780
519457
  });
518781
519458
  return;
518782
519459
  }
518783
519460
  const fallbackStepCount = parseStepCount(stepCountInput) ?? Number(DEFAULT_STEP_COUNT2);
518784
519461
  onSave({
518785
519462
  trigger,
518786
- stepCount: fallbackStepCount
519463
+ stepCount: fallbackStepCount,
519464
+ merge: merge3,
519465
+ mergeInstructions
518787
519466
  });
518788
519467
  };
519468
+ const selectFocusedOption = () => {
519469
+ switch (focusRow) {
519470
+ case "trigger-off":
519471
+ setTrigger("off");
519472
+ break;
519473
+ case "trigger-step-count":
519474
+ setTrigger("step-count");
519475
+ break;
519476
+ case "trigger-compaction":
519477
+ setTrigger("compaction-event");
519478
+ break;
519479
+ case "merge-auto":
519480
+ setMerge("auto");
519481
+ break;
519482
+ case "merge-explicit":
519483
+ setMerge("explicit");
519484
+ break;
519485
+ case "merge-instructions":
519486
+ break;
519487
+ }
519488
+ setValidationError(null);
519489
+ };
518789
519490
  use_input_default((input, key2) => {
518790
519491
  if (key2.ctrl && input === "c") {
518791
519492
  onCancel();
@@ -518805,35 +519506,55 @@ function SleeptimeSelector({
518805
519506
  saveSelection();
518806
519507
  return;
518807
519508
  }
518808
- if (key2.upArrow || key2.downArrow) {
519509
+ if (key2.upArrow || key2.downArrow || key2.tab) {
518809
519510
  if (visibleRows.length === 0)
518810
519511
  return;
518811
519512
  setValidationError(null);
518812
- const direction = key2.downArrow ? 1 : -1;
519513
+ const direction = key2.upArrow ? -1 : 1;
518813
519514
  const currentIndex = visibleRows.indexOf(focusRow);
518814
519515
  const safeIndex = currentIndex >= 0 ? currentIndex : 0;
518815
519516
  const nextIndex = (safeIndex + direction + visibleRows.length) % visibleRows.length;
518816
- const nextRow = visibleRows[nextIndex] ?? "trigger";
519517
+ const nextRow = visibleRows[nextIndex] ?? "trigger-off";
518817
519518
  setFocusRow(nextRow);
518818
519519
  return;
518819
519520
  }
518820
- if (key2.leftArrow || key2.rightArrow || key2.tab) {
519521
+ if (input === " " && !isEditingMergeInstructions) {
519522
+ selectFocusedOption();
519523
+ return;
519524
+ }
519525
+ if (key2.leftArrow || key2.rightArrow) {
518821
519526
  setValidationError(null);
518822
519527
  const direction = key2.leftArrow ? -1 : 1;
518823
- if (focusRow === "trigger") {
518824
- setTrigger((prev) => cycleOption(TRIGGER_OPTIONS, prev, direction));
519528
+ if (focusRow.startsWith("trigger-")) {
519529
+ const nextTrigger = cycleOption(TRIGGER_OPTIONS, trigger, direction);
519530
+ setTrigger(nextTrigger);
519531
+ setFocusRow(triggerFocusRow(nextTrigger));
519532
+ } else if (focusRow.startsWith("merge-")) {
519533
+ const nextMerge = cycleOption(MERGE_OPTIONS, merge3, direction);
519534
+ setMerge(nextMerge);
519535
+ setFocusRow(mergeFocusRow(nextMerge));
518825
519536
  }
518826
519537
  return;
518827
519538
  }
518828
- if (!isEditingStepCount)
519539
+ if (!isEditingStepCount && !isEditingMergeInstructions)
518829
519540
  return;
518830
519541
  if (key2.backspace || key2.delete) {
518831
- setStepCountInput((prev) => prev.slice(0, -1));
519542
+ if (isEditingStepCount) {
519543
+ setTrigger("step-count");
519544
+ setStepCountInput((prev) => prev.slice(0, -1));
519545
+ } else {
519546
+ setMergeInstructions((prev) => prev.slice(0, -1));
519547
+ }
518832
519548
  setValidationError(null);
518833
519549
  return;
518834
519550
  }
518835
519551
  if (input && input.length > 0 && !key2.ctrl && !key2.meta && !key2.tab && !key2.upArrow && !key2.downArrow && !key2.leftArrow && !key2.rightArrow) {
518836
- setStepCountInput((prev) => `${prev}${input}`);
519552
+ if (isEditingStepCount) {
519553
+ setTrigger("step-count");
519554
+ setStepCountInput((prev) => `${prev}${input}`);
519555
+ } else {
519556
+ setMergeInstructions((prev) => `${prev}${input}`);
519557
+ }
518837
519558
  setValidationError(null);
518838
519559
  }
518839
519560
  });
@@ -518851,79 +519572,73 @@ function SleeptimeSelector({
518851
519572
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
518852
519573
  height: 1
518853
519574
  }, undefined, false, undefined, this),
518854
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518855
- bold: true,
518856
- color: colors.selector.title,
518857
- children: "Configure your sleep-time (dream) settings"
518858
- }, undefined, false, undefined, this),
518859
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
518860
- height: 1
518861
- }, undefined, false, undefined, this),
518862
519575
  memfsEnabled ? /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(jsx_dev_runtime74.Fragment, {
518863
519576
  children: [
519577
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
519578
+ bold: true,
519579
+ color: colors.selector.title,
519580
+ children: "Dream Settings"
519581
+ }, undefined, false, undefined, this),
518864
519582
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
518865
- flexDirection: "row",
519583
+ height: 1
519584
+ }, undefined, false, undefined, this),
519585
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(ChoiceRow, {
519586
+ focused: focusRow === "trigger-off",
519587
+ selected: trigger === "off",
519588
+ children: " Off "
519589
+ }, undefined, false, undefined, this),
519590
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(ChoiceRow, {
519591
+ focused: focusRow === "trigger-step-count",
519592
+ selected: trigger === "step-count",
519593
+ children: ` Every [${stepCountInput}${isEditingStepCount ? "█" : ""}] steps `
519594
+ }, undefined, false, undefined, this),
519595
+ validationError && /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
519596
+ color: colors.error.text,
519597
+ children: ` Error: ${validationError}`
519598
+ }, undefined, false, undefined, this),
519599
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(ChoiceRow, {
519600
+ focused: focusRow === "trigger-compaction",
519601
+ selected: trigger === "compaction-event",
519602
+ children: " On compaction "
519603
+ }, undefined, false, undefined, this),
519604
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
519605
+ height: 1
519606
+ }, undefined, false, undefined, this),
519607
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
519608
+ bold: true,
519609
+ color: colors.selector.title,
519610
+ children: "Memory updates"
519611
+ }, undefined, false, undefined, this),
519612
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
519613
+ height: 1
519614
+ }, undefined, false, undefined, this),
519615
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(ChoiceRow, {
519616
+ focused: focusRow === "merge-auto",
519617
+ selected: merge3 === "auto",
519618
+ children: " Apply automatically "
519619
+ }, undefined, false, undefined, this),
519620
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(ChoiceRow, {
519621
+ focused: focusRow === "merge-explicit",
519622
+ selected: merge3 === "explicit",
519623
+ children: " Agent reviews before applying "
519624
+ }, undefined, false, undefined, this),
519625
+ merge3 === "explicit" && /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(jsx_dev_runtime74.Fragment, {
518866
519626
  children: [
518867
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518868
- children: focusRow === "trigger" ? "> " : " "
519627
+ /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
519628
+ height: 1
518869
519629
  }, undefined, false, undefined, this),
518870
519630
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518871
519631
  bold: true,
518872
- children: "Trigger event:"
518873
- }, undefined, false, undefined, this),
518874
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518875
- children: " "
518876
- }, undefined, false, undefined, this),
518877
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518878
- backgroundColor: trigger === "off" ? colors.selector.itemHighlighted : undefined,
518879
- color: trigger === "off" ? "black" : undefined,
518880
- bold: trigger === "off",
518881
- children: " Off "
518882
- }, undefined, false, undefined, this),
518883
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518884
- children: " "
518885
- }, undefined, false, undefined, this),
518886
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518887
- backgroundColor: trigger === "step-count" ? colors.selector.itemHighlighted : undefined,
518888
- color: trigger === "step-count" ? "black" : undefined,
518889
- bold: trigger === "step-count",
518890
- children: " Step count "
518891
- }, undefined, false, undefined, this),
518892
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518893
- children: " "
518894
- }, undefined, false, undefined, this),
518895
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518896
- backgroundColor: trigger === "compaction-event" ? colors.selector.itemHighlighted : undefined,
518897
- color: trigger === "compaction-event" ? "black" : undefined,
518898
- bold: trigger === "compaction-event",
518899
- children: " Compaction event "
518900
- }, undefined, false, undefined, this)
518901
- ]
518902
- }, undefined, true, undefined, this),
518903
- trigger === "step-count" && /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(jsx_dev_runtime74.Fragment, {
518904
- children: [
518905
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
518906
- height: 1
519632
+ children: " Review instructions"
518907
519633
  }, undefined, false, undefined, this),
518908
519634
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
518909
519635
  flexDirection: "row",
518910
519636
  children: [
518911
519637
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518912
- children: focusRow === "step-count" ? "> " : " "
518913
- }, undefined, false, undefined, this),
518914
- /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518915
- bold: true,
518916
- children: "Step count: "
519638
+ children: focusRow === "merge-instructions" ? "> " : " "
518917
519639
  }, undefined, false, undefined, this),
518918
519640
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518919
- children: stepCountInput
518920
- }, undefined, false, undefined, this),
518921
- isEditingStepCount && /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518922
- children: "█"
518923
- }, undefined, false, undefined, this),
518924
- validationError && /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518925
- color: colors.error.text,
518926
- children: ` (error: ${validationError})`
519641
+ children: `[${mergeInstructions}${isEditingMergeInstructions ? "█" : ""}]`
518927
519642
  }, undefined, false, undefined, this)
518928
519643
  ]
518929
519644
  }, undefined, true, undefined, this)
@@ -518934,13 +519649,13 @@ function SleeptimeSelector({
518934
519649
  }, undefined, false, undefined, this),
518935
519650
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518936
519651
  dimColor: true,
518937
- children: " Enter to save · ↑↓ rows · ←→/Tab options · Esc cancel"
519652
+ children: " Enter save · ↑↓/Tab move · Space select · ←→ options · Esc cancel"
518938
519653
  }, undefined, false, undefined, this)
518939
519654
  ]
518940
519655
  }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(jsx_dev_runtime74.Fragment, {
518941
519656
  children: [
518942
519657
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Text2, {
518943
- children: "Sleep-time reflection requires the memory filesystem (memfs) to be enabled for this agent."
519658
+ children: "Dream settings require the memory filesystem (MemFS) to be enabled for this agent."
518944
519659
  }, undefined, false, undefined, this),
518945
519660
  /* @__PURE__ */ jsx_dev_runtime74.jsxDEV(Box_default, {
518946
519661
  height: 1
@@ -518954,7 +519669,7 @@ function SleeptimeSelector({
518954
519669
  ]
518955
519670
  }, undefined, true, undefined, this);
518956
519671
  }
518957
- var import_react96, jsx_dev_runtime74, SOLID_LINE18 = "─", DEFAULT_STEP_COUNT2 = "25", TRIGGER_OPTIONS;
519672
+ var import_react96, jsx_dev_runtime74, SOLID_LINE18 = "─", DEFAULT_STEP_COUNT2 = "25", TRIGGER_OPTIONS, MERGE_OPTIONS;
518958
519673
  var init_SleeptimeSelector = __esm(async () => {
518959
519674
  init_use_terminal_width();
518960
519675
  init_colors();
@@ -518969,6 +519684,7 @@ var init_SleeptimeSelector = __esm(async () => {
518969
519684
  "step-count",
518970
519685
  "compaction-event"
518971
519686
  ];
519687
+ MERGE_OPTIONS = ["auto", "explicit"];
518972
519688
  });
518973
519689
 
518974
519690
  // src/cli/components/StatusMessage.tsx
@@ -519683,7 +520399,8 @@ function parseEnterWorktreeResult(text2) {
519683
520399
  `);
519684
520400
  const firstLine = normalized.split(`
519685
520401
  `).find((line) => line.trim());
519686
- if (firstLine?.trim() !== "Created worktree.") {
520402
+ const action3 = firstLine?.trim() === "Created worktree." ? "created" : firstLine?.trim() === "Switched to existing worktree." ? "switched" : null;
520403
+ if (!action3) {
519687
520404
  return null;
519688
520405
  }
519689
520406
  const field = (name) => {
@@ -519691,11 +520408,12 @@ function parseEnterWorktreeResult(text2) {
519691
520408
  return match4?.[1]?.trim();
519692
520409
  };
519693
520410
  const result = {
520411
+ action: action3,
519694
520412
  path: field("Path"),
519695
520413
  branch: field("Branch"),
519696
520414
  base: field("Base")
519697
520415
  };
519698
- if (normalized.includes("This conversation's working directory is now the new worktree.")) {
520416
+ if (normalized.includes("This conversation's working directory is now the new worktree.") || normalized.includes("This conversation's working directory is now this worktree.")) {
519699
520417
  result.switchedCwd = true;
519700
520418
  } else if (normalized.includes("The conversation working directory was left unchanged.")) {
519701
520419
  result.switchedCwd = false;
@@ -519775,7 +520493,7 @@ function EnterWorktreeResultRenderer({
519775
520493
  flexGrow: 1,
519776
520494
  width: contentWidth,
519777
520495
  children: /* @__PURE__ */ jsx_dev_runtime79.jsxDEV(Text2, {
519778
- children: "Created worktree"
520496
+ children: parsed.action === "created" ? "Created worktree" : "Switched to existing worktree"
519779
520497
  }, undefined, false, undefined, this)
519780
520498
  }, undefined, false, undefined, this)
519781
520499
  ]
@@ -520833,7 +521551,7 @@ var init_ToolCallMessageRich = __esm(async () => {
520833
521551
  let shellSemanticKind = null;
520834
521552
  let hasShellDescription = false;
520835
521553
  if (!isQuestionTool(rawName)) {
520836
- const parseArgs17 = () => {
521554
+ const parseArgs18 = () => {
520837
521555
  if (!argsText.trim()) {
520838
521556
  return { formatted: null, parseable: true };
520839
521557
  }
@@ -520847,7 +521565,7 @@ var init_ToolCallMessageRich = __esm(async () => {
520847
521565
  return { formatted: null, parseable: false };
520848
521566
  }
520849
521567
  };
520850
- const { formatted, parseable } = parseArgs17();
521568
+ const { formatted, parseable } = parseArgs18();
520851
521569
  const argsComplete = parseable || line.phase === "running" || line.phase === "finished" || !isStreaming;
520852
521570
  if (!argsComplete) {
520853
521571
  args = "(…)";
@@ -522407,9 +523125,9 @@ function getFileEditHeader(toolName, toolArgs) {
522407
523125
  } else if (operations.length === 1) {
522408
523126
  const op = operations[0];
522409
523127
  if (op) {
522410
- const { relative: relative19 } = __require("node:path");
523128
+ const { relative: relative18 } = __require("node:path");
522411
523129
  const cwd3 = process.cwd();
522412
- const relPath2 = relative19(cwd3, op.path);
523130
+ const relPath2 = relative18(cwd3, op.path);
522413
523131
  const displayPath3 = relPath2.startsWith("..") ? op.path : relPath2;
522414
523132
  if (op.kind === "add")
522415
523133
  return `Write to ${displayPath3}?`;
@@ -522423,14 +523141,14 @@ function getFileEditHeader(toolName, toolArgs) {
522423
523141
  return "Apply patch?";
522424
523142
  }
522425
523143
  const filePath = args.file_path || "";
522426
- const { relative: relative18 } = __require("node:path");
523144
+ const { relative: relative17 } = __require("node:path");
522427
523145
  const cwd2 = process.cwd();
522428
- const relPath = relative18(cwd2, filePath);
523146
+ const relPath = relative17(cwd2, filePath);
522429
523147
  const displayPath2 = relPath.startsWith("..") ? filePath : relPath;
522430
523148
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
522431
- const { existsSync: existsSync67 } = __require("node:fs");
523149
+ const { existsSync: existsSync68 } = __require("node:fs");
522432
523150
  try {
522433
- if (existsSync67(filePath)) {
523151
+ if (existsSync68(filePath)) {
522434
523152
  return `Overwrite ${displayPath2}?`;
522435
523153
  }
522436
523154
  } catch {}
@@ -522513,9 +523231,9 @@ var init_ApprovalPreview = __esm(async () => {
522513
523231
  /* @__PURE__ */ jsx_dev_runtime90.jsxDEV(Box_default, {
522514
523232
  flexDirection: "column",
522515
523233
  children: operations.map((op, idx) => {
522516
- const { relative: relative18 } = __require("node:path");
523234
+ const { relative: relative17 } = __require("node:path");
522517
523235
  const cwd2 = process.cwd();
522518
- const relPath = relative18(cwd2, op.path);
523236
+ const relPath = relative17(cwd2, op.path);
522519
523237
  const displayPath2 = relPath.startsWith("..") ? op.path : relPath;
522520
523238
  const diffKey = toolCallId ? `${toolCallId}:${op.path}` : undefined;
522521
523239
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -523064,7 +523782,7 @@ function updateCommandResult(buffersRef, refreshDerived, cmdId, input, output, s
523064
523782
  buffersRef.current.byId.set(cmdId, line);
523065
523783
  refreshDerived();
523066
523784
  }
523067
- function parseArgs17(msg) {
523785
+ function parseArgs18(msg) {
523068
523786
  return msg.trim().split(/\s+/).filter(Boolean);
523069
523787
  }
523070
523788
  function formatConnectUsage() {
@@ -523419,7 +524137,7 @@ ${formatBedrockUsage2()}`, false);
523419
524137
  }
523420
524138
  }
523421
524139
  async function handleConnect(ctx, msg) {
523422
- const parts = parseArgs17(msg);
524140
+ const parts = parseArgs18(msg);
523423
524141
  const providerToken = parts[1];
523424
524142
  if (!providerToken) {
523425
524143
  addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, formatConnectUsage(), false);
@@ -537770,9 +538488,9 @@ __export(exports_generate_diff_viewer, {
537770
538488
  generateAndOpenDiffViewer: () => generateAndOpenDiffViewer
537771
538489
  });
537772
538490
  import { execFile as execFileCb8 } from "node:child_process";
537773
- import { chmodSync as chmodSync8, existsSync as existsSync67, mkdirSync as mkdirSync48, writeFileSync as writeFileSync37 } from "node:fs";
538491
+ import { chmodSync as chmodSync8, existsSync as existsSync68, mkdirSync as mkdirSync48, writeFileSync as writeFileSync37 } from "node:fs";
537774
538492
  import { homedir as homedir52 } from "node:os";
537775
- import { isAbsolute as isAbsolute29, join as join88, resolve as resolve38 } from "node:path";
538493
+ import { isAbsolute as isAbsolute29, join as join89, resolve as resolve38 } from "node:path";
537776
538494
  import { promisify as promisify18 } from "node:util";
537777
538495
  async function runGit8(cwd2, args) {
537778
538496
  try {
@@ -537991,13 +538709,13 @@ async function generateAndOpenDiffViewer(targetPath) {
537991
538709
  };
537992
538710
  const jsonPayload = JSON.stringify(payload).replace(/</g, "\\u003c");
537993
538711
  const html5 = diff_viewer_template_default.replace("<!--LETTA_DIFF_DATA_PLACEHOLDER-->", () => jsonPayload);
537994
- if (!existsSync67(VIEWERS_DIR2)) {
538712
+ if (!existsSync68(VIEWERS_DIR2)) {
537995
538713
  mkdirSync48(VIEWERS_DIR2, { recursive: true, mode: 448 });
537996
538714
  }
537997
538715
  try {
537998
538716
  chmodSync8(VIEWERS_DIR2, 448);
537999
538717
  } catch {}
538000
- const filePath = join88(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
538718
+ const filePath = join89(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
538001
538719
  writeFileSync37(filePath, html5);
538002
538720
  chmodSync8(filePath, 384);
538003
538721
  const skipOpen = shouldSkipOpen();
@@ -538068,7 +538786,7 @@ var init_generate_diff_viewer = __esm(() => {
538068
538786
  init_ssr();
538069
538787
  init_diff_viewer_template();
538070
538788
  execFile20 = promisify18(execFileCb8);
538071
- VIEWERS_DIR2 = join88(homedir52(), ".letta", "viewers");
538789
+ VIEWERS_DIR2 = join89(homedir52(), ".letta", "viewers");
538072
538790
  GIT_MAX_BUFFER = 50 * 1024 * 1024;
538073
538791
  });
538074
538792
 
@@ -540056,12 +540774,12 @@ __export(exports_shell_aliases, {
540056
540774
  expandAliases: () => expandAliases,
540057
540775
  clearAliasCache: () => clearAliasCache
540058
540776
  });
540059
- import { existsSync as existsSync68, readFileSync as readFileSync43 } from "node:fs";
540777
+ import { existsSync as existsSync69, readFileSync as readFileSync43 } from "node:fs";
540060
540778
  import { homedir as homedir53 } from "node:os";
540061
- import { join as join89 } from "node:path";
540779
+ import { join as join90 } from "node:path";
540062
540780
  function parseAliasesFromFile(filePath) {
540063
540781
  const aliases = new Map;
540064
- if (!existsSync68(filePath)) {
540782
+ if (!existsSync69(filePath)) {
540065
540783
  return aliases;
540066
540784
  }
540067
540785
  try {
@@ -540130,7 +540848,7 @@ function loadAliases(forceReload = false) {
540130
540848
  const home = homedir53();
540131
540849
  const allAliases = new Map;
540132
540850
  for (const file3 of ALIAS_FILES) {
540133
- const filePath = join89(home, file3);
540851
+ const filePath = join90(home, file3);
540134
540852
  const fileAliases = parseAliasesFromFile(filePath);
540135
540853
  for (const [name, value] of fileAliases) {
540136
540854
  allAliases.set(name, value);
@@ -540312,13 +541030,14 @@ var init_use_bash_handlers = __esm(async () => {
540312
541030
 
540313
541031
  // src/cli/app/reflection.ts
540314
541032
  function formatReflectionSettings(settings3) {
541033
+ const memoryUpdates = settings3.merge === "explicit" ? "agent reviews before applying" : "apply automatically";
540315
541034
  if (settings3.trigger === "off") {
540316
- return "Off";
541035
+ return `Off, ${memoryUpdates}`;
540317
541036
  }
540318
541037
  if (settings3.trigger === "compaction-event") {
540319
- return "Compaction event";
541038
+ return `On compaction, ${memoryUpdates}`;
540320
541039
  }
540321
- return `Step count (every ${settings3.stepCount} turns)`;
541040
+ return `Every ${settings3.stepCount} steps, ${memoryUpdates}`;
540322
541041
  }
540323
541042
 
540324
541043
  // src/cli/app/use-configuration-handlers.ts
@@ -540472,7 +541191,7 @@ function useConfigurationHandlers(ctx) {
540472
541191
  const rawReasoningEffort = modelUpdateArgs?.reasoning_effort;
540473
541192
  const providerType = providerTypeFromUpdateArgs(modelUpdateArgs);
540474
541193
  const isOpenAICompatibleProxy = modelUpdateArgs?.[OPENAI_COMPATIBLE_PROXY_UPDATE_ARG] === true && providerType === "openai";
540475
- const usesDistinctXHighLabel = /Fable 5|Opus 4\.[78]|GPT-5\.6/.test(model2.label);
541194
+ const usesDistinctXHighLabel = /Fable 5|Opus 4\.[78]|Opus 5|Sonnet 5|GPT-5\.6/.test(model2.label);
540476
541195
  const reasoningLevel = isOpenAICompatibleProxy && rawReasoningEffort === null ? "default" : typeof rawReasoningEffort === "string" ? rawReasoningEffort === "none" ? "no" : rawReasoningEffort === "xhigh" ? usesDistinctXHighLabel ? "extra-high" : "max" : rawReasoningEffort : modelUpdateArgs?.enable_reasoner === false ? "no" : null;
540477
541196
  const selectedContextWindow = Number(model2.updateArgs?.context_window) || undefined;
540478
541197
  const capabilitiesMap = getCachedModelReasoningCapabilities();
@@ -543840,7 +544559,7 @@ var init_use_queued_approval_submit = __esm(() => {
543840
544559
 
543841
544560
  // src/cli/app/use-reasoning-cycle.ts
543842
544561
  function supportsDistinctAnthropicXHighEffort2(modelHandle) {
543843
- return modelHandle.includes("claude-fable-5") || modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
544562
+ return modelHandle.includes("claude-fable-5") || modelHandle.includes("claude-opus-5") || modelHandle.includes("claude-sonnet-5") || modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
543844
544563
  }
543845
544564
  function serviceTierForReasoningCycle(modelHandle, modelSettings) {
543846
544565
  if (!getChatGptFastRegistryHandleForModelHandle(modelHandle)) {
@@ -546424,7 +547143,7 @@ var init_mods2 = __esm(async () => {
546424
547143
  });
546425
547144
 
546426
547145
  // src/cli/helpers/chdir-command.ts
546427
- import { realpath as realpath6, stat as stat17 } from "node:fs/promises";
547146
+ import { realpath as realpath5, stat as stat17 } from "node:fs/promises";
546428
547147
  import { homedir as homedir54 } from "node:os";
546429
547148
  import path46 from "node:path";
546430
547149
  function parseChdirCommand(input) {
@@ -546462,7 +547181,7 @@ function expandHome(value) {
546462
547181
  async function resolveChdirTarget(pathArg, currentWorkingDirectory) {
546463
547182
  const expanded = expandHome(pathArg);
546464
547183
  const resolved = path46.isAbsolute(expanded) ? expanded : path46.resolve(currentWorkingDirectory, expanded);
546465
- const normalized = await realpath6(resolved);
547184
+ const normalized = await realpath5(resolved);
546466
547185
  const stats = await stat17(normalized);
546467
547186
  if (!stats.isDirectory()) {
546468
547187
  throw new Error(`Not a directory: ${normalized}`);
@@ -548252,7 +548971,7 @@ __export(exports_export, {
548252
548971
  packageSkills: () => packageSkills
548253
548972
  });
548254
548973
  import { readdir as readdir17, readFile as readFile32 } from "node:fs/promises";
548255
- import { relative as relative18, resolve as resolve39 } from "node:path";
548974
+ import { relative as relative17, resolve as resolve39 } from "node:path";
548256
548975
  async function packageSkills(agentId, skillsDir) {
548257
548976
  const skills = [];
548258
548977
  const skillNames = new Set;
@@ -548305,7 +549024,7 @@ async function readSkillFiles(skillDir) {
548305
549024
  await walk(fullPath);
548306
549025
  } else {
548307
549026
  const content = await readFile32(fullPath, "utf-8");
548308
- const relativePath = relative18(skillDir, fullPath).replace(/\\/g, "/");
549027
+ const relativePath = relative17(skillDir, fullPath).replace(/\\/g, "/");
548309
549028
  files[relativePath] = content;
548310
549029
  }
548311
549030
  }
@@ -548440,9 +549159,9 @@ var init_conversation_switch_alert = __esm(() => {
548440
549159
 
548441
549160
  // src/cli/app/use-submit-handler.ts
548442
549161
  import { randomUUID as randomUUID39 } from "node:crypto";
548443
- import { existsSync as existsSync69, readFileSync as readFileSync44, renameSync as renameSync8, writeFileSync as writeFileSync38 } from "node:fs";
549162
+ import { existsSync as existsSync70, readFileSync as readFileSync44, renameSync as renameSync8, writeFileSync as writeFileSync38 } from "node:fs";
548444
549163
  import { tmpdir as tmpdir12 } from "node:os";
548445
- import { join as join90 } from "node:path";
549164
+ import { join as join91 } from "node:path";
548446
549165
  async function findCustomCommandByName(commandName) {
548447
549166
  const { findCustomCommand: findCustomCommand2 } = await Promise.resolve().then(() => (init_custom(), exports_custom));
548448
549167
  return findCustomCommand2(commandName);
@@ -549137,10 +549856,10 @@ ${SYSTEM_REMINDER_CLOSE}`),
549137
549856
  try {
549138
549857
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
549139
549858
  const personaCandidates = [
549140
- join90(memoryRoot, "system", "persona.md"),
549141
- join90(memoryRoot, "memory", "system", "persona.md")
549859
+ join91(memoryRoot, "system", "persona.md"),
549860
+ join91(memoryRoot, "memory", "system", "persona.md")
549142
549861
  ];
549143
- const personaPath = personaCandidates.find((candidate) => existsSync69(candidate));
549862
+ const personaPath = personaCandidates.find((candidate) => existsSync70(candidate));
549144
549863
  if (personaPath) {
549145
549864
  const personaContent = readFileSync44(personaPath, "utf-8");
549146
549865
  setCurrentPersonalityId(detectPersonalityFromPersonaFile(personaContent));
@@ -549650,8 +550369,7 @@ Tip: Use /clear instead to clear the current message buffer.`;
549650
550369
  feedbackContext: {
549651
550370
  parentAgentName: agentName,
549652
550371
  parentAgentDescription: agentDescription,
549653
- surface: "letta_code_tui",
549654
- model: currentModelId
550372
+ surface: "letta_code_tui"
549655
550373
  },
549656
550374
  onReady: (message2, readyRun) => {
549657
550375
  appendTaskNotificationEvents([message2]);
@@ -549669,7 +550387,6 @@ Tip: Use /clear instead to clear the current message buffer.`;
549669
550387
  conversationId: compactConversationId,
549670
550388
  memfsEnabled: isActiveMemfsEnabled(agentId),
549671
550389
  triggerSource: "compaction-event",
549672
- skipPendingWorktreeReminderScan: true,
549673
550390
  description: AUTO_REFLECTION_DESCRIPTION,
549674
550391
  completionConversationId: () => conversationIdRef.current,
549675
550392
  recompileByConversation: systemPromptRecompileByConversationRef.current,
@@ -549680,8 +550397,7 @@ Tip: Use /clear instead to clear the current message buffer.`;
549680
550397
  feedbackContext: {
549681
550398
  parentAgentName: agentName,
549682
550399
  parentAgentDescription: agentDescription,
549683
- surface: "letta_code_tui",
549684
- model: currentModelId
550400
+ surface: "letta_code_tui"
549685
550401
  }
549686
550402
  });
549687
550403
  }
@@ -550020,11 +550736,11 @@ Path: ${memoryDir}`, true);
550020
550736
  setCommandRunning(true);
550021
550737
  try {
550022
550738
  const memoryDir = getScopedMemoryFilesystemRoot(agentId);
550023
- if (!existsSync69(memoryDir)) {
550739
+ if (!existsSync70(memoryDir)) {
550024
550740
  updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
550025
550741
  return { submitted: true };
550026
550742
  }
550027
- const backupDir = join90(tmpdir12(), `letta-memfs-reset-${agentId}-${Date.now()}`);
550743
+ const backupDir = join91(tmpdir12(), `letta-memfs-reset-${agentId}-${Date.now()}`);
550028
550744
  renameSync8(memoryDir, backupDir);
550029
550745
  if (getBackend().capabilities.localMemfs) {
550030
550746
  const { initializeLocalMemoryRepo: initializeLocalMemoryRepo2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
@@ -550193,8 +550909,7 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550193
550909
  feedbackContext: {
550194
550910
  parentAgentName: agentName,
550195
550911
  parentAgentDescription: agentDescription,
550196
- surface: "letta_code_tui",
550197
- model: currentModelId
550912
+ surface: "letta_code_tui"
550198
550913
  },
550199
550914
  onReady: (message2, readyRun) => {
550200
550915
  appendTaskNotificationEvents([message2]);
@@ -550242,8 +550957,7 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550242
550957
  feedbackContext: {
550243
550958
  parentAgentName: agentName,
550244
550959
  parentAgentDescription: agentDescription,
550245
- surface: "letta_code_tui",
550246
- model: currentModelId
550960
+ surface: "letta_code_tui"
550247
550961
  },
550248
550962
  onReady: (message2, readyRun) => {
550249
550963
  appendTaskNotificationEvents([message2]);
@@ -550254,7 +550968,7 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550254
550968
  }
550255
550969
  });
550256
550970
  if (!arenaResult.launched) {
550257
- cmd.fail("No new transcript content to reflect on.");
550971
+ cmd.fail(getReflectionLaunchSkippedMessage(arenaResult.reason) ?? "Failed to start reflection arena.");
550258
550972
  return { submitted: true };
550259
550973
  }
550260
550974
  cmd.finish(`Started reflection arena run ${arenaResult.run.runId}. View the transcript payload here: ${arenaResult.payloadPath}`, true);
@@ -550276,17 +550990,13 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550276
550990
  feedbackContext: {
550277
550991
  parentAgentName: agentName,
550278
550992
  parentAgentDescription: agentDescription,
550279
- surface: "letta_code_tui",
550280
- model: currentModelId
550993
+ surface: "letta_code_tui"
550281
550994
  }
550282
550995
  });
550283
550996
  if (!result2.launched) {
550284
- if (result2.reason === "already_active") {
550285
- cmd.fail("A reflection agent is already running in the background.");
550286
- } else if (result2.reason === "no_payload") {
550287
- cmd.fail("No new transcript content to reflect on.");
550288
- } else if (result2.reason === "memfs_disabled") {
550289
- cmd.fail("Memory filesystem is not enabled. Use /remember instead.");
550997
+ const skippedMessage = getReflectionLaunchSkippedMessage(result2.reason);
550998
+ if (skippedMessage) {
550999
+ cmd.fail(skippedMessage);
550290
551000
  } else {
550291
551001
  const errorDetails = formatErrorDetails2(result2.error ?? "Unknown error", agentId);
550292
551002
  cmd.fail(`Failed to start reflection agent: ${errorDetails}`);
@@ -550380,13 +551090,15 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550380
551090
  onComplete: async ({
550381
551091
  success: reflectionSuccess,
550382
551092
  error: reflectionError,
550383
- agentId: reflectionAgentId2
551093
+ agentId: reflectionAgentId2,
551094
+ model: reflectionModel
550384
551095
  }) => {
550385
551096
  try {
550386
551097
  telemetry.trackReflectionEnd("manual", reflectionSuccess, {
550387
551098
  subagentId: reflectionAgentId2 ?? undefined,
550388
551099
  conversationId: reflectionConversationId,
550389
- error: reflectionError
551100
+ error: reflectionError,
551101
+ model: reflectionModel
550390
551102
  });
550391
551103
  const { completionSuccess, completionMessage } = await finalizeReflectionMemoryWorktreeLaunch({
550392
551104
  worktree: worktree2,
@@ -550395,6 +551107,9 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550395
551107
  agentId,
550396
551108
  conversationId: conversationIdRef.current,
550397
551109
  subagentAgentId: reflectionAgentId2 ?? undefined,
551110
+ model: reflectionModel,
551111
+ ...getReflectionMergeLaunchOptions(agentId),
551112
+ telemetryContext: { triggerSource: "manual" },
550398
551113
  recompileByConversation: systemPromptRecompileByConversationRef.current,
550399
551114
  recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current,
550400
551115
  logRecompileFailure: (message2) => debugWarn("memory", message2)
@@ -550470,13 +551185,15 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550470
551185
  onComplete: async ({
550471
551186
  success: success2,
550472
551187
  error: error54,
550473
- agentId: reflectionAgentId2
551188
+ agentId: reflectionAgentId2,
551189
+ model: reflectionModel
550474
551190
  }) => {
550475
551191
  try {
550476
551192
  telemetry.trackReflectionEnd("manual", success2, {
550477
551193
  subagentId: reflectionAgentId2 ?? undefined,
550478
551194
  conversationId: reflectionConversationId,
550479
- error: error54
551195
+ error: error54,
551196
+ model: reflectionModel
550480
551197
  });
550481
551198
  const { completionSuccess, completionMessage } = await finalizeReflectionMemoryWorktreeLaunch({
550482
551199
  worktree,
@@ -550485,6 +551202,9 @@ Resumed reflection arena choice prompt for run ${run2.runId}.`, true);
550485
551202
  agentId,
550486
551203
  conversationId: conversationIdRef.current,
550487
551204
  subagentAgentId: reflectionAgentId2 ?? undefined,
551205
+ model: reflectionModel,
551206
+ ...getReflectionMergeLaunchOptions(agentId),
551207
+ telemetryContext: { triggerSource: "manual" },
550488
551208
  recompileByConversation: systemPromptRecompileByConversationRef.current,
550489
551209
  recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current,
550490
551210
  logRecompileFailure: (message2) => debugWarn("memory", message2)
@@ -550975,7 +551695,7 @@ var init_use_submit_handler = __esm(async () => {
550975
551695
  });
550976
551696
 
550977
551697
  // src/cli/app/AppCoordinator.tsx
550978
- import { join as join91 } from "node:path";
551698
+ import { join as join92 } from "node:path";
550979
551699
  function buildStartupCommandHints(options3) {
550980
551700
  const {
550981
551701
  isResumingConversation,
@@ -552282,7 +553002,7 @@ function App2({
552282
553002
  agentId: a2.agentId ?? null
552283
553003
  }))
552284
553004
  });
552285
- const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join91(modContext.memfs.memoryDir, "mods") : null;
553005
+ const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join92(modContext.memfs.memoryDir, "mods") : null;
552286
553006
  const modAdapter = useLocalModAdapter(modContext, {
552287
553007
  agentModsDirectory,
552288
553008
  disabled: modsDisabled
@@ -553060,9 +553780,9 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
553060
553780
  (async () => {
553061
553781
  try {
553062
553782
  const { watch: watch3 } = await import("node:fs");
553063
- const { existsSync: existsSync70 } = await import("node:fs");
553783
+ const { existsSync: existsSync71 } = await import("node:fs");
553064
553784
  const memRoot = getScopedMemoryFilesystemRoot(agentId);
553065
- if (!existsSync70(memRoot))
553785
+ if (!existsSync71(memRoot))
553066
553786
  return;
553067
553787
  watcher2 = watch3(memRoot, { recursive: true }, () => {});
553068
553788
  memfsWatcherRef.current = watcher2;
@@ -553097,10 +553817,6 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
553097
553817
  reflectionSettings: reflectionSettings2,
553098
553818
  reminderState: sharedReminderStateRef.current,
553099
553819
  contextTracker: contextTrackerRef.current,
553100
- onCompaction: () => queuePendingReflectionWorktreeReminders({
553101
- agentId: reflectionAgentId,
553102
- conversationId: conversationIdRef.current ?? "default"
553103
- }),
553104
553820
  launch: async (triggerSource) => {
553105
553821
  if (experimentManager.isEnabled("reflection_arena")) {
553106
553822
  const arenaResult = await launchReflectionArena({
@@ -553114,8 +553830,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
553114
553830
  feedbackContext: {
553115
553831
  parentAgentName: agentName,
553116
553832
  parentAgentDescription: agentDescription,
553117
- surface: "letta_code_tui",
553118
- model: currentModelId
553833
+ surface: "letta_code_tui"
553119
553834
  },
553120
553835
  onReady: (message, readyRun) => {
553121
553836
  appendTaskNotificationEvents([message]);
@@ -553132,7 +553847,6 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
553132
553847
  conversationId: conversationIdRef.current ?? "default",
553133
553848
  memfsEnabled: isActiveMemfsEnabled(reflectionAgentId),
553134
553849
  triggerSource,
553135
- skipPendingWorktreeReminderScan: triggerSource === "compaction-event",
553136
553850
  reflectionSettings: reflectionSettings2,
553137
553851
  description: AUTO_REFLECTION_DESCRIPTION,
553138
553852
  completionConversationId: () => conversationIdRef.current,
@@ -553144,8 +553858,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
553144
553858
  feedbackContext: {
553145
553859
  parentAgentName: agentName,
553146
553860
  parentAgentDescription: agentDescription,
553147
- surface: "letta_code_tui",
553148
- model: currentModelId
553861
+ surface: "letta_code_tui"
553149
553862
  }
553150
553863
  });
553151
553864
  return result.launched;
@@ -553154,12 +553867,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
553154
553867
  } catch (error54) {
553155
553868
  debugWarn("memory", `Failed to evaluate post-turn reflection: ${error54 instanceof Error ? error54.message : String(error54)}`);
553156
553869
  }
553157
- }, [
553158
- agentName,
553159
- agentDescription,
553160
- currentModelId,
553161
- appendTaskNotificationEvents
553162
- ]);
553870
+ }, [agentName, agentDescription, appendTaskNotificationEvents]);
553163
553871
  const processConversation = useConversationLoop({
553164
553872
  abortControllerRef,
553165
553873
  agentIdRef,
@@ -554640,12 +555348,12 @@ EXAMPLES
554640
555348
  console.log(usage);
554641
555349
  }
554642
555350
  async function printInfo() {
554643
- const { join: join92 } = await import("node:path");
555351
+ const { join: join93 } = await import("node:path");
554644
555352
  const { getVersion: getVersion2 } = await Promise.resolve().then(() => (init_version(), exports_version));
554645
555353
  const { SKILLS_DIR: SKILLS_DIR2 } = await Promise.resolve().then(() => (init_skills3(), exports_skills2));
554646
555354
  const { exists: exists2 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
554647
555355
  const cwd2 = process.cwd();
554648
- const skillsDir = join92(cwd2, SKILLS_DIR2);
555356
+ const skillsDir = join93(cwd2, SKILLS_DIR2);
554649
555357
  const skillsExist = exists2(skillsDir);
554650
555358
  await settingsManager.loadLocalProjectSettings(cwd2);
554651
555359
  const pinned = settingsManager.getPinnedAgents();
@@ -555099,40 +555807,18 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
555099
555807
  }
555100
555808
  }
555101
555809
  try {
555102
- validateFlagConflicts({
555103
- guard: specifiedConversationId && specifiedConversationId !== "default",
555104
- checks: [
555105
- {
555106
- when: specifiedAgentId,
555107
- message: "--conversation cannot be used with --agent"
555108
- },
555109
- {
555110
- when: specifiedAgentName,
555111
- message: "--conversation cannot be used with --name"
555112
- },
555113
- {
555114
- when: forceNew,
555115
- message: "--conversation cannot be used with --new-agent"
555116
- },
555117
- {
555118
- when: fromAfFile,
555119
- message: "--conversation cannot be used with --import"
555120
- },
555121
- {
555122
- when: shouldResume,
555123
- message: "--conversation cannot be used with --resume"
555124
- }
555125
- ]
555126
- });
555127
- validateFlagConflicts({
555128
- guard: forceNewConversation,
555129
- checks: [
555130
- {
555131
- when: specifiedConversationId,
555132
- message: "--new cannot be used with --conversation"
555133
- },
555134
- { when: shouldResume, message: "--new cannot be used with --resume" }
555135
- ]
555810
+ validatePrimaryStartupFlagConflicts({
555811
+ specifiedConversationId,
555812
+ specifiedAgentId,
555813
+ specifiedAgentName,
555814
+ forceNewAgent: forceNew,
555815
+ forceNewConversation,
555816
+ importFile: fromAfFile,
555817
+ shouldResume,
555818
+ stateless: values2.stateless,
555819
+ isHeadless,
555820
+ memfs: memfsFlag,
555821
+ memfsStartup: values2["memfs-startup"]
555136
555822
  });
555137
555823
  } catch (error54) {
555138
555824
  console.error(error54 instanceof Error ? `Error: ${error54.message}` : String(error54));
@@ -555176,9 +555862,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
555176
555862
  }
555177
555863
  } else {
555178
555864
  const { resolve: resolve40 } = await import("node:path");
555179
- const { existsSync: existsSync70 } = await import("node:fs");
555865
+ const { existsSync: existsSync71 } = await import("node:fs");
555180
555866
  const resolvedPath = resolve40(fromAfFile);
555181
- if (!existsSync70(resolvedPath)) {
555867
+ if (!existsSync71(resolvedPath)) {
555182
555868
  console.error(`Error: AgentFile not found: ${resolvedPath}`);
555183
555869
  process.exit(1);
555184
555870
  }
@@ -558301,4 +558987,4 @@ function registerBunOAuthFlows() {
558301
558987
  registerBunOAuthFlows();
558302
558988
  await init_src5().then(() => exports_src2);
558303
558989
 
558304
- //# debugId=4E0E0DC994DF7B4864756E2164756E21
558990
+ //# debugId=AF6DD74653AB022F64756E2164756E21