@letta-ai/letta-code 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/letta.js +1332 -536
  2. package/package.json +1 -1
package/letta.js CHANGED
@@ -3250,7 +3250,11 @@ async function revokeToken(refreshToken) {
3250
3250
  }
3251
3251
  async function validateCredentials(baseUrl, apiKey) {
3252
3252
  try {
3253
- const client = new Letta({ apiKey, baseURL: baseUrl });
3253
+ const client = new Letta({
3254
+ apiKey,
3255
+ baseURL: baseUrl,
3256
+ defaultHeaders: { "X-Letta-Source": "letta-code" }
3257
+ });
3254
3258
  await client.agents.list({ limit: 1 });
3255
3259
  return true;
3256
3260
  } catch {
@@ -5087,6 +5091,31 @@ var init_process_manager = __esm(() => {
5087
5091
  backgroundProcesses = new Map;
5088
5092
  });
5089
5093
 
5094
+ // src/tools/impl/shellEnv.ts
5095
+ import { createRequire as createRequire2 } from "node:module";
5096
+ import * as path3 from "node:path";
5097
+ import { fileURLToPath } from "node:url";
5098
+ function getRipgrepBinDir() {
5099
+ try {
5100
+ const __filename2 = fileURLToPath(import.meta.url);
5101
+ const require2 = createRequire2(__filename2);
5102
+ const rgPackage = require2("@vscode/ripgrep");
5103
+ return path3.dirname(rgPackage.rgPath);
5104
+ } catch (_error) {
5105
+ return;
5106
+ }
5107
+ }
5108
+ function getShellEnv() {
5109
+ const env = { ...process.env };
5110
+ const rgBinDir = getRipgrepBinDir();
5111
+ if (rgBinDir) {
5112
+ const currentPath = env.PATH || "";
5113
+ env.PATH = `${rgBinDir}${path3.delimiter}${currentPath}`;
5114
+ }
5115
+ return env;
5116
+ }
5117
+ var init_shellEnv = () => {};
5118
+
5090
5119
  // src/tools/impl/truncation.ts
5091
5120
  function truncateByChars(text, maxChars, _toolName = "output") {
5092
5121
  if (text.length <= maxChars) {
@@ -5150,7 +5179,7 @@ async function bash(args) {
5150
5179
  const childProcess = spawn(command, [], {
5151
5180
  shell: true,
5152
5181
  cwd: userCwd,
5153
- env: { ...process.env }
5182
+ env: getShellEnv()
5154
5183
  });
5155
5184
  backgroundProcesses.set(bashId, {
5156
5185
  process: childProcess,
@@ -5209,7 +5238,7 @@ async function bash(args) {
5209
5238
  timeout: effectiveTimeout,
5210
5239
  maxBuffer: 10 * 1024 * 1024,
5211
5240
  cwd: userCwd,
5212
- env: { ...process.env },
5241
+ env: getShellEnv(),
5213
5242
  signal
5214
5243
  };
5215
5244
  const { stdout, stderr } = await execAsync(command, options);
@@ -5255,6 +5284,7 @@ ${errorMessage}`;
5255
5284
  var execAsync;
5256
5285
  var init_Bash2 = __esm(() => {
5257
5286
  init_process_manager();
5287
+ init_shellEnv();
5258
5288
  init_truncation();
5259
5289
  execAsync = promisify(exec);
5260
5290
  });
@@ -5289,11 +5319,11 @@ var init_BashOutput2 = __esm(() => {
5289
5319
 
5290
5320
  // src/tools/impl/Edit.ts
5291
5321
  import { promises as fs2 } from "node:fs";
5292
- import * as path3 from "node:path";
5322
+ import * as path4 from "node:path";
5293
5323
  async function edit(args) {
5294
5324
  validateRequiredParams(args, ["file_path", "old_string", "new_string"], "Edit");
5295
5325
  const { file_path, old_string, new_string, replace_all = false } = args;
5296
- if (!path3.isAbsolute(file_path))
5326
+ if (!path4.isAbsolute(file_path))
5297
5327
  throw new Error(`File path must be absolute, got: ${file_path}`);
5298
5328
  if (old_string === new_string)
5299
5329
  throw new Error("No changes to make: old_string and new_string are exactly the same.");
@@ -5364,7 +5394,7 @@ Start with updating your todo list if applicable`
5364
5394
 
5365
5395
  // node_modules/picomatch/lib/constants.js
5366
5396
  var require_constants = __commonJS((exports, module) => {
5367
- var path4 = __require("path");
5397
+ var path5 = __require("path");
5368
5398
  var WIN_SLASH = "\\\\/";
5369
5399
  var WIN_NO_SLASH = `[^${WIN_SLASH}]`;
5370
5400
  var DOT_LITERAL = "\\.";
@@ -5486,7 +5516,7 @@ var require_constants = __commonJS((exports, module) => {
5486
5516
  CHAR_UNDERSCORE: 95,
5487
5517
  CHAR_VERTICAL_LINE: 124,
5488
5518
  CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
5489
- SEP: path4.sep,
5519
+ SEP: path5.sep,
5490
5520
  extglobChars(chars) {
5491
5521
  return {
5492
5522
  "!": { type: "negate", open: "(?:(?!(?:", close: `))${chars.STAR})` },
@@ -5504,7 +5534,7 @@ var require_constants = __commonJS((exports, module) => {
5504
5534
 
5505
5535
  // node_modules/picomatch/lib/utils.js
5506
5536
  var require_utils = __commonJS((exports) => {
5507
- var path4 = __require("path");
5537
+ var path5 = __require("path");
5508
5538
  var win32 = process.platform === "win32";
5509
5539
  var {
5510
5540
  REGEX_BACKSLASH,
@@ -5533,7 +5563,7 @@ var require_utils = __commonJS((exports) => {
5533
5563
  if (options && typeof options.windows === "boolean") {
5534
5564
  return options.windows;
5535
5565
  }
5536
- return win32 === true || path4.sep === "\\";
5566
+ return win32 === true || path5.sep === "\\";
5537
5567
  };
5538
5568
  exports.escapeLast = (input, char, lastIdx) => {
5539
5569
  const idx = input.lastIndexOf(char, lastIdx);
@@ -6657,7 +6687,7 @@ var require_parse = __commonJS((exports, module) => {
6657
6687
 
6658
6688
  // node_modules/picomatch/lib/picomatch.js
6659
6689
  var require_picomatch = __commonJS((exports, module) => {
6660
- var path4 = __require("path");
6690
+ var path5 = __require("path");
6661
6691
  var scan = require_scan();
6662
6692
  var parse = require_parse();
6663
6693
  var utils = require_utils();
@@ -6743,7 +6773,7 @@ var require_picomatch = __commonJS((exports, module) => {
6743
6773
  };
6744
6774
  picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
6745
6775
  const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
6746
- return regex.test(path4.basename(input));
6776
+ return regex.test(path5.basename(input));
6747
6777
  };
6748
6778
  picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
6749
6779
  picomatch.parse = (pattern, options) => {
@@ -6798,7 +6828,7 @@ var require_picomatch = __commonJS((exports, module) => {
6798
6828
 
6799
6829
  // src/tools/impl/Glob.ts
6800
6830
  import { promises as fs3 } from "node:fs";
6801
- import * as path4 from "node:path";
6831
+ import * as path5 from "node:path";
6802
6832
  function applyFileLimit(files) {
6803
6833
  const totalFiles = files.length;
6804
6834
  if (totalFiles <= LIMITS.GLOB_MAX_FILES) {
@@ -6818,7 +6848,7 @@ async function walkDirectory(dir) {
6818
6848
  try {
6819
6849
  const entries = await fs3.readdir(dir, { withFileTypes: true });
6820
6850
  for (const entry of entries) {
6821
- const fullPath = path4.join(dir, entry.name);
6851
+ const fullPath = path5.join(dir, entry.name);
6822
6852
  if (entry.isDirectory()) {
6823
6853
  if (entry.name === "node_modules" || entry.name === ".git")
6824
6854
  continue;
@@ -6841,7 +6871,7 @@ async function glob(args) {
6841
6871
  const userCwd = process.env.USER_CWD || process.cwd();
6842
6872
  let baseDir;
6843
6873
  if (searchPath)
6844
- baseDir = path4.isAbsolute(searchPath) ? searchPath : path4.resolve(userCwd, searchPath);
6874
+ baseDir = path5.isAbsolute(searchPath) ? searchPath : path5.resolve(userCwd, searchPath);
6845
6875
  else
6846
6876
  baseDir = userCwd;
6847
6877
  try {
@@ -6859,16 +6889,16 @@ async function glob(args) {
6859
6889
  if (pattern.startsWith("**/")) {
6860
6890
  const subPattern = pattern.slice(3);
6861
6891
  matcher = import_picomatch.default(subPattern);
6862
- const matchedFiles = allFiles.filter((file) => matcher(path4.basename(file)));
6892
+ const matchedFiles = allFiles.filter((file) => matcher(path5.basename(file)));
6863
6893
  return applyFileLimit(matchedFiles.sort());
6864
6894
  } else if (pattern.includes("**")) {
6865
- const fullPattern = path4.join(baseDir, pattern);
6895
+ const fullPattern = path5.join(baseDir, pattern);
6866
6896
  matcher = import_picomatch.default(fullPattern, { dot: true });
6867
6897
  const matchedFiles = allFiles.filter((file) => matcher(file));
6868
6898
  return applyFileLimit(matchedFiles.sort());
6869
6899
  } else {
6870
6900
  matcher = import_picomatch.default(pattern, { dot: true });
6871
- const matchedFiles = allFiles.filter((file) => matcher(path4.relative(baseDir, file)));
6901
+ const matchedFiles = allFiles.filter((file) => matcher(path5.relative(baseDir, file)));
6872
6902
  return applyFileLimit(matchedFiles.sort());
6873
6903
  }
6874
6904
  }
@@ -6895,14 +6925,14 @@ var init_GlobGemini2 = __esm(() => {
6895
6925
 
6896
6926
  // src/tools/impl/Grep.ts
6897
6927
  import { execFile } from "node:child_process";
6898
- import { createRequire as createRequire2 } from "node:module";
6899
- import * as path5 from "node:path";
6900
- import { fileURLToPath } from "node:url";
6928
+ import { createRequire as createRequire3 } from "node:module";
6929
+ import * as path6 from "node:path";
6930
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
6901
6931
  import { promisify as promisify2 } from "node:util";
6902
6932
  function getRipgrepPath() {
6903
6933
  try {
6904
- const __filename2 = fileURLToPath(import.meta.url);
6905
- const require2 = createRequire2(__filename2);
6934
+ const __filename2 = fileURLToPath2(import.meta.url);
6935
+ const require2 = createRequire3(__filename2);
6906
6936
  const rgPackage = require2("@vscode/ripgrep");
6907
6937
  return rgPackage.rgPath;
6908
6938
  } catch (_error) {
@@ -6961,7 +6991,7 @@ async function grep(args) {
6961
6991
  rgArgs.push("-U", "--multiline-dotall");
6962
6992
  rgArgs.push(pattern);
6963
6993
  if (searchPath)
6964
- rgArgs.push(path5.isAbsolute(searchPath) ? searchPath : path5.resolve(userCwd, searchPath));
6994
+ rgArgs.push(path6.isAbsolute(searchPath) ? searchPath : path6.resolve(userCwd, searchPath));
6965
6995
  else
6966
6996
  rgArgs.push(userCwd);
6967
6997
  try {
@@ -7067,10 +7097,10 @@ var init_Grep2 = __esm(() => {
7067
7097
  // src/tools/impl/GrepFiles.ts
7068
7098
  async function grep_files(args) {
7069
7099
  validateRequiredParams(args, ["pattern"], "grep_files");
7070
- const { pattern, include, path: path6, limit: limit2 = DEFAULT_LIMIT } = args;
7100
+ const { pattern, include, path: path7, limit: limit2 = DEFAULT_LIMIT } = args;
7071
7101
  const grepArgs = {
7072
7102
  pattern,
7073
- path: path6,
7103
+ path: path7,
7074
7104
  glob: include,
7075
7105
  output_mode: "files_with_matches"
7076
7106
  };
@@ -7122,7 +7152,7 @@ var init_KillBash2 = __esm(() => {
7122
7152
 
7123
7153
  // src/tools/impl/ListDirCodex.ts
7124
7154
  import { promises as fs4 } from "node:fs";
7125
- import * as path6 from "node:path";
7155
+ import * as path7 from "node:path";
7126
7156
  async function list_dir(args) {
7127
7157
  validateRequiredParams(args, ["dir_path"], "list_dir");
7128
7158
  const { dir_path, offset = 1, limit: limit2 = 25, depth = 2 } = args;
@@ -7135,7 +7165,7 @@ async function list_dir(args) {
7135
7165
  if (depth < 1) {
7136
7166
  throw new Error("depth must be greater than zero");
7137
7167
  }
7138
- if (!path6.isAbsolute(dir_path)) {
7168
+ if (!path7.isAbsolute(dir_path)) {
7139
7169
  throw new Error("dir_path must be an absolute path");
7140
7170
  }
7141
7171
  const entries = await listDirSlice(dir_path, offset, limit2, depth);
@@ -7180,10 +7210,10 @@ async function collectEntries(dirPath, relativePrefix, remainingDepth, entries)
7180
7210
  try {
7181
7211
  const items = await fs4.readdir(absPath, { withFileTypes: true });
7182
7212
  for (const item of items) {
7183
- const itemAbsPath = path6.join(absPath, item.name);
7184
- const relativePath = prefix ? path6.join(prefix, item.name) : item.name;
7213
+ const itemAbsPath = path7.join(absPath, item.name);
7214
+ const relativePath = prefix ? path7.join(prefix, item.name) : item.name;
7185
7215
  const displayName = formatEntryComponent(item.name);
7186
- const displayDepth = prefix ? prefix.split(path6.sep).length : 0;
7216
+ const displayDepth = prefix ? prefix.split(path7.sep).length : 0;
7187
7217
  const sortKey = formatEntryName(relativePath);
7188
7218
  let kind;
7189
7219
  if (item.isSymbolicLink()) {
@@ -7375,11 +7405,11 @@ var init_ListDirectoryGemini2 = __esm(() => {
7375
7405
 
7376
7406
  // src/tools/impl/MultiEdit.ts
7377
7407
  import { promises as fs5 } from "node:fs";
7378
- import * as path7 from "node:path";
7408
+ import * as path8 from "node:path";
7379
7409
  async function multi_edit(args) {
7380
7410
  validateRequiredParams(args, ["file_path", "edits"], "MultiEdit");
7381
7411
  const { file_path, edits } = args;
7382
- if (!path7.isAbsolute(file_path))
7412
+ if (!path8.isAbsolute(file_path))
7383
7413
  throw new Error(`File path must be absolute, got: ${file_path}`);
7384
7414
  if (!edits || edits.length === 0)
7385
7415
  throw new Error("No edits provided");
@@ -7446,7 +7476,7 @@ var init_MultiEdit2 = () => {};
7446
7476
 
7447
7477
  // src/tools/impl/Read.ts
7448
7478
  import { promises as fs6 } from "node:fs";
7449
- import * as path8 from "node:path";
7479
+ import * as path9 from "node:path";
7450
7480
  async function isBinaryFile(filePath) {
7451
7481
  try {
7452
7482
  const fd = await fs6.open(filePath, "r");
@@ -7530,7 +7560,7 @@ function formatWithLineNumbers(content, offset, limit2) {
7530
7560
  async function read(args) {
7531
7561
  validateRequiredParams(args, ["file_path"], "Read");
7532
7562
  const { file_path, offset, limit: limit2 } = args;
7533
- if (!path8.isAbsolute(file_path))
7563
+ if (!path9.isAbsolute(file_path))
7534
7564
  throw new Error(`File path must be absolute, got: ${file_path}`);
7535
7565
  try {
7536
7566
  const stats = await fs6.stat(file_path);
@@ -9098,7 +9128,7 @@ var minimatch = (p, pattern, options = {}) => {
9098
9128
  }, qmarksTestNoExtDot = ([$0]) => {
9099
9129
  const len = $0.length;
9100
9130
  return (f) => f.length === len && f !== "." && f !== "..";
9101
- }, defaultPlatform, path9, sep2, GLOBSTAR, qmark2 = "[^/]", star2, twoStarDot = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?", twoStarNoDot = "(?:(?!(?:\\/|^)\\.).)*?", filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options), ext = (a, b = {}) => Object.assign({}, a, b), defaults2 = (def) => {
9131
+ }, defaultPlatform, path10, sep2, GLOBSTAR, qmark2 = "[^/]", star2, twoStarDot = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?", twoStarNoDot = "(?:(?!(?:\\/|^)\\.).)*?", filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options), ext = (a, b = {}) => Object.assign({}, a, b), defaults2 = (def) => {
9102
9132
  if (!def || typeof def !== "object" || !Object.keys(def).length) {
9103
9133
  return minimatch;
9104
9134
  }
@@ -9156,11 +9186,11 @@ var init_esm2 = __esm(() => {
9156
9186
  starRE = /^\*+$/;
9157
9187
  qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
9158
9188
  defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
9159
- path9 = {
9189
+ path10 = {
9160
9190
  win32: { sep: "\\" },
9161
9191
  posix: { sep: "/" }
9162
9192
  };
9163
- sep2 = defaultPlatform === "win32" ? path9.win32.sep : path9.posix.sep;
9193
+ sep2 = defaultPlatform === "win32" ? path10.win32.sep : path10.posix.sep;
9164
9194
  minimatch.sep = sep2;
9165
9195
  GLOBSTAR = Symbol("globstar **");
9166
9196
  minimatch.GLOBSTAR = GLOBSTAR;
@@ -10963,7 +10993,7 @@ var init_esm4 = __esm(() => {
10963
10993
 
10964
10994
  // node_modules/path-scurry/dist/esm/index.js
10965
10995
  import { posix, win32 } from "node:path";
10966
- import { fileURLToPath as fileURLToPath2 } from "node:url";
10996
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
10967
10997
  import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSync as rps } from "fs";
10968
10998
  import * as actualFS from "node:fs";
10969
10999
  import { lstat, readdir as readdir2, readlink, realpath } from "node:fs/promises";
@@ -11150,12 +11180,12 @@ var init_esm5 = __esm(() => {
11150
11180
  childrenCache() {
11151
11181
  return this.#children;
11152
11182
  }
11153
- resolve(path10) {
11154
- if (!path10) {
11183
+ resolve(path11) {
11184
+ if (!path11) {
11155
11185
  return this;
11156
11186
  }
11157
- const rootPath = this.getRootString(path10);
11158
- const dir = path10.substring(rootPath.length);
11187
+ const rootPath = this.getRootString(path11);
11188
+ const dir = path11.substring(rootPath.length);
11159
11189
  const dirParts = dir.split(this.splitSep);
11160
11190
  const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
11161
11191
  return result;
@@ -11683,8 +11713,8 @@ var init_esm5 = __esm(() => {
11683
11713
  newChild(name, type = UNKNOWN, opts = {}) {
11684
11714
  return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
11685
11715
  }
11686
- getRootString(path10) {
11687
- return win32.parse(path10).root;
11716
+ getRootString(path11) {
11717
+ return win32.parse(path11).root;
11688
11718
  }
11689
11719
  getRoot(rootPath) {
11690
11720
  rootPath = uncToDrive(rootPath.toUpperCase());
@@ -11709,8 +11739,8 @@ var init_esm5 = __esm(() => {
11709
11739
  constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
11710
11740
  super(name, type, root, roots, nocase, children, opts);
11711
11741
  }
11712
- getRootString(path10) {
11713
- return path10.startsWith("/") ? "/" : "";
11742
+ getRootString(path11) {
11743
+ return path11.startsWith("/") ? "/" : "";
11714
11744
  }
11715
11745
  getRoot(_rootPath) {
11716
11746
  return this.root;
@@ -11732,7 +11762,7 @@ var init_esm5 = __esm(() => {
11732
11762
  constructor(cwd = process.cwd(), pathImpl, sep3, { nocase, childrenCacheSize = 16 * 1024, fs: fs8 = defaultFS } = {}) {
11733
11763
  this.#fs = fsFromOption(fs8);
11734
11764
  if (cwd instanceof URL || cwd.startsWith("file://")) {
11735
- cwd = fileURLToPath2(cwd);
11765
+ cwd = fileURLToPath3(cwd);
11736
11766
  }
11737
11767
  const cwdPath = pathImpl.resolve(cwd);
11738
11768
  this.roots = Object.create(null);
@@ -11766,11 +11796,11 @@ var init_esm5 = __esm(() => {
11766
11796
  }
11767
11797
  this.cwd = prev;
11768
11798
  }
11769
- depth(path10 = this.cwd) {
11770
- if (typeof path10 === "string") {
11771
- path10 = this.cwd.resolve(path10);
11799
+ depth(path11 = this.cwd) {
11800
+ if (typeof path11 === "string") {
11801
+ path11 = this.cwd.resolve(path11);
11772
11802
  }
11773
- return path10.depth();
11803
+ return path11.depth();
11774
11804
  }
11775
11805
  childrenCache() {
11776
11806
  return this.#children;
@@ -12186,9 +12216,9 @@ var init_esm5 = __esm(() => {
12186
12216
  process2();
12187
12217
  return results;
12188
12218
  }
12189
- chdir(path10 = this.cwd) {
12219
+ chdir(path11 = this.cwd) {
12190
12220
  const oldCwd = this.cwd;
12191
- this.cwd = typeof path10 === "string" ? this.cwd.resolve(path10) : path10;
12221
+ this.cwd = typeof path11 === "string" ? this.cwd.resolve(path11) : path11;
12192
12222
  this.cwd[setAsCwd](oldCwd);
12193
12223
  }
12194
12224
  };
@@ -12480,8 +12510,8 @@ class MatchRecord {
12480
12510
  this.store.set(target, current === undefined ? n : n & current);
12481
12511
  }
12482
12512
  entries() {
12483
- return [...this.store.entries()].map(([path10, n]) => [
12484
- path10,
12513
+ return [...this.store.entries()].map(([path11, n]) => [
12514
+ path11,
12485
12515
  !!(n & 2),
12486
12516
  !!(n & 1)
12487
12517
  ]);
@@ -12685,9 +12715,9 @@ class GlobUtil {
12685
12715
  signal;
12686
12716
  maxDepth;
12687
12717
  includeChildMatches;
12688
- constructor(patterns, path10, opts) {
12718
+ constructor(patterns, path11, opts) {
12689
12719
  this.patterns = patterns;
12690
- this.path = path10;
12720
+ this.path = path11;
12691
12721
  this.opts = opts;
12692
12722
  this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
12693
12723
  this.includeChildMatches = opts.includeChildMatches !== false;
@@ -12706,11 +12736,11 @@ class GlobUtil {
12706
12736
  });
12707
12737
  }
12708
12738
  }
12709
- #ignored(path10) {
12710
- return this.seen.has(path10) || !!this.#ignore?.ignored?.(path10);
12739
+ #ignored(path11) {
12740
+ return this.seen.has(path11) || !!this.#ignore?.ignored?.(path11);
12711
12741
  }
12712
- #childrenIgnored(path10) {
12713
- return !!this.#ignore?.childrenIgnored?.(path10);
12742
+ #childrenIgnored(path11) {
12743
+ return !!this.#ignore?.childrenIgnored?.(path11);
12714
12744
  }
12715
12745
  pause() {
12716
12746
  this.paused = true;
@@ -12927,8 +12957,8 @@ var init_walker = __esm(() => {
12927
12957
  init_processor();
12928
12958
  GlobWalker = class GlobWalker extends GlobUtil {
12929
12959
  matches = new Set;
12930
- constructor(patterns, path10, opts) {
12931
- super(patterns, path10, opts);
12960
+ constructor(patterns, path11, opts) {
12961
+ super(patterns, path11, opts);
12932
12962
  }
12933
12963
  matchEmit(e) {
12934
12964
  this.matches.add(e);
@@ -12965,8 +12995,8 @@ var init_walker = __esm(() => {
12965
12995
  };
12966
12996
  GlobStream = class GlobStream extends GlobUtil {
12967
12997
  results;
12968
- constructor(patterns, path10, opts) {
12969
- super(patterns, path10, opts);
12998
+ constructor(patterns, path11, opts) {
12999
+ super(patterns, path11, opts);
12970
13000
  this.results = new Minipass({
12971
13001
  signal: this.signal,
12972
13002
  objectMode: true
@@ -13001,7 +13031,7 @@ var init_walker = __esm(() => {
13001
13031
  });
13002
13032
 
13003
13033
  // node_modules/glob/dist/esm/glob.js
13004
- import { fileURLToPath as fileURLToPath3 } from "node:url";
13034
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
13005
13035
  var defaultPlatform3, Glob;
13006
13036
  var init_glob = __esm(() => {
13007
13037
  init_esm2();
@@ -13050,7 +13080,7 @@ var init_glob = __esm(() => {
13050
13080
  if (!opts.cwd) {
13051
13081
  this.cwd = "";
13052
13082
  } else if (opts.cwd instanceof URL || opts.cwd.startsWith("file://")) {
13053
- opts.cwd = fileURLToPath3(opts.cwd);
13083
+ opts.cwd = fileURLToPath4(opts.cwd);
13054
13084
  }
13055
13085
  this.cwd = opts.cwd || "";
13056
13086
  this.root = opts.root;
@@ -13255,7 +13285,7 @@ var init_esm6 = __esm(() => {
13255
13285
  });
13256
13286
 
13257
13287
  // src/tools/impl/ReadManyFilesGemini.ts
13258
- import path10 from "node:path";
13288
+ import path11 from "node:path";
13259
13289
  async function read_many_files(args) {
13260
13290
  const { include, exclude = [], useDefaultExcludes = true } = args;
13261
13291
  if (!Array.isArray(include) || include.length === 0) {
@@ -13286,7 +13316,7 @@ async function read_many_files(args) {
13286
13316
  const skippedFiles = [];
13287
13317
  for (const filePath of sortedFiles) {
13288
13318
  try {
13289
- const _relativePath = path10.relative(cwd, filePath);
13319
+ const _relativePath = path11.relative(cwd, filePath);
13290
13320
  const separator = `--- ${filePath} ---`;
13291
13321
  const result = await read({ file_path: filePath });
13292
13322
  const content = result.content;
@@ -13296,7 +13326,7 @@ ${content}
13296
13326
 
13297
13327
  `);
13298
13328
  } catch (error) {
13299
- const relativePath = path10.relative(cwd, filePath);
13329
+ const relativePath = path11.relative(cwd, filePath);
13300
13330
  skippedFiles.push({
13301
13331
  path: relativePath,
13302
13332
  reason: error instanceof Error ? error.message : "Unknown error reading file"
@@ -13383,27 +13413,85 @@ var init_SearchFileContentGemini2 = __esm(() => {
13383
13413
  init_Grep2();
13384
13414
  });
13385
13415
 
13416
+ // src/tools/impl/shellLaunchers.ts
13417
+ function pushUnique(list, seen, entry) {
13418
+ if (!entry.length || !entry[0])
13419
+ return;
13420
+ const key = entry.join(SEP);
13421
+ if (seen.has(key))
13422
+ return;
13423
+ seen.add(key);
13424
+ list.push(entry);
13425
+ }
13426
+ function windowsLaunchers(command) {
13427
+ const trimmed = command.trim();
13428
+ if (!trimmed)
13429
+ return [];
13430
+ const launchers = [];
13431
+ const seen = new Set;
13432
+ const envComSpecRaw = process.env.ComSpec || process.env.COMSPEC;
13433
+ const envComSpec = envComSpecRaw?.trim();
13434
+ if (envComSpec) {
13435
+ pushUnique(launchers, seen, [envComSpec, "/d", "/s", "/c", trimmed]);
13436
+ }
13437
+ pushUnique(launchers, seen, ["cmd.exe", "/d", "/s", "/c", trimmed]);
13438
+ pushUnique(launchers, seen, [
13439
+ "powershell.exe",
13440
+ "-NoProfile",
13441
+ "-Command",
13442
+ trimmed
13443
+ ]);
13444
+ pushUnique(launchers, seen, ["pwsh", "-NoProfile", "-Command", trimmed]);
13445
+ return launchers;
13446
+ }
13447
+ function unixLaunchers(command) {
13448
+ const trimmed = command.trim();
13449
+ if (!trimmed)
13450
+ return [];
13451
+ const launchers = [];
13452
+ const seen = new Set;
13453
+ const envShell = process.env.SHELL?.trim();
13454
+ if (envShell) {
13455
+ pushUnique(launchers, seen, [envShell, "-lc", trimmed]);
13456
+ pushUnique(launchers, seen, [envShell, "-c", trimmed]);
13457
+ }
13458
+ const defaults3 = [
13459
+ ["/bin/bash", "-lc", trimmed],
13460
+ ["/usr/bin/bash", "-lc", trimmed],
13461
+ ["/bin/zsh", "-lc", trimmed],
13462
+ ["/bin/sh", "-c", trimmed],
13463
+ ["/bin/ash", "-c", trimmed],
13464
+ ["/usr/bin/env", "bash", "-lc", trimmed],
13465
+ ["/usr/bin/env", "zsh", "-lc", trimmed],
13466
+ ["/usr/bin/env", "sh", "-c", trimmed],
13467
+ ["/usr/bin/env", "ash", "-c", trimmed]
13468
+ ];
13469
+ for (const entry of defaults3) {
13470
+ pushUnique(launchers, seen, entry);
13471
+ }
13472
+ return launchers;
13473
+ }
13474
+ function buildShellLaunchers(command) {
13475
+ return process.platform === "win32" ? windowsLaunchers(command) : unixLaunchers(command);
13476
+ }
13477
+ var SEP = "\x00";
13478
+
13386
13479
  // src/tools/impl/Shell.ts
13387
13480
  import { spawn as spawn2 } from "node:child_process";
13388
- import * as path11 from "node:path";
13389
- async function shell(args) {
13390
- validateRequiredParams(args, ["command"], "shell");
13391
- const { command, workdir, timeout_ms } = args;
13392
- if (!Array.isArray(command) || command.length === 0) {
13393
- throw new Error("command must be a non-empty array of strings");
13394
- }
13395
- const [executable, ...execArgs] = command;
13396
- if (!executable) {
13397
- throw new Error("command must be a non-empty array of strings");
13398
- }
13399
- const timeout = timeout_ms ?? DEFAULT_TIMEOUT;
13400
- const cwd = workdir ? path11.isAbsolute(workdir) ? workdir : path11.resolve(process.env.USER_CWD || process.cwd(), workdir) : process.env.USER_CWD || process.cwd();
13481
+ import * as path12 from "node:path";
13482
+ function runProcess(context2) {
13401
13483
  return new Promise((resolve6, reject) => {
13484
+ const { command, cwd, env, timeout } = context2;
13485
+ const [executable, ...execArgs] = command;
13486
+ if (!executable) {
13487
+ reject(new ShellExecutionError("Executable is required"));
13488
+ return;
13489
+ }
13402
13490
  const stdoutChunks = [];
13403
13491
  const stderrChunks = [];
13404
13492
  const child = spawn2(executable, execArgs, {
13405
13493
  cwd,
13406
- env: process.env,
13494
+ env,
13407
13495
  stdio: ["ignore", "pipe", "pipe"]
13408
13496
  });
13409
13497
  const timeoutId = setTimeout(() => {
@@ -13418,7 +13506,10 @@ async function shell(args) {
13418
13506
  });
13419
13507
  child.on("error", (err) => {
13420
13508
  clearTimeout(timeoutId);
13421
- reject(new Error(`Failed to execute command: ${err.message}`));
13509
+ const execError = new ShellExecutionError(err?.code === "ENOENT" ? `Executable not found: ${executable}` : `Failed to execute command: ${err?.message || "unknown error"}`);
13510
+ execError.code = err?.code;
13511
+ execError.executable = executable;
13512
+ reject(execError);
13422
13513
  });
13423
13514
  child.on("close", (code) => {
13424
13515
  clearTimeout(timeoutId);
@@ -13446,46 +13537,138 @@ async function shell(args) {
13446
13537
  });
13447
13538
  });
13448
13539
  }
13449
- var DEFAULT_TIMEOUT = 120000;
13450
- var init_Shell2 = () => {};
13540
+ async function shell(args) {
13541
+ validateRequiredParams(args, ["command"], "shell");
13542
+ const { command, workdir, timeout_ms } = args;
13543
+ if (!Array.isArray(command) || command.length === 0) {
13544
+ throw new Error("command must be a non-empty array of strings");
13545
+ }
13546
+ const timeout = timeout_ms ?? DEFAULT_TIMEOUT;
13547
+ const cwd = workdir ? path12.isAbsolute(workdir) ? workdir : path12.resolve(process.env.USER_CWD || process.cwd(), workdir) : process.env.USER_CWD || process.cwd();
13548
+ const context2 = {
13549
+ command,
13550
+ cwd,
13551
+ env: getShellEnv(),
13552
+ timeout
13553
+ };
13554
+ try {
13555
+ return await runProcess(context2);
13556
+ } catch (error) {
13557
+ if (error instanceof ShellExecutionError && error.code === "ENOENT") {
13558
+ for (const fallback of buildFallbackCommands(command)) {
13559
+ try {
13560
+ return await runProcess({ ...context2, command: fallback });
13561
+ } catch (retryError) {
13562
+ if (retryError instanceof ShellExecutionError && retryError.code === "ENOENT") {
13563
+ continue;
13564
+ }
13565
+ throw retryError;
13566
+ }
13567
+ }
13568
+ }
13569
+ throw error;
13570
+ }
13571
+ }
13572
+ function buildFallbackCommands(command) {
13573
+ if (!command.length)
13574
+ return [];
13575
+ const first = command[0];
13576
+ if (!first)
13577
+ return [];
13578
+ if (!isShellExecutableName(first))
13579
+ return [];
13580
+ const script = extractShellScript(command);
13581
+ if (!script)
13582
+ return [];
13583
+ const launchers = buildShellLaunchers(script);
13584
+ return launchers.filter((launcher) => !arraysEqual(launcher, command));
13585
+ }
13586
+ function arraysEqual(a, b) {
13587
+ if (a.length !== b.length)
13588
+ return false;
13589
+ for (let i = 0;i < a.length; i += 1) {
13590
+ if (a[i] !== b[i])
13591
+ return false;
13592
+ }
13593
+ return true;
13594
+ }
13595
+ function isShellExecutableName(name) {
13596
+ const normalized = name.replace(/\\/g, "/").toLowerCase();
13597
+ if (/(^|\/)(ba|z|a|da)?sh$/.test(normalized)) {
13598
+ return true;
13599
+ }
13600
+ if (normalized.endsWith("cmd.exe")) {
13601
+ return true;
13602
+ }
13603
+ if (normalized.includes("powershell")) {
13604
+ return true;
13605
+ }
13606
+ if (normalized.includes("pwsh")) {
13607
+ return true;
13608
+ }
13609
+ return false;
13610
+ }
13611
+ function extractShellScript(command) {
13612
+ for (let i = 1;i < command.length; i += 1) {
13613
+ const token = command[i];
13614
+ if (!token)
13615
+ continue;
13616
+ const normalized = token.toLowerCase();
13617
+ if (normalized === "-c" || normalized === "-lc" || normalized === "/c" || (normalized.startsWith("-") || normalized.startsWith("/")) && normalized.endsWith("c")) {
13618
+ return command[i + 1] ?? null;
13619
+ }
13620
+ }
13621
+ return null;
13622
+ }
13623
+ var ShellExecutionError, DEFAULT_TIMEOUT = 120000;
13624
+ var init_Shell2 = __esm(() => {
13625
+ init_shellEnv();
13626
+ ShellExecutionError = class ShellExecutionError extends Error {
13627
+ code;
13628
+ executable;
13629
+ };
13630
+ });
13451
13631
 
13452
13632
  // src/tools/impl/ShellCommand.ts
13453
13633
  async function shell_command(args) {
13454
13634
  validateRequiredParams(args, ["command"], "shell_command");
13455
- const { command, workdir, timeout_ms, justification: description } = args;
13456
- const previousUserCwd = process.env.USER_CWD;
13457
- if (workdir) {
13458
- process.env.USER_CWD = workdir;
13635
+ const {
13636
+ command,
13637
+ workdir,
13638
+ timeout_ms,
13639
+ with_escalated_permissions,
13640
+ justification
13641
+ } = args;
13642
+ const launchers = buildShellLaunchers(command);
13643
+ if (launchers.length === 0) {
13644
+ throw new Error("Command must be a non-empty string");
13459
13645
  }
13460
- try {
13461
- const result = await bash({
13462
- command,
13463
- timeout: timeout_ms ?? 120000,
13464
- description,
13465
- run_in_background: false
13466
- });
13467
- const text = (result.content ?? []).map((item) => ("text" in item) && typeof item.text === "string" ? item.text : "").filter(Boolean).join(`
13468
- `);
13469
- const stdout = text ? text.split(`
13470
- `) : [];
13471
- const stderr = result.status === "error" ? ["Command reported an error. See output for details."] : [];
13472
- return {
13473
- output: text,
13474
- stdout,
13475
- stderr
13476
- };
13477
- } finally {
13478
- if (workdir) {
13479
- if (previousUserCwd === undefined) {
13480
- delete process.env.USER_CWD;
13481
- } else {
13482
- process.env.USER_CWD = previousUserCwd;
13646
+ const tried = [];
13647
+ let lastError = null;
13648
+ for (const launcher of launchers) {
13649
+ try {
13650
+ return await shell({
13651
+ command: launcher,
13652
+ workdir,
13653
+ timeout_ms,
13654
+ with_escalated_permissions,
13655
+ justification
13656
+ });
13657
+ } catch (error) {
13658
+ if (error instanceof ShellExecutionError && error.code === "ENOENT") {
13659
+ tried.push(launcher[0] || "");
13660
+ lastError = error;
13661
+ continue;
13483
13662
  }
13663
+ throw error;
13484
13664
  }
13485
13665
  }
13666
+ const suffix = tried.filter(Boolean).join(", ");
13667
+ const reason = lastError?.message || "Shell unavailable";
13668
+ throw new Error(suffix ? `${reason} (tried: ${suffix})` : reason);
13486
13669
  }
13487
13670
  var init_ShellCommand2 = __esm(() => {
13488
- init_Bash2();
13671
+ init_Shell2();
13489
13672
  });
13490
13673
 
13491
13674
  // src/agent/context.ts
@@ -13563,6 +13746,12 @@ var init_context = __esm(() => {
13563
13746
  });
13564
13747
 
13565
13748
  // src/agent/skills.ts
13749
+ var exports_skills = {};
13750
+ __export(exports_skills, {
13751
+ formatSkillsForMemory: () => formatSkillsForMemory,
13752
+ discoverSkills: () => discoverSkills,
13753
+ SKILLS_DIR: () => SKILLS_DIR
13754
+ });
13566
13755
  import { existsSync as existsSync2 } from "node:fs";
13567
13756
  import { readdir as readdir3, readFile as readFile2 } from "node:fs/promises";
13568
13757
  import { join as join6 } from "node:path";
@@ -13798,8 +13987,21 @@ Error: ${error instanceof Error ? error.message : String(error)}`);
13798
13987
  if (!skillsDir) {
13799
13988
  skillsDir = join7(process.cwd(), SKILLS_DIR);
13800
13989
  }
13801
- const skillPath = join7(skillsDir, skillId, "SKILL.md");
13802
- const skillContent = await readFile3(skillPath, "utf-8");
13990
+ let skillPath = join7(skillsDir, skillId, "SKILL.md");
13991
+ let skillContent;
13992
+ try {
13993
+ skillContent = await readFile3(skillPath, "utf-8");
13994
+ } catch (primaryError) {
13995
+ try {
13996
+ const bundledSkillsDir = join7(process.cwd(), "skills", "skills");
13997
+ const bundledSkillPath = join7(bundledSkillsDir, skillId, "SKILL.md");
13998
+ skillContent = await readFile3(bundledSkillPath, "utf-8");
13999
+ skillsDir = bundledSkillsDir;
14000
+ skillPath = bundledSkillPath;
14001
+ } catch {
14002
+ throw primaryError;
14003
+ }
14004
+ }
13803
14005
  let currentValue = loadedSkillsBlock.value?.trim() || "";
13804
14006
  const loadedSkills = parseLoadedSkills(currentValue);
13805
14007
  if (loadedSkills.includes(skillId)) {
@@ -13865,14 +14067,14 @@ async function update_plan(_args) {
13865
14067
 
13866
14068
  // src/tools/impl/Write.ts
13867
14069
  import { promises as fs8 } from "node:fs";
13868
- import * as path12 from "node:path";
14070
+ import * as path13 from "node:path";
13869
14071
  async function write(args) {
13870
14072
  validateRequiredParams(args, ["file_path", "content"], "Write");
13871
14073
  const { file_path, content } = args;
13872
- if (!path12.isAbsolute(file_path))
14074
+ if (!path13.isAbsolute(file_path))
13873
14075
  throw new Error(`File path must be absolute, got: ${file_path}`);
13874
14076
  try {
13875
- const dir = path12.dirname(file_path);
14077
+ const dir = path13.dirname(file_path);
13876
14078
  await fs8.mkdir(dir, { recursive: true });
13877
14079
  try {
13878
14080
  const stats = await fs8.stat(file_path);
@@ -16395,7 +16597,7 @@ var minimatch2 = (p, pattern, options = {}) => {
16395
16597
  }, qmarksTestNoExtDot2 = ([$0]) => {
16396
16598
  const len = $0.length;
16397
16599
  return (f) => f.length === len && f !== "." && f !== "..";
16398
- }, defaultPlatform4, path13, sep3, GLOBSTAR2, qmark4 = "[^/]", star4, twoStarDot2 = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?", twoStarNoDot2 = "(?:(?!(?:\\/|^)\\.).)*?", filter2 = (pattern, options = {}) => (p) => minimatch2(p, pattern, options), ext2 = (a, b = {}) => Object.assign({}, a, b), defaults3 = (def) => {
16600
+ }, defaultPlatform4, path14, sep3, GLOBSTAR2, qmark4 = "[^/]", star4, twoStarDot2 = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?", twoStarNoDot2 = "(?:(?!(?:\\/|^)\\.).)*?", filter2 = (pattern, options = {}) => (p) => minimatch2(p, pattern, options), ext2 = (a, b = {}) => Object.assign({}, a, b), defaults3 = (def) => {
16399
16601
  if (!def || typeof def !== "object" || !Object.keys(def).length) {
16400
16602
  return minimatch2;
16401
16603
  }
@@ -16453,11 +16655,11 @@ var init_esm7 = __esm(() => {
16453
16655
  starRE2 = /^\*+$/;
16454
16656
  qmarksRE2 = /^\?+([^+@!?\*\[\(]*)?$/;
16455
16657
  defaultPlatform4 = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
16456
- path13 = {
16658
+ path14 = {
16457
16659
  win32: { sep: "\\" },
16458
16660
  posix: { sep: "/" }
16459
16661
  };
16460
- sep3 = defaultPlatform4 === "win32" ? path13.win32.sep : path13.posix.sep;
16662
+ sep3 = defaultPlatform4 === "win32" ? path14.win32.sep : path14.posix.sep;
16461
16663
  minimatch2.sep = sep3;
16462
16664
  GLOBSTAR2 = Symbol("globstar **");
16463
16665
  minimatch2.GLOBSTAR = GLOBSTAR2;
@@ -16509,12 +16711,26 @@ function matchesFilePattern(query, pattern, workingDirectory) {
16509
16711
  const relativeFilePath = filePath.startsWith("/") ? absoluteFilePath.replace(`${workingDirectory}/`, "") : filePath;
16510
16712
  return minimatch2(relativeFilePath, globPattern) || minimatch2(absoluteFilePath, globPattern);
16511
16713
  }
16714
+ function extractActualCommand(command) {
16715
+ if (command.includes("&&") || command.includes("|") || command.includes(";")) {
16716
+ const segments = command.split(/\s*(?:&&|\||;)\s*/);
16717
+ for (const segment of segments) {
16718
+ const trimmed = segment.trim();
16719
+ const firstToken = trimmed.split(/\s+/)[0];
16720
+ if (firstToken !== "cd") {
16721
+ return trimmed;
16722
+ }
16723
+ }
16724
+ }
16725
+ return command;
16726
+ }
16512
16727
  function matchesBashPattern(query, pattern) {
16513
16728
  const queryMatch = query.match(/^Bash\((.*)\)$/);
16514
16729
  if (!queryMatch || queryMatch[1] === undefined) {
16515
16730
  return false;
16516
16731
  }
16517
- const command = queryMatch[1];
16732
+ const rawCommand = queryMatch[1];
16733
+ const command = extractActualCommand(rawCommand);
16518
16734
  const patternMatch = pattern.match(/^Bash\((.*)\)$/);
16519
16735
  if (!patternMatch || patternMatch[1] === undefined) {
16520
16736
  return false;
@@ -16522,9 +16738,9 @@ function matchesBashPattern(query, pattern) {
16522
16738
  const commandPattern = patternMatch[1];
16523
16739
  if (commandPattern.endsWith(":*")) {
16524
16740
  const prefix = commandPattern.slice(0, -2);
16525
- return command.startsWith(prefix);
16741
+ return command.startsWith(prefix) || rawCommand.startsWith(prefix);
16526
16742
  }
16527
- return command === commandPattern;
16743
+ return command === commandPattern || rawCommand === commandPattern;
16528
16744
  }
16529
16745
  function matchesToolPattern(toolName, pattern) {
16530
16746
  if (pattern === "*") {
@@ -16583,8 +16799,8 @@ class PermissionModeManager2 {
16583
16799
  getMode() {
16584
16800
  return this.currentMode;
16585
16801
  }
16586
- setPlanFilePath(path14) {
16587
- setGlobalPlanFilePath2(path14);
16802
+ setPlanFilePath(path15) {
16803
+ setGlobalPlanFilePath2(path15);
16588
16804
  }
16589
16805
  getPlanFilePath() {
16590
16806
  return getGlobalPlanFilePath2();
@@ -16612,10 +16828,32 @@ class PermissionModeManager2 {
16612
16828
  "Glob",
16613
16829
  "Grep",
16614
16830
  "NotebookRead",
16615
- "TodoWrite"
16831
+ "TodoWrite",
16832
+ "read_file",
16833
+ "list_dir",
16834
+ "grep_files",
16835
+ "update_plan",
16836
+ "ReadFile",
16837
+ "ListDir",
16838
+ "GrepFiles",
16839
+ "UpdatePlan",
16840
+ "list_directory",
16841
+ "search_file_content",
16842
+ "write_todos",
16843
+ "read_many_files",
16844
+ "ListDirectory",
16845
+ "SearchFileContent",
16846
+ "WriteTodos",
16847
+ "ReadManyFiles"
16848
+ ];
16849
+ const writeTools = [
16850
+ "Write",
16851
+ "Edit",
16852
+ "MultiEdit",
16853
+ "NotebookEdit",
16854
+ "apply_patch",
16855
+ "ApplyPatch"
16616
16856
  ];
16617
- const writeTools = ["Write", "Edit", "MultiEdit", "NotebookEdit"];
16618
- const deniedInPlan = ["Bash", "WebFetch"];
16619
16857
  if (allowedInPlan.includes(toolName)) {
16620
16858
  return "allow";
16621
16859
  }
@@ -16625,12 +16863,8 @@ class PermissionModeManager2 {
16625
16863
  if (planFilePath && targetPath && targetPath === planFilePath) {
16626
16864
  return "allow";
16627
16865
  }
16628
- return "deny";
16629
- }
16630
- if (deniedInPlan.includes(toolName)) {
16631
- return "deny";
16632
16866
  }
16633
- return null;
16867
+ return "deny";
16634
16868
  }
16635
16869
  case "default":
16636
16870
  return null;
@@ -16649,6 +16883,171 @@ var init_mode = __esm(() => {
16649
16883
  permissionMode2 = new PermissionModeManager2;
16650
16884
  });
16651
16885
 
16886
+ // src/permissions/readOnlyShell.ts
16887
+ function isReadOnlyShellCommand(command) {
16888
+ if (!command) {
16889
+ return false;
16890
+ }
16891
+ if (Array.isArray(command)) {
16892
+ if (command.length === 0) {
16893
+ return false;
16894
+ }
16895
+ const joined = command.join(" ");
16896
+ const [executable, ...rest] = command;
16897
+ if (executable && isShellExecutor(executable)) {
16898
+ const nested = extractDashCArgument(rest);
16899
+ if (!nested) {
16900
+ return false;
16901
+ }
16902
+ return isReadOnlyShellCommand(nested);
16903
+ }
16904
+ return isReadOnlyShellCommand(joined);
16905
+ }
16906
+ const trimmed = command.trim();
16907
+ if (!trimmed) {
16908
+ return false;
16909
+ }
16910
+ if (DANGEROUS_OPERATOR_PATTERN.test(trimmed)) {
16911
+ return false;
16912
+ }
16913
+ const segments = trimmed.split("|").map((segment) => segment.trim()).filter(Boolean);
16914
+ if (segments.length === 0) {
16915
+ return false;
16916
+ }
16917
+ for (const segment of segments) {
16918
+ if (!isSafeSegment(segment)) {
16919
+ return false;
16920
+ }
16921
+ }
16922
+ return true;
16923
+ }
16924
+ function isSafeSegment(segment) {
16925
+ const tokens = tokenize(segment);
16926
+ if (tokens.length === 0) {
16927
+ return false;
16928
+ }
16929
+ const command = tokens[0];
16930
+ if (!command) {
16931
+ return false;
16932
+ }
16933
+ if (isShellExecutor(command)) {
16934
+ const nested = extractDashCArgument(tokens.slice(1));
16935
+ if (!nested) {
16936
+ return false;
16937
+ }
16938
+ return isReadOnlyShellCommand(stripQuotes(nested));
16939
+ }
16940
+ if (!ALWAYS_SAFE_COMMANDS.has(command)) {
16941
+ if (command === "git") {
16942
+ const subcommand = tokens[1];
16943
+ if (!subcommand) {
16944
+ return false;
16945
+ }
16946
+ return SAFE_GIT_SUBCOMMANDS.has(subcommand);
16947
+ }
16948
+ if (command === "find") {
16949
+ return !/-delete|\s-exec\b/.test(segment);
16950
+ }
16951
+ if (command === "sort") {
16952
+ return !/\s-o\b/.test(segment);
16953
+ }
16954
+ return false;
16955
+ }
16956
+ return true;
16957
+ }
16958
+ function isShellExecutor(command) {
16959
+ return command === "bash" || command === "sh";
16960
+ }
16961
+ function tokenize(segment) {
16962
+ const matches = segment.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
16963
+ if (!matches) {
16964
+ return [];
16965
+ }
16966
+ return matches.map((token) => stripQuotes(token));
16967
+ }
16968
+ function stripQuotes(value) {
16969
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
16970
+ return value.slice(1, -1);
16971
+ }
16972
+ return value;
16973
+ }
16974
+ function extractDashCArgument(tokens) {
16975
+ for (let i = 0;i < tokens.length; i += 1) {
16976
+ const token = tokens[i];
16977
+ if (!token) {
16978
+ continue;
16979
+ }
16980
+ if (token === "-c" || token === "-lc" || /^-[a-zA-Z]*c$/.test(token)) {
16981
+ return tokens[i + 1];
16982
+ }
16983
+ }
16984
+ return;
16985
+ }
16986
+ var ALWAYS_SAFE_COMMANDS, SAFE_GIT_SUBCOMMANDS, DANGEROUS_OPERATOR_PATTERN;
16987
+ var init_readOnlyShell = __esm(() => {
16988
+ ALWAYS_SAFE_COMMANDS = new Set([
16989
+ "cat",
16990
+ "head",
16991
+ "tail",
16992
+ "less",
16993
+ "more",
16994
+ "grep",
16995
+ "rg",
16996
+ "ag",
16997
+ "ack",
16998
+ "fgrep",
16999
+ "egrep",
17000
+ "ls",
17001
+ "tree",
17002
+ "file",
17003
+ "stat",
17004
+ "du",
17005
+ "df",
17006
+ "wc",
17007
+ "diff",
17008
+ "cmp",
17009
+ "comm",
17010
+ "cut",
17011
+ "tr",
17012
+ "nl",
17013
+ "column",
17014
+ "fold",
17015
+ "pwd",
17016
+ "whoami",
17017
+ "hostname",
17018
+ "date",
17019
+ "uname",
17020
+ "uptime",
17021
+ "id",
17022
+ "echo",
17023
+ "printf",
17024
+ "env",
17025
+ "printenv",
17026
+ "which",
17027
+ "whereis",
17028
+ "type",
17029
+ "basename",
17030
+ "dirname",
17031
+ "realpath",
17032
+ "readlink",
17033
+ "jq",
17034
+ "yq",
17035
+ "strings",
17036
+ "xxd",
17037
+ "hexdump"
17038
+ ]);
17039
+ SAFE_GIT_SUBCOMMANDS = new Set([
17040
+ "status",
17041
+ "diff",
17042
+ "log",
17043
+ "show",
17044
+ "branch",
17045
+ "tag",
17046
+ "remote"
17047
+ ]);
17048
+ DANGEROUS_OPERATOR_PATTERN = /(>>|>|&&|\|\||;|\$\(|`)/;
17049
+ });
17050
+
16652
17051
  // src/permissions/session.ts
16653
17052
  var exports_session = {};
16654
17053
  __export(exports_session, {
@@ -16745,6 +17144,15 @@ function checkPermission(toolName, toolArgs, permissions, workingDirectory = pro
16745
17144
  reason: "Skill tool is always allowed (read-only)"
16746
17145
  };
16747
17146
  }
17147
+ if (READ_ONLY_SHELL_TOOLS.has(toolName)) {
17148
+ const shellCommand = extractShellCommand(toolArgs);
17149
+ if (shellCommand && isReadOnlyShellCommand(shellCommand)) {
17150
+ return {
17151
+ decision: "allow",
17152
+ reason: "Read-only shell command"
17153
+ };
17154
+ }
17155
+ }
16748
17156
  if (WORKING_DIRECTORY_TOOLS.includes(toolName)) {
16749
17157
  const filePath = extractFilePath(toolArgs);
16750
17158
  if (filePath && isWithinAllowedDirectories(filePath, permissions, workingDirectory)) {
@@ -16843,6 +17251,13 @@ function buildPermissionQuery(toolName, toolArgs) {
16843
17251
  return toolName;
16844
17252
  }
16845
17253
  }
17254
+ function extractShellCommand(toolArgs) {
17255
+ const command = toolArgs.command;
17256
+ if (typeof command === "string" || Array.isArray(command)) {
17257
+ return command;
17258
+ }
17259
+ return null;
17260
+ }
16846
17261
  function matchesPattern(toolName, query, pattern, workingDirectory) {
16847
17262
  if ([
16848
17263
  "Read",
@@ -16873,23 +17288,41 @@ function getDefaultDecision(toolName) {
16873
17288
  "list_dir",
16874
17289
  "grep_files",
16875
17290
  "update_plan",
17291
+ "ReadFile",
17292
+ "ListDir",
17293
+ "GrepFiles",
17294
+ "UpdatePlan",
16876
17295
  "list_directory",
16877
17296
  "search_file_content",
16878
17297
  "write_todos",
16879
- "read_many_files"
17298
+ "read_many_files",
17299
+ "ListDirectory",
17300
+ "SearchFileContent",
17301
+ "WriteTodos",
17302
+ "ReadManyFiles"
16880
17303
  ];
16881
17304
  if (autoAllowTools.includes(toolName)) {
16882
17305
  return "allow";
16883
17306
  }
16884
17307
  return "ask";
16885
17308
  }
16886
- var WORKING_DIRECTORY_TOOLS;
17309
+ var WORKING_DIRECTORY_TOOLS, READ_ONLY_SHELL_TOOLS;
16887
17310
  var init_checker = __esm(() => {
16888
17311
  init_cli();
16889
17312
  init_matcher();
16890
17313
  init_mode();
17314
+ init_readOnlyShell();
16891
17315
  init_session();
16892
17316
  WORKING_DIRECTORY_TOOLS = ["Read", "Glob", "Grep"];
17317
+ READ_ONLY_SHELL_TOOLS = new Set([
17318
+ "Bash",
17319
+ "shell",
17320
+ "Shell",
17321
+ "shell_command",
17322
+ "ShellCommand",
17323
+ "run_shell_command",
17324
+ "RunShellCommand"
17325
+ ]);
16893
17326
  });
16894
17327
 
16895
17328
  // src/permissions/loader.ts
@@ -17002,7 +17435,7 @@ var exports_analyzer = {};
17002
17435
  __export(exports_analyzer, {
17003
17436
  analyzeApprovalContext: () => analyzeApprovalContext
17004
17437
  });
17005
- import { dirname as dirname4, resolve as resolve8 } from "node:path";
17438
+ import { dirname as dirname5, resolve as resolve8 } from "node:path";
17006
17439
  function analyzeApprovalContext(toolName, toolArgs, workingDirectory) {
17007
17440
  const resolveFilePath = () => {
17008
17441
  const candidate = toolArgs.file_path ?? toolArgs.path ?? toolArgs.notebook_path ?? "";
@@ -17034,7 +17467,7 @@ function analyzeApprovalContext(toolName, toolArgs, workingDirectory) {
17034
17467
  function analyzeReadApproval(filePath, workingDir) {
17035
17468
  const absolutePath = resolve8(workingDir, filePath);
17036
17469
  if (!absolutePath.startsWith(workingDir)) {
17037
- const dirPath = dirname4(absolutePath);
17470
+ const dirPath = dirname5(absolutePath);
17038
17471
  const displayPath = dirPath.replace(__require("node:os").homedir(), "~");
17039
17472
  return {
17040
17473
  recommendedRule: `Read(/${dirPath}/**)`,
@@ -17046,7 +17479,7 @@ function analyzeReadApproval(filePath, workingDir) {
17046
17479
  };
17047
17480
  }
17048
17481
  const relativePath = absolutePath.slice(workingDir.length + 1);
17049
- const relativeDir = dirname4(relativePath);
17482
+ const relativeDir = dirname5(relativePath);
17050
17483
  const pattern = relativeDir === "." ? "**" : `${relativeDir}/**`;
17051
17484
  return {
17052
17485
  recommendedRule: `Read(${pattern})`,
@@ -17069,7 +17502,7 @@ function analyzeWriteApproval(_filePath, _workingDir) {
17069
17502
  }
17070
17503
  function analyzeEditApproval(filePath, workingDir) {
17071
17504
  const absolutePath = resolve8(workingDir, filePath);
17072
- const dirPath = dirname4(absolutePath);
17505
+ const dirPath = dirname5(absolutePath);
17073
17506
  if (!dirPath.startsWith(workingDir)) {
17074
17507
  const displayPath = dirPath.replace(__require("node:os").homedir(), "~");
17075
17508
  return {
@@ -17867,7 +18300,7 @@ var package_default;
17867
18300
  var init_package = __esm(() => {
17868
18301
  package_default = {
17869
18302
  name: "@letta-ai/letta-code",
17870
- version: "0.5.0",
18303
+ version: "0.5.1",
17871
18304
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
17872
18305
  type: "module",
17873
18306
  bin: {
@@ -19263,6 +19696,10 @@ description: A memory block to store information about this coding project. This
19263
19696
  `;
19264
19697
  var init_project = () => {};
19265
19698
 
19699
+ // src/agent/prompts/skill_creator_mode.md
19700
+ var skill_creator_mode_default = '# Skill Creation Mode\n\nThe user has invoked the `/skill` command. Your task is to help them **design and create a new Skill** for this project.\n\nYou are a Letta Code agent with:\n- Access to the current conversation, project files, and memory blocks\n- Access to the `Skill` tool (for loading skills) and `AskUserQuestion` (for asking clarifying questions)\n- Access to file tools (Read, Write, Edit, ApplyPatch, etc.) via the toolset\n\nYour goal is to guide the user through a **focused, collaborative workflow** to create or update a Skill that will be reused in the future.\n\n## 1. Load the skill-creator Skill (if available)\n\n1. Inspect your memory blocks:\n - `skills` – list of available skills and their descriptions\n - `loaded_skills` – SKILL.md contents for currently loaded skills\n2. If a `skill-creator` skill is **not already loaded** in `loaded_skills`, you should **attempt to load it** using the `Skill` tool:\n - Call the `Skill` tool with:\n - `skill: "skill-creator"`\n - The environment may resolve this from either the project’s `.skills` directory or a bundled `skills/skills/skill-creator/SKILL.md` location.\n3. If loading `skill-creator` fails (for example, the tool errors or the file is missing), or if the environment does not provide it, continue using your own judgment based on these instructions.\n\nDo **not** load unrelated skills unless clearly relevant to the user’s request.\n\n## 2. Understand the requested skill\n\nThe `/skill` command may have been invoked in two ways:\n\n1. `/skill` (no description)\n2. `/skill <description>` (with a short description, e.g. `/skill image editor for marketing screenshots`)\n\nYou should always:\n\n1. Consider:\n - The current conversation and what the user has been working on\n - Relevant project context from files and memory blocks (especially `project` and `skills`)\n2. If a description was provided:\n - Treat it as the **initial specification** of the skill.\n - Restate it briefly in your own words to confirm understanding.\n\n## 3. Ask upfront clarifying questions (using AskUserQuestion)\n\nBefore you start proposing a concrete skill design, you MUST ask a small bundle of **high‑value upfront questions** using the `AskUserQuestion` tool.\n\nKeep the initial question set small (3–6 questions) and focused. Examples:\n\n1. Purpose and scope:\n - “What is the main purpose of this skill?”\n - “Is this skill meant for a specific project or to be reused across many projects?”\n2. Implementation details:\n - “Do you want this skill to be mostly guidance (instructions) or to include reusable scripts/templates?”\n - “Where should the skill live? (e.g. `.skills/your-skill-id` in this repo)”\n\nBundle these together in a single `AskUserQuestion` call. After you receive answers, you can ask follow‑up questions as needed, but avoid overwhelming the user.\n\n## 4. Propose a concrete skill design\n\nUsing:\n- The user’s description (if provided)\n- Answers to your questions\n- The current project and conversation context\n\nYou should propose a **concrete skill design**, including at minimum:\n\n- A skill ID (directory name), e.g. `image-editor`, `pdf-workflow`, `webapp-testing`\n- A concise human‑readable name\n- A one‑paragraph description focused on:\n - What the skill does\n - When it should be used\n - Who is likely to use it\n- Example triggering queries (how users will invoke it in natural language)\n- The planned structure of the skill:\n - `SKILL.md` contents (sections, key instructions)\n - Any `scripts/` you recommend (and what each script does)\n - Any `references/` files (and when to read them)\n - Any `assets/` (templates, fonts, icons, starter projects, etc.)\n\nValidate this design with the user before you start writing files. If something is ambiguous or high‑impact, ask a brief follow‑up question using `AskUserQuestion`.\n\n## 5. Create or update the skill files\n\nOnce the design is agreed upon:\n\n1. Determine the target directory for the skill (in this order):\n - First, check whether the host environment or CLI has configured a default skills directory for this agent (for example via a `--skills` flag or project settings). If such a directory is provided, use it as the base directory for the new skill unless the user explicitly requests a different path.\n - If no explicit skills directory is configured, check the `skills` memory block for a `Skills Directory: <path>` line and use that as the base directory.\n - If neither is available, default to a local `.skills/<skill-id>/` directory in the current project root (or another path the user has requested).\n2. Create or update:\n - `.skills/<skill-id>/SKILL.md` – the main entry point for the skill\n - Optional: `.skills/<skill-id>/scripts/` – reusable scripts\n - Optional: `.skills/<skill-id>/references/` – longer documentation, schemas, or examples\n - Optional: `.skills/<skill-id>/assets/` – templates, fonts, images, or other resources\n3. Use file tools (Write, Edit, ApplyPatch, etc.) to create and refine these files instead of asking the user to do it manually.\n\nWhen writing `SKILL.md`, follow the conventions used by existing skills in this repository:\n\n- YAML frontmatter at the top, including at least:\n - `name`: human‑readable name\n - `description`: when and how the skill should be used\n- Clear sections that:\n - Explain when to use the skill\n - Describe the recommended workflows\n - Link to `scripts/`, `references/`, and `assets/` as needed\n - Emphasize progressive disclosure (only load detailed references as needed)\n\nKeep `SKILL.md` focused and concise; move long reference content into separate files.\n\n## 6. Keep questions focused and iterative\n\nThroughout the process:\n\n- Prefer a small number of **high‑impact questions** over many tiny questions.\n- When you need more detail, group follow‑up questions into a single `AskUserQuestion` call.\n- Use concrete examples from the user’s project or repository when possible.\n\nYour goal is to:\n\n1. Understand the desired skill thoroughly.\n2. Propose a clear, reusable design.\n3. Implement or update the actual skill files in the repository.\n4. Leave the user with a ready‑to‑use skill that appears in the `skills` memory block and can be loaded with the `Skill` tool.\n\n\n';
19701
+ var init_skill_creator_mode = () => {};
19702
+
19266
19703
  // src/agent/prompts/skill_unload_reminder.txt
19267
19704
  var skill_unload_reminder_default = `<system-reminder>
19268
19705
  The \`loaded_skills\` block has at least one skill loaded. You should:
@@ -19342,11 +19779,12 @@ __export(exports_promptAssets, {
19342
19779
  SYSTEM_PROMPTS: () => SYSTEM_PROMPTS,
19343
19780
  SYSTEM_PROMPT: () => SYSTEM_PROMPT,
19344
19781
  SKILL_UNLOAD_REMINDER: () => SKILL_UNLOAD_REMINDER,
19782
+ SKILL_CREATOR_PROMPT: () => SKILL_CREATOR_PROMPT,
19345
19783
  PLAN_MODE_REMINDER: () => PLAN_MODE_REMINDER,
19346
19784
  MEMORY_PROMPTS: () => MEMORY_PROMPTS,
19347
19785
  INITIALIZE_PROMPT: () => INITIALIZE_PROMPT
19348
19786
  });
19349
- var SYSTEM_PROMPT, PLAN_MODE_REMINDER, SKILL_UNLOAD_REMINDER, INITIALIZE_PROMPT, MEMORY_PROMPTS, SYSTEM_PROMPTS;
19787
+ var SYSTEM_PROMPT, PLAN_MODE_REMINDER, SKILL_UNLOAD_REMINDER, INITIALIZE_PROMPT, SKILL_CREATOR_PROMPT, MEMORY_PROMPTS, SYSTEM_PROMPTS;
19350
19788
  var init_promptAssets = __esm(() => {
19351
19789
  init_claude();
19352
19790
  init_codex();
@@ -19362,6 +19800,7 @@ var init_promptAssets = __esm(() => {
19362
19800
  init_persona_kawaii();
19363
19801
  init_plan_mode_reminder();
19364
19802
  init_project();
19803
+ init_skill_creator_mode();
19365
19804
  init_skill_unload_reminder();
19366
19805
  init_skills2();
19367
19806
  init_style();
@@ -19370,6 +19809,7 @@ var init_promptAssets = __esm(() => {
19370
19809
  PLAN_MODE_REMINDER = plan_mode_reminder_default;
19371
19810
  SKILL_UNLOAD_REMINDER = skill_unload_reminder_default;
19372
19811
  INITIALIZE_PROMPT = init_memory_default;
19812
+ SKILL_CREATOR_PROMPT = skill_creator_mode_default;
19373
19813
  MEMORY_PROMPTS = {
19374
19814
  "persona.mdx": persona_default,
19375
19815
  "persona_empty.mdx": persona_empty_default,
@@ -21428,14 +21868,14 @@ __export(exports_base, {
21428
21868
  ConEmu: () => ConEmu
21429
21869
  });
21430
21870
  import process2 from "node:process";
21431
- var ESC = "\x1B[", OSC = "\x1B]", BEL = "\x07", SEP = ";", isTerminalApp, isWindows2, cwdFunction, cursorTo = (x, y) => {
21871
+ var ESC = "\x1B[", OSC = "\x1B]", BEL = "\x07", SEP2 = ";", isTerminalApp, isWindows2, cwdFunction, cursorTo = (x, y) => {
21432
21872
  if (typeof x !== "number") {
21433
21873
  throw new TypeError("The `x` argument is required");
21434
21874
  }
21435
21875
  if (typeof y !== "number") {
21436
21876
  return ESC + (x + 1) + "G";
21437
21877
  }
21438
- return ESC + (y + 1) + SEP + (x + 1) + "H";
21878
+ return ESC + (y + 1) + SEP2 + (x + 1) + "H";
21439
21879
  }, cursorMove = (x, y) => {
21440
21880
  if (typeof x !== "number") {
21441
21881
  throw new TypeError("The `x` argument is required");
@@ -21464,15 +21904,15 @@ var ESC = "\x1B[", OSC = "\x1B]", BEL = "\x07", SEP = ";", isTerminalApp, isWind
21464
21904
  }, eraseEndLine, eraseStartLine, eraseLine, eraseDown, eraseUp, eraseScreen, scrollUp, scrollDown, clearScreen = "\x1Bc", clearViewport, clearTerminal, enterAlternativeScreen, exitAlternativeScreen, beep, link = (text, url) => [
21465
21905
  OSC,
21466
21906
  "8",
21467
- SEP,
21468
- SEP,
21907
+ SEP2,
21908
+ SEP2,
21469
21909
  url,
21470
21910
  BEL,
21471
21911
  text,
21472
21912
  OSC,
21473
21913
  "8",
21474
- SEP,
21475
- SEP,
21914
+ SEP2,
21915
+ SEP2,
21476
21916
  BEL
21477
21917
  ].join(""), image = (data, options = {}) => {
21478
21918
  let returnValue = `${OSC}1337;File=inline=1`;
@@ -38402,10 +38842,10 @@ Check the render method of \`` + ownerName + "`.";
38402
38842
  var setErrorHandler = null;
38403
38843
  var setSuspenseHandler = null;
38404
38844
  {
38405
- var copyWithDeleteImpl = function(obj, path14, index2) {
38406
- var key = path14[index2];
38845
+ var copyWithDeleteImpl = function(obj, path15, index2) {
38846
+ var key = path15[index2];
38407
38847
  var updated = isArray2(obj) ? obj.slice() : assign({}, obj);
38408
- if (index2 + 1 === path14.length) {
38848
+ if (index2 + 1 === path15.length) {
38409
38849
  if (isArray2(updated)) {
38410
38850
  updated.splice(key, 1);
38411
38851
  } else {
@@ -38413,11 +38853,11 @@ Check the render method of \`` + ownerName + "`.";
38413
38853
  }
38414
38854
  return updated;
38415
38855
  }
38416
- updated[key] = copyWithDeleteImpl(obj[key], path14, index2 + 1);
38856
+ updated[key] = copyWithDeleteImpl(obj[key], path15, index2 + 1);
38417
38857
  return updated;
38418
38858
  };
38419
- var copyWithDelete = function(obj, path14) {
38420
- return copyWithDeleteImpl(obj, path14, 0);
38859
+ var copyWithDelete = function(obj, path15) {
38860
+ return copyWithDeleteImpl(obj, path15, 0);
38421
38861
  };
38422
38862
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
38423
38863
  var oldKey = oldPath[index2];
@@ -38449,17 +38889,17 @@ Check the render method of \`` + ownerName + "`.";
38449
38889
  }
38450
38890
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
38451
38891
  };
38452
- var copyWithSetImpl = function(obj, path14, index2, value) {
38453
- if (index2 >= path14.length) {
38892
+ var copyWithSetImpl = function(obj, path15, index2, value) {
38893
+ if (index2 >= path15.length) {
38454
38894
  return value;
38455
38895
  }
38456
- var key = path14[index2];
38896
+ var key = path15[index2];
38457
38897
  var updated = isArray2(obj) ? obj.slice() : assign({}, obj);
38458
- updated[key] = copyWithSetImpl(obj[key], path14, index2 + 1, value);
38898
+ updated[key] = copyWithSetImpl(obj[key], path15, index2 + 1, value);
38459
38899
  return updated;
38460
38900
  };
38461
- var copyWithSet = function(obj, path14, value) {
38462
- return copyWithSetImpl(obj, path14, 0, value);
38901
+ var copyWithSet = function(obj, path15, value) {
38902
+ return copyWithSetImpl(obj, path15, 0, value);
38463
38903
  };
38464
38904
  var findHook = function(fiber, id) {
38465
38905
  var currentHook2 = fiber.memoizedState;
@@ -38469,10 +38909,10 @@ Check the render method of \`` + ownerName + "`.";
38469
38909
  }
38470
38910
  return currentHook2;
38471
38911
  };
38472
- overrideHookState = function(fiber, id, path14, value) {
38912
+ overrideHookState = function(fiber, id, path15, value) {
38473
38913
  var hook = findHook(fiber, id);
38474
38914
  if (hook !== null) {
38475
- var newState = copyWithSet(hook.memoizedState, path14, value);
38915
+ var newState = copyWithSet(hook.memoizedState, path15, value);
38476
38916
  hook.memoizedState = newState;
38477
38917
  hook.baseState = newState;
38478
38918
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -38482,10 +38922,10 @@ Check the render method of \`` + ownerName + "`.";
38482
38922
  }
38483
38923
  }
38484
38924
  };
38485
- overrideHookStateDeletePath = function(fiber, id, path14) {
38925
+ overrideHookStateDeletePath = function(fiber, id, path15) {
38486
38926
  var hook = findHook(fiber, id);
38487
38927
  if (hook !== null) {
38488
- var newState = copyWithDelete(hook.memoizedState, path14);
38928
+ var newState = copyWithDelete(hook.memoizedState, path15);
38489
38929
  hook.memoizedState = newState;
38490
38930
  hook.baseState = newState;
38491
38931
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -38508,8 +38948,8 @@ Check the render method of \`` + ownerName + "`.";
38508
38948
  }
38509
38949
  }
38510
38950
  };
38511
- overrideProps = function(fiber, path14, value) {
38512
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path14, value);
38951
+ overrideProps = function(fiber, path15, value) {
38952
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path15, value);
38513
38953
  if (fiber.alternate) {
38514
38954
  fiber.alternate.pendingProps = fiber.pendingProps;
38515
38955
  }
@@ -38518,8 +38958,8 @@ Check the render method of \`` + ownerName + "`.";
38518
38958
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
38519
38959
  }
38520
38960
  };
38521
- overridePropsDeletePath = function(fiber, path14) {
38522
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path14);
38961
+ overridePropsDeletePath = function(fiber, path15) {
38962
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path15);
38523
38963
  if (fiber.alternate) {
38524
38964
  fiber.alternate.pendingProps = fiber.pendingProps;
38525
38965
  }
@@ -40785,7 +41225,7 @@ function parseAnsiCode(string, offset) {
40785
41225
  return string.slice(0, endIndex + 1);
40786
41226
  }
40787
41227
  }
40788
- function tokenize(string, endCharacter = Number.POSITIVE_INFINITY) {
41228
+ function tokenize2(string, endCharacter = Number.POSITIVE_INFINITY) {
40789
41229
  const returnValue = [];
40790
41230
  let index = 0;
40791
41231
  let visibleCount = 0;
@@ -40838,7 +41278,7 @@ function undoAnsiCodes(codes) {
40838
41278
  return endCodes.reverse().join("");
40839
41279
  }
40840
41280
  function sliceAnsi2(string, start, end) {
40841
- const tokens = tokenize(string, end);
41281
+ const tokens = tokenize2(string, end);
40842
41282
  let activeCodes = [];
40843
41283
  let position = 0;
40844
41284
  let returnValue = "";
@@ -41037,7 +41477,7 @@ function parseAnsiCode2(string, offset) {
41037
41477
  return string.slice(0, endIndex + 1);
41038
41478
  }
41039
41479
  }
41040
- function tokenize2(str, endChar = Number.POSITIVE_INFINITY) {
41480
+ function tokenize3(str, endChar = Number.POSITIVE_INFINITY) {
41041
41481
  const ret = [];
41042
41482
  let index = 0;
41043
41483
  let visible = 0;
@@ -41191,7 +41631,7 @@ class Output {
41191
41631
  for (const transformer of transformers) {
41192
41632
  line = transformer(line, index);
41193
41633
  }
41194
- const characters = styledCharsFromTokens(tokenize2(line));
41634
+ const characters = styledCharsFromTokens(tokenize3(line));
41195
41635
  let offsetX = x;
41196
41636
  for (const character of characters) {
41197
41637
  currentLine[offsetX] = character;
@@ -41796,8 +42236,8 @@ function ErrorOverview({ error }) {
41796
42236
  return import_react4.default.createElement(Box_default, { key: line }, import_react4.default.createElement(Text, { dimColor: true }, "- "), import_react4.default.createElement(Text, { dimColor: true, bold: true }, parsedLine.function), import_react4.default.createElement(Text, { dimColor: true, color: "gray" }, " ", "(", cleanupPath(parsedLine.file) ?? "", ":", parsedLine.line, ":", parsedLine.column, ")"));
41797
42237
  })));
41798
42238
  }
41799
- var import_react4, import_stack_utils, cleanupPath = (path14) => {
41800
- return path14?.replace(`file://${cwd()}/`, "");
42239
+ var import_react4, import_stack_utils, cleanupPath = (path15) => {
42240
+ return path15?.replace(`file://${cwd()}/`, "");
41801
42241
  }, stackUtils;
41802
42242
  var init_ErrorOverview = __esm(() => {
41803
42243
  init_dist3();
@@ -44053,8 +44493,8 @@ __export(exports_open, {
44053
44493
  });
44054
44494
  import process18 from "node:process";
44055
44495
  import { Buffer as Buffer3 } from "node:buffer";
44056
- import path14 from "node:path";
44057
- import { fileURLToPath as fileURLToPath4 } from "node:url";
44496
+ import path15 from "node:path";
44497
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
44058
44498
  import { promisify as promisify7 } from "node:util";
44059
44499
  import childProcess from "node:child_process";
44060
44500
  import fs14, { constants as fsConstants2 } from "node:fs/promises";
@@ -44278,8 +44718,8 @@ var init_open = __esm(() => {
44278
44718
  init_default_browser();
44279
44719
  init_is_inside_container();
44280
44720
  execFile6 = promisify7(childProcess.execFile);
44281
- __dirname2 = path14.dirname(fileURLToPath4(import.meta.url));
44282
- localXdgOpenPath = path14.join(__dirname2, "xdg-open");
44721
+ __dirname2 = path15.dirname(fileURLToPath5(import.meta.url));
44722
+ localXdgOpenPath = path15.join(__dirname2, "xdg-open");
44283
44723
  ({ platform: platform2, arch } = process18);
44284
44724
  apps = {};
44285
44725
  defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
@@ -44661,7 +45101,11 @@ async function revokeToken2(refreshToken) {
44661
45101
  }
44662
45102
  async function validateCredentials2(baseUrl, apiKey) {
44663
45103
  try {
44664
- const client = new Letta({ apiKey, baseURL: baseUrl });
45104
+ const client = new Letta({
45105
+ apiKey,
45106
+ baseURL: baseUrl,
45107
+ defaultHeaders: { "X-Letta-Source": "letta-code" }
45108
+ });
44665
45109
  await client.agents.list({ limit: 1 });
44666
45110
  return true;
44667
45111
  } catch {
@@ -44830,7 +45274,11 @@ async function getClient2() {
44830
45274
  updatedEnv.LETTA_API_KEY = process.env.LETTA_API_KEY;
44831
45275
  settingsManager.updateSettings({ env: updatedEnv });
44832
45276
  }
44833
- return new Letta({ apiKey, baseURL });
45277
+ return new Letta({
45278
+ apiKey,
45279
+ baseURL,
45280
+ defaultHeaders: { "X-Letta-Source": "letta-code" }
45281
+ });
44834
45282
  }
44835
45283
  var init_client2 = __esm(() => {
44836
45284
  init_letta_client();
@@ -45339,11 +45787,12 @@ __export(exports_promptAssets2, {
45339
45787
  SYSTEM_PROMPTS: () => SYSTEM_PROMPTS2,
45340
45788
  SYSTEM_PROMPT: () => SYSTEM_PROMPT2,
45341
45789
  SKILL_UNLOAD_REMINDER: () => SKILL_UNLOAD_REMINDER2,
45790
+ SKILL_CREATOR_PROMPT: () => SKILL_CREATOR_PROMPT2,
45342
45791
  PLAN_MODE_REMINDER: () => PLAN_MODE_REMINDER2,
45343
45792
  MEMORY_PROMPTS: () => MEMORY_PROMPTS2,
45344
45793
  INITIALIZE_PROMPT: () => INITIALIZE_PROMPT2
45345
45794
  });
45346
- var SYSTEM_PROMPT2, PLAN_MODE_REMINDER2, SKILL_UNLOAD_REMINDER2, INITIALIZE_PROMPT2, MEMORY_PROMPTS2, SYSTEM_PROMPTS2;
45795
+ var SYSTEM_PROMPT2, PLAN_MODE_REMINDER2, SKILL_UNLOAD_REMINDER2, INITIALIZE_PROMPT2, SKILL_CREATOR_PROMPT2, MEMORY_PROMPTS2, SYSTEM_PROMPTS2;
45347
45796
  var init_promptAssets2 = __esm(() => {
45348
45797
  init_claude();
45349
45798
  init_codex();
@@ -45359,6 +45808,7 @@ var init_promptAssets2 = __esm(() => {
45359
45808
  init_persona_kawaii();
45360
45809
  init_plan_mode_reminder();
45361
45810
  init_project();
45811
+ init_skill_creator_mode();
45362
45812
  init_skill_unload_reminder();
45363
45813
  init_skills2();
45364
45814
  init_style();
@@ -45367,6 +45817,7 @@ var init_promptAssets2 = __esm(() => {
45367
45817
  PLAN_MODE_REMINDER2 = plan_mode_reminder_default;
45368
45818
  SKILL_UNLOAD_REMINDER2 = skill_unload_reminder_default;
45369
45819
  INITIALIZE_PROMPT2 = init_memory_default;
45820
+ SKILL_CREATOR_PROMPT2 = skill_creator_mode_default;
45370
45821
  MEMORY_PROMPTS2 = {
45371
45822
  "persona.mdx": persona_default,
45372
45823
  "persona_empty.mdx": persona_empty_default,
@@ -45499,38 +45950,46 @@ __export(exports_modify, {
45499
45950
  linkToolsToAgent: () => linkToolsToAgent
45500
45951
  });
45501
45952
  function buildModelSettings(modelHandle, updateArgs) {
45502
- const settings = {};
45503
45953
  const isOpenAI = modelHandle.startsWith("openai/");
45504
45954
  const isAnthropic = modelHandle.startsWith("anthropic/");
45505
45955
  const isGoogleAI = modelHandle.startsWith("google_ai/");
45506
- if (isOpenAI && updateArgs?.reasoning_effort) {
45507
- const openaiSettings = settings;
45508
- openaiSettings.provider_type = "openai";
45509
- openaiSettings.reasoning = {
45510
- reasoning_effort: updateArgs.reasoning_effort
45956
+ if (isOpenAI) {
45957
+ const openaiSettings = {
45958
+ provider_type: "openai",
45959
+ parallel_tool_calls: true
45960
+ };
45961
+ if (updateArgs?.reasoning_effort) {
45962
+ openaiSettings.reasoning = {
45963
+ reasoning_effort: updateArgs.reasoning_effort
45964
+ };
45965
+ }
45966
+ return openaiSettings;
45967
+ }
45968
+ if (isAnthropic) {
45969
+ const anthropicSettings = {
45970
+ provider_type: "anthropic",
45971
+ parallel_tool_calls: true
45511
45972
  };
45512
- openaiSettings.parallel_tool_calls = true;
45513
- } else if (isAnthropic && updateArgs?.enable_reasoner !== undefined) {
45514
- const anthropicSettings = settings;
45515
- anthropicSettings.provider_type = "anthropic";
45516
- anthropicSettings.thinking = {
45517
- type: updateArgs.enable_reasoner ? "enabled" : "disabled"
45973
+ if (updateArgs?.enable_reasoner !== undefined) {
45974
+ anthropicSettings.thinking = {
45975
+ type: updateArgs.enable_reasoner ? "enabled" : "disabled"
45976
+ };
45977
+ }
45978
+ return anthropicSettings;
45979
+ }
45980
+ if (isGoogleAI) {
45981
+ const googleSettings = {
45982
+ provider_type: "google_ai",
45983
+ parallel_tool_calls: true
45518
45984
  };
45519
- anthropicSettings.parallel_tool_calls = true;
45520
- } else if (isGoogleAI) {
45521
- const googleSettings = settings;
45522
- googleSettings.provider_type = "google_ai";
45523
- googleSettings.parallel_tool_calls = true;
45524
45985
  if (updateArgs?.thinking_budget !== undefined) {
45525
45986
  googleSettings.thinking_config = {
45526
45987
  thinking_budget: updateArgs.thinking_budget
45527
45988
  };
45528
45989
  }
45990
+ return googleSettings;
45529
45991
  }
45530
- if (Object.keys(settings).length === 0) {
45531
- return;
45532
- }
45533
- return settings;
45992
+ return { parallel_tool_calls: true };
45534
45993
  }
45535
45994
  async function updateAgentLLMConfig(agentId, modelHandle, updateArgs) {
45536
45995
  const client = await getClient2();
@@ -46437,6 +46896,17 @@ async function executeApprovalBatch(decisions, onChunk2, options) {
46437
46896
  continue;
46438
46897
  }
46439
46898
  if (decision.type === "approve") {
46899
+ if (decision.precomputedResult) {
46900
+ results.push({
46901
+ type: "tool",
46902
+ tool_call_id: decision.approval.toolCallId,
46903
+ tool_return: decision.precomputedResult.toolReturn,
46904
+ status: decision.precomputedResult.status,
46905
+ stdout: decision.precomputedResult.stdout,
46906
+ stderr: decision.precomputedResult.stderr
46907
+ });
46908
+ continue;
46909
+ }
46440
46910
  try {
46441
46911
  const parsedArgs = typeof decision.approval.toolArgs === "string" ? JSON.parse(decision.approval.toolArgs) : decision.approval.toolArgs || {};
46442
46912
  const toolResult = await executeTool2(decision.approval.toolName, parsedArgs, { signal: options?.abortSignal });
@@ -46627,6 +47097,25 @@ async function handleHeadlessCommand(argv, model, skillsDirectory) {
46627
47097
  settingsManager.updateSettings({ lastAgent: agent.id });
46628
47098
  setAgentContext2(agent.id, client, skillsDirectory);
46629
47099
  await initializeLoadedSkillsFlag2();
47100
+ try {
47101
+ const { discoverSkills: discoverSkills2, formatSkillsForMemory: formatSkillsForMemory2, SKILLS_DIR: SKILLS_DIR2 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
47102
+ const { join: join10 } = await import("node:path");
47103
+ const resolvedSkillsDirectory = skillsDirectory || join10(process.cwd(), SKILLS_DIR2);
47104
+ const { skills, errors } = await discoverSkills2(resolvedSkillsDirectory);
47105
+ if (errors.length > 0) {
47106
+ console.warn("Errors encountered during skill discovery:");
47107
+ for (const error of errors) {
47108
+ console.warn(` ${error.path}: ${error.message}`);
47109
+ }
47110
+ }
47111
+ const formattedSkills = formatSkillsForMemory2(skills, resolvedSkillsDirectory);
47112
+ await client.agents.blocks.update("skills", {
47113
+ agent_id: agent.id,
47114
+ value: formattedSkills
47115
+ });
47116
+ } catch (error) {
47117
+ console.warn(`Failed to update skills: ${error instanceof Error ? error.message : String(error)}`);
47118
+ }
46630
47119
  const outputFormat = values["output-format"] || "text";
46631
47120
  if (!["text", "json", "stream-json"].includes(outputFormat)) {
46632
47121
  console.error(`Error: Invalid output format "${outputFormat}". Valid formats: text, json, stream-json`);
@@ -47505,16 +47994,16 @@ class Diff {
47505
47994
  }
47506
47995
  }
47507
47996
  }
47508
- addToPath(path15, added, removed, oldPosInc, options) {
47509
- const last = path15.lastComponent;
47997
+ addToPath(path16, added, removed, oldPosInc, options) {
47998
+ const last = path16.lastComponent;
47510
47999
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
47511
48000
  return {
47512
- oldPos: path15.oldPos + oldPosInc,
48001
+ oldPos: path16.oldPos + oldPosInc,
47513
48002
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
47514
48003
  };
47515
48004
  } else {
47516
48005
  return {
47517
- oldPos: path15.oldPos + oldPosInc,
48006
+ oldPos: path16.oldPos + oldPosInc,
47518
48007
  lastComponent: { count: 1, added, removed, previousComponent: last }
47519
48008
  };
47520
48009
  }
@@ -47862,7 +48351,7 @@ var init_word = __esm(() => {
47862
48351
  function diffLines(oldStr, newStr, options) {
47863
48352
  return lineDiff.diff(oldStr, newStr, options);
47864
48353
  }
47865
- function tokenize4(value, options) {
48354
+ function tokenize5(value, options) {
47866
48355
  if (options.stripTrailingCr) {
47867
48356
  value = value.replace(/\r\n/g, `
47868
48357
  `);
@@ -47886,7 +48375,7 @@ var init_line2 = __esm(() => {
47886
48375
  LineDiff = class LineDiff extends Diff {
47887
48376
  constructor() {
47888
48377
  super(...arguments);
47889
- this.tokenize = tokenize4;
48378
+ this.tokenize = tokenize5;
47890
48379
  }
47891
48380
  equals(left, right, options) {
47892
48381
  if (options.ignoreWhitespace) {
@@ -48014,7 +48503,7 @@ var init_json = __esm(() => {
48014
48503
  JsonDiff = class JsonDiff extends Diff {
48015
48504
  constructor() {
48016
48505
  super(...arguments);
48017
- this.tokenize = tokenize4;
48506
+ this.tokenize = tokenize5;
48018
48507
  }
48019
48508
  get useLongestToken() {
48020
48509
  return true;
@@ -48289,11 +48778,14 @@ function allocatePaste(content) {
48289
48778
  function resolvePlaceholders(text) {
48290
48779
  if (!text)
48291
48780
  return text;
48292
- return text.replace(/\[Pasted text #(\d+) \+(\d+) lines\]/g, (_match, idStr) => {
48781
+ let result = text.replace(/\[Pasted text #(\d+) \+(\d+) lines\]/g, (_match, idStr) => {
48293
48782
  const id = Number(idStr);
48294
48783
  const content = textRegistry.get(id);
48295
48784
  return content !== undefined ? content : _match;
48296
48785
  });
48786
+ result = result.replace(/↵/g, `
48787
+ `);
48788
+ return result;
48297
48789
  }
48298
48790
  function extractTextPlaceholderIds(text) {
48299
48791
  const ids = [];
@@ -49184,6 +49676,9 @@ var init_clipboard = __esm(() => {
49184
49676
  function countLines3(text) {
49185
49677
  return (text.match(/\r\n|\r|\n/g) || []).length + 1;
49186
49678
  }
49679
+ function sanitizeForDisplay(text) {
49680
+ return text.replace(/\r\n|\r|\n/g, "↵");
49681
+ }
49187
49682
  function PasteAwareTextInput({
49188
49683
  value,
49189
49684
  onChange,
@@ -49237,12 +49732,13 @@ function PasteAwareTextInput({
49237
49732
  setNudgeCursorOffset(nextCaret);
49238
49733
  caretOffsetRef.current = nextCaret;
49239
49734
  } else {
49240
- const newDisplay = displayValue.slice(0, at) + translated + displayValue.slice(at);
49735
+ const displayText = sanitizeForDisplay(translated);
49736
+ const newDisplay = displayValue.slice(0, at) + displayText + displayValue.slice(at);
49241
49737
  const newActual = actualValue.slice(0, at) + translated + actualValue.slice(at);
49242
49738
  setDisplayValue(newDisplay);
49243
49739
  setActualValue(newActual);
49244
49740
  onChange(newDisplay);
49245
- const nextCaret = at + translated.length;
49741
+ const nextCaret = at + displayText.length;
49246
49742
  setNudgeCursorOffset(nextCaret);
49247
49743
  caretOffsetRef.current = nextCaret;
49248
49744
  }
@@ -49299,12 +49795,13 @@ function PasteAwareTextInput({
49299
49795
  caretOffsetRef.current = nextCaret2;
49300
49796
  return;
49301
49797
  }
49302
- const newDisplayValue = a.slice(0, lcp) + translated + a.slice(a.length - lcs);
49798
+ const displayText = sanitizeForDisplay(translated);
49799
+ const newDisplayValue = a.slice(0, lcp) + displayText + a.slice(a.length - lcs);
49303
49800
  const newActualValue = actualValue.slice(0, lcp) + translated + actualValue.slice(actualValue.length - lcs);
49304
49801
  setDisplayValue(newDisplayValue);
49305
49802
  setActualValue(newActualValue);
49306
49803
  onChange(newDisplayValue);
49307
- const nextCaret = lcp + translated.length;
49804
+ const nextCaret = lcp + displayText.length;
49308
49805
  setNudgeCursorOffset(nextCaret);
49309
49806
  caretOffsetRef.current = nextCaret;
49310
49807
  return;
@@ -49386,6 +49883,18 @@ function getHeaderLabel(toolName) {
49386
49883
  return "Apply Patch";
49387
49884
  if (t === "update_plan")
49388
49885
  return "Plan update";
49886
+ if (t === "shellcommand")
49887
+ return "Shell command";
49888
+ if (t === "readfile")
49889
+ return "Read File";
49890
+ if (t === "listdir")
49891
+ return "List Files";
49892
+ if (t === "grepfiles")
49893
+ return "Search in Files";
49894
+ if (t === "applypatch")
49895
+ return "Apply Patch";
49896
+ if (t === "updateplan")
49897
+ return "Plan update";
49389
49898
  if (t === "run_shell_command")
49390
49899
  return "Shell command";
49391
49900
  if (t === "list_directory")
@@ -49396,14 +49905,24 @@ function getHeaderLabel(toolName) {
49396
49905
  return "Update Todos";
49397
49906
  if (t === "read_many_files")
49398
49907
  return "Read Multiple Files";
49399
- if (t === "read_file")
49400
- return "Read File";
49401
- if (t === "glob")
49402
- return "Find Files";
49908
+ if (t === "runshellcommand")
49909
+ return "Shell command";
49910
+ if (t === "listdirectory")
49911
+ return "List Directory";
49912
+ if (t === "searchfilecontent")
49913
+ return "Search in Files";
49914
+ if (t === "writetodos")
49915
+ return "Update Todos";
49916
+ if (t === "readmanyfiles")
49917
+ return "Read Multiple Files";
49403
49918
  if (t === "replace")
49404
49919
  return "Edit File";
49405
- if (t === "write_file")
49920
+ if (t === "write_file" || t === "writefile")
49406
49921
  return "Write File";
49922
+ if (t === "killbash")
49923
+ return "Kill Shell";
49924
+ if (t === "bashoutput")
49925
+ return "Shell Output";
49407
49926
  return toolName;
49408
49927
  }
49409
49928
  var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
@@ -49413,7 +49932,7 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49413
49932
  precomputedDiff
49414
49933
  }) => {
49415
49934
  const t = toolName.toLowerCase();
49416
- if (t === "bash" || t === "shell_command" || t === "run_shell_command") {
49935
+ if (t === "bash" || t === "shell_command" || t === "shellcommand" || t === "run_shell_command" || t === "runshellcommand") {
49417
49936
  const cmdVal = parsedArgs?.command;
49418
49937
  const cmd = typeof cmdVal === "string" ? cmdVal : toolArgs || "(no arguments)";
49419
49938
  const descVal = parsedArgs?.description;
@@ -49451,9 +49970,9 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49451
49970
  ]
49452
49971
  }, undefined, true, undefined, this);
49453
49972
  }
49454
- if (t === "ls" || t === "list_dir" || t === "list_directory") {
49973
+ if (t === "ls" || t === "list_dir" || t === "listdir" || t === "list_directory" || t === "listdirectory") {
49455
49974
  const pathVal = parsedArgs?.path || parsedArgs?.target_directory || parsedArgs?.dir_path;
49456
- const path15 = typeof pathVal === "string" ? pathVal : "(current directory)";
49975
+ const path16 = typeof pathVal === "string" ? pathVal : "(current directory)";
49457
49976
  const ignoreVal = parsedArgs?.ignore || parsedArgs?.ignore_globs;
49458
49977
  const ignore = Array.isArray(ignoreVal) && ignoreVal.length > 0 ? ` (ignoring: ${ignoreVal.join(", ")})` : "";
49459
49978
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
@@ -49463,7 +49982,7 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49463
49982
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
49464
49983
  children: [
49465
49984
  "List files in: ",
49466
- path15
49985
+ path16
49467
49986
  ]
49468
49987
  }, undefined, true, undefined, this),
49469
49988
  ignore ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
@@ -49473,9 +49992,9 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49473
49992
  ]
49474
49993
  }, undefined, true, undefined, this);
49475
49994
  }
49476
- if (t === "read" || t === "read_file") {
49995
+ if (t === "read" || t === "read_file" || t === "readfile") {
49477
49996
  const pathVal = parsedArgs?.file_path || parsedArgs?.target_file;
49478
- const path15 = typeof pathVal === "string" ? pathVal : "(no file specified)";
49997
+ const path16 = typeof pathVal === "string" ? pathVal : "(no file specified)";
49479
49998
  const offsetVal = parsedArgs?.offset;
49480
49999
  const limitVal = parsedArgs?.limit;
49481
50000
  const rangeInfo = typeof offsetVal === "number" || typeof limitVal === "number" ? ` (lines ${offsetVal ?? 1}–${typeof offsetVal === "number" && typeof limitVal === "number" ? offsetVal + limitVal : "end"})` : "";
@@ -49485,17 +50004,17 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49485
50004
  children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
49486
50005
  children: [
49487
50006
  "Read file: ",
49488
- path15,
50007
+ path16,
49489
50008
  rangeInfo
49490
50009
  ]
49491
50010
  }, undefined, true, undefined, this)
49492
50011
  }, undefined, false, undefined, this);
49493
50012
  }
49494
- if (t === "grep" || t === "grep_files" || t === "search_file_content") {
50013
+ if (t === "grep" || t === "grep_files" || t === "grepfiles" || t === "search_file_content" || t === "searchfilecontent") {
49495
50014
  const patternVal = parsedArgs?.pattern;
49496
50015
  const pattern = typeof patternVal === "string" ? patternVal : "(no pattern)";
49497
50016
  const pathVal = parsedArgs?.path;
49498
- const path15 = typeof pathVal === "string" ? ` in ${pathVal}` : "";
50017
+ const path16 = typeof pathVal === "string" ? ` in ${pathVal}` : "";
49499
50018
  const includeVal = parsedArgs?.include || parsedArgs?.glob;
49500
50019
  const includeInfo = typeof includeVal === "string" ? ` (${includeVal})` : "";
49501
50020
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
@@ -49505,30 +50024,25 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49505
50024
  children: [
49506
50025
  "Search for: ",
49507
50026
  pattern,
49508
- path15,
50027
+ path16,
49509
50028
  includeInfo
49510
50029
  ]
49511
50030
  }, undefined, true, undefined, this)
49512
50031
  }, undefined, false, undefined, this);
49513
50032
  }
49514
- if (t === "apply_patch") {
50033
+ if (t === "apply_patch" || t === "applypatch") {
49515
50034
  const inputVal = parsedArgs?.input;
49516
50035
  const patchPreview = typeof inputVal === "string" && inputVal.length > 100 ? `${inputVal.slice(0, 100)}...` : typeof inputVal === "string" ? inputVal : "(no patch content)";
49517
50036
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
49518
50037
  flexDirection: "column",
49519
50038
  paddingLeft: 2,
49520
- children: [
49521
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
49522
- children: "Apply patch:"
49523
- }, undefined, false, undefined, this),
49524
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
49525
- dimColor: true,
49526
- children: patchPreview
49527
- }, undefined, false, undefined, this)
49528
- ]
49529
- }, undefined, true, undefined, this);
50039
+ children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
50040
+ dimColor: true,
50041
+ children: patchPreview
50042
+ }, undefined, false, undefined, this)
50043
+ }, undefined, false, undefined, this);
49530
50044
  }
49531
- if (t === "update_plan") {
50045
+ if (t === "update_plan" || t === "updateplan") {
49532
50046
  const planVal = parsedArgs?.plan;
49533
50047
  const explanationVal = parsedArgs?.explanation;
49534
50048
  if (Array.isArray(planVal)) {
@@ -49579,7 +50093,7 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49579
50093
  }, undefined, true, undefined, this)
49580
50094
  }, undefined, false, undefined, this);
49581
50095
  }
49582
- if ((t === "write" || t === "edit" || t === "multiedit" || t === "replace" || t === "write_file") && parsedArgs) {
50096
+ if ((t === "write" || t === "edit" || t === "multiedit" || t === "replace" || t === "write_file" || t === "writefile") && parsedArgs) {
49583
50097
  try {
49584
50098
  const filePath = String(parsedArgs.file_path || "");
49585
50099
  if (!filePath)
@@ -49588,7 +50102,7 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49588
50102
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
49589
50103
  flexDirection: "column",
49590
50104
  paddingLeft: 2,
49591
- children: t === "write" || t === "write_file" ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(AdvancedDiffRenderer, {
50105
+ children: t === "write" || t === "write_file" || t === "writefile" ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(AdvancedDiffRenderer, {
49592
50106
  precomputed: precomputedDiff,
49593
50107
  kind: "write",
49594
50108
  filePath,
@@ -49611,7 +50125,7 @@ var import_react29, jsx_dev_runtime6, OptionsRenderer, DynamicPreview = ({
49611
50125
  }, undefined, false, undefined, this)
49612
50126
  }, undefined, false, undefined, this);
49613
50127
  }
49614
- if (t === "write" || t === "write_file") {
50128
+ if (t === "write" || t === "write_file" || t === "writefile") {
49615
50129
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
49616
50130
  flexDirection: "column",
49617
50131
  paddingLeft: 2,
@@ -52191,6 +52705,14 @@ var init_build5 = __esm(async () => {
52191
52705
  build_default2 = Spinner;
52192
52706
  });
52193
52707
 
52708
+ // src/version.ts
52709
+ function getVersion2() {
52710
+ return package_default.version;
52711
+ }
52712
+ var init_version2 = __esm(() => {
52713
+ init_package();
52714
+ });
52715
+
52194
52716
  // node_modules/react/cjs/react-jsx-runtime.development.js
52195
52717
  var require_react_jsx_runtime_development = __commonJS((exports) => {
52196
52718
  var React13 = __toESM(require_react(), 1);
@@ -53491,6 +54013,12 @@ var init_registry = __esm(() => {
53491
54013
  handler: () => {
53492
54014
  return "Initializing memory...";
53493
54015
  }
54016
+ },
54017
+ "/skill": {
54018
+ desc: "Enter skill creation mode (optionally: /skill <description>)",
54019
+ handler: () => {
54020
+ return "Starting skill creation...";
54021
+ }
53494
54022
  }
53495
54023
  };
53496
54024
  });
@@ -53947,7 +54475,8 @@ function Input({
53947
54475
  onInterrupt,
53948
54476
  interruptRequested = false,
53949
54477
  agentId,
53950
- agentName
54478
+ agentName,
54479
+ currentModel
53951
54480
  }) {
53952
54481
  const [value, setValue] = import_react36.useState("");
53953
54482
  const [escapePressed, setEscapePressed] = import_react36.useState(false);
@@ -54339,7 +54868,7 @@ function Input({
54339
54868
  }, undefined, false, undefined, this),
54340
54869
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
54341
54870
  dimColor: true,
54342
- children: "https://discord.gg/letta"
54871
+ children: `Letta Code v${appVersion} [${currentModel ?? "unknown"}]`
54343
54872
  }, undefined, false, undefined, this)
54344
54873
  ]
54345
54874
  }, undefined, true, undefined, this)
@@ -54348,10 +54877,11 @@ function Input({
54348
54877
  ]
54349
54878
  }, undefined, true, undefined, this);
54350
54879
  }
54351
- var import_react36, jsx_dev_runtime17, Spinner2, COUNTER_VISIBLE_THRESHOLD = 1000;
54880
+ var import_react36, jsx_dev_runtime17, Spinner2, appVersion, COUNTER_VISIBLE_THRESHOLD = 1000;
54352
54881
  var init_InputRich = __esm(async () => {
54353
54882
  init_mode();
54354
54883
  init_settings_manager();
54884
+ init_version2();
54355
54885
  init_useTerminalWidth();
54356
54886
  init_colors();
54357
54887
  await __promiseAll([
@@ -54364,6 +54894,7 @@ var init_InputRich = __esm(async () => {
54364
54894
  import_react36 = __toESM(require_react(), 1);
54365
54895
  jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
54366
54896
  Spinner2 = build_default2;
54897
+ appVersion = getVersion2();
54367
54898
  });
54368
54899
 
54369
54900
  // src/cli/components/ModelSelector.tsx
@@ -55383,8 +55914,10 @@ var init_ToolCallMessageRich = __esm(async () => {
55383
55914
  displayName = "Planning";
55384
55915
  else if (displayName === "ExitPlanMode")
55385
55916
  displayName = "Planning";
55917
+ else if (displayName === "AskUserQuestion")
55918
+ displayName = "Question";
55386
55919
  else if (displayName === "update_plan")
55387
- displayName = "Plan";
55920
+ displayName = "Planning";
55388
55921
  else if (displayName === "shell_command")
55389
55922
  displayName = "Shell";
55390
55923
  else if (displayName === "shell")
@@ -55397,6 +55930,20 @@ var init_ToolCallMessageRich = __esm(async () => {
55397
55930
  displayName = "Grep";
55398
55931
  else if (displayName === "apply_patch")
55399
55932
  displayName = "Patch";
55933
+ else if (displayName === "UpdatePlan")
55934
+ displayName = "Planning";
55935
+ else if (displayName === "ShellCommand")
55936
+ displayName = "Shell";
55937
+ else if (displayName === "Shell")
55938
+ displayName = "Shell";
55939
+ else if (displayName === "ReadFile")
55940
+ displayName = "Read";
55941
+ else if (displayName === "ListDir")
55942
+ displayName = "LS";
55943
+ else if (displayName === "GrepFiles")
55944
+ displayName = "Grep";
55945
+ else if (displayName === "ApplyPatch")
55946
+ displayName = "Patch";
55400
55947
  else if (displayName === "run_shell_command")
55401
55948
  displayName = "Shell";
55402
55949
  else if (displayName === "list_directory")
@@ -55407,6 +55954,26 @@ var init_ToolCallMessageRich = __esm(async () => {
55407
55954
  displayName = "TODO";
55408
55955
  else if (displayName === "read_many_files")
55409
55956
  displayName = "Read Multiple";
55957
+ else if (displayName === "RunShellCommand")
55958
+ displayName = "Shell";
55959
+ else if (displayName === "ListDirectory")
55960
+ displayName = "LS";
55961
+ else if (displayName === "SearchFileContent")
55962
+ displayName = "Grep";
55963
+ else if (displayName === "WriteTodos")
55964
+ displayName = "TODO";
55965
+ else if (displayName === "ReadManyFiles")
55966
+ displayName = "Read Multiple";
55967
+ else if (displayName === "Replace" || displayName === "replace")
55968
+ displayName = "Edit";
55969
+ else if (displayName === "WriteFile" || displayName === "write_file")
55970
+ displayName = "Write";
55971
+ else if (displayName === "KillBash")
55972
+ displayName = "Kill Shell";
55973
+ else if (displayName === "BashOutput")
55974
+ displayName = "Shell Output";
55975
+ else if (displayName === "MultiEdit")
55976
+ displayName = "Edit";
55410
55977
  const formatted = formatArgsDisplay(argsText);
55411
55978
  const args = `(${formatted.display})`;
55412
55979
  const rightWidth = Math.max(0, columns - 2);
@@ -55495,7 +56062,7 @@ var init_ToolCallMessageRich = __esm(async () => {
55495
56062
  }
55496
56063
  const displayResultText = clipToolReturn2(line.resultText).replace(/\n+$/, "");
55497
56064
  const isRecord5 = (v) => typeof v === "object" && v !== null;
55498
- const isTodoTool = rawName === "todo_write" || rawName === "TodoWrite" || displayName === "TODO";
56065
+ const isTodoTool = rawName === "todo_write" || rawName === "TodoWrite" || rawName === "write_todos" || rawName === "WriteTodos" || displayName === "TODO";
55499
56066
  if (isTodoTool && line.resultOk !== false && line.argsText) {
55500
56067
  try {
55501
56068
  const parsedArgs = JSON.parse(line.argsText);
@@ -55514,7 +56081,7 @@ var init_ToolCallMessageRich = __esm(async () => {
55514
56081
  }
55515
56082
  } catch {}
55516
56083
  }
55517
- const isPlanTool = rawName === "update_plan" || displayName === "Plan";
56084
+ const isPlanTool = rawName === "update_plan" || rawName === "UpdatePlan" || displayName === "Planning";
55518
56085
  if (isPlanTool && line.resultOk !== false && line.argsText) {
55519
56086
  try {
55520
56087
  const parsedArgs = JSON.parse(line.argsText);
@@ -55861,14 +56428,6 @@ var init_UserMessageRich = __esm(async () => {
55861
56428
  UserMessage.displayName = "UserMessage";
55862
56429
  });
55863
56430
 
55864
- // src/version.ts
55865
- function getVersion2() {
55866
- return package_default.version;
55867
- }
55868
- var init_version2 = __esm(() => {
55869
- init_package();
55870
- });
55871
-
55872
56431
  // src/cli/components/WelcomeScreen.tsx
55873
56432
  function WelcomeScreen({
55874
56433
  loadingState,
@@ -56509,6 +57068,13 @@ function readPlanFile() {
56509
57068
  return `Failed to read plan file at ${planFilePath}`;
56510
57069
  }
56511
57070
  }
57071
+ function isFancyUITool(name) {
57072
+ return name === "AskUserQuestion" || name === "EnterPlanMode" || name === "ExitPlanMode";
57073
+ }
57074
+ function getQuestionsFromApproval(approval) {
57075
+ const parsed = safeJsonParseOr(approval.toolArgs, {});
57076
+ return parsed.questions || [];
57077
+ }
56512
57078
  function getSkillUnloadReminder() {
56513
57079
  const { hasLoadedSkills: hasLoadedSkills2 } = (init_context(), __toCommonJS(exports_context));
56514
57080
  if (hasLoadedSkills2()) {
@@ -56550,9 +57116,7 @@ function App2({
56550
57116
  const toolAbortControllerRef = import_react45.useRef(null);
56551
57117
  const [autoHandledResults, setAutoHandledResults] = import_react45.useState([]);
56552
57118
  const [autoDeniedApprovals, setAutoDeniedApprovals] = import_react45.useState([]);
56553
- const [planApprovalPending, setPlanApprovalPending] = import_react45.useState(null);
56554
- const [questionApprovalPending, setQuestionApprovalPending] = import_react45.useState(null);
56555
- const [enterPlanModeApprovalPending, setEnterPlanModeApprovalPending] = import_react45.useState(null);
57119
+ const currentApproval = pendingApprovals[approvalResults.length];
56556
57120
  const [modelSelectorOpen, setModelSelectorOpen] = import_react45.useState(false);
56557
57121
  const [toolsetSelectorOpen, setToolsetSelectorOpen] = import_react45.useState(false);
56558
57122
  const [systemPromptSelectorOpen, setSystemPromptSelectorOpen] = import_react45.useState(false);
@@ -56560,6 +57124,8 @@ function App2({
56560
57124
  const [currentToolset, setCurrentToolset] = import_react45.useState(null);
56561
57125
  const [llmConfig, setLlmConfig] = import_react45.useState(null);
56562
57126
  const [agentName, setAgentName] = import_react45.useState(null);
57127
+ const currentModelLabel = llmConfig?.model_endpoint_type && llmConfig?.model ? `${llmConfig.model_endpoint_type}/${llmConfig.model}` : llmConfig?.model ?? null;
57128
+ const currentModelDisplay = currentModelLabel?.split("/").pop() ?? null;
56563
57129
  const [agentSelectorOpen, setAgentSelectorOpen] = import_react45.useState(false);
56564
57130
  const [tokenStreamingEnabled, setTokenStreamingEnabled] = import_react45.useState(tokenStreaming);
56565
57131
  const [tokenCount, setTokenCount] = import_react45.useState(0);
@@ -56634,35 +57200,6 @@ function App2({
56634
57200
  import_react45.useEffect(() => {
56635
57201
  const approvals = startupApprovals?.length > 0 ? startupApprovals : startupApproval ? [startupApproval] : [];
56636
57202
  if (loadingState === "ready" && approvals.length > 0) {
56637
- const planApproval = approvals.find((a) => a.toolName === "ExitPlanMode");
56638
- if (planApproval) {
56639
- const plan = readPlanFile();
56640
- setPlanApprovalPending({
56641
- plan,
56642
- toolCallId: planApproval.toolCallId,
56643
- toolArgs: planApproval.toolArgs
56644
- });
56645
- return;
56646
- }
56647
- const questionApproval = approvals.find((a) => a.toolName === "AskUserQuestion");
56648
- if (questionApproval) {
56649
- const parsedArgs = safeJsonParseOr(questionApproval.toolArgs, {});
56650
- const questions = parsedArgs.questions || [];
56651
- if (questions.length > 0) {
56652
- setQuestionApprovalPending({
56653
- questions,
56654
- toolCallId: questionApproval.toolCallId
56655
- });
56656
- return;
56657
- }
56658
- }
56659
- const enterPlanModeApproval = approvals.find((a) => a.toolName === "EnterPlanMode");
56660
- if (enterPlanModeApproval) {
56661
- setEnterPlanModeApprovalPending({
56662
- toolCallId: enterPlanModeApproval.toolCallId
56663
- });
56664
- return;
56665
- }
56666
57203
  setPendingApprovals(approvals);
56667
57204
  const analyzeStartupApprovals = async () => {
56668
57205
  try {
@@ -56769,38 +57306,6 @@ function App2({
56769
57306
  setStreaming(false);
56770
57307
  return;
56771
57308
  }
56772
- const planApproval = approvalsToProcess.find((a) => a.toolName === "ExitPlanMode");
56773
- if (planApproval) {
56774
- const plan = readPlanFile();
56775
- setPlanApprovalPending({
56776
- plan,
56777
- toolCallId: planApproval.toolCallId,
56778
- toolArgs: planApproval.toolArgs
56779
- });
56780
- setStreaming(false);
56781
- return;
56782
- }
56783
- const questionApproval = approvalsToProcess.find((a) => a.toolName === "AskUserQuestion");
56784
- if (questionApproval) {
56785
- const parsedArgs = safeJsonParseOr(questionApproval.toolArgs, {});
56786
- const questions = parsedArgs.questions || [];
56787
- if (questions.length > 0) {
56788
- setQuestionApprovalPending({
56789
- questions,
56790
- toolCallId: questionApproval.toolCallId
56791
- });
56792
- setStreaming(false);
56793
- return;
56794
- }
56795
- }
56796
- const enterPlanModeApproval = approvalsToProcess.find((a) => a.toolName === "EnterPlanMode");
56797
- if (enterPlanModeApproval) {
56798
- setEnterPlanModeApprovalPending({
56799
- toolCallId: enterPlanModeApproval.toolCallId
56800
- });
56801
- setStreaming(false);
56802
- return;
56803
- }
56804
57309
  const approvalResults2 = await Promise.all(approvalsToProcess.map(async (approvalItem) => {
56805
57310
  if (!approvalItem.toolName || !approvalItem.toolArgs) {
56806
57311
  return {
@@ -56817,9 +57322,23 @@ function App2({
56817
57322
  const context3 = await analyzeToolApproval2(approvalItem.toolName, parsedArgs);
56818
57323
  return { approval: approvalItem, permission, context: context3 };
56819
57324
  }));
56820
- const needsUserInput = approvalResults2.filter((ac) => ac.permission.decision === "ask");
56821
- const autoDenied = approvalResults2.filter((ac) => ac.permission.decision === "deny");
56822
- const autoAllowed = approvalResults2.filter((ac) => ac.permission.decision === "allow");
57325
+ const needsUserInput = [];
57326
+ const autoDenied = [];
57327
+ const autoAllowed = [];
57328
+ for (const ac of approvalResults2) {
57329
+ const { approval: approval2, permission } = ac;
57330
+ let decision = permission.decision;
57331
+ if (isFancyUITool(approval2.toolName) && decision === "allow") {
57332
+ decision = "ask";
57333
+ }
57334
+ if (decision === "ask") {
57335
+ needsUserInput.push(ac);
57336
+ } else if (decision === "deny") {
57337
+ autoDenied.push(ac);
57338
+ } else {
57339
+ autoAllowed.push(ac);
57340
+ }
57341
+ }
56823
57342
  const autoAllowedResults = await Promise.all(autoAllowed.map(async (ac) => {
56824
57343
  const parsedArgs = safeJsonParseOr(ac.approval.toolArgs, {});
56825
57344
  const result = await executeTool2(ac.approval.toolName, parsedArgs);
@@ -56967,19 +57486,20 @@ ${detail}` : "";
56967
57486
  if (!msg || streaming || commandRunning || isExecutingTool)
56968
57487
  return { submitted: false };
56969
57488
  if (msg.startsWith("/")) {
56970
- if (msg.trim() === "/model") {
57489
+ const trimmed = msg.trim();
57490
+ if (trimmed === "/model") {
56971
57491
  setModelSelectorOpen(true);
56972
57492
  return { submitted: true };
56973
57493
  }
56974
- if (msg.trim() === "/toolset") {
57494
+ if (trimmed === "/toolset") {
56975
57495
  setToolsetSelectorOpen(true);
56976
57496
  return { submitted: true };
56977
57497
  }
56978
- if (msg.trim() === "/system") {
57498
+ if (trimmed === "/system") {
56979
57499
  setSystemPromptSelectorOpen(true);
56980
57500
  return { submitted: true };
56981
57501
  }
56982
- if (msg.trim() === "/agent") {
57502
+ if (trimmed === "/agent") {
56983
57503
  const cmdId2 = uid("cmd");
56984
57504
  const agentUrl = `https://app.letta.com/projects/default-project/agents/${agentId}`;
56985
57505
  buffersRef.current.byId.set(cmdId2, {
@@ -56994,11 +57514,11 @@ ${detail}` : "";
56994
57514
  refreshDerived();
56995
57515
  return { submitted: true };
56996
57516
  }
56997
- if (msg.trim() === "/exit") {
57517
+ if (trimmed === "/exit") {
56998
57518
  handleExit();
56999
57519
  return { submitted: true };
57000
57520
  }
57001
- if (msg.trim() === "/logout") {
57521
+ if (trimmed === "/logout") {
57002
57522
  const cmdId2 = uid("cmd");
57003
57523
  buffersRef.current.byId.set(cmdId2, {
57004
57524
  kind: "command",
@@ -57410,7 +57930,64 @@ ${detail}` : "";
57410
57930
  }
57411
57931
  return { submitted: true };
57412
57932
  }
57413
- if (msg.trim() === "/init") {
57933
+ if (trimmed.startsWith("/skill")) {
57934
+ const cmdId2 = uid("cmd");
57935
+ const [, ...rest] = trimmed.split(/\s+/);
57936
+ const description = rest.join(" ").trim();
57937
+ const initialOutput = description ? `Starting skill creation for: ${description}` : "Starting skill creation. I’ll load the skill-creator skill and ask a few questions about the skill you want to build...";
57938
+ buffersRef.current.byId.set(cmdId2, {
57939
+ kind: "command",
57940
+ id: cmdId2,
57941
+ input: msg,
57942
+ output: initialOutput,
57943
+ phase: "running"
57944
+ });
57945
+ buffersRef.current.order.push(cmdId2);
57946
+ refreshDerived();
57947
+ setCommandRunning(true);
57948
+ try {
57949
+ const { SKILL_CREATOR_PROMPT: SKILL_CREATOR_PROMPT3 } = await Promise.resolve().then(() => (init_promptAssets2(), exports_promptAssets2));
57950
+ const userDescriptionLine = description ? `
57951
+
57952
+ User-provided skill description:
57953
+ ${description}` : `
57954
+
57955
+ The user did not provide a description with /skill. Ask what kind of skill they want to create before proceeding.`;
57956
+ const skillMessage = `<system-reminder>
57957
+ ${SKILL_CREATOR_PROMPT3}${userDescriptionLine}
57958
+ </system-reminder>`;
57959
+ buffersRef.current.byId.set(cmdId2, {
57960
+ kind: "command",
57961
+ id: cmdId2,
57962
+ input: msg,
57963
+ output: "Entered skill creation mode. Answer the assistant’s questions to design your new skill.",
57964
+ phase: "finished",
57965
+ success: true
57966
+ });
57967
+ refreshDerived();
57968
+ await processConversation([
57969
+ {
57970
+ type: "message",
57971
+ role: "user",
57972
+ content: skillMessage
57973
+ }
57974
+ ]);
57975
+ } catch (error) {
57976
+ buffersRef.current.byId.set(cmdId2, {
57977
+ kind: "command",
57978
+ id: cmdId2,
57979
+ input: msg,
57980
+ output: `Failed: ${error instanceof Error ? error.message : String(error)}`,
57981
+ phase: "finished",
57982
+ success: false
57983
+ });
57984
+ refreshDerived();
57985
+ } finally {
57986
+ setCommandRunning(false);
57987
+ }
57988
+ return { submitted: true };
57989
+ }
57990
+ if (trimmed === "/init") {
57414
57991
  const cmdId2 = uid("cmd");
57415
57992
  buffersRef.current.byId.set(cmdId2, {
57416
57993
  kind: "command",
@@ -57695,14 +58272,14 @@ ${gitContext}
57695
58272
  if (isExecutingTool)
57696
58273
  return;
57697
58274
  const currentIndex = approvalResults.length;
57698
- const currentApproval = pendingApprovals[currentIndex];
57699
- if (!currentApproval)
58275
+ const currentApproval2 = pendingApprovals[currentIndex];
58276
+ if (!currentApproval2)
57700
58277
  return;
57701
58278
  setIsExecutingTool(true);
57702
58279
  try {
57703
58280
  const decision = {
57704
58281
  type: "approve",
57705
- approval: currentApproval
58282
+ approval: currentApproval2
57706
58283
  };
57707
58284
  if (currentIndex + 1 >= pendingApprovals.length) {
57708
58285
  await sendAllResults(decision);
@@ -57757,14 +58334,14 @@ ${gitContext}
57757
58334
  if (isExecutingTool)
57758
58335
  return;
57759
58336
  const currentIndex = approvalResults.length;
57760
- const currentApproval = pendingApprovals[currentIndex];
57761
- if (!currentApproval)
58337
+ const currentApproval2 = pendingApprovals[currentIndex];
58338
+ if (!currentApproval2)
57762
58339
  return;
57763
58340
  setIsExecutingTool(true);
57764
58341
  try {
57765
58342
  const decision = {
57766
58343
  type: "deny",
57767
- approval: currentApproval,
58344
+ approval: currentApproval2,
57768
58345
  reason: reason || "User denied the tool execution"
57769
58346
  };
57770
58347
  if (currentIndex + 1 >= pendingApprovals.length) {
@@ -58040,21 +58617,22 @@ Consider switching to a different system prompt using /system to match.` : null;
58040
58617
  }, [refreshDerived, commitEligibleLines, columns]);
58041
58618
  const [uiPermissionMode, setUiPermissionMode] = import_react45.useState(permissionMode2.getMode());
58042
58619
  const handlePlanApprove = import_react45.useCallback(async (acceptEdits = false) => {
58043
- if (!planApprovalPending)
58620
+ const currentIndex = approvalResults.length;
58621
+ const approval = pendingApprovals[currentIndex];
58622
+ if (!approval)
58044
58623
  return;
58045
- const { toolCallId, toolArgs } = planApprovalPending;
58046
- setPlanApprovalPending(null);
58624
+ const isLast = currentIndex + 1 >= pendingApprovals.length;
58047
58625
  const newMode = acceptEdits ? "acceptEdits" : "default";
58048
58626
  permissionMode2.setMode(newMode);
58049
58627
  setUiPermissionMode(newMode);
58050
58628
  try {
58051
- const parsedArgs = safeJsonParseOr(toolArgs, {});
58629
+ const parsedArgs = safeJsonParseOr(approval.toolArgs, {});
58052
58630
  const toolResult = await executeTool2("ExitPlanMode", parsedArgs);
58053
58631
  onChunk(buffersRef.current, {
58054
58632
  message_type: "tool_return_message",
58055
58633
  id: "dummy",
58056
58634
  date: new Date().toISOString(),
58057
- tool_call_id: toolCallId,
58635
+ tool_call_id: approval.toolCallId,
58058
58636
  tool_return: toolResult.toolReturn,
58059
58637
  status: toolResult.status,
58060
58638
  stdout: toolResult.stdout,
@@ -58062,94 +58640,93 @@ Consider switching to a different system prompt using /system to match.` : null;
58062
58640
  });
58063
58641
  setThinkingMessage(getRandomThinkingMessage());
58064
58642
  refreshDerived();
58065
- await processConversation([
58066
- {
58067
- type: "approval",
58068
- approvals: [
58069
- {
58070
- type: "tool",
58071
- tool_call_id: toolCallId,
58072
- tool_return: toolResult.toolReturn,
58073
- status: toolResult.status,
58074
- stdout: toolResult.stdout,
58075
- stderr: toolResult.stderr
58076
- }
58077
- ]
58078
- }
58079
- ]);
58643
+ const decision = {
58644
+ type: "approve",
58645
+ approval,
58646
+ precomputedResult: toolResult
58647
+ };
58648
+ if (isLast) {
58649
+ setIsExecutingTool(true);
58650
+ await sendAllResults(decision);
58651
+ } else {
58652
+ setApprovalResults((prev) => [...prev, decision]);
58653
+ }
58080
58654
  } catch (e) {
58081
58655
  appendError(String(e));
58082
58656
  setStreaming(false);
58083
58657
  }
58084
- }, [planApprovalPending, processConversation, appendError, refreshDerived]);
58658
+ }, [
58659
+ pendingApprovals,
58660
+ approvalResults,
58661
+ sendAllResults,
58662
+ appendError,
58663
+ refreshDerived
58664
+ ]);
58085
58665
  const handlePlanKeepPlanning = import_react45.useCallback(async (reason) => {
58086
- if (!planApprovalPending)
58666
+ const currentIndex = approvalResults.length;
58667
+ const approval = pendingApprovals[currentIndex];
58668
+ if (!approval)
58087
58669
  return;
58088
- const { toolCallId } = planApprovalPending;
58089
- setPlanApprovalPending(null);
58090
- try {
58091
- setThinkingMessage(getRandomThinkingMessage());
58092
- await processConversation([
58093
- {
58094
- type: "approval",
58095
- approval_request_id: toolCallId,
58096
- approve: false,
58097
- reason: reason || "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed."
58098
- }
58099
- ]);
58100
- } catch (e) {
58101
- appendError(String(e));
58102
- setStreaming(false);
58670
+ const isLast = currentIndex + 1 >= pendingApprovals.length;
58671
+ const denialReason = reason || "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.";
58672
+ const decision = {
58673
+ type: "deny",
58674
+ approval,
58675
+ reason: denialReason
58676
+ };
58677
+ if (isLast) {
58678
+ setIsExecutingTool(true);
58679
+ await sendAllResults(decision);
58680
+ } else {
58681
+ setApprovalResults((prev) => [...prev, decision]);
58103
58682
  }
58104
- }, [planApprovalPending, processConversation, appendError]);
58683
+ }, [pendingApprovals, approvalResults, sendAllResults]);
58105
58684
  const handleQuestionSubmit = import_react45.useCallback(async (answers) => {
58106
- if (!questionApprovalPending)
58685
+ const currentIndex = approvalResults.length;
58686
+ const approval = pendingApprovals[currentIndex];
58687
+ if (!approval)
58107
58688
  return;
58108
- const { toolCallId, questions } = questionApprovalPending;
58109
- setQuestionApprovalPending(null);
58110
- try {
58111
- const answerParts = questions.map((q) => {
58112
- const answer = answers[q.question] || "";
58113
- return `"${q.question}"="${answer}"`;
58114
- });
58115
- const toolReturn = `User has answered your questions: ${answerParts.join(", ")}. You can now continue with the user's answers in mind.`;
58116
- onChunk(buffersRef.current, {
58117
- message_type: "tool_return_message",
58118
- id: "dummy",
58119
- date: new Date().toISOString(),
58120
- tool_call_id: toolCallId,
58121
- tool_return: toolReturn,
58122
- status: "success",
58123
- stdout: null,
58124
- stderr: null
58125
- });
58126
- setThinkingMessage(getRandomThinkingMessage());
58127
- refreshDerived();
58128
- await processConversation([
58129
- {
58130
- type: "approval",
58131
- approvals: [
58132
- {
58133
- type: "tool",
58134
- tool_call_id: toolCallId,
58135
- tool_return: toolReturn,
58136
- status: "success",
58137
- stdout: null,
58138
- stderr: null
58139
- }
58140
- ]
58141
- }
58142
- ]);
58143
- } catch (e) {
58144
- appendError(String(e));
58145
- setStreaming(false);
58689
+ const isLast = currentIndex + 1 >= pendingApprovals.length;
58690
+ const questions = getQuestionsFromApproval(approval);
58691
+ const answerParts = questions.map((q) => {
58692
+ const answer = answers[q.question] || "";
58693
+ return `"${q.question}"="${answer}"`;
58694
+ });
58695
+ const toolReturn = `User has answered your questions: ${answerParts.join(", ")}. You can now continue with the user's answers in mind.`;
58696
+ const precomputedResult = {
58697
+ toolReturn,
58698
+ status: "success"
58699
+ };
58700
+ onChunk(buffersRef.current, {
58701
+ message_type: "tool_return_message",
58702
+ id: "dummy",
58703
+ date: new Date().toISOString(),
58704
+ tool_call_id: approval.toolCallId,
58705
+ tool_return: toolReturn,
58706
+ status: "success",
58707
+ stdout: null,
58708
+ stderr: null
58709
+ });
58710
+ setThinkingMessage(getRandomThinkingMessage());
58711
+ refreshDerived();
58712
+ const decision = {
58713
+ type: "approve",
58714
+ approval,
58715
+ precomputedResult
58716
+ };
58717
+ if (isLast) {
58718
+ setIsExecutingTool(true);
58719
+ await sendAllResults(decision);
58720
+ } else {
58721
+ setApprovalResults((prev) => [...prev, decision]);
58146
58722
  }
58147
- }, [questionApprovalPending, processConversation, appendError, refreshDerived]);
58723
+ }, [pendingApprovals, approvalResults, sendAllResults, refreshDerived]);
58148
58724
  const handleEnterPlanModeApprove = import_react45.useCallback(async () => {
58149
- if (!enterPlanModeApprovalPending)
58725
+ const currentIndex = approvalResults.length;
58726
+ const approval = pendingApprovals[currentIndex];
58727
+ if (!approval)
58150
58728
  return;
58151
- const { toolCallId } = enterPlanModeApprovalPending;
58152
- setEnterPlanModeApprovalPending(null);
58729
+ const isLast = currentIndex + 1 >= pendingApprovals.length;
58153
58730
  const planFilePath = generatePlanFilePath();
58154
58731
  permissionMode2.setMode("plan");
58155
58732
  permissionMode2.setPlanFilePath(planFilePath);
@@ -58167,81 +58744,53 @@ In plan mode, you should:
58167
58744
  Remember: DO NOT write or edit any files yet. This is a read-only exploration and planning phase.
58168
58745
 
58169
58746
  Plan file path: ${planFilePath}`;
58170
- try {
58171
- onChunk(buffersRef.current, {
58172
- message_type: "tool_return_message",
58173
- id: "dummy",
58174
- date: new Date().toISOString(),
58175
- tool_call_id: toolCallId,
58176
- tool_return: toolReturn,
58177
- status: "success",
58178
- stdout: null,
58179
- stderr: null
58180
- });
58181
- setThinkingMessage(getRandomThinkingMessage());
58182
- refreshDerived();
58183
- await processConversation([
58184
- {
58185
- type: "approval",
58186
- approvals: [
58187
- {
58188
- type: "tool",
58189
- tool_call_id: toolCallId,
58190
- tool_return: toolReturn,
58191
- status: "success",
58192
- stdout: null,
58193
- stderr: null
58194
- }
58195
- ]
58196
- }
58197
- ]);
58198
- } catch (e) {
58199
- appendError(String(e));
58200
- setStreaming(false);
58747
+ const precomputedResult = {
58748
+ toolReturn,
58749
+ status: "success"
58750
+ };
58751
+ onChunk(buffersRef.current, {
58752
+ message_type: "tool_return_message",
58753
+ id: "dummy",
58754
+ date: new Date().toISOString(),
58755
+ tool_call_id: approval.toolCallId,
58756
+ tool_return: toolReturn,
58757
+ status: "success",
58758
+ stdout: null,
58759
+ stderr: null
58760
+ });
58761
+ setThinkingMessage(getRandomThinkingMessage());
58762
+ refreshDerived();
58763
+ const decision = {
58764
+ type: "approve",
58765
+ approval,
58766
+ precomputedResult
58767
+ };
58768
+ if (isLast) {
58769
+ setIsExecutingTool(true);
58770
+ await sendAllResults(decision);
58771
+ } else {
58772
+ setApprovalResults((prev) => [...prev, decision]);
58201
58773
  }
58202
- }, [
58203
- enterPlanModeApprovalPending,
58204
- processConversation,
58205
- appendError,
58206
- refreshDerived
58207
- ]);
58774
+ }, [pendingApprovals, approvalResults, sendAllResults, refreshDerived]);
58208
58775
  const handleEnterPlanModeReject = import_react45.useCallback(async () => {
58209
- if (!enterPlanModeApprovalPending)
58776
+ const currentIndex = approvalResults.length;
58777
+ const approval = pendingApprovals[currentIndex];
58778
+ if (!approval)
58210
58779
  return;
58211
- const { toolCallId } = enterPlanModeApprovalPending;
58212
- setEnterPlanModeApprovalPending(null);
58780
+ const isLast = currentIndex + 1 >= pendingApprovals.length;
58213
58781
  const rejectionReason = "User chose to skip plan mode and start implementing directly.";
58214
- try {
58215
- onChunk(buffersRef.current, {
58216
- message_type: "tool_return_message",
58217
- id: "dummy",
58218
- date: new Date().toISOString(),
58219
- tool_call_id: toolCallId,
58220
- tool_return: `Error: request to call tool denied. User reason: ${rejectionReason}`,
58221
- status: "error",
58222
- stdout: null,
58223
- stderr: null
58224
- });
58225
- setThinkingMessage(getRandomThinkingMessage());
58226
- refreshDerived();
58227
- await processConversation([
58228
- {
58229
- type: "approval",
58230
- approval_request_id: toolCallId,
58231
- approve: false,
58232
- reason: rejectionReason
58233
- }
58234
- ]);
58235
- } catch (e) {
58236
- appendError(String(e));
58237
- setStreaming(false);
58782
+ const decision = {
58783
+ type: "deny",
58784
+ approval,
58785
+ reason: rejectionReason
58786
+ };
58787
+ if (isLast) {
58788
+ setIsExecutingTool(true);
58789
+ await sendAllResults(decision);
58790
+ } else {
58791
+ setApprovalResults((prev) => [...prev, decision]);
58238
58792
  }
58239
- }, [
58240
- enterPlanModeApprovalPending,
58241
- processConversation,
58242
- appendError,
58243
- refreshDerived
58244
- ]);
58793
+ }, [pendingApprovals, approvalResults, sendAllResults]);
58245
58794
  const liveItems = import_react45.useMemo(() => {
58246
58795
  return lines.filter((ln) => {
58247
58796
  if (!("phase" in ln))
@@ -58318,7 +58867,7 @@ Plan file path: ${planFilePath}`;
58318
58867
  }, undefined, false, undefined, this),
58319
58868
  loadingState === "ready" && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58320
58869
  children: [
58321
- liveItems.length > 0 && pendingApprovals.length === 0 && !planApprovalPending && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58870
+ liveItems.length > 0 && pendingApprovals.length === 0 && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58322
58871
  flexDirection: "column",
58323
58872
  children: liveItems.map((ln) => /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58324
58873
  marginTop: 1,
@@ -58345,7 +58894,7 @@ Plan file path: ${planFilePath}`;
58345
58894
  agentId
58346
58895
  }, undefined, false, undefined, this),
58347
58896
  /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Input, {
58348
- visible: !showExitStats && pendingApprovals.length === 0 && !modelSelectorOpen && !toolsetSelectorOpen && !systemPromptSelectorOpen && !agentSelectorOpen && !planApprovalPending && !questionApprovalPending && !enterPlanModeApprovalPending,
58897
+ visible: !showExitStats && pendingApprovals.length === 0 && !modelSelectorOpen && !toolsetSelectorOpen && !systemPromptSelectorOpen && !agentSelectorOpen,
58349
58898
  streaming,
58350
58899
  commandRunning,
58351
58900
  tokenCount,
@@ -58357,7 +58906,8 @@ Plan file path: ${planFilePath}`;
58357
58906
  onInterrupt: handleInterrupt,
58358
58907
  interruptRequested,
58359
58908
  agentId,
58360
- agentName
58909
+ agentName,
58910
+ currentModel: currentModelDisplay
58361
58911
  }, undefined, false, undefined, this),
58362
58912
  modelSelectorOpen && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(ModelSelector, {
58363
58913
  currentModel: llmConfig?.model_endpoint_type && llmConfig?.model ? `${llmConfig.model_endpoint_type}/${llmConfig.model}` : undefined,
@@ -58379,24 +58929,31 @@ Plan file path: ${planFilePath}`;
58379
58929
  onSelect: handleAgentSelect,
58380
58930
  onCancel: () => setAgentSelectorOpen(false)
58381
58931
  }, undefined, false, undefined, this),
58382
- planApprovalPending && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58932
+ currentApproval?.toolName === "ExitPlanMode" && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58383
58933
  children: [
58384
58934
  /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58385
58935
  height: 1
58386
58936
  }, undefined, false, undefined, this),
58387
58937
  /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(PlanModeDialog, {
58388
- plan: planApprovalPending.plan,
58938
+ plan: readPlanFile(),
58389
58939
  onApprove: () => handlePlanApprove(false),
58390
58940
  onApproveAndAcceptEdits: () => handlePlanApprove(true),
58391
58941
  onKeepPlanning: handlePlanKeepPlanning
58392
58942
  }, undefined, false, undefined, this)
58393
58943
  ]
58394
58944
  }, undefined, true, undefined, this),
58395
- questionApprovalPending && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(QuestionDialog, {
58396
- questions: questionApprovalPending.questions,
58397
- onSubmit: handleQuestionSubmit
58398
- }, undefined, false, undefined, this),
58399
- enterPlanModeApprovalPending && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58945
+ currentApproval?.toolName === "AskUserQuestion" && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58946
+ children: [
58947
+ /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58948
+ height: 1
58949
+ }, undefined, false, undefined, this),
58950
+ /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(QuestionDialog, {
58951
+ questions: getQuestionsFromApproval(currentApproval),
58952
+ onSubmit: handleQuestionSubmit
58953
+ }, undefined, false, undefined, this)
58954
+ ]
58955
+ }, undefined, true, undefined, this),
58956
+ currentApproval?.toolName === "EnterPlanMode" && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58400
58957
  children: [
58401
58958
  /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58402
58959
  height: 1
@@ -58407,15 +58964,13 @@ Plan file path: ${planFilePath}`;
58407
58964
  }, undefined, false, undefined, this)
58408
58965
  ]
58409
58966
  }, undefined, true, undefined, this),
58410
- pendingApprovals.length > 0 && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58967
+ currentApproval && !isFancyUITool(currentApproval.toolName) && /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(jsx_dev_runtime30.Fragment, {
58411
58968
  children: [
58412
58969
  /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
58413
58970
  height: 1
58414
58971
  }, undefined, false, undefined, this),
58415
58972
  /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(ApprovalDialog, {
58416
- approvals: pendingApprovals[approvalResults.length] ? [
58417
- pendingApprovals[approvalResults.length]
58418
- ] : [],
58973
+ approvals: [currentApproval],
58419
58974
  approvalContexts: approvalContexts[approvalResults.length] ? [
58420
58975
  approvalContexts[approvalResults.length]
58421
58976
  ] : [],
@@ -58586,38 +59141,46 @@ __export(exports_modify2, {
58586
59141
  linkToolsToAgent: () => linkToolsToAgent2
58587
59142
  });
58588
59143
  function buildModelSettings2(modelHandle, updateArgs) {
58589
- const settings = {};
58590
59144
  const isOpenAI = modelHandle.startsWith("openai/");
58591
59145
  const isAnthropic = modelHandle.startsWith("anthropic/");
58592
59146
  const isGoogleAI = modelHandle.startsWith("google_ai/");
58593
- if (isOpenAI && updateArgs?.reasoning_effort) {
58594
- const openaiSettings = settings;
58595
- openaiSettings.provider_type = "openai";
58596
- openaiSettings.reasoning = {
58597
- reasoning_effort: updateArgs.reasoning_effort
59147
+ if (isOpenAI) {
59148
+ const openaiSettings = {
59149
+ provider_type: "openai",
59150
+ parallel_tool_calls: true
59151
+ };
59152
+ if (updateArgs?.reasoning_effort) {
59153
+ openaiSettings.reasoning = {
59154
+ reasoning_effort: updateArgs.reasoning_effort
59155
+ };
59156
+ }
59157
+ return openaiSettings;
59158
+ }
59159
+ if (isAnthropic) {
59160
+ const anthropicSettings = {
59161
+ provider_type: "anthropic",
59162
+ parallel_tool_calls: true
58598
59163
  };
58599
- openaiSettings.parallel_tool_calls = true;
58600
- } else if (isAnthropic && updateArgs?.enable_reasoner !== undefined) {
58601
- const anthropicSettings = settings;
58602
- anthropicSettings.provider_type = "anthropic";
58603
- anthropicSettings.thinking = {
58604
- type: updateArgs.enable_reasoner ? "enabled" : "disabled"
59164
+ if (updateArgs?.enable_reasoner !== undefined) {
59165
+ anthropicSettings.thinking = {
59166
+ type: updateArgs.enable_reasoner ? "enabled" : "disabled"
59167
+ };
59168
+ }
59169
+ return anthropicSettings;
59170
+ }
59171
+ if (isGoogleAI) {
59172
+ const googleSettings = {
59173
+ provider_type: "google_ai",
59174
+ parallel_tool_calls: true
58605
59175
  };
58606
- anthropicSettings.parallel_tool_calls = true;
58607
- } else if (isGoogleAI) {
58608
- const googleSettings = settings;
58609
- googleSettings.provider_type = "google_ai";
58610
- googleSettings.parallel_tool_calls = true;
58611
59176
  if (updateArgs?.thinking_budget !== undefined) {
58612
59177
  googleSettings.thinking_config = {
58613
59178
  thinking_budget: updateArgs.thinking_budget
58614
59179
  };
58615
59180
  }
59181
+ return googleSettings;
58616
59182
  }
58617
- if (Object.keys(settings).length === 0) {
58618
- return;
58619
- }
58620
- return settings;
59183
+ return { parallel_tool_calls: true };
58621
59184
  }
58622
59185
  async function updateAgentLLMConfig2(agentId, modelHandle, updateArgs) {
58623
59186
  const client = await getClient2();
@@ -58993,6 +59556,198 @@ var init_model2 = __esm(() => {
58993
59556
  models2 = models_default;
58994
59557
  });
58995
59558
 
59559
+ // src/agent/skills.ts
59560
+ var exports_skills2 = {};
59561
+ __export(exports_skills2, {
59562
+ formatSkillsForMemory: () => formatSkillsForMemory2,
59563
+ discoverSkills: () => discoverSkills2,
59564
+ SKILLS_DIR: () => SKILLS_DIR2
59565
+ });
59566
+ import { existsSync as existsSync6 } from "node:fs";
59567
+ import { readdir as readdir4, readFile as readFile4 } from "node:fs/promises";
59568
+ import { join as join13 } from "node:path";
59569
+ function parseFrontmatter2(content) {
59570
+ const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
59571
+ const match3 = content.match(frontmatterRegex);
59572
+ if (!match3 || !match3[1] || !match3[2]) {
59573
+ return { frontmatter: {}, body: content };
59574
+ }
59575
+ const frontmatterText = match3[1];
59576
+ const body = match3[2];
59577
+ const frontmatter = {};
59578
+ const lines = frontmatterText.split(`
59579
+ `);
59580
+ let currentKey = null;
59581
+ let currentArray = [];
59582
+ for (const line of lines) {
59583
+ if (line.trim().startsWith("-") && currentKey) {
59584
+ const value = line.trim().slice(1).trim();
59585
+ currentArray.push(value);
59586
+ continue;
59587
+ }
59588
+ if (currentKey && currentArray.length > 0) {
59589
+ frontmatter[currentKey] = currentArray;
59590
+ currentKey = null;
59591
+ currentArray = [];
59592
+ }
59593
+ const colonIndex = line.indexOf(":");
59594
+ if (colonIndex > 0) {
59595
+ const key = line.slice(0, colonIndex).trim();
59596
+ const value = line.slice(colonIndex + 1).trim();
59597
+ currentKey = key;
59598
+ if (value) {
59599
+ frontmatter[key] = value;
59600
+ currentKey = null;
59601
+ } else {
59602
+ currentArray = [];
59603
+ }
59604
+ }
59605
+ }
59606
+ if (currentKey && currentArray.length > 0) {
59607
+ frontmatter[currentKey] = currentArray;
59608
+ }
59609
+ return { frontmatter, body: body.trim() };
59610
+ }
59611
+ async function discoverSkills2(skillsPath = join13(process.cwd(), SKILLS_DIR2)) {
59612
+ const errors = [];
59613
+ if (!existsSync6(skillsPath)) {
59614
+ return { skills: [], errors: [] };
59615
+ }
59616
+ const skills = [];
59617
+ try {
59618
+ await findSkillFiles2(skillsPath, skillsPath, skills, errors);
59619
+ } catch (error) {
59620
+ errors.push({
59621
+ path: skillsPath,
59622
+ message: `Failed to read skills directory: ${error instanceof Error ? error.message : String(error)}`
59623
+ });
59624
+ }
59625
+ return { skills, errors };
59626
+ }
59627
+ async function findSkillFiles2(currentPath, rootPath, skills, errors) {
59628
+ try {
59629
+ const entries = await readdir4(currentPath, { withFileTypes: true });
59630
+ for (const entry of entries) {
59631
+ const fullPath = join13(currentPath, entry.name);
59632
+ if (entry.isDirectory()) {
59633
+ await findSkillFiles2(fullPath, rootPath, skills, errors);
59634
+ } else if (entry.isFile() && entry.name.toUpperCase() === "SKILL.MD") {
59635
+ try {
59636
+ const skill2 = await parseSkillFile2(fullPath, rootPath);
59637
+ if (skill2) {
59638
+ skills.push(skill2);
59639
+ }
59640
+ } catch (error) {
59641
+ errors.push({
59642
+ path: fullPath,
59643
+ message: error instanceof Error ? error.message : String(error)
59644
+ });
59645
+ }
59646
+ }
59647
+ }
59648
+ } catch (error) {
59649
+ errors.push({
59650
+ path: currentPath,
59651
+ message: `Failed to read directory: ${error instanceof Error ? error.message : String(error)}`
59652
+ });
59653
+ }
59654
+ }
59655
+ async function parseSkillFile2(filePath, rootPath) {
59656
+ const content = await readFile4(filePath, "utf-8");
59657
+ const { frontmatter, body } = parseFrontmatter2(content);
59658
+ const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
59659
+ const relativePath = filePath.slice(normalizedRoot.length + 1);
59660
+ const dirPath = relativePath.slice(0, -"/SKILL.MD".length);
59661
+ const defaultId = dirPath || "root";
59662
+ const id = (typeof frontmatter.id === "string" ? frontmatter.id : null) || defaultId;
59663
+ const name = (typeof frontmatter.name === "string" ? frontmatter.name : null) || (typeof frontmatter.title === "string" ? frontmatter.title : null) || (id.split("/").pop() ?? "").replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
59664
+ let description = typeof frontmatter.description === "string" ? frontmatter.description : null;
59665
+ if (!description) {
59666
+ const firstParagraph = body.trim().split(`
59667
+
59668
+ `)[0];
59669
+ description = firstParagraph || "No description available";
59670
+ }
59671
+ description = description.trim();
59672
+ if (description.startsWith('"') && description.endsWith('"') || description.startsWith("'") && description.endsWith("'")) {
59673
+ description = description.slice(1, -1);
59674
+ }
59675
+ let tags;
59676
+ if (Array.isArray(frontmatter.tags)) {
59677
+ tags = frontmatter.tags;
59678
+ } else if (typeof frontmatter.tags === "string") {
59679
+ tags = [frontmatter.tags];
59680
+ }
59681
+ return {
59682
+ id,
59683
+ name,
59684
+ description,
59685
+ category: typeof frontmatter.category === "string" ? frontmatter.category : undefined,
59686
+ tags,
59687
+ path: filePath
59688
+ };
59689
+ }
59690
+ function formatSkillsForMemory2(skills, skillsDirectory) {
59691
+ let output = `Skills Directory: ${skillsDirectory}
59692
+
59693
+ `;
59694
+ if (skills.length === 0) {
59695
+ return `${output}[NO SKILLS AVAILABLE]`;
59696
+ }
59697
+ output += `Available Skills:
59698
+
59699
+ `;
59700
+ const categorized = new Map;
59701
+ const uncategorized = [];
59702
+ for (const skill2 of skills) {
59703
+ if (skill2.category) {
59704
+ const existing = categorized.get(skill2.category) || [];
59705
+ existing.push(skill2);
59706
+ categorized.set(skill2.category, existing);
59707
+ } else {
59708
+ uncategorized.push(skill2);
59709
+ }
59710
+ }
59711
+ for (const [category, categorySkills] of categorized) {
59712
+ output += `## ${category}
59713
+
59714
+ `;
59715
+ for (const skill2 of categorySkills) {
59716
+ output += formatSkill2(skill2);
59717
+ }
59718
+ output += `
59719
+ `;
59720
+ }
59721
+ if (uncategorized.length > 0) {
59722
+ if (categorized.size > 0) {
59723
+ output += `## Other
59724
+
59725
+ `;
59726
+ }
59727
+ for (const skill2 of uncategorized) {
59728
+ output += formatSkill2(skill2);
59729
+ }
59730
+ }
59731
+ return output.trim();
59732
+ }
59733
+ function formatSkill2(skill2) {
59734
+ let output = `### ${skill2.name}
59735
+ `;
59736
+ output += `ID: \`${skill2.id}\`
59737
+ `;
59738
+ output += `Description: ${skill2.description}
59739
+ `;
59740
+ if (skill2.tags && skill2.tags.length > 0) {
59741
+ output += `Tags: ${skill2.tags.map((t) => `\`${t}\``).join(", ")}
59742
+ `;
59743
+ }
59744
+ output += `
59745
+ `;
59746
+ return output;
59747
+ }
59748
+ var SKILLS_DIR2 = ".skills";
59749
+ var init_skills3 = () => {};
59750
+
58996
59751
  // src/index.ts
58997
59752
  import { parseArgs as parseArgs2 } from "util";
58998
59753
 
@@ -59109,7 +59864,11 @@ async function getClient() {
59109
59864
  updatedEnv.LETTA_API_KEY = process.env.LETTA_API_KEY;
59110
59865
  settingsManager.updateSettings({ env: updatedEnv });
59111
59866
  }
59112
- return new Letta({ apiKey, baseURL });
59867
+ return new Letta({
59868
+ apiKey,
59869
+ baseURL,
59870
+ defaultHeaders: { "X-Letta-Source": "letta-code" }
59871
+ });
59113
59872
  }
59114
59873
 
59115
59874
  // src/agent/context.ts
@@ -59213,10 +59972,32 @@ class PermissionModeManager {
59213
59972
  "Glob",
59214
59973
  "Grep",
59215
59974
  "NotebookRead",
59216
- "TodoWrite"
59975
+ "TodoWrite",
59976
+ "read_file",
59977
+ "list_dir",
59978
+ "grep_files",
59979
+ "update_plan",
59980
+ "ReadFile",
59981
+ "ListDir",
59982
+ "GrepFiles",
59983
+ "UpdatePlan",
59984
+ "list_directory",
59985
+ "search_file_content",
59986
+ "write_todos",
59987
+ "read_many_files",
59988
+ "ListDirectory",
59989
+ "SearchFileContent",
59990
+ "WriteTodos",
59991
+ "ReadManyFiles"
59992
+ ];
59993
+ const writeTools = [
59994
+ "Write",
59995
+ "Edit",
59996
+ "MultiEdit",
59997
+ "NotebookEdit",
59998
+ "apply_patch",
59999
+ "ApplyPatch"
59217
60000
  ];
59218
- const writeTools = ["Write", "Edit", "MultiEdit", "NotebookEdit"];
59219
- const deniedInPlan = ["Bash", "WebFetch"];
59220
60001
  if (allowedInPlan.includes(toolName)) {
59221
60002
  return "allow";
59222
60003
  }
@@ -59226,12 +60007,8 @@ class PermissionModeManager {
59226
60007
  if (planFilePath && targetPath && targetPath === planFilePath) {
59227
60008
  return "allow";
59228
60009
  }
59229
- return "deny";
59230
- }
59231
- if (deniedInPlan.includes(toolName)) {
59232
- return "deny";
59233
60010
  }
59234
- return null;
60011
+ return "deny";
59235
60012
  }
59236
60013
  case "default":
59237
60014
  return null;
@@ -59896,6 +60673,25 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
59896
60673
  settingsManager2.updateSettings({ lastAgent: agent.id });
59897
60674
  setAgentContext(agent.id, client, skillsDirectory2);
59898
60675
  await initializeLoadedSkillsFlag();
60676
+ try {
60677
+ const { discoverSkills: discoverSkills3, formatSkillsForMemory: formatSkillsForMemory3, SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills3(), exports_skills2));
60678
+ const { join: join14 } = await import("path");
60679
+ const resolvedSkillsDirectory = skillsDirectory2 || join14(process.cwd(), SKILLS_DIR3);
60680
+ const { skills, errors } = await discoverSkills3(resolvedSkillsDirectory);
60681
+ if (errors.length > 0) {
60682
+ console.warn("Errors encountered during skill discovery:");
60683
+ for (const error of errors) {
60684
+ console.warn(` ${error.path}: ${error.message}`);
60685
+ }
60686
+ }
60687
+ const formattedSkills = formatSkillsForMemory3(skills, resolvedSkillsDirectory);
60688
+ await client.agents.blocks.update("skills", {
60689
+ agent_id: agent.id,
60690
+ value: formattedSkills
60691
+ });
60692
+ } catch (error) {
60693
+ console.warn(`Failed to update skills: ${error instanceof Error ? error.message : String(error)}`);
60694
+ }
59899
60695
  const localProjectSettings = settingsManager2.getLocalProjectSettings();
59900
60696
  const isResumingProject = !forceNew2 && localProjectSettings?.lastAgent && agent.id === localProjectSettings.lastAgent;
59901
60697
  const resuming = !!(continueSession || agentIdArg || isResumingProject);
@@ -59950,4 +60746,4 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
59950
60746
  }
59951
60747
  main();
59952
60748
 
59953
- //# debugId=C0C2CA7817B463D264756E2164756E21
60749
+ //# debugId=4DD178C2F4ABE09364756E2164756E21