deepagents 1.7.2 → 1.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2021,7 +2021,8 @@ function parseSkillMetadataFromContent(content, skillPath, directoryName) {
2021
2021
  */
2022
2022
  async function listSkillsFromBackend(backend, sourcePath) {
2023
2023
  const skills = [];
2024
- const normalizedPath = sourcePath.endsWith("/") || sourcePath.endsWith("\\") ? sourcePath : `${sourcePath}/`;
2024
+ const pathSep = sourcePath.includes("\\") ? "\\" : "/";
2025
+ const normalizedPath = sourcePath.endsWith("/") || sourcePath.endsWith("\\") ? sourcePath : `${sourcePath}${pathSep}`;
2025
2026
  let fileInfos;
2026
2027
  try {
2027
2028
  fileInfos = await backend.lsInfo(normalizedPath);
@@ -2034,7 +2035,7 @@ async function listSkillsFromBackend(backend, sourcePath) {
2034
2035
  }));
2035
2036
  for (const entry of entries) {
2036
2037
  if (entry.type !== "directory") continue;
2037
- const skillMdPath = `${normalizedPath}${entry.name}/SKILL.md`;
2038
+ const skillMdPath = `${normalizedPath}${entry.name}${pathSep}SKILL.md`;
2038
2039
  let content;
2039
2040
  if (backend.downloadFiles) {
2040
2041
  const results = await backend.downloadFiles([skillMdPath]);
@@ -2135,11 +2136,10 @@ function createSkillsMiddleware(options) {
2135
2136
  const skillsLocations = formatSkillsLocations(sources);
2136
2137
  const skillsList = formatSkillsList(skillsMetadata, sources);
2137
2138
  const skillsSection = SKILLS_SYSTEM_PROMPT.replace("{skills_locations}", skillsLocations).replace("{skills_list}", skillsList);
2138
- const currentSystemPrompt = request.systemPrompt || "";
2139
- const newSystemPrompt = currentSystemPrompt ? `${currentSystemPrompt}\n\n${skillsSection}` : skillsSection;
2139
+ const newSystemMessage = request.systemMessage.concat(skillsSection);
2140
2140
  return handler({
2141
2141
  ...request,
2142
- systemPrompt: newSystemPrompt
2142
+ systemMessage: newSystemMessage
2143
2143
  });
2144
2144
  }
2145
2145
  });
@@ -3335,11 +3335,18 @@ function globToPathRegex(pattern) {
3335
3335
  return new RegExp(regex);
3336
3336
  }
3337
3337
  /**
3338
- * Parse a single line of stat output in the format: size\tmtime\ttype\tpath
3338
+ * Parse a single line of stat/find output in the format: size\tmtime\ttype\tpath
3339
3339
  *
3340
3340
  * The first three tab-delimited fields are always fixed (number, number, string),
3341
3341
  * so we safely take everything after the third tab as the file path — even if the
3342
3342
  * path itself contains tabs.
3343
+ *
3344
+ * The type field varies by platform / tool:
3345
+ * - GNU find -printf %y: single letter "d", "f", "l"
3346
+ * - BSD stat -f %Sp: permission strings like "drwxr-xr-x", "-rw-r--r--"
3347
+ *
3348
+ * The mtime field may be a float (GNU find %T@ → "1234567890.0000000000")
3349
+ * or an integer (BSD stat %m → "1234567890"); parseInt handles both.
3343
3350
  */
3344
3351
  function parseStatLine(line) {
3345
3352
  const firstTab = line.indexOf(" ");
@@ -3356,29 +3363,43 @@ function parseStatLine(line) {
3356
3363
  return {
3357
3364
  size,
3358
3365
  mtime,
3359
- isDir: fileType === "directory",
3366
+ isDir: fileType === "d" || fileType === "directory" || fileType.startsWith("d"),
3360
3367
  fullPath
3361
3368
  };
3362
3369
  }
3363
3370
  /**
3364
- * Pure POSIX shell command for listing directory contents with metadata.
3365
- * Uses find -maxdepth 1 + stat — works on any Linux including Alpine (busybox).
3371
+ * BusyBox/Alpine fallback script for stat -c.
3372
+ *
3373
+ * Determines file type with POSIX test builtins, then uses stat -c
3374
+ * (supported by both GNU coreutils and BusyBox) for size and mtime.
3375
+ * printf handles tab-delimited output formatting.
3376
+ */
3377
+ const STAT_C_SCRIPT = "for f; do if [ -d \"$f\" ]; then t=d; elif [ -L \"$f\" ]; then t=l; else t=f; fi; sz=$(stat -c %s \"$f\" 2>/dev/null) || continue; mt=$(stat -c %Y \"$f\" 2>/dev/null) || continue; printf \"%s\\t%s\\t%s\\t%s\\n\" \"$sz\" \"$mt\" \"$t\" \"$f\"; done";
3378
+ /**
3379
+ * Shell command for listing directory contents with metadata.
3380
+ *
3381
+ * Detects the environment at runtime with three-way probing:
3382
+ * 1. GNU find (full Linux): uses built-in `-printf` (most efficient)
3383
+ * 2. BusyBox / Alpine: uses `find -exec sh -c` with `stat -c` fallback
3384
+ * 3. BSD / macOS: uses `find -exec stat -f`
3366
3385
  *
3367
3386
  * Output format per line: size\tmtime\ttype\tpath
3368
3387
  */
3369
3388
  function buildLsCommand(dirPath) {
3370
3389
  const quotedPath = shellQuote(dirPath);
3371
- return `find ${quotedPath} -maxdepth 1 -not -path ${quotedPath} -exec stat -c '%s\\t%Y\\t%F\\t%n' {} + 2>/dev/null || true`;
3390
+ const findBase = `find ${quotedPath} -maxdepth 1 -not -path ${quotedPath}`;
3391
+ return `if find /dev/null -maxdepth 0 -printf '' 2>/dev/null; then ${findBase} -printf '%s\\t%T@\\t%y\\t%p\\n' 2>/dev/null; elif stat -c %s /dev/null >/dev/null 2>&1; then ${findBase} -exec sh -c '${STAT_C_SCRIPT}' _ {} +; else ${findBase} -exec stat -f '%z\t%m\t%Sp\t%N' {} + 2>/dev/null; fi || true`;
3372
3392
  }
3373
3393
  /**
3374
- * Pure POSIX shell command for listing files recursively with metadata.
3375
- * Uses find + stat works on any Linux including Alpine (busybox).
3394
+ * Shell command for listing files recursively with metadata.
3395
+ * Same three-way detection as buildLsCommand (GNU -printf / stat -c / BSD stat -f).
3376
3396
  *
3377
3397
  * Output format per line: size\tmtime\ttype\tpath
3378
3398
  */
3379
3399
  function buildFindCommand(searchPath) {
3380
3400
  const quotedPath = shellQuote(searchPath);
3381
- return `find ${quotedPath} -not -path ${quotedPath} -exec stat -c '%s\\t%Y\\t%F\\t%n' {} + 2>/dev/null || true`;
3401
+ const findBase = `find ${quotedPath} -not -path ${quotedPath}`;
3402
+ return `if find /dev/null -maxdepth 0 -printf '' 2>/dev/null; then ${findBase} -printf '%s\\t%T@\\t%y\\t%p\\n' 2>/dev/null; elif stat -c %s /dev/null >/dev/null 2>&1; then ${findBase} -exec sh -c '${STAT_C_SCRIPT}' _ {} +; else ${findBase} -exec stat -f '%z\t%m\t%Sp\t%N' {} + 2>/dev/null; fi || true`;
3382
3403
  }
3383
3404
  /**
3384
3405
  * Pure POSIX shell command for reading files with line numbers.
@@ -3399,7 +3420,9 @@ function buildReadCommand(filePath, offset, limit) {
3399
3420
  /**
3400
3421
  * Build a grep command for literal (fixed-string) search.
3401
3422
  * Uses grep -rHnF for recursive, with-filename, with-line-number, fixed-string search.
3402
- * Pure POSIX — works on any Linux including Alpine.
3423
+ *
3424
+ * When a glob pattern is provided, uses `find -name GLOB -exec grep` instead of
3425
+ * `grep --include=GLOB` for universal compatibility (BusyBox grep lacks --include).
3403
3426
  *
3404
3427
  * @param pattern - Literal string to search for (NOT regex).
3405
3428
  * @param searchPath - Base path to search in.
@@ -3408,7 +3431,8 @@ function buildReadCommand(filePath, offset, limit) {
3408
3431
  function buildGrepCommand(pattern, searchPath, globPattern) {
3409
3432
  const patternEscaped = shellQuote(pattern);
3410
3433
  const searchPathQuoted = shellQuote(searchPath);
3411
- return `grep -rHnF ${globPattern ? `--include=${shellQuote(globPattern)}` : ""} -e ${patternEscaped} ${searchPathQuoted} 2>/dev/null || true`;
3434
+ if (globPattern) return `find ${searchPathQuoted} -type f -name ${shellQuote(globPattern)} -exec grep -HnF -e ${patternEscaped} {} + 2>/dev/null || true`;
3435
+ return `grep -rHnF -e ${patternEscaped} ${searchPathQuoted} 2>/dev/null || true`;
3412
3436
  }
3413
3437
  /**
3414
3438
  * Base sandbox implementation with execute() as the only abstract method.
@@ -3461,6 +3485,7 @@ var BaseSandbox = class {
3461
3485
  * @returns Formatted file content with line numbers, or error message
3462
3486
  */
3463
3487
  async read(filePath, offset = 0, limit = 500) {
3488
+ if (limit === 0) return "";
3464
3489
  const command = buildReadCommand(filePath, offset, limit);
3465
3490
  const result = await this.execute(command);
3466
3491
  if (result.exitCode !== 0) return `Error: File '${filePath}' not found`;