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.
- package/dist/agent/index.js +74 -27
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +88 -34
- package/dist/cli.js.map +1 -1
- package/dist/index.js +87 -33
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +87 -33
- package/dist/server/index.js.map +1 -1
- package/dist/skills/default/browser.md +143 -0
- package/dist/skills/default/code-review.md +122 -0
- package/dist/skills/default/debugging.md +105 -0
- package/dist/skills/default/refactoring.md +197 -0
- package/dist/tools/index.d.ts +16 -1
- package/dist/tools/index.js +74 -27
- package/dist/tools/index.js.map +1 -1
- package/package.json +4 -1
- package/src/skills/default/browser.md +143 -0
- package/src/skills/default/code-review.md +122 -0
- package/src/skills/default/debugging.md +105 -0
- package/src/skills/default/refactoring.md +197 -0
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/R5xiWSOp_Nqqe_js-LROo}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/R5xiWSOp_Nqqe_js-LROo}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/R5xiWSOp_Nqqe_js-LROo}/_ssgManifest.js +0 -0
- /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_buildManifest.js +0 -0
- /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → R5xiWSOp_Nqqe_js-LROo}/_clientMiddlewareManifest.json +0 -0
- /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
|
|
525
|
-
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
2237
|
-
|
|
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(
|
|
2263
|
+
const absolutePath = isAbsolute(filePath) ? filePath : resolve2(options.workingDirectory, filePath);
|
|
2242
2264
|
const relativePath = relative(options.workingDirectory, absolutePath);
|
|
2243
|
-
if (relativePath.startsWith("..") && !isAbsolute(
|
|
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: ${
|
|
2275
|
+
error: `File not found: ${filePath}`,
|
|
2254
2276
|
content: null
|
|
2255
2277
|
};
|
|
2256
2278
|
}
|
|
2257
2279
|
const stats = await stat(absolutePath);
|
|
2258
|
-
if (stats.
|
|
2280
|
+
if (stats.isDirectory()) {
|
|
2259
2281
|
return {
|
|
2260
2282
|
success: false,
|
|
2261
|
-
error:
|
|
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 (
|
|
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:
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
6623
|
+
const ext = extname7(entry.name).toLowerCase();
|
|
6570
6624
|
if (IGNORED_EXTENSIONS.has(ext)) {
|
|
6571
6625
|
continue;
|
|
6572
6626
|
}
|