@letta-ai/letta-code 0.27.7 → 0.27.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/letta.js CHANGED
@@ -5087,7 +5087,7 @@ var package_default;
5087
5087
  var init_package = __esm(() => {
5088
5088
  package_default = {
5089
5089
  name: "@letta-ai/letta-code",
5090
- version: "0.27.7",
5090
+ version: "0.27.8",
5091
5091
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5092
5092
  type: "module",
5093
5093
  packageManager: "bun@1.3.0",
@@ -5168,6 +5168,7 @@ var init_package = __esm(() => {
5168
5168
  "check:filename-casing": "node scripts/check-filename-casing.js",
5169
5169
  "check:test-mock-isolation": "bun run scripts/check-test-mock-isolation.js",
5170
5170
  "check:test-coverage": "node scripts/check-test-coverage.cjs",
5171
+ "check:bundled-skill-scripts": "node scripts/check-bundled-skill-scripts.js",
5171
5172
  check: "bun run scripts/check.js",
5172
5173
  dev: "LETTA_DEBUG=${LETTA_DEBUG:-1} LETTA_RESPONSES_WS=${LETTA_RESPONSES_WS:-1} bun --loader=.md:text --loader=.mdx:text --loader=.txt:text run src/index.ts",
5173
5174
  build: "node scripts/postinstall-patches.js && bun run build.js",
@@ -144416,20 +144417,19 @@ var init_models7 = __esm(() => {
144416
144417
  handle: "letta/auto",
144417
144418
  label: "Auto",
144418
144419
  description: "Automatically select the best model",
144419
- isFeatured: true,
144420
144420
  free: true,
144421
144421
  updateArgs: {
144422
144422
  context_window: 140000,
144423
144423
  max_output_tokens: 28000,
144424
144424
  parallel_tool_calls: true
144425
- }
144425
+ },
144426
+ isFeatured: true
144426
144427
  },
144427
144428
  {
144428
144429
  id: "auto-fast",
144429
144430
  handle: "letta/auto-fast",
144430
144431
  label: "Auto Fast",
144431
144432
  description: "Automatically select the best fast model",
144432
- isFeatured: true,
144433
144433
  free: true,
144434
144434
  updateArgs: {
144435
144435
  context_window: 140000,
@@ -144442,19 +144442,303 @@ var init_models7 = __esm(() => {
144442
144442
  handle: "letta/auto-chat",
144443
144443
  label: "Auto Chat",
144444
144444
  description: "Automatically select the best model for chat",
144445
- isFeatured: true,
144446
144445
  free: true,
144447
144446
  updateArgs: {
144448
144447
  context_window: 140000,
144449
144448
  max_output_tokens: 28000,
144450
144449
  parallel_tool_calls: true
144450
+ },
144451
+ isFeatured: true
144452
+ },
144453
+ {
144454
+ id: "fable",
144455
+ handle: "anthropic/claude-fable-5",
144456
+ label: "Fable 5",
144457
+ description: "Fable 5 (high reasoning)",
144458
+ isFeatured: true,
144459
+ updateArgs: {
144460
+ context_window: 1e6,
144461
+ max_output_tokens: 128000,
144462
+ enable_reasoner: true,
144463
+ reasoning_effort: "high",
144464
+ parallel_tool_calls: true
144465
+ }
144466
+ },
144467
+ {
144468
+ id: "fable-low",
144469
+ handle: "anthropic/claude-fable-5",
144470
+ label: "Fable 5",
144471
+ description: "Fable 5 (low reasoning)",
144472
+ updateArgs: {
144473
+ context_window: 1e6,
144474
+ max_output_tokens: 128000,
144475
+ enable_reasoner: true,
144476
+ reasoning_effort: "low",
144477
+ max_reasoning_tokens: 4000,
144478
+ parallel_tool_calls: true
144479
+ }
144480
+ },
144481
+ {
144482
+ id: "fable-medium",
144483
+ handle: "anthropic/claude-fable-5",
144484
+ label: "Fable 5",
144485
+ description: "Fable 5 (med reasoning)",
144486
+ updateArgs: {
144487
+ context_window: 1e6,
144488
+ max_output_tokens: 128000,
144489
+ enable_reasoner: true,
144490
+ reasoning_effort: "medium",
144491
+ max_reasoning_tokens: 12000,
144492
+ parallel_tool_calls: true
144493
+ }
144494
+ },
144495
+ {
144496
+ id: "fable-xhigh",
144497
+ handle: "anthropic/claude-fable-5",
144498
+ label: "Fable 5",
144499
+ description: "Fable 5 (extra-high reasoning)",
144500
+ updateArgs: {
144501
+ context_window: 1e6,
144502
+ max_output_tokens: 128000,
144503
+ enable_reasoner: true,
144504
+ reasoning_effort: "xhigh",
144505
+ parallel_tool_calls: true
144506
+ }
144507
+ },
144508
+ {
144509
+ id: "fable-max",
144510
+ handle: "anthropic/claude-fable-5",
144511
+ label: "Fable 5",
144512
+ description: "Fable 5 (max reasoning)",
144513
+ updateArgs: {
144514
+ context_window: 1e6,
144515
+ max_output_tokens: 128000,
144516
+ enable_reasoner: true,
144517
+ reasoning_effort: "max",
144518
+ parallel_tool_calls: true
144519
+ }
144520
+ },
144521
+ {
144522
+ id: "opus",
144523
+ handle: "anthropic/claude-opus-4-8",
144524
+ label: "Opus 4.8",
144525
+ description: "Opus 4.8 (high reasoning)",
144526
+ isFeatured: true,
144527
+ updateArgs: {
144528
+ context_window: 200000,
144529
+ max_output_tokens: 128000,
144530
+ reasoning_effort: "high",
144531
+ enable_reasoner: true,
144532
+ parallel_tool_calls: true
144533
+ }
144534
+ },
144535
+ {
144536
+ id: "opus-4.8-low",
144537
+ handle: "anthropic/claude-opus-4-8",
144538
+ label: "Opus 4.8",
144539
+ description: "Opus 4.8 (low reasoning)",
144540
+ updateArgs: {
144541
+ context_window: 200000,
144542
+ max_output_tokens: 128000,
144543
+ reasoning_effort: "low",
144544
+ enable_reasoner: true,
144545
+ max_reasoning_tokens: 4000,
144546
+ parallel_tool_calls: true
144547
+ }
144548
+ },
144549
+ {
144550
+ id: "opus-4.8-medium",
144551
+ handle: "anthropic/claude-opus-4-8",
144552
+ label: "Opus 4.8",
144553
+ description: "Opus 4.8 (med reasoning)",
144554
+ updateArgs: {
144555
+ context_window: 200000,
144556
+ max_output_tokens: 128000,
144557
+ reasoning_effort: "medium",
144558
+ enable_reasoner: true,
144559
+ max_reasoning_tokens: 12000,
144560
+ parallel_tool_calls: true
144561
+ }
144562
+ },
144563
+ {
144564
+ id: "opus-4.8-high",
144565
+ handle: "anthropic/claude-opus-4-8",
144566
+ label: "Opus 4.8",
144567
+ description: "Opus 4.8 (high reasoning)",
144568
+ updateArgs: {
144569
+ context_window: 200000,
144570
+ max_output_tokens: 128000,
144571
+ reasoning_effort: "high",
144572
+ enable_reasoner: true,
144573
+ parallel_tool_calls: true
144574
+ }
144575
+ },
144576
+ {
144577
+ id: "opus-4.8-xhigh",
144578
+ handle: "anthropic/claude-opus-4-8",
144579
+ label: "Opus 4.8",
144580
+ description: "Opus 4.8 (extra-high reasoning)",
144581
+ updateArgs: {
144582
+ context_window: 200000,
144583
+ max_output_tokens: 128000,
144584
+ reasoning_effort: "xhigh",
144585
+ enable_reasoner: true,
144586
+ parallel_tool_calls: true
144587
+ }
144588
+ },
144589
+ {
144590
+ id: "opus-4.8-max",
144591
+ handle: "anthropic/claude-opus-4-8",
144592
+ label: "Opus 4.8",
144593
+ description: "Opus 4.8 (max reasoning)",
144594
+ updateArgs: {
144595
+ context_window: 200000,
144596
+ max_output_tokens: 128000,
144597
+ reasoning_effort: "max",
144598
+ enable_reasoner: true,
144599
+ parallel_tool_calls: true
144600
+ }
144601
+ },
144602
+ {
144603
+ id: "opus-4.8-1m",
144604
+ handle: "anthropic/claude-opus-4-8",
144605
+ label: "Opus 4.8 1M",
144606
+ description: "Claude Opus 4.8 with 1M token context window (high reasoning)",
144607
+ updateArgs: {
144608
+ context_window: 950000,
144609
+ max_output_tokens: 128000,
144610
+ reasoning_effort: "high",
144611
+ enable_reasoner: true,
144612
+ parallel_tool_calls: true
144613
+ },
144614
+ isFeatured: true
144615
+ },
144616
+ {
144617
+ id: "opus-4.8-1m-no-reasoning",
144618
+ handle: "anthropic/claude-opus-4-8",
144619
+ label: "Opus 4.8 1M",
144620
+ description: "Opus 4.8 1M with no reasoning (faster)",
144621
+ updateArgs: {
144622
+ context_window: 950000,
144623
+ max_output_tokens: 128000,
144624
+ reasoning_effort: "none",
144625
+ enable_reasoner: false,
144626
+ parallel_tool_calls: true
144627
+ }
144628
+ },
144629
+ {
144630
+ id: "opus-4.8-1m-low",
144631
+ handle: "anthropic/claude-opus-4-8",
144632
+ label: "Opus 4.8 1M",
144633
+ description: "Opus 4.8 1M (low reasoning)",
144634
+ updateArgs: {
144635
+ context_window: 950000,
144636
+ max_output_tokens: 128000,
144637
+ reasoning_effort: "low",
144638
+ enable_reasoner: true,
144639
+ parallel_tool_calls: true,
144640
+ max_reasoning_tokens: 4000
144641
+ }
144642
+ },
144643
+ {
144644
+ id: "opus-4.8-1m-medium",
144645
+ handle: "anthropic/claude-opus-4-8",
144646
+ label: "Opus 4.8 1M",
144647
+ description: "Opus 4.8 1M (med reasoning)",
144648
+ updateArgs: {
144649
+ context_window: 950000,
144650
+ max_output_tokens: 128000,
144651
+ reasoning_effort: "medium",
144652
+ enable_reasoner: true,
144653
+ parallel_tool_calls: true,
144654
+ max_reasoning_tokens: 12000
144655
+ }
144656
+ },
144657
+ {
144658
+ id: "opus-4.8-1m-xhigh",
144659
+ handle: "anthropic/claude-opus-4-8",
144660
+ label: "Opus 4.8 1M",
144661
+ description: "Opus 4.8 1M (max reasoning)",
144662
+ updateArgs: {
144663
+ context_window: 950000,
144664
+ max_output_tokens: 128000,
144665
+ reasoning_effort: "xhigh",
144666
+ enable_reasoner: true,
144667
+ parallel_tool_calls: true
144668
+ }
144669
+ },
144670
+ {
144671
+ id: "opus-1m",
144672
+ handle: "anthropic/claude-opus-4-6",
144673
+ label: "Opus 4.6 1M",
144674
+ description: "Claude Opus 4.6 with 1M token context window (high reasoning)",
144675
+ updateArgs: {
144676
+ context_window: 950000,
144677
+ max_output_tokens: 128000,
144678
+ reasoning_effort: "high",
144679
+ enable_reasoner: true,
144680
+ parallel_tool_calls: true
144681
+ }
144682
+ },
144683
+ {
144684
+ id: "opus-1m-no-reasoning",
144685
+ handle: "anthropic/claude-opus-4-6",
144686
+ label: "Opus 4.6 1M",
144687
+ description: "Opus 4.6 1M with no reasoning (faster)",
144688
+ updateArgs: {
144689
+ context_window: 950000,
144690
+ max_output_tokens: 128000,
144691
+ reasoning_effort: "none",
144692
+ enable_reasoner: false,
144693
+ parallel_tool_calls: true
144694
+ }
144695
+ },
144696
+ {
144697
+ id: "opus-1m-low",
144698
+ handle: "anthropic/claude-opus-4-6",
144699
+ label: "Opus 4.6 1M",
144700
+ description: "Opus 4.6 1M (low reasoning)",
144701
+ updateArgs: {
144702
+ context_window: 950000,
144703
+ max_output_tokens: 128000,
144704
+ reasoning_effort: "low",
144705
+ enable_reasoner: true,
144706
+ max_reasoning_tokens: 4000,
144707
+ parallel_tool_calls: true
144708
+ }
144709
+ },
144710
+ {
144711
+ id: "opus-1m-medium",
144712
+ handle: "anthropic/claude-opus-4-6",
144713
+ label: "Opus 4.6 1M",
144714
+ description: "Opus 4.6 1M (med reasoning)",
144715
+ updateArgs: {
144716
+ context_window: 950000,
144717
+ max_output_tokens: 128000,
144718
+ reasoning_effort: "medium",
144719
+ enable_reasoner: true,
144720
+ max_reasoning_tokens: 12000,
144721
+ parallel_tool_calls: true
144722
+ }
144723
+ },
144724
+ {
144725
+ id: "opus-1m-xhigh",
144726
+ handle: "anthropic/claude-opus-4-6",
144727
+ label: "Opus 4.6 1M",
144728
+ description: "Opus 4.6 1M (max reasoning)",
144729
+ updateArgs: {
144730
+ context_window: 950000,
144731
+ max_output_tokens: 128000,
144732
+ reasoning_effort: "xhigh",
144733
+ enable_reasoner: true,
144734
+ parallel_tool_calls: true
144451
144735
  }
144452
144736
  },
144453
144737
  {
144454
144738
  id: "sonnet",
144455
144739
  handle: "anthropic/claude-sonnet-4-6",
144456
144740
  label: "Sonnet 4.6",
144457
- description: "Anthropic's new Sonnet model (high reasoning)",
144741
+ description: "Sonnet 4.6 (high reasoning)",
144458
144742
  isFeatured: true,
144459
144743
  updateArgs: {
144460
144744
  context_window: 200000,
@@ -144590,8 +144874,7 @@ var init_models7 = __esm(() => {
144590
144874
  id: "opus-4.6-high",
144591
144875
  handle: "anthropic/claude-opus-4-6",
144592
144876
  label: "Opus 4.6",
144593
- description: "Anthropic's (legacy) best model (high reasoning)",
144594
- isFeatured: true,
144877
+ description: "Opus 4.6 (high reasoning)",
144595
144878
  updateArgs: {
144596
144879
  context_window: 200000,
144597
144880
  max_output_tokens: 128000,
@@ -144654,87 +144937,6 @@ var init_models7 = __esm(() => {
144654
144937
  parallel_tool_calls: true
144655
144938
  }
144656
144939
  },
144657
- {
144658
- id: "opus",
144659
- handle: "anthropic/claude-opus-4-8",
144660
- label: "Opus 4.8",
144661
- description: "Anthropic's best model (high reasoning)",
144662
- isFeatured: true,
144663
- updateArgs: {
144664
- context_window: 200000,
144665
- max_output_tokens: 128000,
144666
- reasoning_effort: "high",
144667
- enable_reasoner: true,
144668
- parallel_tool_calls: true
144669
- }
144670
- },
144671
- {
144672
- id: "opus-4.8-low",
144673
- handle: "anthropic/claude-opus-4-8",
144674
- label: "Opus 4.8",
144675
- description: "Opus 4.8 (low reasoning)",
144676
- updateArgs: {
144677
- context_window: 200000,
144678
- max_output_tokens: 128000,
144679
- reasoning_effort: "low",
144680
- enable_reasoner: true,
144681
- max_reasoning_tokens: 4000,
144682
- parallel_tool_calls: true
144683
- }
144684
- },
144685
- {
144686
- id: "opus-4.8-medium",
144687
- handle: "anthropic/claude-opus-4-8",
144688
- label: "Opus 4.8",
144689
- description: "Opus 4.8 (med reasoning)",
144690
- updateArgs: {
144691
- context_window: 200000,
144692
- max_output_tokens: 128000,
144693
- reasoning_effort: "medium",
144694
- enable_reasoner: true,
144695
- max_reasoning_tokens: 12000,
144696
- parallel_tool_calls: true
144697
- }
144698
- },
144699
- {
144700
- id: "opus-4.8-high",
144701
- handle: "anthropic/claude-opus-4-8",
144702
- label: "Opus 4.8",
144703
- description: "Opus 4.8 (high reasoning)",
144704
- updateArgs: {
144705
- context_window: 200000,
144706
- max_output_tokens: 128000,
144707
- reasoning_effort: "high",
144708
- enable_reasoner: true,
144709
- parallel_tool_calls: true
144710
- }
144711
- },
144712
- {
144713
- id: "opus-4.8-xhigh",
144714
- handle: "anthropic/claude-opus-4-8",
144715
- label: "Opus 4.8",
144716
- description: "Opus 4.8 (extra-high reasoning)",
144717
- updateArgs: {
144718
- context_window: 200000,
144719
- max_output_tokens: 128000,
144720
- reasoning_effort: "xhigh",
144721
- enable_reasoner: true,
144722
- parallel_tool_calls: true
144723
- }
144724
- },
144725
- {
144726
- id: "opus-4.8-max",
144727
- handle: "anthropic/claude-opus-4-8",
144728
- label: "Opus 4.8",
144729
- description: "Opus 4.8 (max reasoning)",
144730
- updateArgs: {
144731
- context_window: 200000,
144732
- max_output_tokens: 128000,
144733
- reasoning_effort: "max",
144734
- enable_reasoner: true,
144735
- parallel_tool_calls: true
144736
- }
144737
- },
144738
144940
  {
144739
144941
  id: "opus-4.7-medium",
144740
144942
  handle: "anthropic/claude-opus-4-7",
@@ -144802,79 +145004,11 @@ var init_models7 = __esm(() => {
144802
145004
  parallel_tool_calls: true
144803
145005
  }
144804
145006
  },
144805
- {
144806
- id: "opus-1m",
144807
- handle: "anthropic/claude-opus-4-6",
144808
- label: "Opus 4.6 1M",
144809
- description: "Claude Opus 4.6 with 1M token context window (high reasoning)",
144810
- isFeatured: true,
144811
- updateArgs: {
144812
- context_window: 950000,
144813
- max_output_tokens: 128000,
144814
- reasoning_effort: "high",
144815
- enable_reasoner: true,
144816
- parallel_tool_calls: true
144817
- }
144818
- },
144819
- {
144820
- id: "opus-1m-no-reasoning",
144821
- handle: "anthropic/claude-opus-4-6",
144822
- label: "Opus 4.6 1M",
144823
- description: "Opus 4.6 1M with no reasoning (faster)",
144824
- updateArgs: {
144825
- context_window: 950000,
144826
- max_output_tokens: 128000,
144827
- reasoning_effort: "none",
144828
- enable_reasoner: false,
144829
- parallel_tool_calls: true
144830
- }
144831
- },
144832
- {
144833
- id: "opus-1m-low",
144834
- handle: "anthropic/claude-opus-4-6",
144835
- label: "Opus 4.6 1M",
144836
- description: "Opus 4.6 1M (low reasoning)",
144837
- updateArgs: {
144838
- context_window: 950000,
144839
- max_output_tokens: 128000,
144840
- reasoning_effort: "low",
144841
- enable_reasoner: true,
144842
- max_reasoning_tokens: 4000,
144843
- parallel_tool_calls: true
144844
- }
144845
- },
144846
- {
144847
- id: "opus-1m-medium",
144848
- handle: "anthropic/claude-opus-4-6",
144849
- label: "Opus 4.6 1M",
144850
- description: "Opus 4.6 1M (med reasoning)",
144851
- updateArgs: {
144852
- context_window: 950000,
144853
- max_output_tokens: 128000,
144854
- reasoning_effort: "medium",
144855
- enable_reasoner: true,
144856
- max_reasoning_tokens: 12000,
144857
- parallel_tool_calls: true
144858
- }
144859
- },
144860
- {
144861
- id: "opus-1m-xhigh",
144862
- handle: "anthropic/claude-opus-4-6",
144863
- label: "Opus 4.6 1M",
144864
- description: "Opus 4.6 1M (max reasoning)",
144865
- updateArgs: {
144866
- context_window: 950000,
144867
- max_output_tokens: 128000,
144868
- reasoning_effort: "xhigh",
144869
- enable_reasoner: true,
144870
- parallel_tool_calls: true
144871
- }
144872
- },
144873
145007
  {
144874
145008
  id: "opus-4.5",
144875
145009
  handle: "anthropic/claude-opus-4-5-20251101",
144876
145010
  label: "Opus 4.5",
144877
- description: "Anthropic's (legacy) best model (high reasoning)",
145011
+ description: "Opus 4.5 (high reasoning)",
144878
145012
  updateArgs: {
144879
145013
  context_window: 180000,
144880
145014
  max_output_tokens: 64000,
@@ -144930,7 +145064,7 @@ var init_models7 = __esm(() => {
144930
145064
  handle: "bedrock/us.anthropic.claude-opus-4-5-20251101-v1:0",
144931
145065
  label: "Bedrock Opus 4.5",
144932
145066
  shortLabel: "Opus 4.5 BR",
144933
- description: "Anthropic's Opus 4.5 (via AWS Bedrock)",
145067
+ description: "Opus 4.5 via AWS Bedrock",
144934
145068
  updateArgs: {
144935
145069
  context_window: 180000,
144936
145070
  max_output_tokens: 64000,
@@ -144943,7 +145077,7 @@ var init_models7 = __esm(() => {
144943
145077
  handle: "bedrock/us.anthropic.claude-opus-4-6-v1",
144944
145078
  label: "Bedrock Opus 4.6",
144945
145079
  shortLabel: "Opus 4.6 BR",
144946
- description: "Anthropic's Opus 4.6 (via AWS Bedrock)",
145080
+ description: "Opus 4.6 via AWS Bedrock",
144947
145081
  updateArgs: {
144948
145082
  context_window: 180000,
144949
145083
  max_output_tokens: 64000,
@@ -144956,7 +145090,7 @@ var init_models7 = __esm(() => {
144956
145090
  handle: "bedrock/us.anthropic.claude-opus-4-7",
144957
145091
  label: "Bedrock Opus 4.7",
144958
145092
  shortLabel: "Opus 4.7 BR",
144959
- description: "Anthropic's Opus 4.7 (via AWS Bedrock)",
145093
+ description: "Opus 4.7 via AWS Bedrock",
144960
145094
  updateArgs: {
144961
145095
  context_window: 200000,
144962
145096
  max_output_tokens: 128000,
@@ -144970,7 +145104,7 @@ var init_models7 = __esm(() => {
144970
145104
  handle: "bedrock/us.anthropic.claude-sonnet-4-6",
144971
145105
  label: "Bedrock Sonnet 4.6",
144972
145106
  shortLabel: "Sonnet 4.6 BR",
144973
- description: "Anthropic's Sonnet 4.6 (via AWS Bedrock)",
145107
+ description: "Sonnet 4.6 via AWS Bedrock",
144974
145108
  updateArgs: {
144975
145109
  context_window: 180000,
144976
145110
  max_output_tokens: 64000,
@@ -144982,7 +145116,7 @@ var init_models7 = __esm(() => {
144982
145116
  id: "haiku",
144983
145117
  handle: "anthropic/claude-haiku-4-5",
144984
145118
  label: "Haiku 4.5",
144985
- description: "Anthropic's fastest model",
145119
+ description: "Haiku 4.5",
144986
145120
  updateArgs: {
144987
145121
  context_window: 180000,
144988
145122
  max_output_tokens: 64000,
@@ -145804,7 +145938,6 @@ var init_models7 = __esm(() => {
145804
145938
  handle: "openai/gpt-5.3-codex",
145805
145939
  label: "GPT-5.3-Codex",
145806
145940
  description: "OpenAI's best coding model (high reasoning)",
145807
- isFeatured: true,
145808
145941
  updateArgs: {
145809
145942
  reasoning_effort: "high",
145810
145943
  verbosity: "medium",
@@ -146113,12 +146246,17 @@ function displayRegistryHandleForServiceTier(modelHandle, serviceTier) {
146113
146246
  function getReasoningTierOptionsForHandle(modelHandle, contextWindow) {
146114
146247
  const byEffort = new Map;
146115
146248
  const registryHandle = normalizeModelHandleForRegistry(modelHandle) ?? modelHandle;
146249
+ const effectiveContextWindow = contextWindow ?? (() => {
146250
+ const contextWindows = models2.filter((model) => model.handle === registryHandle).map((model) => model.updateArgs?.context_window).filter((value) => typeof value === "number");
146251
+ const uniqueContextWindows = [...new Set(contextWindows)];
146252
+ return uniqueContextWindows.length > 1 ? Math.min(...uniqueContextWindows) : undefined;
146253
+ })();
146116
146254
  for (const model of models2) {
146117
146255
  if (model.handle !== registryHandle)
146118
146256
  continue;
146119
- if (contextWindow !== undefined) {
146257
+ if (effectiveContextWindow !== undefined) {
146120
146258
  const mCtx = model.updateArgs?.context_window;
146121
- if (mCtx !== contextWindow)
146259
+ if (mCtx !== effectiveContextWindow)
146122
146260
  continue;
146123
146261
  }
146124
146262
  const effort = model.updateArgs?.reasoning_effort;
@@ -163508,8 +163646,9 @@ Prefer this tool over manually running \`git worktree add\` with Bash because it
163508
163646
  Do not use this tool for read-only tasks, code review, answering questions, continuing work already in the correct checkout, or when the user explicitly asks not to use worktrees.
163509
163647
 
163510
163648
  Behavior:
163511
- - Verifies the current cwd is inside a git repository.
163512
- - Creates the worktree under \`.letta/worktrees/\` for the repository.
163649
+ - Uses the current cwd as the target git repository by default, or \`repo_path\` when provided.
163650
+ - If the current cwd is not inside a git repository, pass \`repo_path\` instead of falling back to manual \`git worktree\` commands.
163651
+ - Creates the worktree under \`.letta/worktrees/\` for the target repository.
163513
163652
  - Creates a new branch from the default base ref unless \`branch_name\` or \`base_ref\` is provided.
163514
163653
  - By default, switches the active conversation/session cwd to the new worktree.
163515
163654
  - Does not copy uncommitted changes from the current checkout.
@@ -165080,6 +165219,8 @@ function createSharedReminderState() {
165080
165219
  hasSentConversationBootstrap: false,
165081
165220
  pendingConversationBootstrap: false,
165082
165221
  hasSentSecretsInfo: false,
165222
+ pendingSecretsInfoRefresh: false,
165223
+ lastSentSecretNamesKey: null,
165083
165224
  lastNotifiedPermissionMode: null,
165084
165225
  turnCount: 0,
165085
165226
  pendingReflectionTrigger: false,
@@ -165113,6 +165254,10 @@ function enqueueMemoryGitSyncReminder(state, reminder) {
165113
165254
  function enqueueToolsetChangeReminder(state, reminder) {
165114
165255
  pushBounded(state.pendingToolsetChangeReminders, reminder);
165115
165256
  }
165257
+ function markSecretsInfoReminderPending(state) {
165258
+ state.hasSentSecretsInfo = false;
165259
+ state.pendingSecretsInfoRefresh = true;
165260
+ }
165116
165261
  var MAX_PENDING_INTERACTION_REMINDERS = 25;
165117
165262
 
165118
165263
  // src/websocket/listener/scope.ts
@@ -169124,6 +169269,22 @@ async function assertValidBranchName(cwd, branchName) {
169124
169269
  async function resolveRepoRoot(cwd) {
169125
169270
  return await gitStdout(["rev-parse", "--show-toplevel"], cwd);
169126
169271
  }
169272
+ async function resolveWorktreeSourceRoot(params) {
169273
+ const sourcePath = params.requestedRepoPath ? path12.resolve(params.currentCwd, params.requestedRepoPath) : params.currentCwd;
169274
+ try {
169275
+ return await resolveRepoRoot(sourcePath);
169276
+ } catch (error54) {
169277
+ if (params.requestedRepoPath) {
169278
+ throw error54;
169279
+ }
169280
+ throw new Error([
169281
+ `Current working directory is not inside a git repository: ${params.currentCwd}`,
169282
+ "Pass `repo_path` to CreateWorktree or start the session from inside the target repo.",
169283
+ formatGitFailure(error54)
169284
+ ].join(`
169285
+ `));
169286
+ }
169287
+ }
169127
169288
  async function resolvePrimaryWorktreeRoot(repoRoot) {
169128
169289
  const commonDir = await gitStdout(["rev-parse", "--path-format=absolute", "--git-common-dir"], repoRoot);
169129
169290
  return path12.basename(commonDir) === ".git" ? path12.dirname(commonDir) : repoRoot;
@@ -169230,7 +169391,10 @@ async function create_worktree(rawArgs) {
169230
169391
  try {
169231
169392
  const runtimeContext = getRuntimeContext();
169232
169393
  const currentCwd = runtimeContext?.workingDirectory || process.env.USER_CWD || process.cwd();
169233
- const repoRoot = await resolveRepoRoot(currentCwd);
169394
+ const repoRoot = await resolveWorktreeSourceRoot({
169395
+ currentCwd,
169396
+ requestedRepoPath: getStringArg(args, "repo_path")
169397
+ });
169234
169398
  const primaryRoot = await resolvePrimaryWorktreeRoot(repoRoot);
169235
169399
  const worktreesDir = path12.join(primaryRoot, ".letta", "worktrees");
169236
169400
  const slug = slugifyName(name);
@@ -187254,6 +187418,7 @@ var init_search_file_content_gemini = __esm(() => {
187254
187418
  var exports_skills2 = {};
187255
187419
  __export(exports_skills2, {
187256
187420
  isUserInvocableSkill: () => isUserInvocableSkill,
187421
+ isSkillAvailableForAgent: () => isSkillAvailableForAgent,
187257
187422
  isModelInvocableSkill: () => isModelInvocableSkill,
187258
187423
  getFrontmatterStringList: () => getFrontmatterStringList,
187259
187424
  getFrontmatterString: () => getFrontmatterString,
@@ -187315,6 +187480,12 @@ function isModelInvocableSkill(skill) {
187315
187480
  function isUserInvocableSkill(skill) {
187316
187481
  return skill.userInvocable !== false;
187317
187482
  }
187483
+ function isSkillAvailableForAgent(skill, agentId) {
187484
+ if (skill.source === "bundled" && agentId && isLocalAgentId(agentId) && LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS.has(skill.id)) {
187485
+ return false;
187486
+ }
187487
+ return true;
187488
+ }
187318
187489
  function getAgentSkillsDir(agentId) {
187319
187490
  return join23(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "memory/skills");
187320
187491
  }
@@ -187481,9 +187652,10 @@ ${lines.join(`
187481
187652
  `)}
187482
187653
  </system-reminder>`;
187483
187654
  }
187484
- var SKILLS_DIR = ".skills", GLOBAL_SKILLS_DIR;
187655
+ var LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS, SKILLS_DIR = ".skills", GLOBAL_SKILLS_DIR;
187485
187656
  var init_skills3 = __esm(() => {
187486
187657
  init_skill_sources();
187658
+ LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS = new Set(["image-generation"]);
187487
187659
  GLOBAL_SKILLS_DIR = join23(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
187488
187660
  });
187489
187661
 
@@ -187568,7 +187740,7 @@ async function readSkillContent(skillId, skillsDir, agentId) {
187568
187740
  } catch {}
187569
187741
  const bundledSkills = await getBundledSkills();
187570
187742
  const bundledSkill = bundledSkills.find((s2) => s2.id === skillId);
187571
- if (bundledSkill?.path) {
187743
+ if (bundledSkill?.path && isSkillAvailableForAgent(bundledSkill, agentId)) {
187572
187744
  try {
187573
187745
  const content = await readFile9(bundledSkill.path, "utf-8");
187574
187746
  return { content, path: bundledSkill.path };
@@ -189867,6 +190039,10 @@ var init_CreateWorktree2 = __esm(() => {
189867
190039
  type: "string",
189868
190040
  description: "Optional git ref to base the worktree on. Defaults to the latest remote default branch, usually origin/main."
189869
190041
  },
190042
+ repo_path: {
190043
+ type: "string",
190044
+ description: "Optional path to the git repository to create the worktree from. Use this when the current conversation cwd is not inside the target repo."
190045
+ },
189870
190046
  refresh_base: {
189871
190047
  type: "boolean",
189872
190048
  description: "Whether to fetch the remote base branch before creating the worktree. Defaults to true."
@@ -194935,7 +195111,9 @@ async function collectClientSideSkills(options3) {
194935
195111
  });
194936
195112
  errors7.push(...discovery.errors);
194937
195113
  for (const skill2 of discovery.skills) {
194938
- skillsById.set(skill2.id, skill2);
195114
+ if (isSkillAvailableForAgent(skill2, options3.agentId)) {
195115
+ skillsById.set(skill2.id, skill2);
195116
+ }
194939
195117
  }
194940
195118
  } catch (error54) {
194941
195119
  const message = error54 instanceof Error ? error54.message : `Unknown error: ${String(error54)}`;
@@ -194946,6 +195124,9 @@ async function collectClientSideSkills(options3) {
194946
195124
  const memoryDiscovery = await discoverMemorySkills(options3.agentId);
194947
195125
  errors7.push(...memoryDiscovery.errors);
194948
195126
  for (const skill2 of memoryDiscovery.skills) {
195127
+ if (!isSkillAvailableForAgent(skill2, options3.agentId)) {
195128
+ continue;
195129
+ }
194949
195130
  const existing = skillsById.get(skill2.id);
194950
195131
  if (existing?.source === "project" || existing?.source === "agent") {
194951
195132
  continue;
@@ -206207,12 +206388,17 @@ function displayRegistryHandleForServiceTier2(modelHandle, serviceTier) {
206207
206388
  function getReasoningTierOptionsForHandle2(modelHandle, contextWindow) {
206208
206389
  const byEffort = new Map;
206209
206390
  const registryHandle = normalizeModelHandleForRegistry2(modelHandle) ?? modelHandle;
206391
+ const effectiveContextWindow = contextWindow ?? (() => {
206392
+ const contextWindows = models3.filter((model) => model.handle === registryHandle).map((model) => model.updateArgs?.context_window).filter((value) => typeof value === "number");
206393
+ const uniqueContextWindows = [...new Set(contextWindows)];
206394
+ return uniqueContextWindows.length > 1 ? Math.min(...uniqueContextWindows) : undefined;
206395
+ })();
206210
206396
  for (const model of models3) {
206211
206397
  if (model.handle !== registryHandle)
206212
206398
  continue;
206213
- if (contextWindow !== undefined) {
206399
+ if (effectiveContextWindow !== undefined) {
206214
206400
  const mCtx = model.updateArgs?.context_window;
206215
- if (mCtx !== contextWindow)
206401
+ if (mCtx !== effectiveContextWindow)
206216
206402
  continue;
206217
206403
  }
206218
206404
  const effort = model.updateArgs?.reasoning_effort;
@@ -258407,6 +258593,11 @@ function trimToWordLimit(value, maxWords) {
258407
258593
  }
258408
258594
  return words.slice(0, maxWords).join(" ");
258409
258595
  }
258596
+ function paginatedItems2(value) {
258597
+ if (Array.isArray(value))
258598
+ return value;
258599
+ return value.getPaginatedItems?.() ?? [];
258600
+ }
258410
258601
  function normalizeConversationDescription(value) {
258411
258602
  let normalized = value.replace(/\s+/g, " ").trim();
258412
258603
  if (normalized.startsWith('"') && normalized.endsWith('"') || normalized.startsWith("'") && normalized.endsWith("'")) {
@@ -258432,48 +258623,70 @@ function extractAssistantText(content) {
258432
258623
  }
258433
258624
  return "";
258434
258625
  }
258435
- async function generateConversationDescriptionFromFork(client, conversationId) {
258436
- let forkId = null;
258626
+ function extractUserText(content) {
258627
+ if (typeof content === "string") {
258628
+ return content;
258629
+ }
258630
+ if (Array.isArray(content)) {
258631
+ const parts = [];
258632
+ for (const part of content) {
258633
+ if (!part || typeof part !== "object")
258634
+ continue;
258635
+ const record5 = part;
258636
+ if (typeof record5.text === "string") {
258637
+ parts.push(record5.text);
258638
+ } else if (record5.type === "image") {
258639
+ parts.push("[image]");
258640
+ }
258641
+ }
258642
+ return parts.join(`
258643
+ `);
258644
+ }
258645
+ return "";
258646
+ }
258647
+ function messageToDescriptionMessage(message) {
258648
+ if (message.message_type === "user_message") {
258649
+ const content = extractUserText(message.content).trim();
258650
+ return content ? { role: "user", content } : null;
258651
+ }
258652
+ if (message.message_type === "assistant_message") {
258653
+ const content = extractAssistantText(message.content).trim();
258654
+ return content ? { role: "assistant", content } : null;
258655
+ }
258656
+ return null;
258657
+ }
258658
+ function buildConversationDescriptionMessages(messages) {
258659
+ const descriptionMessages = [];
258660
+ for (const message of messages) {
258661
+ const descriptionMessage = messageToDescriptionMessage(message);
258662
+ if (descriptionMessage) {
258663
+ descriptionMessages.push(descriptionMessage);
258664
+ }
258665
+ }
258666
+ return descriptionMessages;
258667
+ }
258668
+ async function generateConversationDescriptionFromSummary(conversationId, messages, model = DEFAULT_SUMMARIZATION_MODEL) {
258669
+ if (messages.length === 0) {
258670
+ return null;
258671
+ }
258437
258672
  const abortController = new AbortController;
258438
258673
  const timeoutId = setTimeout(() => abortController.abort(), CONVERSATION_DESCRIPTION_TIMEOUT_MS);
258439
258674
  try {
258440
- const fork = await forkConversation(conversationId, { hidden: true });
258441
- forkId = fork.id;
258442
- const stream5 = await client.conversations.messages.create(forkId, {
258443
- messages: [
258444
- {
258445
- role: "user",
258446
- content: CONVERSATION_DESCRIPTION_USER_PROMPT
258447
- }
258448
- ],
258449
- override_model: DEFAULT_SUMMARIZATION_MODEL,
258450
- override_system: CONVERSATION_DESCRIPTION_SYSTEM_PROMPT,
258451
- max_steps: 1,
258452
- streaming: true,
258453
- stream_tokens: false,
258454
- include_pings: false
258455
- }, { signal: abortController.signal });
258456
- let descriptionText = "";
258457
- for await (const chunk of stream5) {
258458
- if (chunk && typeof chunk === "object" && "message_type" in chunk && chunk.message_type === "assistant_message") {
258459
- descriptionText += extractAssistantText(chunk.content);
258460
- }
258461
- }
258462
- return normalizeConversationDescription(descriptionText);
258675
+ const response = await summarizeConversation(conversationId, {
258676
+ prompt: CONVERSATION_DESCRIPTION_SYSTEM_PROMPT,
258677
+ messages,
258678
+ model
258679
+ }, {
258680
+ signal: abortController.signal
258681
+ });
258682
+ return normalizeConversationDescription(response.summary);
258463
258683
  } catch (err) {
258464
258684
  if (isDebugEnabled()) {
258465
- console.error("[DEBUG] generateConversationDescriptionFromFork failed:", err);
258685
+ console.error("[DEBUG] generateConversationDescriptionFromSummary failed:", err);
258466
258686
  }
258467
258687
  return null;
258468
258688
  } finally {
258469
258689
  clearTimeout(timeoutId);
258470
- if (forkId) {
258471
- client.conversations.delete(forkId).catch((err) => {
258472
- if (isDebugEnabled()) {
258473
- console.error("[DEBUG] failed to delete description-fork conversation:", err);
258474
- }
258475
- });
258476
- }
258477
258690
  }
258478
258691
  }
258479
258692
  async function regenerateConversationDescription(conversationId) {
@@ -258487,8 +258700,13 @@ async function regenerateConversationDescription(conversationId) {
258487
258700
  return false;
258488
258701
  }
258489
258702
  try {
258490
- const client = await getClient();
258491
- const description = await generateConversationDescriptionFromFork(client, conversationId);
258703
+ const page = await getBackend().listConversationMessages(conversationId, {
258704
+ limit: CONVERSATION_DESCRIPTION_MESSAGE_LIMIT,
258705
+ order: "desc",
258706
+ include_return_message_types: ["user_message", "assistant_message"]
258707
+ });
258708
+ const messages = buildConversationDescriptionMessages(paginatedItems2(page).reverse());
258709
+ const description = await generateConversationDescriptionFromSummary(conversationId, messages, DEFAULT_SUMMARIZATION_MODEL);
258492
258710
  if (!description) {
258493
258711
  return false;
258494
258712
  }
@@ -258501,7 +258719,7 @@ async function regenerateConversationDescription(conversationId) {
258501
258719
  return false;
258502
258720
  }
258503
258721
  }
258504
- var CONVERSATION_DESCRIPTION_MAX_WORDS = 40, CONVERSATION_DESCRIPTION_TIMEOUT_MS = 30000, CONVERSATION_DESCRIPTION_SYSTEM_PROMPT = `You generate short internal conversation descriptions.
258722
+ var CONVERSATION_DESCRIPTION_MAX_WORDS = 40, CONVERSATION_DESCRIPTION_MESSAGE_LIMIT = 40, CONVERSATION_DESCRIPTION_TIMEOUT_MS = 30000, CONVERSATION_DESCRIPTION_SYSTEM_PROMPT = `You generate short internal conversation descriptions.
258505
258723
 
258506
258724
  Output ONLY a concise description of the conversation above.
258507
258725
  Rules:
@@ -258509,10 +258727,9 @@ Rules:
258509
258727
  - capture the concrete topic, the user's goal, and any meaningful constraints or decisions
258510
258728
  - no quotes, markdown, bullets, prefixes, or trailing punctuation
258511
258729
  - never call any tools — reply with plain text only
258512
- - ignore setup noise like tool chatter, system reminders, approvals, and boilerplate unless the conversation is explicitly about them`, CONVERSATION_DESCRIPTION_USER_PROMPT = "Based on the conversation above, output a concise internal description for search and bootstrap context. Reply with ONLY the description text — no quotes, no tools, no preamble.";
258730
+ - ignore setup noise like tool chatter, system reminders, approvals, and boilerplate unless the conversation is explicitly about them`;
258513
258731
  var init_conversation_description = __esm(() => {
258514
258732
  init_backend2();
258515
- init_client2();
258516
258733
  init_conversations2();
258517
258734
  init_constants();
258518
258735
  init_manager();
@@ -259913,20 +260130,31 @@ async function buildAgentInfoReminder(context3) {
259913
260130
  return reminder || null;
259914
260131
  }
259915
260132
  async function buildSecretsInfoReminder(context3) {
259916
- if (context3.state.hasSentSecretsInfo) {
259917
- return null;
259918
- }
259919
- context3.state.hasSentSecretsInfo = true;
259920
260133
  try {
259921
260134
  const { listSecretNames: listSecretNames2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
259922
- const names = listSecretNames2();
260135
+ const names = listSecretNames2(context3.agent.id);
260136
+ const namesKey = names.join("\x00");
260137
+ const isRefresh = context3.state.pendingSecretsInfoRefresh;
260138
+ const namesChanged = context3.state.lastSentSecretNamesKey !== null && context3.state.lastSentSecretNamesKey !== namesKey;
260139
+ if (context3.state.hasSentSecretsInfo && !isRefresh && !namesChanged) {
260140
+ return null;
260141
+ }
260142
+ context3.state.hasSentSecretsInfo = true;
260143
+ context3.state.pendingSecretsInfoRefresh = false;
260144
+ context3.state.lastSentSecretNamesKey = namesKey;
259923
260145
  if (names.length === 0) {
260146
+ if (isRefresh || namesChanged) {
260147
+ return `${SYSTEM_REMINDER_OPEN}
260148
+ The agent secrets were updated. No secrets are currently set.
260149
+ ${SYSTEM_REMINDER_CLOSE}`;
260150
+ }
259924
260151
  return null;
259925
260152
  }
259926
260153
  const list = names.map((n) => `- \`$${n}\``).join(`
259927
260154
  `);
260155
+ const intro = isRefresh || namesChanged ? "The agent secrets were updated. The following secrets are now available for use." : "The following secrets are set on your agent and available for use.";
259928
260156
  return `${SYSTEM_REMINDER_OPEN}
259929
- The following secrets are set on your agent and available for use.
260157
+ ${intro}
259930
260158
  Reference them with \`$SECRET_NAME\` in shell commands — substitution happens automatically at exec time:
259931
260159
  ${list}
259932
260160
 
@@ -436650,6 +436878,91 @@ var init_goal_loop_mode = __esm(() => {
436650
436878
  goalLoopMode = new GoalLoopModeManager;
436651
436879
  });
436652
436880
 
436881
+ // src/websocket/listener/commands/secrets.ts
436882
+ function markSecretsReminderRefreshPending(runtime, agentId) {
436883
+ const prefix = `agent:${agentId}::conversation:`;
436884
+ for (const [key2, state] of runtime.reminderStateByConversation) {
436885
+ if (key2.startsWith(prefix)) {
436886
+ markSecretsInfoReminderPending(state);
436887
+ }
436888
+ }
436889
+ for (const conversationRuntime of runtime.conversationRuntimes.values()) {
436890
+ if (conversationRuntime.agentId === agentId) {
436891
+ markSecretsInfoReminderPending(conversationRuntime.reminderState);
436892
+ }
436893
+ }
436894
+ }
436895
+ function handleSecretsCommand(parsed, context3) {
436896
+ const { socket, runtime, safeSocketSend, runDetachedListenerTask } = context3;
436897
+ if (isSecretListCommand(parsed)) {
436898
+ runDetachedListenerTask("secret_list", async () => {
436899
+ try {
436900
+ const { refreshAndListSecrets: refreshAndListSecrets2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
436901
+ const secrets2 = await refreshAndListSecrets2(parsed.agent_id);
436902
+ safeSocketSend(socket, {
436903
+ type: "secret_list_response",
436904
+ request_id: parsed.request_id,
436905
+ success: true,
436906
+ secrets: secrets2
436907
+ }, "listener_secret_list_send_failed", "listener_secret_list");
436908
+ } catch (error54) {
436909
+ safeSocketSend(socket, {
436910
+ type: "secret_list_response",
436911
+ request_id: parsed.request_id,
436912
+ success: false,
436913
+ secrets: [],
436914
+ error: error54 instanceof Error ? error54.message : "Failed to list secrets"
436915
+ }, "listener_secret_list_send_failed", "listener_secret_list");
436916
+ }
436917
+ });
436918
+ return true;
436919
+ }
436920
+ if (isSecretApplyCommand(parsed)) {
436921
+ runDetachedListenerTask("secret_apply", async () => {
436922
+ for (const key2 of Object.keys(parsed.set)) {
436923
+ if (!/^[A-Z_][A-Z0-9_]*$/.test(key2.toUpperCase())) {
436924
+ safeSocketSend(socket, {
436925
+ type: "secret_apply_response",
436926
+ request_id: parsed.request_id,
436927
+ success: false,
436928
+ names: [],
436929
+ error: `Invalid secret name '${key2}'. Use uppercase letters, numbers, and underscores only.`
436930
+ }, "listener_secret_apply_send_failed", "listener_secret_apply");
436931
+ return;
436932
+ }
436933
+ }
436934
+ try {
436935
+ const { applySecretBatch: applySecretBatch2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
436936
+ const names = await applySecretBatch2({ set: parsed.set, unset: parsed.unset }, parsed.agent_id);
436937
+ if (parsed.agent_id) {
436938
+ invalidateSecretsCacheForAgent(runtime, parsed.agent_id);
436939
+ markSecretsReminderRefreshPending(runtime, parsed.agent_id);
436940
+ }
436941
+ safeSocketSend(socket, {
436942
+ type: "secret_apply_response",
436943
+ request_id: parsed.request_id,
436944
+ success: true,
436945
+ names
436946
+ }, "listener_secret_apply_send_failed", "listener_secret_apply");
436947
+ } catch (error54) {
436948
+ safeSocketSend(socket, {
436949
+ type: "secret_apply_response",
436950
+ request_id: parsed.request_id,
436951
+ success: false,
436952
+ names: [],
436953
+ error: error54 instanceof Error ? error54.message : "Failed to apply secrets"
436954
+ }, "listener_secret_apply_send_failed", "listener_secret_apply");
436955
+ }
436956
+ });
436957
+ return true;
436958
+ }
436959
+ return false;
436960
+ }
436961
+ var init_secrets2 = __esm(() => {
436962
+ init_protocol_inbound();
436963
+ init_secrets_sync();
436964
+ });
436965
+
436653
436966
  // src/websocket/listener/commands.ts
436654
436967
  import { spawn as spawn9 } from "node:child_process";
436655
436968
  async function handleExecuteCommand(command, socket, conversationRuntime, opts) {
@@ -436687,7 +437000,7 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
436687
437000
  output = await handleCompactCommand(conversationRuntime, trimmedArgs);
436688
437001
  break;
436689
437002
  case "reload":
436690
- output = await handleReloadCommand(conversationRuntime.listener);
437003
+ output = await handleReloadCommand(conversationRuntime);
436691
437004
  break;
436692
437005
  case "context-limit":
436693
437006
  case "set-max-context":
@@ -436731,7 +437044,8 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
436731
437044
  conversationRuntime.cancelRequested = false;
436732
437045
  }
436733
437046
  }
436734
- async function handleReloadCommand(listener) {
437047
+ async function handleReloadCommand(conversationRuntime) {
437048
+ const { listener } = conversationRuntime;
436735
437049
  settingsManager.clearCaches();
436736
437050
  await settingsManager.loadProjectSettings();
436737
437051
  await settingsManager.loadLocalProjectSettings();
@@ -436741,7 +437055,12 @@ async function handleReloadCommand(listener) {
436741
437055
  debugLog("commands", "refreshCustomCommands failed during /reload:", error54 instanceof Error ? error54.message : String(error54));
436742
437056
  }
436743
437057
  await reloadListenerExtensionAdapter(listener);
436744
- return "Reloaded settings and local extensions";
437058
+ if (conversationRuntime.agentId) {
437059
+ invalidateSecretsCacheForAgent(listener, conversationRuntime.agentId);
437060
+ markSecretsReminderRefreshPending(listener, conversationRuntime.agentId);
437061
+ await ensureSecretsHydratedForAgent(listener, conversationRuntime.agentId);
437062
+ }
437063
+ return "Reloaded settings, local extensions, and agent secrets";
436745
437064
  }
436746
437065
  async function handleUpgradeLettaCodeCommand(opts) {
436747
437066
  const log2 = (message) => {
@@ -437221,9 +437540,11 @@ var init_commands2 = __esm(async () => {
437221
437540
  init_settings_manager();
437222
437541
  init_error_reporting();
437223
437542
  init_debug();
437543
+ init_secrets2();
437224
437544
  init_permission_mode();
437225
437545
  init_protocol_outbound();
437226
437546
  init_runtime5();
437547
+ init_secrets_sync();
437227
437548
  init_listener_constants();
437228
437549
  await __promiseAll([
437229
437550
  init_extension_adapter2(),
@@ -437615,77 +437936,6 @@ var init_git_branches = __esm(() => {
437615
437936
  init_protocol_outbound();
437616
437937
  });
437617
437938
 
437618
- // src/websocket/listener/commands/secrets.ts
437619
- function handleSecretsCommand(parsed, context3) {
437620
- const { socket, runtime, safeSocketSend, runDetachedListenerTask } = context3;
437621
- if (isSecretListCommand(parsed)) {
437622
- runDetachedListenerTask("secret_list", async () => {
437623
- try {
437624
- const { refreshAndListSecrets: refreshAndListSecrets2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
437625
- const secrets2 = await refreshAndListSecrets2(parsed.agent_id);
437626
- safeSocketSend(socket, {
437627
- type: "secret_list_response",
437628
- request_id: parsed.request_id,
437629
- success: true,
437630
- secrets: secrets2
437631
- }, "listener_secret_list_send_failed", "listener_secret_list");
437632
- } catch (error54) {
437633
- safeSocketSend(socket, {
437634
- type: "secret_list_response",
437635
- request_id: parsed.request_id,
437636
- success: false,
437637
- secrets: [],
437638
- error: error54 instanceof Error ? error54.message : "Failed to list secrets"
437639
- }, "listener_secret_list_send_failed", "listener_secret_list");
437640
- }
437641
- });
437642
- return true;
437643
- }
437644
- if (isSecretApplyCommand(parsed)) {
437645
- runDetachedListenerTask("secret_apply", async () => {
437646
- for (const key2 of Object.keys(parsed.set)) {
437647
- if (!/^[A-Z_][A-Z0-9_]*$/.test(key2.toUpperCase())) {
437648
- safeSocketSend(socket, {
437649
- type: "secret_apply_response",
437650
- request_id: parsed.request_id,
437651
- success: false,
437652
- names: [],
437653
- error: `Invalid secret name '${key2}'. Use uppercase letters, numbers, and underscores only.`
437654
- }, "listener_secret_apply_send_failed", "listener_secret_apply");
437655
- return;
437656
- }
437657
- }
437658
- try {
437659
- const { applySecretBatch: applySecretBatch2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
437660
- const names = await applySecretBatch2({ set: parsed.set, unset: parsed.unset }, parsed.agent_id);
437661
- if (parsed.agent_id) {
437662
- invalidateSecretsCacheForAgent(runtime, parsed.agent_id);
437663
- }
437664
- safeSocketSend(socket, {
437665
- type: "secret_apply_response",
437666
- request_id: parsed.request_id,
437667
- success: true,
437668
- names
437669
- }, "listener_secret_apply_send_failed", "listener_secret_apply");
437670
- } catch (error54) {
437671
- safeSocketSend(socket, {
437672
- type: "secret_apply_response",
437673
- request_id: parsed.request_id,
437674
- success: false,
437675
- names: [],
437676
- error: error54 instanceof Error ? error54.message : "Failed to apply secrets"
437677
- }, "listener_secret_apply_send_failed", "listener_secret_apply");
437678
- }
437679
- });
437680
- return true;
437681
- }
437682
- return false;
437683
- }
437684
- var init_secrets2 = __esm(() => {
437685
- init_protocol_inbound();
437686
- init_secrets_sync();
437687
- });
437688
-
437689
437939
  // src/websocket/listener/message-router.ts
437690
437940
  function createListenerMessageHandler(params) {
437691
437941
  const {
@@ -441379,6 +441629,7 @@ var init_version2 = __esm(() => {
441379
441629
  var exports_skills3 = {};
441380
441630
  __export(exports_skills3, {
441381
441631
  isUserInvocableSkill: () => isUserInvocableSkill2,
441632
+ isSkillAvailableForAgent: () => isSkillAvailableForAgent2,
441382
441633
  isModelInvocableSkill: () => isModelInvocableSkill2,
441383
441634
  getFrontmatterStringList: () => getFrontmatterStringList2,
441384
441635
  getFrontmatterString: () => getFrontmatterString2,
@@ -441440,6 +441691,12 @@ function isModelInvocableSkill2(skill2) {
441440
441691
  function isUserInvocableSkill2(skill2) {
441441
441692
  return skill2.userInvocable !== false;
441442
441693
  }
441694
+ function isSkillAvailableForAgent2(skill2, agentId) {
441695
+ if (skill2.source === "bundled" && agentId && isLocalAgentId(agentId) && LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS2.has(skill2.id)) {
441696
+ return false;
441697
+ }
441698
+ return true;
441699
+ }
441443
441700
  function getAgentSkillsDir2(agentId) {
441444
441701
  return join46(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "memory/skills");
441445
441702
  }
@@ -441606,9 +441863,10 @@ ${lines.join(`
441606
441863
  `)}
441607
441864
  </system-reminder>`;
441608
441865
  }
441609
- var SKILLS_DIR2 = ".skills", GLOBAL_SKILLS_DIR2;
441866
+ var LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS2, SKILLS_DIR2 = ".skills", GLOBAL_SKILLS_DIR2;
441610
441867
  var init_skills4 = __esm(() => {
441611
441868
  init_skill_sources();
441869
+ LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS2 = new Set(["image-generation"]);
441612
441870
  GLOBAL_SKILLS_DIR2 = join46(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
441613
441871
  });
441614
441872
 
@@ -443300,6 +443558,232 @@ async function writeWireMessageAsync(msg) {
443300
443558
  });
443301
443559
  }
443302
443560
 
443561
+ // src/skills/builtin/creating-skills/scripts/validate-skill.ts
443562
+ import { existsSync as existsSync49, readFileSync as readFileSync33 } from "node:fs";
443563
+ import { basename as basename22, join as join50, resolve as resolve34 } from "node:path";
443564
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
443565
+ function parseQuotedScalar(value) {
443566
+ if (value.startsWith('"')) {
443567
+ if (!value.endsWith('"') || value.length === 1) {
443568
+ throw new Error("Unterminated double-quoted scalar");
443569
+ }
443570
+ return JSON.parse(value);
443571
+ }
443572
+ if (value.startsWith("'")) {
443573
+ if (!value.endsWith("'") || value.length === 1) {
443574
+ throw new Error("Unterminated single-quoted scalar");
443575
+ }
443576
+ return value.slice(1, -1).replace(/''/g, "'");
443577
+ }
443578
+ return value;
443579
+ }
443580
+ function parseScalar(value) {
443581
+ const trimmed = value.trim();
443582
+ if (!trimmed)
443583
+ return "";
443584
+ if (trimmed === "true")
443585
+ return true;
443586
+ if (trimmed === "false")
443587
+ return false;
443588
+ if (trimmed === "null" || trimmed === "~")
443589
+ return null;
443590
+ if (trimmed.startsWith('"') || trimmed.startsWith("'")) {
443591
+ return parseQuotedScalar(trimmed);
443592
+ }
443593
+ if (trimmed.includes(": ")) {
443594
+ throw new Error(`Unexpected ':' in unquoted scalar: ${trimmed}`);
443595
+ }
443596
+ if (/^-?\d+(?:\.\d+)?$/.test(trimmed)) {
443597
+ return Number(trimmed);
443598
+ }
443599
+ return trimmed;
443600
+ }
443601
+ function parseFrontmatterFallback(source2) {
443602
+ const result = {};
443603
+ const lines = source2.split(/\r?\n/);
443604
+ for (let i4 = 0;i4 < lines.length; i4++) {
443605
+ const line = lines[i4];
443606
+ if (line === undefined)
443607
+ continue;
443608
+ const trimmed = line.trim();
443609
+ if (!trimmed || trimmed.startsWith("#")) {
443610
+ continue;
443611
+ }
443612
+ if (/^\s/.test(line)) {
443613
+ continue;
443614
+ }
443615
+ const colonIndex = line.indexOf(":");
443616
+ if (colonIndex <= 0) {
443617
+ throw new Error(`Invalid frontmatter line: ${line}`);
443618
+ }
443619
+ const key2 = line.slice(0, colonIndex).trim();
443620
+ const rawValue = line.slice(colonIndex + 1).trim();
443621
+ if (!key2) {
443622
+ throw new Error(`Invalid frontmatter line: ${line}`);
443623
+ }
443624
+ if (!rawValue) {
443625
+ result[key2] = {};
443626
+ continue;
443627
+ }
443628
+ if (rawValue === "|" || rawValue === ">") {
443629
+ const blockLines = [];
443630
+ for (let j2 = i4 + 1;j2 < lines.length; j2++) {
443631
+ const nextLine = lines[j2];
443632
+ if (nextLine === undefined)
443633
+ continue;
443634
+ if (nextLine.trim() && !/^\s/.test(nextLine)) {
443635
+ break;
443636
+ }
443637
+ blockLines.push(nextLine.replace(/^\s{2}/, ""));
443638
+ i4 = j2;
443639
+ }
443640
+ result[key2] = rawValue === ">" ? blockLines.join(" ").trim() : blockLines.join(`
443641
+ `);
443642
+ continue;
443643
+ }
443644
+ result[key2] = parseScalar(rawValue);
443645
+ }
443646
+ return result;
443647
+ }
443648
+ function parseFrontmatter2(source2) {
443649
+ const bunParse = globalThis.Bun?.YAML?.parse;
443650
+ if (bunParse) {
443651
+ const parsed = bunParse(source2);
443652
+ if (typeof parsed !== "object" || parsed === null) {
443653
+ throw new Error("Frontmatter must be a YAML dictionary");
443654
+ }
443655
+ return parsed;
443656
+ }
443657
+ return parseFrontmatterFallback(source2);
443658
+ }
443659
+ function validateSkill(skillPath) {
443660
+ const skillMdPath = join50(skillPath, "SKILL.md");
443661
+ if (!existsSync49(skillMdPath)) {
443662
+ return { valid: false, message: "SKILL.md not found" };
443663
+ }
443664
+ const content = readFileSync33(skillMdPath, "utf-8");
443665
+ if (!content.startsWith("---")) {
443666
+ return { valid: false, message: "No YAML frontmatter found" };
443667
+ }
443668
+ const match4 = content.match(/^---\n([\s\S]*?)\n---/);
443669
+ if (!match4) {
443670
+ return { valid: false, message: "Invalid frontmatter format" };
443671
+ }
443672
+ const frontmatterText = match4[1];
443673
+ let frontmatter;
443674
+ try {
443675
+ frontmatter = parseFrontmatter2(frontmatterText);
443676
+ if (typeof frontmatter !== "object" || frontmatter === null) {
443677
+ return { valid: false, message: "Frontmatter must be a YAML dictionary" };
443678
+ }
443679
+ } catch (e2) {
443680
+ return {
443681
+ valid: false,
443682
+ message: `Invalid YAML in frontmatter: ${e2 instanceof Error ? e2.message : String(e2)}`
443683
+ };
443684
+ }
443685
+ const warnings = [];
443686
+ const unexpectedKeys = Object.keys(frontmatter).filter((key2) => !ALLOWED_PROPERTIES.has(key2));
443687
+ if (unexpectedKeys.length > 0) {
443688
+ warnings.push(`Unknown frontmatter key(s): ${unexpectedKeys.sort().join(", ")}. Known properties are: ${[...ALLOWED_PROPERTIES].sort().join(", ")}`);
443689
+ }
443690
+ if (!("name" in frontmatter)) {
443691
+ return { valid: false, message: "Missing 'name' in frontmatter" };
443692
+ }
443693
+ if (!("description" in frontmatter)) {
443694
+ return { valid: false, message: "Missing 'description' in frontmatter" };
443695
+ }
443696
+ const name = frontmatter.name;
443697
+ if (typeof name !== "string") {
443698
+ return {
443699
+ valid: false,
443700
+ message: `Name must be a string, got ${typeof name}`
443701
+ };
443702
+ }
443703
+ const trimmedName = name.trim();
443704
+ if (trimmedName) {
443705
+ if (!/^[a-z0-9-]+$/.test(trimmedName)) {
443706
+ return {
443707
+ valid: false,
443708
+ message: `Name '${trimmedName}' should be hyphen-case (lowercase letters, digits, and hyphens only)`
443709
+ };
443710
+ }
443711
+ if (trimmedName.startsWith("-") || trimmedName.endsWith("-") || trimmedName.includes("--")) {
443712
+ return {
443713
+ valid: false,
443714
+ message: `Name '${trimmedName}' cannot start/end with hyphen or contain consecutive hyphens`
443715
+ };
443716
+ }
443717
+ if (trimmedName.length > MAX_SKILL_NAME_LENGTH) {
443718
+ return {
443719
+ valid: false,
443720
+ message: `Name is too long (${trimmedName.length} characters). Maximum is ${MAX_SKILL_NAME_LENGTH} characters.`
443721
+ };
443722
+ }
443723
+ const dirName = basename22(skillPath);
443724
+ if (trimmedName !== dirName) {
443725
+ warnings.push(`Name '${trimmedName}' doesn't match directory name '${dirName}'. For portability, these should match.`);
443726
+ }
443727
+ }
443728
+ const description = frontmatter.description;
443729
+ if (typeof description !== "string") {
443730
+ return {
443731
+ valid: false,
443732
+ message: `Description must be a string, got ${typeof description}`
443733
+ };
443734
+ }
443735
+ const trimmedDescription = description.trim();
443736
+ if (trimmedDescription) {
443737
+ if (trimmedDescription.includes("<") || trimmedDescription.includes(">")) {
443738
+ return {
443739
+ valid: false,
443740
+ message: "Description cannot contain angle brackets (< or >)"
443741
+ };
443742
+ }
443743
+ if (trimmedDescription.length > 1024) {
443744
+ return {
443745
+ valid: false,
443746
+ message: `Description is too long (${trimmedDescription.length} characters). Maximum is 1024 characters.`
443747
+ };
443748
+ }
443749
+ }
443750
+ return {
443751
+ valid: true,
443752
+ message: "Skill is valid!",
443753
+ warnings: warnings.length > 0 ? warnings : undefined
443754
+ };
443755
+ }
443756
+ function isMainModule() {
443757
+ const entrypoint = process.argv[1];
443758
+ return entrypoint ? resolve34(entrypoint) === fileURLToPath9(import.meta.url) : false;
443759
+ }
443760
+ var ALLOWED_PROPERTIES, MAX_SKILL_NAME_LENGTH = 64;
443761
+ var init_validate_skill = __esm(() => {
443762
+ ALLOWED_PROPERTIES = new Set([
443763
+ "name",
443764
+ "description",
443765
+ "license",
443766
+ "compatibility",
443767
+ "metadata",
443768
+ "allowed-tools"
443769
+ ]);
443770
+ if (isMainModule()) {
443771
+ const args = process.argv.slice(2);
443772
+ if (args.length !== 1) {
443773
+ console.log("Usage: npx tsx validate-skill.ts <skill-directory>");
443774
+ process.exit(1);
443775
+ }
443776
+ const { valid: valid2, message, warnings } = validateSkill(args[0]);
443777
+ console.log(message);
443778
+ if (warnings && warnings.length > 0) {
443779
+ for (const warning of warnings) {
443780
+ console.warn(`Warning: ${warning}`);
443781
+ }
443782
+ }
443783
+ process.exit(valid2 ? 0 : 1);
443784
+ }
443785
+ });
443786
+
443303
443787
  // src/agent/github-utils.ts
443304
443788
  var exports_github_utils = {};
443305
443789
  __export(exports_github_utils, {
@@ -443309,8 +443793,8 @@ __export(exports_github_utils, {
443309
443793
  async function fetchGitHubContents(owner, repo, branch, path36) {
443310
443794
  const apiPath = path36 ? `repos/${owner}/${repo}/contents/${path36}?ref=${branch}` : `repos/${owner}/${repo}/contents?ref=${branch}`;
443311
443795
  try {
443312
- const { execSync: execSync2 } = await import("node:child_process");
443313
- const result = execSync2(`gh api ${apiPath}`, {
443796
+ const { execFileSync: execFileSync5 } = await import("node:child_process");
443797
+ const result = execFileSync5("gh", ["api", apiPath], {
443314
443798
  encoding: "utf-8",
443315
443799
  stdio: ["pipe", "pipe", "ignore"]
443316
443800
  });
@@ -443341,7 +443825,38 @@ __export(exports_import, {
443341
443825
  });
443342
443826
  import { createReadStream as createReadStream2 } from "node:fs";
443343
443827
  import { access as access2, chmod, mkdir as mkdir13, readFile as readFile17, writeFile as writeFile15 } from "node:fs/promises";
443344
- import { dirname as dirname26, resolve as resolve34 } from "node:path";
443828
+ import { dirname as dirname26, isAbsolute as isAbsolute22, relative as relative9, resolve as resolve35, sep as sep6, win32 as win324 } from "node:path";
443829
+ function validateImportedSkillName(name) {
443830
+ const trimmedName = name.trim();
443831
+ if (trimmedName !== name || trimmedName.length === 0 || trimmedName.length > MAX_SKILL_NAME_LENGTH || trimmedName === "." || trimmedName === ".." || !IMPORTED_SKILL_NAME_PATTERN.test(trimmedName)) {
443832
+ throw new Error(`Invalid imported skill name "${String(name)}". Skill names may only contain letters, numbers, dots, underscores, and hyphens.`);
443833
+ }
443834
+ return trimmedName;
443835
+ }
443836
+ function assertPathInside(parent, child) {
443837
+ const parentPath = resolve35(parent);
443838
+ const childPath = resolve35(child);
443839
+ const relativePath = relative9(parentPath, childPath);
443840
+ if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep6}`) || isAbsolute22(relativePath)) {
443841
+ throw new Error(`Imported skill file path escapes skill directory: ${child}`);
443842
+ }
443843
+ }
443844
+ function validateImportedSkillFilePath(filePath) {
443845
+ if (filePath.length === 0 || filePath === "." || filePath.includes("\x00") || filePath.includes("\\") || isAbsolute22(filePath) || win324.isAbsolute(filePath)) {
443846
+ throw new Error(`Invalid imported skill file path "${filePath}".`);
443847
+ }
443848
+ const segments = filePath.split("/");
443849
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
443850
+ throw new Error(`Invalid imported skill file path "${filePath}".`);
443851
+ }
443852
+ return filePath;
443853
+ }
443854
+ function resolveImportedSkillFilePath(skillDir, filePath) {
443855
+ const safeFilePath = validateImportedSkillFilePath(filePath);
443856
+ const fullPath = resolve35(skillDir, safeFilePath);
443857
+ assertPathInside(skillDir, fullPath);
443858
+ return fullPath;
443859
+ }
443345
443860
  function tagsEqual(left, right) {
443346
443861
  return left.length === right.length && left.every((tag, i4) => tag === right[i4]);
443347
443862
  }
@@ -443374,7 +443889,7 @@ async function importAgentFromFile(options3) {
443374
443889
  if (!getBackend().capabilities.agentFileImportExport) {
443375
443890
  throw new Error("Agent file import is not supported by this backend yet");
443376
443891
  }
443377
- const resolvedPath = resolve34(options3.filePath);
443892
+ const resolvedPath = resolve35(options3.filePath);
443378
443893
  try {
443379
443894
  await access2(resolvedPath);
443380
443895
  } catch {
@@ -443418,16 +443933,17 @@ async function extractSkillsFromAf(afPath, destDir) {
443418
443933
  return [];
443419
443934
  }
443420
443935
  for (const skill2 of afData.skills) {
443421
- const skillDir = resolve34(destDir, skill2.name);
443936
+ const skillName = validateImportedSkillName(skill2.name);
443937
+ const skillDir = resolve35(destDir, skillName);
443422
443938
  await mkdir13(skillDir, { recursive: true });
443423
443939
  if (skill2.files) {
443424
443940
  await writeSkillFiles(skillDir, skill2.files);
443425
- extracted.push(skill2.name);
443941
+ extracted.push(skillName);
443426
443942
  } else if (skill2.source_url) {
443427
443943
  await fetchSkillFromUrl(skillDir, skill2.source_url);
443428
- extracted.push(skill2.name);
443944
+ extracted.push(skillName);
443429
443945
  } else {
443430
- console.warn(`Skipping skill ${skill2.name}: no files or source_url`);
443946
+ console.warn(`Skipping skill ${skillName}: no files or source_url`);
443431
443947
  }
443432
443948
  }
443433
443949
  return extracted;
@@ -443438,7 +443954,7 @@ async function writeSkillFiles(skillDir, files) {
443438
443954
  }
443439
443955
  }
443440
443956
  async function writeSkillFile(skillDir, filePath, content) {
443441
- const fullPath = resolve34(skillDir, filePath);
443957
+ const fullPath = resolveImportedSkillFilePath(skillDir, filePath);
443442
443958
  await mkdir13(dirname26(fullPath), { recursive: true });
443443
443959
  await writeFile15(fullPath, content, "utf-8");
443444
443960
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
@@ -443492,7 +444008,7 @@ function parseRegistryHandle(handle2) {
443492
444008
  }
443493
444009
  async function importAgentFromRegistry(options3) {
443494
444010
  const { tmpdir: tmpdir7 } = await import("node:os");
443495
- const { join: join50 } = await import("node:path");
444011
+ const { join: join51 } = await import("node:path");
443496
444012
  const { writeFile: writeFile16, unlink: unlink4 } = await import("node:fs/promises");
443497
444013
  const { author, name } = parseRegistryHandle(options3.handle);
443498
444014
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
@@ -443504,7 +444020,7 @@ async function importAgentFromRegistry(options3) {
443504
444020
  throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
443505
444021
  }
443506
444022
  const afContent = await response.text();
443507
- const tempPath = join50(tmpdir7(), `letta-import-${author}-${name}-${Date.now()}.af`);
444023
+ const tempPath = join51(tmpdir7(), `letta-import-${author}-${name}-${Date.now()}.af`);
443508
444024
  await writeFile16(tempPath, afContent, "utf-8");
443509
444025
  try {
443510
444026
  const result = await importAgentFromFile({
@@ -443521,13 +444037,15 @@ async function importAgentFromRegistry(options3) {
443521
444037
  } catch {}
443522
444038
  }
443523
444039
  }
443524
- var AGENT_REGISTRY_OWNER = "letta-ai", AGENT_REGISTRY_REPO = "agent-file", AGENT_REGISTRY_BRANCH = "main";
444040
+ var IMPORTED_SKILL_NAME_PATTERN, AGENT_REGISTRY_OWNER = "letta-ai", AGENT_REGISTRY_REPO = "agent-file", AGENT_REGISTRY_BRANCH = "main";
443525
444041
  var init_import = __esm(() => {
443526
444042
  init_backend2();
443527
444043
  init_client2();
444044
+ init_validate_skill();
443528
444045
  init_create6();
443529
444046
  init_model();
443530
444047
  init_modify();
444048
+ IMPORTED_SKILL_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;
443531
444049
  });
443532
444050
 
443533
444051
  // src/agent/defaults.ts
@@ -443823,12 +444341,12 @@ async function sendScopedApprovalMessages(params) {
443823
444341
  });
443824
444342
  }
443825
444343
  async function flushAndExit(code2) {
443826
- const flushWritable = (stream5) => new Promise((resolve35) => {
444344
+ const flushWritable = (stream5) => new Promise((resolve36) => {
443827
444345
  if (stream5.destroyed || stream5.writableEnded) {
443828
- resolve35();
444346
+ resolve36();
443829
444347
  return;
443830
444348
  }
443831
- stream5.write("", () => resolve35());
444349
+ stream5.write("", () => resolve36());
443832
444350
  });
443833
444351
  await Promise.allSettled([
443834
444352
  flushWritable(process.stdout),
@@ -443837,12 +444355,12 @@ async function flushAndExit(code2) {
443837
444355
  process.exit(code2);
443838
444356
  }
443839
444357
  async function writeFinalHeadlessStdout(text2) {
443840
- await new Promise((resolve35) => {
444358
+ await new Promise((resolve36) => {
443841
444359
  if (process.stdout.destroyed || process.stdout.writableEnded) {
443842
- resolve35();
444360
+ resolve36();
443843
444361
  return;
443844
444362
  }
443845
- process.stdout.write(text2, () => resolve35());
444363
+ process.stdout.write(text2, () => resolve36());
443846
444364
  });
443847
444365
  }
443848
444366
  async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride, skillSourcesOverride, systemInfoReminderEnabledOverride, startupOptions = {}) {
@@ -444911,7 +445429,7 @@ ${loadedContents.join(`
444911
445429
  } else {
444912
445430
  console.error(`Conversation is busy, waiting ${Math.round(retryDelayMs / 1000)}s and retrying...`);
444913
445431
  }
444914
- await new Promise((resolve35) => setTimeout(resolve35, retryDelayMs));
445432
+ await new Promise((resolve36) => setTimeout(resolve36, retryDelayMs));
444915
445433
  continue;
444916
445434
  }
444917
445435
  }
@@ -444960,7 +445478,7 @@ ${loadedContents.join(`
444960
445478
  const delaySeconds = Math.round(delayMs / 1000);
444961
445479
  console.error(`Transient API error before streaming (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
444962
445480
  }
444963
- await new Promise((resolve35) => setTimeout(resolve35, delayMs));
445481
+ await new Promise((resolve36) => setTimeout(resolve36, delayMs));
444964
445482
  conversationBusyRetries = 0;
444965
445483
  continue;
444966
445484
  }
@@ -445190,7 +445708,7 @@ ${loadedContents.join(`
445190
445708
  const delaySeconds = Math.round(delayMs / 1000);
445191
445709
  console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
445192
445710
  }
445193
- await new Promise((resolve35) => setTimeout(resolve35, delayMs));
445711
+ await new Promise((resolve36) => setTimeout(resolve36, delayMs));
445194
445712
  currentInput = refreshInputOtidsForNewRequest(currentInput);
445195
445713
  continue;
445196
445714
  }
@@ -445282,7 +445800,7 @@ ${loadedContents.join(`
445282
445800
  } else {
445283
445801
  console.error(`Empty LLM response, retrying (attempt ${attempt} of ${EMPTY_RESPONSE_MAX_RETRIES2})...`);
445284
445802
  }
445285
- await new Promise((resolve35) => setTimeout(resolve35, delayMs));
445803
+ await new Promise((resolve36) => setTimeout(resolve36, delayMs));
445286
445804
  currentInput = refreshInputOtidsForNewRequest(currentInput);
445287
445805
  continue;
445288
445806
  }
@@ -445310,7 +445828,7 @@ ${loadedContents.join(`
445310
445828
  const delaySeconds = Math.round(delayMs / 1000);
445311
445829
  console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
445312
445830
  }
445313
- await new Promise((resolve35) => setTimeout(resolve35, delayMs));
445831
+ await new Promise((resolve36) => setTimeout(resolve36, delayMs));
445314
445832
  currentInput = refreshInputOtidsForNewRequest(currentInput);
445315
445833
  continue;
445316
445834
  }
@@ -445340,7 +445858,7 @@ ${loadedContents.join(`
445340
445858
  const delaySeconds = Math.round(delayMs / 1000);
445341
445859
  console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
445342
445860
  }
445343
- await new Promise((resolve35) => setTimeout(resolve35, delayMs));
445861
+ await new Promise((resolve36) => setTimeout(resolve36, delayMs));
445344
445862
  currentInput = refreshInputOtidsForNewRequest(currentInput);
445345
445863
  continue;
445346
445864
  }
@@ -445702,9 +446220,9 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
445702
446220
  const syntheticUserLine = serializeQueuedMessageAsUserLine(queuedMessage);
445703
446221
  maybeNotifyBlocked(syntheticUserLine);
445704
446222
  if (lineResolver) {
445705
- const resolve35 = lineResolver;
446223
+ const resolve36 = lineResolver;
445706
446224
  lineResolver = null;
445707
- resolve35(syntheticUserLine);
446225
+ resolve36(syntheticUserLine);
445708
446226
  return;
445709
446227
  }
445710
446228
  lineQueue.push(syntheticUserLine);
@@ -445712,9 +446230,9 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
445712
446230
  rl.on("line", (line) => {
445713
446231
  maybeNotifyBlocked(line);
445714
446232
  if (lineResolver) {
445715
- const resolve35 = lineResolver;
446233
+ const resolve36 = lineResolver;
445716
446234
  lineResolver = null;
445717
- resolve35(line);
446235
+ resolve36(line);
445718
446236
  } else {
445719
446237
  lineQueue.push(line);
445720
446238
  }
@@ -445723,17 +446241,17 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
445723
446241
  setMessageQueueAdder(null);
445724
446242
  msgQueueRuntime.clear("shutdown");
445725
446243
  if (lineResolver) {
445726
- const resolve35 = lineResolver;
446244
+ const resolve36 = lineResolver;
445727
446245
  lineResolver = null;
445728
- resolve35(null);
446246
+ resolve36(null);
445729
446247
  }
445730
446248
  });
445731
446249
  async function getNextLine() {
445732
446250
  if (lineQueue.length > 0) {
445733
446251
  return lineQueue.shift() ?? null;
445734
446252
  }
445735
- return new Promise((resolve35) => {
445736
- lineResolver = resolve35;
446253
+ return new Promise((resolve36) => {
446254
+ lineResolver = resolve36;
445737
446255
  });
445738
446256
  }
445739
446257
  async function requestPermission(toolCallId, toolName, toolInput) {
@@ -446219,7 +446737,7 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
446219
446737
  uuid: `retry-bidir-${randomUUID26()}`
446220
446738
  };
446221
446739
  writeWireMessage(retryMsg);
446222
- await new Promise((resolve35) => setTimeout(resolve35, delayMs));
446740
+ await new Promise((resolve36) => setTimeout(resolve36, delayMs));
446223
446741
  continue;
446224
446742
  }
446225
446743
  throw preStreamError;
@@ -446896,7 +447414,7 @@ var MAX_TERMINAL_TITLE_CHARS = 240;
446896
447414
 
446897
447415
  // src/cli/helpers/window-title-config.ts
446898
447416
  import { homedir as homedir31 } from "node:os";
446899
- import { basename as basename22, resolve as resolve35 } from "node:path";
447417
+ import { basename as basename23, resolve as resolve36 } from "node:path";
446900
447418
  function isWindowTitleField(value) {
446901
447419
  return WINDOW_TITLE_FIELDS.includes(value);
446902
447420
  }
@@ -447054,8 +447572,8 @@ function terminalTitleProjectName(data) {
447054
447572
  const directory = titleDirectory(data);
447055
447573
  if (!directory)
447056
447574
  return null;
447057
- const resolved = resolve35(directory);
447058
- const name = basename22(resolved) || formatDirectoryDisplay(resolved) || resolved;
447575
+ const resolved = resolve36(directory);
447576
+ const name = basename23(resolved) || formatDirectoryDisplay(resolved) || resolved;
447059
447577
  return truncateTerminalTitlePart(name, 24);
447060
447578
  }
447061
447579
  function titleDirectory(data) {
@@ -447064,7 +447582,7 @@ function titleDirectory(data) {
447064
447582
  function formatDirectoryDisplay(directory) {
447065
447583
  if (!directory)
447066
447584
  return null;
447067
- const resolved = resolve35(directory);
447585
+ const resolved = resolve36(directory);
447068
447586
  const home = homedir31();
447069
447587
  if (resolved === home)
447070
447588
  return "~";
@@ -447450,8 +447968,8 @@ async function pushToMemoryRepositoryWithTimeout(agentId) {
447450
447968
  try {
447451
447969
  return await Promise.race([
447452
447970
  pushToMemoryRepository(agentId),
447453
- new Promise((resolve36) => {
447454
- timeout = setTimeout(() => resolve36("timeout"), INITIAL_PUSH_TIMEOUT_MS);
447971
+ new Promise((resolve37) => {
447972
+ timeout = setTimeout(() => resolve37("timeout"), INITIAL_PUSH_TIMEOUT_MS);
447455
447973
  })
447456
447974
  ]);
447457
447975
  } finally {
@@ -447709,13 +448227,13 @@ __export(exports_terminal_keybinding_installer, {
447709
448227
  });
447710
448228
  import {
447711
448229
  copyFileSync as copyFileSync2,
447712
- existsSync as existsSync50,
448230
+ existsSync as existsSync51,
447713
448231
  mkdirSync as mkdirSync37,
447714
- readFileSync as readFileSync34,
448232
+ readFileSync as readFileSync35,
447715
448233
  writeFileSync as writeFileSync27
447716
448234
  } from "node:fs";
447717
448235
  import { homedir as homedir32, platform as platform8 } from "node:os";
447718
- import { dirname as dirname27, join as join51 } from "node:path";
448236
+ import { dirname as dirname27, join as join52 } from "node:path";
447719
448237
  function detectTerminalType() {
447720
448238
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
447721
448239
  return "cursor";
@@ -447747,16 +448265,16 @@ function getKeybindingsPath(terminal) {
447747
448265
  }[terminal];
447748
448266
  const os7 = platform8();
447749
448267
  if (os7 === "darwin") {
447750
- return join51(homedir32(), "Library", "Application Support", appName, "User", "keybindings.json");
448268
+ return join52(homedir32(), "Library", "Application Support", appName, "User", "keybindings.json");
447751
448269
  }
447752
448270
  if (os7 === "win32") {
447753
448271
  const appData = process.env.APPDATA;
447754
448272
  if (!appData)
447755
448273
  return null;
447756
- return join51(appData, appName, "User", "keybindings.json");
448274
+ return join52(appData, appName, "User", "keybindings.json");
447757
448275
  }
447758
448276
  if (os7 === "linux") {
447759
- return join51(homedir32(), ".config", appName, "User", "keybindings.json");
448277
+ return join52(homedir32(), ".config", appName, "User", "keybindings.json");
447760
448278
  }
447761
448279
  return null;
447762
448280
  }
@@ -447778,10 +448296,10 @@ function parseKeybindings(content) {
447778
448296
  }
447779
448297
  }
447780
448298
  function keybindingExists(keybindingsPath) {
447781
- if (!existsSync50(keybindingsPath))
448299
+ if (!existsSync51(keybindingsPath))
447782
448300
  return false;
447783
448301
  try {
447784
- const content = readFileSync34(keybindingsPath, { encoding: "utf-8" });
448302
+ const content = readFileSync35(keybindingsPath, { encoding: "utf-8" });
447785
448303
  const keybindings = parseKeybindings(content);
447786
448304
  if (!keybindings)
447787
448305
  return false;
@@ -447791,7 +448309,7 @@ function keybindingExists(keybindingsPath) {
447791
448309
  }
447792
448310
  }
447793
448311
  function createBackup(keybindingsPath) {
447794
- if (!existsSync50(keybindingsPath))
448312
+ if (!existsSync51(keybindingsPath))
447795
448313
  return null;
447796
448314
  const backupPath = `${keybindingsPath}.letta-backup`;
447797
448315
  try {
@@ -447807,14 +448325,14 @@ function installKeybinding(keybindingsPath) {
447807
448325
  return { success: true, alreadyExists: true };
447808
448326
  }
447809
448327
  const parentDir = dirname27(keybindingsPath);
447810
- if (!existsSync50(parentDir)) {
448328
+ if (!existsSync51(parentDir)) {
447811
448329
  mkdirSync37(parentDir, { recursive: true });
447812
448330
  }
447813
448331
  let keybindings = [];
447814
448332
  let backupPath = null;
447815
- if (existsSync50(keybindingsPath)) {
448333
+ if (existsSync51(keybindingsPath)) {
447816
448334
  backupPath = createBackup(keybindingsPath);
447817
- const content = readFileSync34(keybindingsPath, { encoding: "utf-8" });
448335
+ const content = readFileSync35(keybindingsPath, { encoding: "utf-8" });
447818
448336
  const parsed = parseKeybindings(content);
447819
448337
  if (parsed === null) {
447820
448338
  return {
@@ -447842,10 +448360,10 @@ function installKeybinding(keybindingsPath) {
447842
448360
  }
447843
448361
  function removeKeybinding(keybindingsPath) {
447844
448362
  try {
447845
- if (!existsSync50(keybindingsPath)) {
448363
+ if (!existsSync51(keybindingsPath)) {
447846
448364
  return { success: true };
447847
448365
  }
447848
- const content = readFileSync34(keybindingsPath, { encoding: "utf-8" });
448366
+ const content = readFileSync35(keybindingsPath, { encoding: "utf-8" });
447849
448367
  const keybindings = parseKeybindings(content);
447850
448368
  if (!keybindings) {
447851
448369
  return {
@@ -447909,14 +448427,14 @@ function getWezTermConfigPath() {
447909
448427
  }
447910
448428
  const xdgConfig = process.env.XDG_CONFIG_HOME;
447911
448429
  if (xdgConfig) {
447912
- const xdgPath = join51(xdgConfig, "wezterm", "wezterm.lua");
447913
- if (existsSync50(xdgPath))
448430
+ const xdgPath = join52(xdgConfig, "wezterm", "wezterm.lua");
448431
+ if (existsSync51(xdgPath))
447914
448432
  return xdgPath;
447915
448433
  }
447916
- const configPath = join51(homedir32(), ".config", "wezterm", "wezterm.lua");
447917
- if (existsSync50(configPath))
448434
+ const configPath = join52(homedir32(), ".config", "wezterm", "wezterm.lua");
448435
+ if (existsSync51(configPath))
447918
448436
  return configPath;
447919
- return join51(homedir32(), ".wezterm.lua");
448437
+ return join52(homedir32(), ".wezterm.lua");
447920
448438
  }
447921
448439
  function stripLuaCommentsFromLine(line, blockCommentEnd) {
447922
448440
  let code2 = "";
@@ -448019,10 +448537,10 @@ ${WEZTERM_DELETE_FIX}
448019
448537
  `;
448020
448538
  }
448021
448539
  function wezTermDeleteFixExists(configPath) {
448022
- if (!existsSync50(configPath))
448540
+ if (!existsSync51(configPath))
448023
448541
  return false;
448024
448542
  try {
448025
- const content = readFileSync34(configPath, { encoding: "utf-8" });
448543
+ const content = readFileSync35(configPath, { encoding: "utf-8" });
448026
448544
  return content.includes("Letta Code: Fix Delete key") || content.includes("key = 'Delete'") && content.includes("SendString") && content.includes("\\x1b[3~");
448027
448545
  } catch {
448028
448546
  return false;
@@ -448036,14 +448554,14 @@ function installWezTermDeleteFix() {
448036
448554
  }
448037
448555
  let content = "";
448038
448556
  let backupPath = null;
448039
- if (existsSync50(configPath)) {
448557
+ if (existsSync51(configPath)) {
448040
448558
  backupPath = `${configPath}.letta-backup`;
448041
448559
  copyFileSync2(configPath, backupPath);
448042
- content = readFileSync34(configPath, { encoding: "utf-8" });
448560
+ content = readFileSync35(configPath, { encoding: "utf-8" });
448043
448561
  }
448044
448562
  content = injectWezTermDeleteFix(content);
448045
448563
  const parentDir = dirname27(configPath);
448046
- if (!existsSync50(parentDir)) {
448564
+ if (!existsSync51(parentDir)) {
448047
448565
  mkdirSync37(parentDir, { recursive: true });
448048
448566
  }
448049
448567
  writeFileSync27(configPath, content, { encoding: "utf-8" });
@@ -448095,9 +448613,9 @@ __export(exports_settings2, {
448095
448613
  getSetting: () => getSetting
448096
448614
  });
448097
448615
  import { homedir as homedir33 } from "node:os";
448098
- import { join as join52 } from "node:path";
448616
+ import { join as join53 } from "node:path";
448099
448617
  function getSettingsPath() {
448100
- return join52(homedir33(), ".letta", "settings.json");
448618
+ return join53(homedir33(), ".letta", "settings.json");
448101
448619
  }
448102
448620
  async function loadSettings() {
448103
448621
  const settingsPath = getSettingsPath();
@@ -448134,7 +448652,7 @@ async function getSetting(key2) {
448134
448652
  return settings3[key2];
448135
448653
  }
448136
448654
  function getProjectSettingsPath() {
448137
- return join52(process.cwd(), ".letta", "settings.local.json");
448655
+ return join53(process.cwd(), ".letta", "settings.local.json");
448138
448656
  }
448139
448657
  async function loadProjectSettings() {
448140
448658
  const settingsPath = getProjectSettingsPath();
@@ -448152,7 +448670,7 @@ async function loadProjectSettings() {
448152
448670
  }
448153
448671
  async function saveProjectSettings(settings3) {
448154
448672
  const settingsPath = getProjectSettingsPath();
448155
- const dirPath = join52(process.cwd(), ".letta");
448673
+ const dirPath = join53(process.cwd(), ".letta");
448156
448674
  try {
448157
448675
  if (!exists(dirPath)) {
448158
448676
  await mkdir(dirPath, { recursive: true });
@@ -449895,10 +450413,10 @@ var init_InlineBashApproval = __esm(async () => {
449895
450413
  });
449896
450414
 
449897
450415
  // src/cli/components/DiffRenderer.tsx
449898
- import { relative as relative9 } from "node:path";
450416
+ import { relative as relative10 } from "node:path";
449899
450417
  function formatDisplayPath4(filePath) {
449900
450418
  const cwd2 = process.cwd();
449901
- const relativePath = relative9(cwd2, filePath);
450419
+ const relativePath = relative10(cwd2, filePath);
449902
450420
  if (relativePath.startsWith("..")) {
449903
450421
  return filePath;
449904
450422
  }
@@ -450257,10 +450775,10 @@ var init_DiffRenderer = __esm(async () => {
450257
450775
  });
450258
450776
 
450259
450777
  // src/cli/components/AdvancedDiffRenderer.tsx
450260
- import { relative as relative10 } from "node:path";
450778
+ import { relative as relative11 } from "node:path";
450261
450779
  function formatRelativePath(filePath) {
450262
450780
  const cwd2 = process.cwd();
450263
- const relativePath = relative10(cwd2, filePath);
450781
+ const relativePath = relative11(cwd2, filePath);
450264
450782
  return relativePath.startsWith("..") ? relativePath : `./${relativePath}`;
450265
450783
  }
450266
450784
  function padLeft(n, width) {
@@ -450542,7 +451060,7 @@ function AdvancedDiffRenderer(props) {
450542
451060
  }
450543
451061
  const { hunks } = result;
450544
451062
  const filePath = props.filePath;
450545
- const relative11 = formatRelativePath(filePath);
451063
+ const relative12 = formatRelativePath(filePath);
450546
451064
  const lang41 = languageFromPath(filePath);
450547
451065
  const shouldHighlight = lang41 && !exceedsAdvancedDiffHighlightLimits(hunks);
450548
451066
  const hunkSyntaxLines = [];
@@ -450565,7 +451083,7 @@ function AdvancedDiffRenderer(props) {
450565
451083
  const rows = buildAdvancedDiffRows(hunks, hunkSyntaxLines);
450566
451084
  const maxDisplayNo = rows.reduce((m4, r5) => Math.max(m4, r5.displayNo), 1);
450567
451085
  const gutterWidth = String(maxDisplayNo).length;
450568
- const header = props.kind === "write" ? `Wrote changes to ${relative11}` : `Updated ${relative11}`;
451086
+ const header = props.kind === "write" ? `Wrote changes to ${relative12}` : `Updated ${relative12}`;
450569
451087
  if (rows.length === 0) {
450570
451088
  const noChangesGutter = 4;
450571
451089
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
@@ -450616,7 +451134,7 @@ function AdvancedDiffRenderer(props) {
450616
451134
  "No changes to ",
450617
451135
  /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text2, {
450618
451136
  bold: true,
450619
- children: relative11
451137
+ children: relative12
450620
451138
  }, undefined, false, undefined, this),
450621
451139
  " (file content identical)"
450622
451140
  ]
@@ -450722,9 +451240,9 @@ function getHeaderText(fileEdit) {
450722
451240
  } else if (operations.length === 1) {
450723
451241
  const op = operations[0];
450724
451242
  if (op) {
450725
- const { relative: relative12 } = __require("node:path");
451243
+ const { relative: relative13 } = __require("node:path");
450726
451244
  const cwd3 = process.cwd();
450727
- const relPath2 = relative12(cwd3, op.path);
451245
+ const relPath2 = relative13(cwd3, op.path);
450728
451246
  const displayPath2 = relPath2.startsWith("..") ? op.path : relPath2;
450729
451247
  if (op.kind === "add") {
450730
451248
  return `Write to ${displayPath2}?`;
@@ -450738,14 +451256,14 @@ function getHeaderText(fileEdit) {
450738
451256
  }
450739
451257
  return "Apply patch?";
450740
451258
  }
450741
- const { relative: relative11 } = __require("node:path");
451259
+ const { relative: relative12 } = __require("node:path");
450742
451260
  const cwd2 = process.cwd();
450743
- const relPath = relative11(cwd2, fileEdit.filePath);
451261
+ const relPath = relative12(cwd2, fileEdit.filePath);
450744
451262
  const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
450745
451263
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
450746
- const { existsSync: existsSync51 } = __require("node:fs");
451264
+ const { existsSync: existsSync52 } = __require("node:fs");
450747
451265
  try {
450748
- if (existsSync51(fileEdit.filePath)) {
451266
+ if (existsSync52(fileEdit.filePath)) {
450749
451267
  return `Overwrite ${displayPath}?`;
450750
451268
  }
450751
451269
  } catch {}
@@ -450923,9 +451441,9 @@ var init_InlineFileEditApproval = __esm(async () => {
450923
451441
  children: fileEdit.patchInput ? /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
450924
451442
  flexDirection: "column",
450925
451443
  children: parsePatchOperations2(fileEdit.patchInput).map((op, idx) => {
450926
- const { relative: relative11 } = __require("node:path");
451444
+ const { relative: relative12 } = __require("node:path");
450927
451445
  const cwd2 = process.cwd();
450928
- const relPath = relative11(cwd2, op.path);
451446
+ const relPath = relative12(cwd2, op.path);
450929
451447
  const displayPath = relPath.startsWith("..") ? op.path : relPath;
450930
451448
  const diffKey = fileEdit.toolCallId ? `${fileEdit.toolCallId}:${op.path}` : undefined;
450931
451449
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -453726,7 +454244,7 @@ function isConversationPinned2(params) {
453726
454244
  function buildConversationSelectorHints2(params) {
453727
454245
  return params.isSelectedDefaultConversation ? "Enter select · ↑↓ navigate · Esc clear/cancel" : "Enter select · ↑↓ navigate · Alt+P pin/unpin · Esc clear/cancel";
453728
454246
  }
453729
- function paginatedItems3(value) {
454247
+ function paginatedItems4(value) {
453730
454248
  return Array.isArray(value) ? value : value.getPaginatedItems();
453731
454249
  }
453732
454250
  function formatRelativeTime4(dateStr) {
@@ -453908,7 +454426,7 @@ function ConversationSelector2({
453908
454426
  include_return_message_types: RESUME_PREVIEW_MESSAGE_TYPES2,
453909
454427
  agent_id: agentId
453910
454428
  });
453911
- const chronological = [...paginatedItems3(messages)].reverse();
454429
+ const chronological = [...paginatedItems4(messages)].reverse();
453912
454430
  const stats = getMessageStats2(chronological);
453913
454431
  setConversations((prev) => prev.map((c) => c.conversation.id === convId ? {
453914
454432
  ...c,
@@ -453964,10 +454482,10 @@ function ConversationSelector2({
453964
454482
  order: "asc"
453965
454483
  })
453966
454484
  ]).then(([msgs, firstMsgs]) => {
453967
- const items3 = paginatedItems3(msgs);
454485
+ const items3 = paginatedItems4(msgs);
453968
454486
  if (items3.length === 0)
453969
454487
  return null;
453970
- const firstMessage = paginatedItems3(firstMsgs)[0];
454488
+ const firstMessage = paginatedItems4(firstMsgs)[0];
453971
454489
  const stats = getMessageStats2([...items3].reverse());
453972
454490
  return buildDefaultConversationEntry2(agentId, stats, getMessageTimestamp2(firstMessage));
453973
454491
  }).catch(() => null) : Promise.resolve(null);
@@ -454080,7 +454598,7 @@ function ConversationSelector2({
454080
454598
  order_by: "last_run_completion",
454081
454599
  summary_search: query2
454082
454600
  });
454083
- const results = paginatedItems3(page);
454601
+ const results = paginatedItems4(page);
454084
454602
  const seenConversationIds = new Set;
454085
454603
  const dedupedResults = results.filter((conversation) => {
454086
454604
  const conversationId = conversation.id;
@@ -455071,6 +455589,7 @@ function FeedbackDialog({
455071
455589
  }) {
455072
455590
  const terminalWidth = useTerminalWidth();
455073
455591
  const solidLine = SOLID_LINE11.repeat(Math.max(terminalWidth, 10));
455592
+ const inputWidth = Math.max(terminalWidth - INPUT_PROMPT.length, 10);
455074
455593
  const [feedbackText, setFeedbackText] = import_react72.useState(initialValue);
455075
455594
  const [error54, setError] = import_react72.useState("");
455076
455595
  use_input_default((_input, key2) => {
@@ -455121,15 +455640,23 @@ function FeedbackDialog({
455121
455640
  /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
455122
455641
  flexDirection: "row",
455123
455642
  children: [
455124
- /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text2, {
455125
- color: colors.selector.itemHighlighted,
455126
- children: "> "
455643
+ /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
455644
+ width: INPUT_PROMPT.length,
455645
+ flexShrink: 0,
455646
+ children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text2, {
455647
+ color: colors.selector.itemHighlighted,
455648
+ children: INPUT_PROMPT
455649
+ }, undefined, false, undefined, this)
455127
455650
  }, undefined, false, undefined, this),
455128
- /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(PasteAwareTextInput, {
455129
- value: feedbackText,
455130
- onChange: setFeedbackText,
455131
- onSubmit: handleSubmit,
455132
- placeholder: "(type your feedback)"
455651
+ /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
455652
+ width: inputWidth,
455653
+ flexGrow: 1,
455654
+ children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(PasteAwareTextInput, {
455655
+ value: feedbackText,
455656
+ onChange: setFeedbackText,
455657
+ onSubmit: handleSubmit,
455658
+ placeholder: "(type your feedback)"
455659
+ }, undefined, false, undefined, this)
455133
455660
  }, undefined, false, undefined, this)
455134
455661
  ]
455135
455662
  }, undefined, true, undefined, this),
@@ -455156,7 +455683,7 @@ function FeedbackDialog({
455156
455683
  ]
455157
455684
  }, undefined, true, undefined, this);
455158
455685
  }
455159
- var import_react72, jsx_dev_runtime46, SOLID_LINE11 = "─";
455686
+ var import_react72, jsx_dev_runtime46, SOLID_LINE11 = "─", INPUT_PROMPT = "> ";
455160
455687
  var init_FeedbackDialog = __esm(async () => {
455161
455688
  init_use_terminal_width();
455162
455689
  init_colors();
@@ -455381,11 +455908,11 @@ var init_HelpDialog = __esm(async () => {
455381
455908
 
455382
455909
  // src/hooks/writer.ts
455383
455910
  import { homedir as homedir34 } from "node:os";
455384
- import { resolve as resolve36 } from "node:path";
455911
+ import { resolve as resolve37 } from "node:path";
455385
455912
  function isProjectSettingsPathCollidingWithGlobal2(workingDirectory) {
455386
455913
  const home = process.env.HOME || homedir34();
455387
- const globalSettingsPath = resolve36(home, ".letta", "settings.json");
455388
- const projectSettingsPath = resolve36(workingDirectory, ".letta", "settings.json");
455914
+ const globalSettingsPath = resolve37(home, ".letta", "settings.json");
455915
+ const projectSettingsPath = resolve37(workingDirectory, ".letta", "settings.json");
455389
455916
  return globalSettingsPath === projectSettingsPath;
455390
455917
  }
455391
455918
  function loadHooksFromLocation(location, workingDirectory = process.cwd()) {
@@ -458226,7 +458753,7 @@ import { spawn as spawn10, spawnSync as spawnSync3 } from "node:child_process";
458226
458753
  import {
458227
458754
  chmodSync as chmodSync6,
458228
458755
  createWriteStream as createWriteStream4,
458229
- existsSync as existsSync51,
458756
+ existsSync as existsSync52,
458230
458757
  mkdirSync as mkdirSync38,
458231
458758
  readdirSync as readdirSync20,
458232
458759
  renameSync as renameSync5,
@@ -458234,7 +458761,7 @@ import {
458234
458761
  statSync as statSync19
458235
458762
  } from "node:fs";
458236
458763
  import { arch as arch4, homedir as homedir35, platform as platform9 } from "node:os";
458237
- import { basename as basename23, join as join53 } from "node:path";
458764
+ import { basename as basename24, join as join54 } from "node:path";
458238
458765
  function toDisplayPath(value) {
458239
458766
  return value.replace(/\\/g, "/");
458240
458767
  }
@@ -458361,9 +458888,9 @@ async function walkDirectoryWithFd(baseDir, fdPath, query2, maxResults, signal)
458361
458888
  if (query2) {
458362
458889
  args.push(buildFdPathQuery(query2));
458363
458890
  }
458364
- return await new Promise((resolve37) => {
458891
+ return await new Promise((resolve38) => {
458365
458892
  if (signal.aborted) {
458366
- resolve37([]);
458893
+ resolve38([]);
458367
458894
  return;
458368
458895
  }
458369
458896
  const child = spawn10(fdPath, args, {
@@ -458376,7 +458903,7 @@ async function walkDirectoryWithFd(baseDir, fdPath, query2, maxResults, signal)
458376
458903
  return;
458377
458904
  resolved = true;
458378
458905
  signal.removeEventListener("abort", onAbort);
458379
- resolve37(results);
458906
+ resolve38(results);
458380
458907
  };
458381
458908
  const onAbort = () => {
458382
458909
  if (child.exitCode === null) {
@@ -458476,7 +459003,7 @@ class FileAutocompleteProvider {
458476
459003
  }
458477
459004
  expandHomePath(path37) {
458478
459005
  if (path37.startsWith("~/")) {
458479
- const expandedPath = join53(homedir35(), path37.slice(2));
459006
+ const expandedPath = join54(homedir35(), path37.slice(2));
458480
459007
  return path37.endsWith("/") && !expandedPath.endsWith("/") ? `${expandedPath}/` : expandedPath;
458481
459008
  } else if (path37 === "~") {
458482
459009
  return homedir35();
@@ -458497,7 +459024,7 @@ class FileAutocompleteProvider {
458497
459024
  } else if (displayBase.startsWith("/")) {
458498
459025
  baseDir = displayBase;
458499
459026
  } else {
458500
- baseDir = join53(this.basePath, displayBase);
459027
+ baseDir = join54(this.basePath, displayBase);
458501
459028
  }
458502
459029
  try {
458503
459030
  if (!statSync19(baseDir).isDirectory()) {
@@ -458516,7 +459043,7 @@ class FileAutocompleteProvider {
458516
459043
  return `${toDisplayPath(displayBase)}${normalizedRelativePath}`;
458517
459044
  }
458518
459045
  scoreEntry(filePath, query2, isDirectory) {
458519
- const fileName = basename23(filePath);
459046
+ const fileName = basename24(filePath);
458520
459047
  const lowerFileName = fileName.toLowerCase();
458521
459048
  const lowerQuery = query2.toLowerCase();
458522
459049
  let score = 0;
@@ -458554,7 +459081,7 @@ class FileAutocompleteProvider {
458554
459081
  for (const { path: entryPath, isDirectory } of topEntries) {
458555
459082
  const pathWithoutSlash = isDirectory ? entryPath.slice(0, -1) : entryPath;
458556
459083
  const displayPath2 = scopedQuery ? this.scopedPathForDisplay(scopedQuery.displayBase, pathWithoutSlash) : pathWithoutSlash;
458557
- const entryName = basename23(pathWithoutSlash);
459084
+ const entryName = basename24(pathWithoutSlash);
458558
459085
  const completionPath = isDirectory ? `${displayPath2}/` : displayPath2;
458559
459086
  const value = buildCompletionValue(completionPath, {
458560
459087
  isDirectory,
@@ -458576,9 +459103,9 @@ class FileAutocompleteProvider {
458576
459103
  var PATH_DELIMITERS2, FD_TOOLS_DIR2, FD_BINARY_NAME2, FD_LOCAL_PATH2;
458577
459104
  var init_file_autocomplete = __esm(() => {
458578
459105
  PATH_DELIMITERS2 = new Set([" ", "\t", '"', "'", "="]);
458579
- FD_TOOLS_DIR2 = join53(homedir35(), ".letta", "bin");
459106
+ FD_TOOLS_DIR2 = join54(homedir35(), ".letta", "bin");
458580
459107
  FD_BINARY_NAME2 = platform9() === "win32" ? "fd.exe" : "fd";
458581
- FD_LOCAL_PATH2 = join53(FD_TOOLS_DIR2, FD_BINARY_NAME2);
459108
+ FD_LOCAL_PATH2 = join54(FD_TOOLS_DIR2, FD_BINARY_NAME2);
458582
459109
  });
458583
459110
 
458584
459111
  // src/cli/hooks/use-autocomplete-navigation.ts
@@ -461486,15 +462013,15 @@ var init_agents7 = __esm(() => {
461486
462013
  // src/cli/commands/install-github-app.ts
461487
462014
  import { execFileSync as execFileSync5 } from "node:child_process";
461488
462015
  import {
461489
- existsSync as existsSync52,
462016
+ existsSync as existsSync53,
461490
462017
  mkdirSync as mkdirSync39,
461491
462018
  mkdtempSync as mkdtempSync2,
461492
- readFileSync as readFileSync35,
462019
+ readFileSync as readFileSync36,
461493
462020
  rmSync as rmSync11,
461494
462021
  writeFileSync as writeFileSync28
461495
462022
  } from "node:fs";
461496
462023
  import { tmpdir as tmpdir7 } from "node:os";
461497
- import { dirname as dirname28, join as join54 } from "node:path";
462024
+ import { dirname as dirname28, join as join55 } from "node:path";
461498
462025
  function runCommand(command, args, cwd2, input) {
461499
462026
  try {
461500
462027
  return execFileSync5(command, args, {
@@ -461715,8 +462242,8 @@ async function createLettaAgent(apiKey, name) {
461715
462242
  return createMinimalAgent(apiKey, name);
461716
462243
  }
461717
462244
  function cloneRepoToTemp(repo) {
461718
- const tempDir = mkdtempSync2(join54(tmpdir7(), "letta-install-github-app-"));
461719
- const repoDir = join54(tempDir, "repo");
462245
+ const tempDir = mkdtempSync2(join55(tmpdir7(), "letta-install-github-app-"));
462246
+ const repoDir = join55(tempDir, "repo");
461720
462247
  runCommand("gh", ["repo", "clone", repo, repoDir, "--", "--depth=1"]);
461721
462248
  return { tempDir, repoDir };
461722
462249
  }
@@ -461727,14 +462254,14 @@ function runGit4(args, cwd2) {
461727
462254
  return runCommand("git", args, cwd2);
461728
462255
  }
461729
462256
  function writeWorkflow(repoDir, workflowPath, content) {
461730
- const absolutePath = join54(repoDir, workflowPath);
461731
- if (!existsSync52(dirname28(absolutePath))) {
462257
+ const absolutePath = join55(repoDir, workflowPath);
462258
+ if (!existsSync53(dirname28(absolutePath))) {
461732
462259
  mkdirSync39(dirname28(absolutePath), { recursive: true });
461733
462260
  }
461734
462261
  const next = `${content.trimEnd()}
461735
462262
  `;
461736
- if (existsSync52(absolutePath)) {
461737
- const previous = readFileSync35(absolutePath, "utf8");
462263
+ if (existsSync53(absolutePath)) {
462264
+ const previous = readFileSync36(absolutePath, "utf8");
461738
462265
  if (previous === next) {
461739
462266
  return false;
461740
462267
  }
@@ -466138,9 +466665,9 @@ __export(exports_generate_memory_viewer, {
466138
466665
  generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
466139
466666
  });
466140
466667
  import { execFile as execFileCb4 } from "node:child_process";
466141
- import { chmodSync as chmodSync7, existsSync as existsSync53, mkdirSync as mkdirSync40, writeFileSync as writeFileSync29 } from "node:fs";
466668
+ import { chmodSync as chmodSync7, existsSync as existsSync54, mkdirSync as mkdirSync40, writeFileSync as writeFileSync29 } from "node:fs";
466142
466669
  import { homedir as homedir36 } from "node:os";
466143
- import { join as join55 } from "node:path";
466670
+ import { join as join56 } from "node:path";
466144
466671
  import { promisify as promisify15 } from "node:util";
466145
466672
  function messagesFromOverview(overview) {
466146
466673
  return overview.messages?.map((message) => ({
@@ -466178,7 +466705,7 @@ async function runGitSafe(cwd2, args) {
466178
466705
  return "";
466179
466706
  }
466180
466707
  }
466181
- function parseFrontmatter2(raw2) {
466708
+ function parseFrontmatter3(raw2) {
466182
466709
  if (!raw2.startsWith("---")) {
466183
466710
  return { frontmatter: {}, body: raw2 };
466184
466711
  }
@@ -466207,7 +466734,7 @@ function collectFiles(memoryRoot) {
466207
466734
  const fileNodes = getFileNodes(treeNodes);
466208
466735
  return fileNodes.filter((n) => n.name.endsWith(".md")).map((n) => {
466209
466736
  const raw2 = readFileContent(n.fullPath);
466210
- const { frontmatter, body: body3 } = parseFrontmatter2(raw2);
466737
+ const { frontmatter, body: body3 } = parseFrontmatter3(raw2);
466211
466738
  return {
466212
466739
  path: n.relativePath,
466213
466740
  isSystem: n.relativePath.startsWith("system/") || n.relativePath.startsWith("system\\"),
@@ -466449,7 +466976,7 @@ ${m4.body}` : m4.subject;
466449
466976
  async function generateAndOpenMemoryViewer(agentId, options3) {
466450
466977
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
466451
466978
  const repoDir = memoryRoot;
466452
- if (!existsSync53(join55(repoDir, ".git"))) {
466979
+ if (!existsSync54(join56(repoDir, ".git"))) {
466453
466980
  throw new Error("Memory viewer requires memfs. Run /memfs enable first.");
466454
466981
  }
466455
466982
  const data = await collectMemoryData(agentId, repoDir, memoryRoot, options3?.conversationId);
@@ -466459,13 +466986,13 @@ async function generateAndOpenMemoryViewer(agentId, options3) {
466459
466986
  data.context = applyContextUsageSnapshot(data.context, options3?.contextUsage);
466460
466987
  const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
466461
466988
  const html5 = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
466462
- if (!existsSync53(VIEWERS_DIR)) {
466989
+ if (!existsSync54(VIEWERS_DIR)) {
466463
466990
  mkdirSync40(VIEWERS_DIR, { recursive: true, mode: 448 });
466464
466991
  }
466465
466992
  try {
466466
466993
  chmodSync7(VIEWERS_DIR, 448);
466467
466994
  } catch {}
466468
- const filePath = join55(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
466995
+ const filePath = join56(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
466469
466996
  writeFileSync29(filePath, html5);
466470
466997
  chmodSync7(filePath, 384);
466471
466998
  const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
@@ -466490,13 +467017,13 @@ var init_generate_memory_viewer = __esm(() => {
466490
467017
  init_local_memory_context();
466491
467018
  init_memory_viewer_template();
466492
467019
  execFile17 = promisify15(execFileCb4);
466493
- VIEWERS_DIR = join55(homedir36(), ".letta", "viewers");
467020
+ VIEWERS_DIR = join56(homedir36(), ".letta", "viewers");
466494
467021
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
466495
467022
  });
466496
467023
 
466497
467024
  // src/cli/components/MemfsTreeViewer.tsx
466498
- import { existsSync as existsSync54 } from "node:fs";
466499
- import { join as join56 } from "node:path";
467025
+ import { existsSync as existsSync55 } from "node:fs";
467026
+ import { join as join57 } from "node:path";
466500
467027
  function renderTreePrefix(node) {
466501
467028
  let prefix = "";
466502
467029
  for (let i4 = 0;i4 < node.depth; i4++) {
@@ -466524,8 +467051,8 @@ function MemfsTreeViewer({
466524
467051
  const [status, setStatus] = import_react91.useState(null);
466525
467052
  const statusTimerRef = import_react91.useRef(null);
466526
467053
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
466527
- const memoryExists = existsSync54(memoryRoot);
466528
- const hasGitRepo = import_react91.useMemo(() => existsSync54(join56(memoryRoot, ".git")), [memoryRoot]);
467054
+ const memoryExists = existsSync55(memoryRoot);
467055
+ const hasGitRepo = import_react91.useMemo(() => existsSync55(join57(memoryRoot, ".git")), [memoryRoot]);
466529
467056
  function showStatus(msg, durationMs) {
466530
467057
  if (statusTimerRef.current)
466531
467058
  clearTimeout(statusTimerRef.current);
@@ -468881,10 +469408,10 @@ var init_PersonalitySelector = __esm(async () => {
468881
469408
  // src/utils/aws-credentials.ts
468882
469409
  import { readFile as readFile18 } from "node:fs/promises";
468883
469410
  import { homedir as homedir37 } from "node:os";
468884
- import { join as join57 } from "node:path";
469411
+ import { join as join58 } from "node:path";
468885
469412
  async function parseAwsCredentials() {
468886
- const credentialsPath = join57(homedir37(), ".aws", "credentials");
468887
- const configPath = join57(homedir37(), ".aws", "config");
469413
+ const credentialsPath = join58(homedir37(), ".aws", "credentials");
469414
+ const configPath = join58(homedir37(), ".aws", "config");
468888
469415
  const profiles = new Map;
468889
469416
  try {
468890
469417
  const content = await readFile18(credentialsPath, "utf-8");
@@ -470239,8 +470766,8 @@ function SkillsDialog({ onClose, agentId }) {
470239
470766
  try {
470240
470767
  const { discoverSkills: discoverSkills3, SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills3(), exports_skills2));
470241
470768
  const { getSkillsDirectory: getSkillsDirectory2, getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
470242
- const { join: join58 } = await import("node:path");
470243
- const skillsDir = getSkillsDirectory2() || join58(process.cwd(), SKILLS_DIR3);
470769
+ const { join: join59 } = await import("node:path");
470770
+ const skillsDir = getSkillsDirectory2() || join59(process.cwd(), SKILLS_DIR3);
470244
470771
  const result = await discoverSkills3(skillsDir, agentId, {
470245
470772
  sources: getSkillSources2()
470246
470773
  });
@@ -474189,9 +474716,9 @@ function getFileEditHeader(toolName, toolArgs) {
474189
474716
  } else if (operations.length === 1) {
474190
474717
  const op = operations[0];
474191
474718
  if (op) {
474192
- const { relative: relative12 } = __require("node:path");
474719
+ const { relative: relative13 } = __require("node:path");
474193
474720
  const cwd3 = process.cwd();
474194
- const relPath2 = relative12(cwd3, op.path);
474721
+ const relPath2 = relative13(cwd3, op.path);
474195
474722
  const displayPath3 = relPath2.startsWith("..") ? op.path : relPath2;
474196
474723
  if (op.kind === "add")
474197
474724
  return `Write to ${displayPath3}?`;
@@ -474205,14 +474732,14 @@ function getFileEditHeader(toolName, toolArgs) {
474205
474732
  return "Apply patch?";
474206
474733
  }
474207
474734
  const filePath = args.file_path || "";
474208
- const { relative: relative11 } = __require("node:path");
474735
+ const { relative: relative12 } = __require("node:path");
474209
474736
  const cwd2 = process.cwd();
474210
- const relPath = relative11(cwd2, filePath);
474737
+ const relPath = relative12(cwd2, filePath);
474211
474738
  const displayPath2 = relPath.startsWith("..") ? filePath : relPath;
474212
474739
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
474213
- const { existsSync: existsSync55 } = __require("node:fs");
474740
+ const { existsSync: existsSync56 } = __require("node:fs");
474214
474741
  try {
474215
- if (existsSync55(filePath)) {
474742
+ if (existsSync56(filePath)) {
474216
474743
  return `Overwrite ${displayPath2}?`;
474217
474744
  }
474218
474745
  } catch {}
@@ -474294,9 +474821,9 @@ var init_ApprovalPreview = __esm(async () => {
474294
474821
  /* @__PURE__ */ jsx_dev_runtime90.jsxDEV(Box_default, {
474295
474822
  flexDirection: "column",
474296
474823
  children: operations.map((op, idx) => {
474297
- const { relative: relative11 } = __require("node:path");
474824
+ const { relative: relative12 } = __require("node:path");
474298
474825
  const cwd2 = process.cwd();
474299
- const relPath = relative11(cwd2, op.path);
474826
+ const relPath = relative12(cwd2, op.path);
474300
474827
  const displayPath2 = relPath.startsWith("..") ? op.path : relPath;
474301
474828
  const diffKey = toolCallId ? `${toolCallId}:${op.path}` : undefined;
474302
474829
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -489516,9 +490043,9 @@ __export(exports_generate_diff_viewer, {
489516
490043
  generateAndOpenDiffViewer: () => generateAndOpenDiffViewer
489517
490044
  });
489518
490045
  import { execFile as execFileCb5 } from "node:child_process";
489519
- import { chmodSync as chmodSync8, existsSync as existsSync55, mkdirSync as mkdirSync41, writeFileSync as writeFileSync30 } from "node:fs";
490046
+ import { chmodSync as chmodSync8, existsSync as existsSync56, mkdirSync as mkdirSync41, writeFileSync as writeFileSync30 } from "node:fs";
489520
490047
  import { homedir as homedir38 } from "node:os";
489521
- import { isAbsolute as isAbsolute22, join as join58, resolve as resolve37 } from "node:path";
490048
+ import { isAbsolute as isAbsolute23, join as join59, resolve as resolve38 } from "node:path";
489522
490049
  import { promisify as promisify16 } from "node:util";
489523
490050
  async function runGit5(cwd2, args) {
489524
490051
  try {
@@ -489716,7 +490243,7 @@ function escapeHtml2(value) {
489716
490243
  function resolveTargetPath(targetPath) {
489717
490244
  if (!targetPath?.trim())
489718
490245
  return process.cwd();
489719
- return isAbsolute22(targetPath) ? targetPath : resolve37(process.cwd(), targetPath);
490246
+ return isAbsolute23(targetPath) ? targetPath : resolve38(process.cwd(), targetPath);
489720
490247
  }
489721
490248
  function shouldSkipOpen() {
489722
490249
  return Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
@@ -489737,13 +490264,13 @@ async function generateAndOpenDiffViewer(targetPath) {
489737
490264
  };
489738
490265
  const jsonPayload = JSON.stringify(payload).replace(/</g, "\\u003c");
489739
490266
  const html5 = diff_viewer_template_default.replace("<!--LETTA_DIFF_DATA_PLACEHOLDER-->", () => jsonPayload);
489740
- if (!existsSync55(VIEWERS_DIR2)) {
490267
+ if (!existsSync56(VIEWERS_DIR2)) {
489741
490268
  mkdirSync41(VIEWERS_DIR2, { recursive: true, mode: 448 });
489742
490269
  }
489743
490270
  try {
489744
490271
  chmodSync8(VIEWERS_DIR2, 448);
489745
490272
  } catch {}
489746
- const filePath = join58(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
490273
+ const filePath = join59(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
489747
490274
  writeFileSync30(filePath, html5);
489748
490275
  chmodSync8(filePath, 384);
489749
490276
  const skipOpen = shouldSkipOpen();
@@ -489814,7 +490341,7 @@ var init_generate_diff_viewer = __esm(() => {
489814
490341
  init_ssr();
489815
490342
  init_diff_viewer_template();
489816
490343
  execFile18 = promisify16(execFileCb5);
489817
- VIEWERS_DIR2 = join58(homedir38(), ".letta", "viewers");
490344
+ VIEWERS_DIR2 = join59(homedir38(), ".letta", "viewers");
489818
490345
  GIT_MAX_BUFFER = 50 * 1024 * 1024;
489819
490346
  });
489820
490347
 
@@ -491777,16 +492304,16 @@ __export(exports_shell_aliases, {
491777
492304
  expandAliases: () => expandAliases,
491778
492305
  clearAliasCache: () => clearAliasCache
491779
492306
  });
491780
- import { existsSync as existsSync56, readFileSync as readFileSync36 } from "node:fs";
492307
+ import { existsSync as existsSync57, readFileSync as readFileSync37 } from "node:fs";
491781
492308
  import { homedir as homedir39 } from "node:os";
491782
- import { join as join59 } from "node:path";
492309
+ import { join as join60 } from "node:path";
491783
492310
  function parseAliasesFromFile(filePath) {
491784
492311
  const aliases = new Map;
491785
- if (!existsSync56(filePath)) {
492312
+ if (!existsSync57(filePath)) {
491786
492313
  return aliases;
491787
492314
  }
491788
492315
  try {
491789
- const content = readFileSync36(filePath, "utf-8");
492316
+ const content = readFileSync37(filePath, "utf-8");
491790
492317
  const lines = content.split(`
491791
492318
  `);
491792
492319
  let inFunction = false;
@@ -491851,7 +492378,7 @@ function loadAliases(forceReload = false) {
491851
492378
  const home = homedir39();
491852
492379
  const allAliases = new Map;
491853
492380
  for (const file3 of ALIAS_FILES) {
491854
- const filePath = join59(home, file3);
492381
+ const filePath = join60(home, file3);
491855
492382
  const fileAliases = parseAliasesFromFile(filePath);
491856
492383
  for (const [name, value] of fileAliases) {
491857
492384
  allAliases.set(name, value);
@@ -492949,7 +493476,7 @@ var init_system_reminders = __esm(() => {
492949
493476
  // src/cli/app/use-conversation-loop.ts
492950
493477
  import { randomUUID as randomUUID29 } from "node:crypto";
492951
493478
  function sleep9(ms) {
492952
- return new Promise((resolve38) => setTimeout(resolve38, ms));
493479
+ return new Promise((resolve39) => setTimeout(resolve39, ms));
492953
493480
  }
492954
493481
  function makeExecutionPhaseHook(setExecutionPhase) {
492955
493482
  return ({ chunk }) => {
@@ -493428,7 +493955,7 @@ function useConversationLoop(ctx) {
493428
493955
  cancelled = true;
493429
493956
  break;
493430
493957
  }
493431
- await new Promise((resolve38) => setTimeout(resolve38, 100));
493958
+ await new Promise((resolve39) => setTimeout(resolve39, 100));
493432
493959
  }
493433
493960
  buffersRef.current.byId.delete(statusId);
493434
493961
  buffersRef.current.order = buffersRef.current.order.filter((id2) => id2 !== statusId);
@@ -493492,7 +494019,7 @@ function useConversationLoop(ctx) {
493492
494019
  cancelled = true;
493493
494020
  break;
493494
494021
  }
493495
- await new Promise((resolve38) => setTimeout(resolve38, 100));
494022
+ await new Promise((resolve39) => setTimeout(resolve39, 100));
493496
494023
  }
493497
494024
  if (retryStatusId) {
493498
494025
  buffersRef.current.byId.delete(retryStatusId);
@@ -494297,7 +494824,7 @@ ${feedback}
494297
494824
  });
494298
494825
  buffersRef.current.order.push(statusId);
494299
494826
  refreshDerived();
494300
- await new Promise((resolve38) => setTimeout(resolve38, delayMs));
494827
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
494301
494828
  buffersRef.current.byId.delete(statusId);
494302
494829
  buffersRef.current.order = buffersRef.current.order.filter((id2) => id2 !== statusId);
494303
494830
  refreshDerived();
@@ -494357,7 +494884,7 @@ ${feedback}
494357
494884
  cancelled = true;
494358
494885
  break;
494359
494886
  }
494360
- await new Promise((resolve38) => setTimeout(resolve38, 100));
494887
+ await new Promise((resolve39) => setTimeout(resolve39, 100));
494361
494888
  }
494362
494889
  if (retryStatusId) {
494363
494890
  buffersRef.current.byId.delete(retryStatusId);
@@ -497733,7 +498260,7 @@ __export(exports_worktree_diff_list, {
497733
498260
  listWorktreeDiffOptions: () => listWorktreeDiffOptions
497734
498261
  });
497735
498262
  import { execFile as execFileCb6 } from "node:child_process";
497736
- import { basename as basename24 } from "node:path";
498263
+ import { basename as basename25 } from "node:path";
497737
498264
  import { promisify as promisify17 } from "node:util";
497738
498265
  async function runGit6(cwd2, args) {
497739
498266
  try {
@@ -497782,7 +498309,7 @@ function parseWorktreeList(output, currentPath) {
497782
498309
  if (current?.path) {
497783
498310
  worktrees.push({
497784
498311
  path: current.path,
497785
- name: basename24(current.path),
498312
+ name: basename25(current.path),
497786
498313
  branch: current.branch ?? "detached",
497787
498314
  head: current.head ?? "",
497788
498315
  isCurrent: current.path === currentPath,
@@ -497808,7 +498335,7 @@ function parseWorktreeList(output, currentPath) {
497808
498335
  if (current?.path) {
497809
498336
  worktrees.push({
497810
498337
  path: current.path,
497811
- name: basename24(current.path),
498338
+ name: basename25(current.path),
497812
498339
  branch: current.branch ?? "detached",
497813
498340
  head: current.head ?? "",
497814
498341
  isCurrent: current.path === currentPath,
@@ -497878,14 +498405,14 @@ __export(exports_export, {
497878
498405
  packageSkills: () => packageSkills
497879
498406
  });
497880
498407
  import { readdir as readdir14, readFile as readFile19 } from "node:fs/promises";
497881
- import { relative as relative11, resolve as resolve38 } from "node:path";
498408
+ import { relative as relative12, resolve as resolve39 } from "node:path";
497882
498409
  async function packageSkills(agentId, skillsDir) {
497883
498410
  const skills = [];
497884
498411
  const skillNames = new Set;
497885
498412
  const dirsToCheck = skillsDir ? [skillsDir] : [
497886
498413
  agentId && getAgentSkillsDir(agentId),
497887
- resolve38(process.cwd(), ".skills"),
497888
- resolve38(process.env.HOME || "~", ".letta", "skills")
498414
+ resolve39(process.cwd(), ".skills"),
498415
+ resolve39(process.env.HOME || "~", ".letta", "skills")
497889
498416
  ].filter((dir) => Boolean(dir));
497890
498417
  for (const baseDir of dirsToCheck) {
497891
498418
  try {
@@ -497895,8 +498422,8 @@ async function packageSkills(agentId, skillsDir) {
497895
498422
  continue;
497896
498423
  if (skillNames.has(entry.name))
497897
498424
  continue;
497898
- const skillDir = resolve38(baseDir, entry.name);
497899
- const skillMdPath = resolve38(skillDir, "SKILL.md");
498425
+ const skillDir = resolve39(baseDir, entry.name);
498426
+ const skillMdPath = resolve39(skillDir, "SKILL.md");
497900
498427
  try {
497901
498428
  await readFile19(skillMdPath, "utf-8");
497902
498429
  } catch {
@@ -497926,12 +498453,12 @@ async function readSkillFiles(skillDir) {
497926
498453
  async function walk(dir) {
497927
498454
  const entries = await readdir14(dir, { withFileTypes: true });
497928
498455
  for (const entry of entries) {
497929
- const fullPath = resolve38(dir, entry.name);
498456
+ const fullPath = resolve39(dir, entry.name);
497930
498457
  if (entry.isDirectory()) {
497931
498458
  await walk(fullPath);
497932
498459
  } else {
497933
498460
  const content = await readFile19(fullPath, "utf-8");
497934
- const relativePath = relative11(skillDir, fullPath).replace(/\\/g, "/");
498461
+ const relativePath = relative12(skillDir, fullPath).replace(/\\/g, "/");
497935
498462
  files[relativePath] = content;
497936
498463
  }
497937
498464
  }
@@ -498066,9 +498593,9 @@ var init_conversation_switch_alert = __esm(() => {
498066
498593
 
498067
498594
  // src/cli/app/use-submit-handler.ts
498068
498595
  import { randomUUID as randomUUID31 } from "node:crypto";
498069
- import { existsSync as existsSync57, readFileSync as readFileSync37, renameSync as renameSync6, writeFileSync as writeFileSync31 } from "node:fs";
498596
+ import { existsSync as existsSync58, readFileSync as readFileSync38, renameSync as renameSync6, writeFileSync as writeFileSync31 } from "node:fs";
498070
498597
  import { tmpdir as tmpdir8 } from "node:os";
498071
- import { join as join60 } from "node:path";
498598
+ import { join as join61 } from "node:path";
498072
498599
  async function findCustomCommandByName(commandName) {
498073
498600
  const { findCustomCommand: findCustomCommand2 } = await Promise.resolve().then(() => (init_custom(), exports_custom));
498074
498601
  return findCustomCommand2(commandName);
@@ -498535,12 +499062,12 @@ ${SYSTEM_REMINDER_CLOSE}`),
498535
499062
  try {
498536
499063
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
498537
499064
  const personaCandidates = [
498538
- join60(memoryRoot, "system", "persona.md"),
498539
- join60(memoryRoot, "memory", "system", "persona.md")
499065
+ join61(memoryRoot, "system", "persona.md"),
499066
+ join61(memoryRoot, "memory", "system", "persona.md")
498540
499067
  ];
498541
- const personaPath = personaCandidates.find((candidate) => existsSync57(candidate));
499068
+ const personaPath = personaCandidates.find((candidate) => existsSync58(candidate));
498542
499069
  if (personaPath) {
498543
- const personaContent = readFileSync37(personaPath, "utf-8");
499070
+ const personaContent = readFileSync38(personaPath, "utf-8");
498544
499071
  setCurrentPersonalityId(detectPersonalityFromPersonaFile(personaContent));
498545
499072
  } else {
498546
499073
  setCurrentPersonalityId(null);
@@ -499493,11 +500020,11 @@ Path: ${memoryDir}`, true);
499493
500020
  setCommandRunning(true);
499494
500021
  try {
499495
500022
  const memoryDir = getScopedMemoryFilesystemRoot(agentId);
499496
- if (!existsSync57(memoryDir)) {
500023
+ if (!existsSync58(memoryDir)) {
499497
500024
  updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
499498
500025
  return { submitted: true };
499499
500026
  }
499500
- const backupDir = join60(tmpdir8(), `letta-memfs-reset-${agentId}-${Date.now()}`);
500027
+ const backupDir = join61(tmpdir8(), `letta-memfs-reset-${agentId}-${Date.now()}`);
499501
500028
  renameSync6(memoryDir, backupDir);
499502
500029
  if (getBackend().capabilities.localMemfs) {
499503
500030
  const { initializeLocalMemoryRepo: initializeLocalMemoryRepo2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
@@ -499541,8 +500068,8 @@ Run \`/memfs sync\` to repopulate from API.`, true, msg);
499541
500068
  await removeGitMemoryTag2(agentId);
499542
500069
  let backupInfo = "";
499543
500070
  const memoryDir = getScopedMemoryFilesystemRoot(agentId);
499544
- if (existsSync57(memoryDir)) {
499545
- const backupDir = join60(tmpdir8(), `letta-memfs-disable-${agentId}-${Date.now()}`);
500071
+ if (existsSync58(memoryDir)) {
500072
+ const backupDir = join61(tmpdir8(), `letta-memfs-disable-${agentId}-${Date.now()}`);
499546
500073
  renameSync6(memoryDir, backupDir);
499547
500074
  backupInfo = `
499548
500075
  Local files backed up to ${backupDir}`;
@@ -502281,9 +502808,9 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
502281
502808
  (async () => {
502282
502809
  try {
502283
502810
  const { watch: watch3 } = await import("node:fs");
502284
- const { existsSync: existsSync58 } = await import("node:fs");
502811
+ const { existsSync: existsSync59 } = await import("node:fs");
502285
502812
  const memRoot = getScopedMemoryFilesystemRoot(agentId);
502286
- if (!existsSync58(memRoot))
502813
+ if (!existsSync59(memRoot))
502287
502814
  return;
502288
502815
  watcher = watch3(memRoot, { recursive: true }, () => {});
502289
502816
  memfsWatcherRef.current = watcher;
@@ -503495,13 +504022,13 @@ __export(exports_terminal_keybinding_installer2, {
503495
504022
  });
503496
504023
  import {
503497
504024
  copyFileSync as copyFileSync3,
503498
- existsSync as existsSync58,
504025
+ existsSync as existsSync59,
503499
504026
  mkdirSync as mkdirSync42,
503500
- readFileSync as readFileSync38,
504027
+ readFileSync as readFileSync39,
503501
504028
  writeFileSync as writeFileSync32
503502
504029
  } from "node:fs";
503503
504030
  import { homedir as homedir41, platform as platform10 } from "node:os";
503504
- import { dirname as dirname29, join as join61 } from "node:path";
504031
+ import { dirname as dirname29, join as join62 } from "node:path";
503505
504032
  function detectTerminalType2() {
503506
504033
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
503507
504034
  return "cursor";
@@ -503533,16 +504060,16 @@ function getKeybindingsPath2(terminal) {
503533
504060
  }[terminal];
503534
504061
  const os8 = platform10();
503535
504062
  if (os8 === "darwin") {
503536
- return join61(homedir41(), "Library", "Application Support", appName, "User", "keybindings.json");
504063
+ return join62(homedir41(), "Library", "Application Support", appName, "User", "keybindings.json");
503537
504064
  }
503538
504065
  if (os8 === "win32") {
503539
504066
  const appData = process.env.APPDATA;
503540
504067
  if (!appData)
503541
504068
  return null;
503542
- return join61(appData, appName, "User", "keybindings.json");
504069
+ return join62(appData, appName, "User", "keybindings.json");
503543
504070
  }
503544
504071
  if (os8 === "linux") {
503545
- return join61(homedir41(), ".config", appName, "User", "keybindings.json");
504072
+ return join62(homedir41(), ".config", appName, "User", "keybindings.json");
503546
504073
  }
503547
504074
  return null;
503548
504075
  }
@@ -503564,10 +504091,10 @@ function parseKeybindings2(content) {
503564
504091
  }
503565
504092
  }
503566
504093
  function keybindingExists2(keybindingsPath) {
503567
- if (!existsSync58(keybindingsPath))
504094
+ if (!existsSync59(keybindingsPath))
503568
504095
  return false;
503569
504096
  try {
503570
- const content = readFileSync38(keybindingsPath, { encoding: "utf-8" });
504097
+ const content = readFileSync39(keybindingsPath, { encoding: "utf-8" });
503571
504098
  const keybindings = parseKeybindings2(content);
503572
504099
  if (!keybindings)
503573
504100
  return false;
@@ -503577,7 +504104,7 @@ function keybindingExists2(keybindingsPath) {
503577
504104
  }
503578
504105
  }
503579
504106
  function createBackup2(keybindingsPath) {
503580
- if (!existsSync58(keybindingsPath))
504107
+ if (!existsSync59(keybindingsPath))
503581
504108
  return null;
503582
504109
  const backupPath = `${keybindingsPath}.letta-backup`;
503583
504110
  try {
@@ -503593,14 +504120,14 @@ function installKeybinding2(keybindingsPath) {
503593
504120
  return { success: true, alreadyExists: true };
503594
504121
  }
503595
504122
  const parentDir = dirname29(keybindingsPath);
503596
- if (!existsSync58(parentDir)) {
504123
+ if (!existsSync59(parentDir)) {
503597
504124
  mkdirSync42(parentDir, { recursive: true });
503598
504125
  }
503599
504126
  let keybindings = [];
503600
504127
  let backupPath = null;
503601
- if (existsSync58(keybindingsPath)) {
504128
+ if (existsSync59(keybindingsPath)) {
503602
504129
  backupPath = createBackup2(keybindingsPath);
503603
- const content = readFileSync38(keybindingsPath, { encoding: "utf-8" });
504130
+ const content = readFileSync39(keybindingsPath, { encoding: "utf-8" });
503604
504131
  const parsed = parseKeybindings2(content);
503605
504132
  if (parsed === null) {
503606
504133
  return {
@@ -503628,10 +504155,10 @@ function installKeybinding2(keybindingsPath) {
503628
504155
  }
503629
504156
  function removeKeybinding2(keybindingsPath) {
503630
504157
  try {
503631
- if (!existsSync58(keybindingsPath)) {
504158
+ if (!existsSync59(keybindingsPath)) {
503632
504159
  return { success: true };
503633
504160
  }
503634
- const content = readFileSync38(keybindingsPath, { encoding: "utf-8" });
504161
+ const content = readFileSync39(keybindingsPath, { encoding: "utf-8" });
503635
504162
  const keybindings = parseKeybindings2(content);
503636
504163
  if (!keybindings) {
503637
504164
  return {
@@ -503695,14 +504222,14 @@ function getWezTermConfigPath2() {
503695
504222
  }
503696
504223
  const xdgConfig = process.env.XDG_CONFIG_HOME;
503697
504224
  if (xdgConfig) {
503698
- const xdgPath = join61(xdgConfig, "wezterm", "wezterm.lua");
503699
- if (existsSync58(xdgPath))
504225
+ const xdgPath = join62(xdgConfig, "wezterm", "wezterm.lua");
504226
+ if (existsSync59(xdgPath))
503700
504227
  return xdgPath;
503701
504228
  }
503702
- const configPath = join61(homedir41(), ".config", "wezterm", "wezterm.lua");
503703
- if (existsSync58(configPath))
504229
+ const configPath = join62(homedir41(), ".config", "wezterm", "wezterm.lua");
504230
+ if (existsSync59(configPath))
503704
504231
  return configPath;
503705
- return join61(homedir41(), ".wezterm.lua");
504232
+ return join62(homedir41(), ".wezterm.lua");
503706
504233
  }
503707
504234
  function stripLuaCommentsFromLine2(line, blockCommentEnd) {
503708
504235
  let code2 = "";
@@ -503805,10 +504332,10 @@ ${WEZTERM_DELETE_FIX2}
503805
504332
  `;
503806
504333
  }
503807
504334
  function wezTermDeleteFixExists2(configPath) {
503808
- if (!existsSync58(configPath))
504335
+ if (!existsSync59(configPath))
503809
504336
  return false;
503810
504337
  try {
503811
- const content = readFileSync38(configPath, { encoding: "utf-8" });
504338
+ const content = readFileSync39(configPath, { encoding: "utf-8" });
503812
504339
  return content.includes("Letta Code: Fix Delete key") || content.includes("key = 'Delete'") && content.includes("SendString") && content.includes("\\x1b[3~");
503813
504340
  } catch {
503814
504341
  return false;
@@ -503822,14 +504349,14 @@ function installWezTermDeleteFix2() {
503822
504349
  }
503823
504350
  let content = "";
503824
504351
  let backupPath = null;
503825
- if (existsSync58(configPath)) {
504352
+ if (existsSync59(configPath)) {
503826
504353
  backupPath = `${configPath}.letta-backup`;
503827
504354
  copyFileSync3(configPath, backupPath);
503828
- content = readFileSync38(configPath, { encoding: "utf-8" });
504355
+ content = readFileSync39(configPath, { encoding: "utf-8" });
503829
504356
  }
503830
504357
  content = injectWezTermDeleteFix2(content);
503831
504358
  const parentDir = dirname29(configPath);
503832
- if (!existsSync58(parentDir)) {
504359
+ if (!existsSync59(parentDir)) {
503833
504360
  mkdirSync42(parentDir, { recursive: true });
503834
504361
  }
503835
504362
  writeFileSync32(configPath, content, { encoding: "utf-8" });
@@ -503881,9 +504408,9 @@ __export(exports_settings3, {
503881
504408
  getSetting: () => getSetting2
503882
504409
  });
503883
504410
  import { homedir as homedir42 } from "node:os";
503884
- import { join as join62 } from "node:path";
504411
+ import { join as join63 } from "node:path";
503885
504412
  function getSettingsPath2() {
503886
- return join62(homedir42(), ".letta", "settings.json");
504413
+ return join63(homedir42(), ".letta", "settings.json");
503887
504414
  }
503888
504415
  async function loadSettings2() {
503889
504416
  const settingsPath = getSettingsPath2();
@@ -503920,7 +504447,7 @@ async function getSetting2(key2) {
503920
504447
  return settings3[key2];
503921
504448
  }
503922
504449
  function getProjectSettingsPath2() {
503923
- return join62(process.cwd(), ".letta", "settings.local.json");
504450
+ return join63(process.cwd(), ".letta", "settings.local.json");
503924
504451
  }
503925
504452
  async function loadProjectSettings2() {
503926
504453
  const settingsPath = getProjectSettingsPath2();
@@ -503938,7 +504465,7 @@ async function loadProjectSettings2() {
503938
504465
  }
503939
504466
  async function saveProjectSettings2(settings3) {
503940
504467
  const settingsPath = getProjectSettingsPath2();
503941
- const dirPath = join62(process.cwd(), ".letta");
504468
+ const dirPath = join63(process.cwd(), ".letta");
503942
504469
  try {
503943
504470
  if (!exists(dirPath)) {
503944
504471
  await mkdir(dirPath, { recursive: true });
@@ -504479,7 +505006,38 @@ __export(exports_import2, {
504479
505006
  });
504480
505007
  import { createReadStream as createReadStream3 } from "node:fs";
504481
505008
  import { access as access3, chmod as chmod2, mkdir as mkdir14, readFile as readFile20, writeFile as writeFile16 } from "node:fs/promises";
504482
- import { dirname as dirname30, resolve as resolve39 } from "node:path";
505009
+ import { dirname as dirname30, isAbsolute as isAbsolute24, relative as relative13, resolve as resolve40, sep as sep7, win32 as win325 } from "node:path";
505010
+ function validateImportedSkillName2(name) {
505011
+ const trimmedName = name.trim();
505012
+ if (trimmedName !== name || trimmedName.length === 0 || trimmedName.length > MAX_SKILL_NAME_LENGTH || trimmedName === "." || trimmedName === ".." || !IMPORTED_SKILL_NAME_PATTERN2.test(trimmedName)) {
505013
+ throw new Error(`Invalid imported skill name "${String(name)}". Skill names may only contain letters, numbers, dots, underscores, and hyphens.`);
505014
+ }
505015
+ return trimmedName;
505016
+ }
505017
+ function assertPathInside2(parent, child) {
505018
+ const parentPath = resolve40(parent);
505019
+ const childPath = resolve40(child);
505020
+ const relativePath = relative13(parentPath, childPath);
505021
+ if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep7}`) || isAbsolute24(relativePath)) {
505022
+ throw new Error(`Imported skill file path escapes skill directory: ${child}`);
505023
+ }
505024
+ }
505025
+ function validateImportedSkillFilePath2(filePath) {
505026
+ if (filePath.length === 0 || filePath === "." || filePath.includes("\x00") || filePath.includes("\\") || isAbsolute24(filePath) || win325.isAbsolute(filePath)) {
505027
+ throw new Error(`Invalid imported skill file path "${filePath}".`);
505028
+ }
505029
+ const segments = filePath.split("/");
505030
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
505031
+ throw new Error(`Invalid imported skill file path "${filePath}".`);
505032
+ }
505033
+ return filePath;
505034
+ }
505035
+ function resolveImportedSkillFilePath2(skillDir, filePath) {
505036
+ const safeFilePath = validateImportedSkillFilePath2(filePath);
505037
+ const fullPath = resolve40(skillDir, safeFilePath);
505038
+ assertPathInside2(skillDir, fullPath);
505039
+ return fullPath;
505040
+ }
504483
505041
  function tagsEqual2(left, right) {
504484
505042
  return left.length === right.length && left.every((tag, i4) => tag === right[i4]);
504485
505043
  }
@@ -504512,7 +505070,7 @@ async function importAgentFromFile2(options3) {
504512
505070
  if (!getBackend().capabilities.agentFileImportExport) {
504513
505071
  throw new Error("Agent file import is not supported by this backend yet");
504514
505072
  }
504515
- const resolvedPath = resolve39(options3.filePath);
505073
+ const resolvedPath = resolve40(options3.filePath);
504516
505074
  try {
504517
505075
  await access3(resolvedPath);
504518
505076
  } catch {
@@ -504556,16 +505114,17 @@ async function extractSkillsFromAf2(afPath, destDir) {
504556
505114
  return [];
504557
505115
  }
504558
505116
  for (const skill2 of afData.skills) {
504559
- const skillDir = resolve39(destDir, skill2.name);
505117
+ const skillName = validateImportedSkillName2(skill2.name);
505118
+ const skillDir = resolve40(destDir, skillName);
504560
505119
  await mkdir14(skillDir, { recursive: true });
504561
505120
  if (skill2.files) {
504562
505121
  await writeSkillFiles2(skillDir, skill2.files);
504563
- extracted.push(skill2.name);
505122
+ extracted.push(skillName);
504564
505123
  } else if (skill2.source_url) {
504565
505124
  await fetchSkillFromUrl2(skillDir, skill2.source_url);
504566
- extracted.push(skill2.name);
505125
+ extracted.push(skillName);
504567
505126
  } else {
504568
- console.warn(`Skipping skill ${skill2.name}: no files or source_url`);
505127
+ console.warn(`Skipping skill ${skillName}: no files or source_url`);
504569
505128
  }
504570
505129
  }
504571
505130
  return extracted;
@@ -504576,7 +505135,7 @@ async function writeSkillFiles2(skillDir, files) {
504576
505135
  }
504577
505136
  }
504578
505137
  async function writeSkillFile2(skillDir, filePath, content) {
504579
- const fullPath = resolve39(skillDir, filePath);
505138
+ const fullPath = resolveImportedSkillFilePath2(skillDir, filePath);
504580
505139
  await mkdir14(dirname30(fullPath), { recursive: true });
504581
505140
  await writeFile16(fullPath, content, "utf-8");
504582
505141
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
@@ -504630,7 +505189,7 @@ function parseRegistryHandle2(handle2) {
504630
505189
  }
504631
505190
  async function importAgentFromRegistry2(options3) {
504632
505191
  const { tmpdir: tmpdir9 } = await import("node:os");
504633
- const { join: join63 } = await import("node:path");
505192
+ const { join: join64 } = await import("node:path");
504634
505193
  const { writeFile: writeFile17, unlink: unlink4 } = await import("node:fs/promises");
504635
505194
  const { author, name } = parseRegistryHandle2(options3.handle);
504636
505195
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
@@ -504642,7 +505201,7 @@ async function importAgentFromRegistry2(options3) {
504642
505201
  throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
504643
505202
  }
504644
505203
  const afContent = await response.text();
504645
- const tempPath = join63(tmpdir9(), `letta-import-${author}-${name}-${Date.now()}.af`);
505204
+ const tempPath = join64(tmpdir9(), `letta-import-${author}-${name}-${Date.now()}.af`);
504646
505205
  await writeFile17(tempPath, afContent, "utf-8");
504647
505206
  try {
504648
505207
  const result = await importAgentFromFile2({
@@ -504659,13 +505218,15 @@ async function importAgentFromRegistry2(options3) {
504659
505218
  } catch {}
504660
505219
  }
504661
505220
  }
504662
- var AGENT_REGISTRY_OWNER2 = "letta-ai", AGENT_REGISTRY_REPO2 = "agent-file", AGENT_REGISTRY_BRANCH2 = "main";
505221
+ var IMPORTED_SKILL_NAME_PATTERN2, AGENT_REGISTRY_OWNER2 = "letta-ai", AGENT_REGISTRY_REPO2 = "agent-file", AGENT_REGISTRY_BRANCH2 = "main";
504663
505222
  var init_import2 = __esm(() => {
504664
505223
  init_backend2();
504665
505224
  init_client2();
505225
+ init_validate_skill();
504666
505226
  init_create6();
504667
505227
  init_model();
504668
505228
  init_modify();
505229
+ IMPORTED_SKILL_NAME_PATTERN2 = /^[A-Za-z0-9._-]+$/;
504669
505230
  });
504670
505231
 
504671
505232
  // src/agent/memory-filesystem.ts
@@ -504693,14 +505254,14 @@ __export(exports_memory_filesystem2, {
504693
505254
  MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR2,
504694
505255
  MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
504695
505256
  });
504696
- import { existsSync as existsSync59, mkdirSync as mkdirSync43 } from "node:fs";
505257
+ import { existsSync as existsSync60, mkdirSync as mkdirSync43 } from "node:fs";
504697
505258
  import { homedir as homedir43 } from "node:os";
504698
- import { join as join63, resolve as resolve40 } from "node:path";
505259
+ import { join as join64, resolve as resolve41 } from "node:path";
504699
505260
  function getMemoryFilesystemRoot2(agentId, homeDir = homedir43()) {
504700
- return join63(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
505261
+ return join64(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
504701
505262
  }
504702
505263
  function getMemorySystemDir2(agentId, homeDir = homedir43()) {
504703
- return join63(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
505264
+ return join64(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
504704
505265
  }
504705
505266
  function getScopedMemoryFilesystemRoot2(agentId, options3 = {}) {
504706
505267
  const env6 = options3.env ?? process.env;
@@ -504725,7 +505286,7 @@ function resolveScopedMemoryDir2(options3 = {}) {
504725
505286
  } catch {}
504726
505287
  const directMemoryDir = (env6.LETTA_MEMORY_DIR || env6.MEMORY_DIR || "").trim();
504727
505288
  if (directMemoryDir) {
504728
- return resolve40(directMemoryDir);
505289
+ return resolve41(directMemoryDir);
504729
505290
  }
504730
505291
  const envAgentId = (env6.LETTA_AGENT_ID || env6.AGENT_ID || "").trim();
504731
505292
  if (envAgentId) {
@@ -504736,10 +505297,10 @@ function resolveScopedMemoryDir2(options3 = {}) {
504736
505297
  function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir43()) {
504737
505298
  const root2 = getMemoryFilesystemRoot2(agentId, homeDir);
504738
505299
  const systemDir = getMemorySystemDir2(agentId, homeDir);
504739
- if (!existsSync59(root2)) {
505300
+ if (!existsSync60(root2)) {
504740
505301
  mkdirSync43(root2, { recursive: true });
504741
505302
  }
504742
- if (!existsSync59(systemDir)) {
505303
+ if (!existsSync60(systemDir)) {
504743
505304
  mkdirSync43(systemDir, { recursive: true });
504744
505305
  }
504745
505306
  }
@@ -513113,7 +513674,7 @@ function getExplicitAgentId(values2) {
513113
513674
  const explicitAgent = values2.agent || values2["agent-id"];
513114
513675
  return typeof explicitAgent === "string" && explicitAgent.trim() ? explicitAgent.trim() : null;
513115
513676
  }
513116
- function paginatedItems2(page) {
513677
+ function paginatedItems3(page) {
513117
513678
  if (Array.isArray(page))
513118
513679
  return page;
513119
513680
  const items3 = page.items;
@@ -513127,7 +513688,7 @@ async function findAgentsByName(name) {
513127
513688
  limit: 100
513128
513689
  });
513129
513690
  const normalizedName = name.toLowerCase();
513130
- return paginatedItems2(page).filter((agent2) => agent2.name?.toLowerCase() === normalizedName);
513691
+ return paginatedItems3(page).filter((agent2) => agent2.name?.toLowerCase() === normalizedName);
513131
513692
  }
513132
513693
  async function resolveAgentByName(name) {
513133
513694
  const matches2 = await findAgentsByName(name);
@@ -515938,12 +516499,12 @@ EXAMPLES
515938
516499
  console.log(usage);
515939
516500
  }
515940
516501
  async function printInfo() {
515941
- const { join: join64 } = await import("path");
516502
+ const { join: join65 } = await import("path");
515942
516503
  const { getVersion: getVersion3 } = await Promise.resolve().then(() => (init_version2(), exports_version2));
515943
516504
  const { SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills4(), exports_skills3));
515944
516505
  const { exists: exists3 } = await Promise.resolve().then(() => (init_fs2(), exports_fs));
515945
516506
  const cwd2 = process.cwd();
515946
- const skillsDir = join64(cwd2, SKILLS_DIR3);
516507
+ const skillsDir = join65(cwd2, SKILLS_DIR3);
515947
516508
  const skillsExist = exists3(skillsDir);
515948
516509
  await settingsManager2.loadLocalProjectSettings(cwd2);
515949
516510
  const localPinned = settingsManager2.getLocalPinnedAgents(cwd2);
@@ -516040,7 +516601,7 @@ async function findLocalAgentsByName(name) {
516040
516601
  query_text: name,
516041
516602
  limit: 100
516042
516603
  });
516043
- return paginatedItems4(page).filter((agent2) => agent2.name?.toLowerCase() === normalizedName);
516604
+ return paginatedItems5(page).filter((agent2) => agent2.name?.toLowerCase() === normalizedName);
516044
516605
  } catch {
516045
516606
  return [];
516046
516607
  }
@@ -516129,7 +516690,7 @@ async function resolveConversationAcrossBackends(conversationId, backendLookupOr
516129
516690
  }
516130
516691
  return null;
516131
516692
  }
516132
- function paginatedItems4(page) {
516693
+ function paginatedItems5(page) {
516133
516694
  if (Array.isArray(page))
516134
516695
  return page;
516135
516696
  if (page && typeof page === "object") {
@@ -516164,7 +516725,7 @@ async function getLocalBackendStartupFallbackSession(backend4) {
516164
516725
  const candidates2 = [];
516165
516726
  try {
516166
516727
  const agentsPage = await backend4.listAgents({ limit: 20 });
516167
- for (const agent2 of paginatedItems4(agentsPage)) {
516728
+ for (const agent2 of paginatedItems5(agentsPage)) {
516168
516729
  const lastActiveAt = agent2.last_run_completion ?? "";
516169
516730
  candidates2.push({ agentId: agent2.id, lastActiveAt });
516170
516731
  }
@@ -516175,7 +516736,7 @@ async function getLocalBackendStartupFallbackSession(backend4) {
516175
516736
  order: "desc",
516176
516737
  order_by: "last_run_completion"
516177
516738
  });
516178
- for (const conversation of paginatedItems4(conversationsPage)) {
516739
+ for (const conversation of paginatedItems5(conversationsPage)) {
516179
516740
  if (!conversation.agent_id)
516180
516741
  continue;
516181
516742
  candidates2.push({
@@ -516280,7 +516841,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
516280
516841
  printHelp();
516281
516842
  const helpDelayMs = Number.parseInt(process.env.LETTA_TEST_HELP_EXIT_DELAY_MS ?? "", 10);
516282
516843
  if (Number.isFinite(helpDelayMs) && helpDelayMs > 0) {
516283
- await new Promise((resolve41) => setTimeout(resolve41, helpDelayMs));
516844
+ await new Promise((resolve42) => setTimeout(resolve42, helpDelayMs));
516284
516845
  }
516285
516846
  process.exit(0);
516286
516847
  }
@@ -516573,10 +517134,10 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
516573
517134
  process.exit(1);
516574
517135
  }
516575
517136
  } else {
516576
- const { resolve: resolve41 } = await import("path");
516577
- const { existsSync: existsSync60 } = await import("fs");
516578
- const resolvedPath = resolve41(fromAfFile);
516579
- if (!existsSync60(resolvedPath)) {
517137
+ const { resolve: resolve42 } = await import("path");
517138
+ const { existsSync: existsSync61 } = await import("fs");
517139
+ const resolvedPath = resolve42(fromAfFile);
517140
+ if (!existsSync61(resolvedPath)) {
516580
517141
  console.error(`Error: AgentFile not found: ${resolvedPath}`);
516581
517142
  process.exit(1);
516582
517143
  }
@@ -517611,4 +518172,4 @@ Error during initialization: ${message}`);
517611
518172
  }
517612
518173
  main2();
517613
518174
 
517614
- //# debugId=C426D273BECF874364756E2164756E21
518175
+ //# debugId=0B9ED738B787990264756E2164756E21