sparkecoder 0.1.59 → 0.1.60

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 (95) hide show
  1. package/dist/agent/index.js +74 -27
  2. package/dist/agent/index.js.map +1 -1
  3. package/dist/cli.js +88 -34
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +87 -33
  6. package/dist/index.js.map +1 -1
  7. package/dist/server/index.js +87 -33
  8. package/dist/server/index.js.map +1 -1
  9. package/dist/skills/default/browser.md +143 -0
  10. package/dist/skills/default/code-review.md +122 -0
  11. package/dist/skills/default/debugging.md +105 -0
  12. package/dist/skills/default/refactoring.md +197 -0
  13. package/dist/tools/index.d.ts +16 -1
  14. package/dist/tools/index.js +74 -27
  15. package/dist/tools/index.js.map +1 -1
  16. package/package.json +4 -1
  17. package/src/skills/default/browser.md +143 -0
  18. package/src/skills/default/code-review.md +122 -0
  19. package/src/skills/default/debugging.md +105 -0
  20. package/src/skills/default/refactoring.md +197 -0
  21. package/web/.next/BUILD_ID +1 -1
  22. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  23. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  24. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  25. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  26. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  41. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  50. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  68. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  76. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  84. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  85. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  86. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  87. /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_buildManifest.js +0 -0
  88. /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_clientMiddlewareManifest.json +0 -0
  89. /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_ssgManifest.js +0 -0
  90. /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/R5xiWSOp_Nqqe_js-LROo}/_buildManifest.js +0 -0
  91. /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/R5xiWSOp_Nqqe_js-LROo}/_clientMiddlewareManifest.json +0 -0
  92. /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/R5xiWSOp_Nqqe_js-LROo}/_ssgManifest.js +0 -0
  93. /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_buildManifest.js +0 -0
  94. /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_clientMiddlewareManifest.json +0 -0
  95. /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -521,8 +521,15 @@ function discoverSkillDirectories(workingDir) {
521
521
  if (existsSync(agentsMd)) {
522
522
  agentsMdPath = agentsMd;
523
523
  }
524
- const builtInSkillsDir = resolve(dirname(import.meta.url.replace("file://", "")), "../skills/default");
525
- if (existsSync(builtInSkillsDir)) {
524
+ const baseDir = dirname(import.meta.url.replace("file://", ""));
525
+ const builtInCandidates = [
526
+ resolve(baseDir, "../skills/default"),
527
+ // dev: src/config → src/skills/default
528
+ resolve(baseDir, "./skills/default")
529
+ // prod: dist/ → dist/skills/default
530
+ ];
531
+ const builtInSkillsDir = builtInCandidates.find((p) => existsSync(p));
532
+ if (builtInSkillsDir) {
526
533
  onDemandDirs.push({ path: builtInSkillsDir, priority: 100 });
527
534
  allDirectories.push(builtInSkillsDir);
528
535
  }
@@ -874,7 +881,7 @@ __export(skills_exports, {
874
881
  loadSkillsFromDirectory: () => loadSkillsFromDirectory
875
882
  });
876
883
  import { readFile as readFile6, readdir } from "fs/promises";
877
- import { resolve as resolve6, basename, extname as extname3, relative as relative4 } from "path";
884
+ import { resolve as resolve6, basename, extname as extname4, relative as relative4 } from "path";
878
885
  import { existsSync as existsSync8 } from "fs";
879
886
  import { minimatch } from "minimatch";
880
887
  function parseSkillFrontmatter(content) {
@@ -945,7 +952,7 @@ function parseSkillFrontmatter(content) {
945
952
  }
946
953
  }
947
954
  function getSkillNameFromPath(filePath) {
948
- return basename(filePath, extname3(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
955
+ return basename(filePath, extname4(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
949
956
  }
950
957
  async function loadSkillsFromDirectory(directory, options = {}) {
951
958
  const {
@@ -1250,7 +1257,7 @@ var init_hasher = __esm({
1250
1257
  });
1251
1258
 
1252
1259
  // src/semantic/chunker.ts
1253
- import { extname as extname5, basename as basename2 } from "path";
1260
+ import { extname as extname6, basename as basename2 } from "path";
1254
1261
  var init_chunker = __esm({
1255
1262
  "src/semantic/chunker.ts"() {
1256
1263
  "use strict";
@@ -2221,26 +2228,41 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
2221
2228
  import { tool as tool2 } from "ai";
2222
2229
  import { z as z3 } from "zod";
2223
2230
  import { readFile as readFile2, stat } from "fs/promises";
2224
- import { resolve as resolve2, relative, isAbsolute } from "path";
2231
+ import { resolve as resolve2, relative, isAbsolute, extname } from "path";
2225
2232
  import { existsSync as existsSync3 } from "fs";
2226
2233
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
2234
+ var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
2227
2235
  var MAX_OUTPUT_CHARS3 = 5e4;
2236
+ var IMAGE_EXTENSIONS = {
2237
+ ".png": "image/png",
2238
+ ".jpg": "image/jpeg",
2239
+ ".jpeg": "image/jpeg",
2240
+ ".gif": "image/gif",
2241
+ ".webp": "image/webp"
2242
+ };
2243
+ function isImageFile(filePath) {
2244
+ return extname(filePath).toLowerCase() in IMAGE_EXTENSIONS;
2245
+ }
2246
+ function getImageMediaType(filePath) {
2247
+ return IMAGE_EXTENSIONS[extname(filePath).toLowerCase()] || "image/png";
2248
+ }
2228
2249
  var readFileInputSchema = z3.object({
2229
- path: z3.string().describe("The path to the file to read. Can be relative to working directory or absolute."),
2230
- startLine: z3.number().optional().describe("Optional: Start reading from this line number (1-indexed)"),
2231
- endLine: z3.number().optional().describe("Optional: Stop reading at this line number (1-indexed, inclusive)")
2250
+ path: z3.string().describe("The path to the file to read. Can be relative to working directory or absolute. Supports text files and images (png, jpg, jpeg, gif, webp)."),
2251
+ startLine: z3.number().optional().describe("Optional: Start reading from this line number (1-indexed). Only for text files."),
2252
+ endLine: z3.number().optional().describe("Optional: Stop reading at this line number (1-indexed, inclusive). Only for text files.")
2232
2253
  });
2233
2254
  function createReadFileTool(options) {
2234
2255
  return tool2({
2235
2256
  description: `Read the contents of a file. Provide a path relative to the working directory (${options.workingDirectory}) or an absolute path.
2236
- Large files will be automatically truncated. Binary files are not supported.
2237
- Use this to understand existing code, check file contents, or gather context.`,
2257
+ Supports text files (automatically truncated if large) and image files (png, jpg, jpeg, gif, webp).
2258
+ For images, the file contents are returned as visual data you can see and analyze.
2259
+ Use this to understand existing code, check file contents, view screenshots, or gather context.`,
2238
2260
  inputSchema: readFileInputSchema,
2239
- execute: async ({ path, startLine, endLine }) => {
2261
+ execute: async ({ path: filePath, startLine, endLine }) => {
2240
2262
  try {
2241
- const absolutePath = isAbsolute(path) ? path : resolve2(options.workingDirectory, path);
2263
+ const absolutePath = isAbsolute(filePath) ? filePath : resolve2(options.workingDirectory, filePath);
2242
2264
  const relativePath = relative(options.workingDirectory, absolutePath);
2243
- if (relativePath.startsWith("..") && !isAbsolute(path)) {
2265
+ if (relativePath.startsWith("..") && !isAbsolute(filePath)) {
2244
2266
  return {
2245
2267
  success: false,
2246
2268
  error: "Path escapes the working directory. Use an absolute path if intentional.",
@@ -2250,22 +2272,43 @@ Use this to understand existing code, check file contents, or gather context.`,
2250
2272
  if (!existsSync3(absolutePath)) {
2251
2273
  return {
2252
2274
  success: false,
2253
- error: `File not found: ${path}`,
2275
+ error: `File not found: ${filePath}`,
2254
2276
  content: null
2255
2277
  };
2256
2278
  }
2257
2279
  const stats = await stat(absolutePath);
2258
- if (stats.size > MAX_FILE_SIZE) {
2280
+ if (stats.isDirectory()) {
2259
2281
  return {
2260
2282
  success: false,
2261
- error: `File is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_FILE_SIZE / 1024 / 1024}MB.`,
2283
+ error: 'Path is a directory, not a file. Use bash with "ls" to list directory contents.',
2262
2284
  content: null
2263
2285
  };
2264
2286
  }
2265
- if (stats.isDirectory()) {
2287
+ if (isImageFile(absolutePath)) {
2288
+ if (stats.size > MAX_IMAGE_SIZE) {
2289
+ return {
2290
+ success: false,
2291
+ error: `Image is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_IMAGE_SIZE / 1024 / 1024}MB.`,
2292
+ content: null
2293
+ };
2294
+ }
2295
+ const buffer = await readFile2(absolutePath);
2296
+ const base64 = buffer.toString("base64");
2297
+ const mediaType = getImageMediaType(absolutePath);
2298
+ return {
2299
+ success: true,
2300
+ path: absolutePath,
2301
+ relativePath: relative(options.workingDirectory, absolutePath),
2302
+ content: `[Image: ${relativePath} (${mediaType}, ${(stats.size / 1024).toFixed(1)}KB)]`,
2303
+ mediaType,
2304
+ imageData: base64,
2305
+ sizeBytes: stats.size
2306
+ };
2307
+ }
2308
+ if (stats.size > MAX_FILE_SIZE) {
2266
2309
  return {
2267
2310
  success: false,
2268
- error: 'Path is a directory, not a file. Use bash with "ls" to list directory contents.',
2311
+ error: `File is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_FILE_SIZE / 1024 / 1024}MB.`,
2269
2312
  content: null
2270
2313
  };
2271
2314
  }
@@ -2281,9 +2324,7 @@ Use this to understand existing code, check file contents, or gather context.`,
2281
2324
  content: null
2282
2325
  };
2283
2326
  }
2284
- content = lines.slice(start, end).join("\n");
2285
- const lineNumbers = lines.slice(start, end).map((line, idx) => `${(start + idx + 1).toString().padStart(4)}: ${line}`).join("\n");
2286
- content = lineNumbers;
2327
+ content = lines.slice(start, end).map((line, idx) => `${(start + idx + 1).toString().padStart(4)}: ${line}`).join("\n");
2287
2328
  }
2288
2329
  const truncatedContent = truncateOutput(content, MAX_OUTPUT_CHARS3);
2289
2330
  const wasTruncated = truncatedContent.length < content.length;
@@ -2310,6 +2351,19 @@ Use this to understand existing code, check file contents, or gather context.`,
2310
2351
  content: null
2311
2352
  };
2312
2353
  }
2354
+ },
2355
+ toModelOutput: ({ output }) => {
2356
+ if (output && typeof output === "object" && "imageData" in output && output.imageData) {
2357
+ const result = output;
2358
+ return {
2359
+ type: "content",
2360
+ value: [
2361
+ { type: "text", text: result.content },
2362
+ { type: "image-data", data: result.imageData, mediaType: result.mediaType }
2363
+ ]
2364
+ };
2365
+ }
2366
+ return typeof output === "string" ? { type: "text", value: output } : { type: "json", value: output };
2313
2367
  }
2314
2368
  });
2315
2369
  }
@@ -2510,7 +2564,7 @@ function clearCheckpointManager(sessionId) {
2510
2564
  }
2511
2565
 
2512
2566
  // src/lsp/index.ts
2513
- import { extname as extname2, dirname as dirname4 } from "path";
2567
+ import { extname as extname3, dirname as dirname4 } from "path";
2514
2568
 
2515
2569
  // src/lsp/servers.ts
2516
2570
  import { spawn } from "child_process";
@@ -2633,9 +2687,9 @@ import {
2633
2687
  import { pathToFileURL, fileURLToPath } from "url";
2634
2688
  import { readFile as readFile4 } from "fs/promises";
2635
2689
  import { existsSync as existsSync6 } from "fs";
2636
- import { extname, normalize } from "path";
2690
+ import { extname as extname2, normalize } from "path";
2637
2691
  function getLanguageId(filePath) {
2638
- const ext = extname(filePath).toLowerCase();
2692
+ const ext = extname2(filePath).toLowerCase();
2639
2693
  const map = {
2640
2694
  ".ts": "typescript",
2641
2695
  ".tsx": "typescriptreact",
@@ -3023,7 +3077,7 @@ var state = {
3023
3077
  };
3024
3078
  async function getClientForFile(filePath) {
3025
3079
  const normalized = normalizePath(filePath);
3026
- const ext = extname2(normalized);
3080
+ const ext = extname3(normalized);
3027
3081
  const serverDef = getServerForExtension(ext);
3028
3082
  if (!serverDef) {
3029
3083
  return null;
@@ -3116,7 +3170,7 @@ async function formatDiagnosticsOutput(filePath, options = {}) {
3116
3170
  return formatDiagnosticsForAgent(filePath, diagnostics, options);
3117
3171
  }
3118
3172
  function isSupported(filePath) {
3119
- const ext = extname2(filePath);
3173
+ const ext = extname3(filePath);
3120
3174
  return getServerForExtension(ext) !== null;
3121
3175
  }
3122
3176
 
@@ -3543,7 +3597,7 @@ Once loaded, a skill's content will be available in the conversation context.`,
3543
3597
  // src/tools/linter.ts
3544
3598
  import { tool as tool6 } from "ai";
3545
3599
  import { z as z7 } from "zod";
3546
- import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as extname4 } from "path";
3600
+ import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as extname5 } from "path";
3547
3601
  import { existsSync as existsSync9 } from "fs";
3548
3602
  import { readdir as readdir2, stat as stat2 } from "fs/promises";
3549
3603
  var linterInputSchema = z7.object({
@@ -3566,7 +3620,7 @@ async function findSupportedFiles(dir, workingDirectory, maxFiles = 50) {
3566
3620
  }
3567
3621
  await walk(fullPath);
3568
3622
  } else if (entry.isFile()) {
3569
- const ext = extname4(entry.name);
3623
+ const ext = extname5(entry.name);
3570
3624
  if (supportedExtensions.includes(ext)) {
3571
3625
  files.push(fullPath);
3572
3626
  }
@@ -5894,7 +5948,7 @@ import { zValidator } from "@hono/zod-validator";
5894
5948
  import { z as z13 } from "zod";
5895
5949
  import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readdirSync, statSync as statSync2, unlinkSync } from "fs";
5896
5950
  import { readdir as readdir5 } from "fs/promises";
5897
- import { join as join5, basename as basename4, extname as extname6, relative as relative9 } from "path";
5951
+ import { join as join5, basename as basename4, extname as extname7, relative as relative9 } from "path";
5898
5952
  import { nanoid as nanoid4 } from "nanoid";
5899
5953
  init_config();
5900
5954
 
@@ -6410,7 +6464,7 @@ sessions.post("/:id/attachments", async (c) => {
6410
6464
  }
6411
6465
  const dir = ensureAttachmentsDir(sessionId);
6412
6466
  const id = nanoid4(10);
6413
- const ext = extname6(file.name) || "";
6467
+ const ext = extname7(file.name) || "";
6414
6468
  const safeFilename = `${id}_${basename4(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
6415
6469
  const filePath = join5(dir, safeFilename);
6416
6470
  const arrayBuffer = await file.arrayBuffer();
@@ -6436,7 +6490,7 @@ sessions.post("/:id/attachments", async (c) => {
6436
6490
  }
6437
6491
  const dir = ensureAttachmentsDir(sessionId);
6438
6492
  const id = nanoid4(10);
6439
- const ext = extname6(body.filename) || "";
6493
+ const ext = extname7(body.filename) || "";
6440
6494
  const safeFilename = `${id}_${basename4(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
6441
6495
  const filePath = join5(dir, safeFilename);
6442
6496
  let base64Data = body.data;
@@ -6566,7 +6620,7 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
6566
6620
  if (entry.name.startsWith(".")) {
6567
6621
  continue;
6568
6622
  }
6569
- const ext = extname6(entry.name).toLowerCase();
6623
+ const ext = extname7(entry.name).toLowerCase();
6570
6624
  if (IGNORED_EXTENSIONS.has(ext)) {
6571
6625
  continue;
6572
6626
  }