@ystemsrx/cfshare 0.1.1 → 0.1.2
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/package.json +1 -1
- package/skills/cfshare/SKILL.md +1 -1
- package/src/manager.ts +36 -5
package/package.json
CHANGED
package/skills/cfshare/SKILL.md
CHANGED
|
@@ -22,7 +22,7 @@ Expose local services, ports, files, or directories as temporary public `https:/
|
|
|
22
22
|
|
|
23
23
|
**This tool is useful when you need to:**
|
|
24
24
|
|
|
25
|
-
1. Share files;
|
|
25
|
+
1. Share or send files;
|
|
26
26
|
2. Present web pages, services, lengthy Markdown content, PDFs, images, audio, video, and other media.
|
|
27
27
|
|
|
28
28
|
---
|
package/src/manager.ts
CHANGED
|
@@ -282,7 +282,22 @@ function normalizeWorkspaceRelativePath(input: string | undefined): string | und
|
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
function sanitizeFilename(input: string): string {
|
|
285
|
-
|
|
285
|
+
// Keep Unicode to preserve original filenames, but replace characters that are
|
|
286
|
+
// invalid or problematic across common filesystems (Windows in particular).
|
|
287
|
+
// We only sanitize a single path segment (basename), not a full path.
|
|
288
|
+
//
|
|
289
|
+
// Reference set:
|
|
290
|
+
// - ASCII control chars: 0x00-0x1F and 0x7F
|
|
291
|
+
// - Windows reserved: <>:"/\\|?*
|
|
292
|
+
// - Trailing dots/spaces are invalid on Windows
|
|
293
|
+
const cleaned = input
|
|
294
|
+
.replace(/[\u0000-\u001F\u007F]/g, "_")
|
|
295
|
+
.replace(/[<>:"/\\|?*]/g, "_")
|
|
296
|
+
.replace(/_+/g, "_")
|
|
297
|
+
.replace(/[. ]+$/g, "_");
|
|
298
|
+
|
|
299
|
+
const trimmed = cleaned.trim();
|
|
300
|
+
return trimmed || "item";
|
|
286
301
|
}
|
|
287
302
|
|
|
288
303
|
function ensureString(input: unknown): string | undefined {
|
|
@@ -1097,10 +1112,12 @@ export class CfshareManager {
|
|
|
1097
1112
|
zip.outputStream.pipe(out);
|
|
1098
1113
|
|
|
1099
1114
|
for (const relPath of files) {
|
|
1100
|
-
|
|
1115
|
+
// Zip entries should use "/" separators regardless of OS.
|
|
1116
|
+
const zipEntry = relPath.split(path.sep).join("/");
|
|
1117
|
+
if (zipEntry === path.basename(zipPath)) {
|
|
1101
1118
|
continue;
|
|
1102
1119
|
}
|
|
1103
|
-
zip.addFile(path.join(workspaceDir, relPath),
|
|
1120
|
+
zip.addFile(path.join(workspaceDir, relPath), zipEntry);
|
|
1104
1121
|
}
|
|
1105
1122
|
zip.end();
|
|
1106
1123
|
});
|
|
@@ -1316,6 +1333,7 @@ export class CfshareManager {
|
|
|
1316
1333
|
res,
|
|
1317
1334
|
session: params.session,
|
|
1318
1335
|
filePath: zipBundle.zipPath,
|
|
1336
|
+
downloadName: "download.zip",
|
|
1319
1337
|
presentation: "download",
|
|
1320
1338
|
countAsDownload: true,
|
|
1321
1339
|
});
|
|
@@ -1421,10 +1439,23 @@ export class CfshareManager {
|
|
|
1421
1439
|
|
|
1422
1440
|
const sourceStat = await fs.stat(real);
|
|
1423
1441
|
const baseName = sanitizeFilename(path.basename(real) || "item");
|
|
1424
|
-
|
|
1442
|
+
const makeCandidate = (n: number) => {
|
|
1443
|
+
if (n === 0) {
|
|
1444
|
+
return baseName;
|
|
1445
|
+
}
|
|
1446
|
+
// For directories, treat dots as part of the name (do not split extension).
|
|
1447
|
+
if (sourceStat.isDirectory()) {
|
|
1448
|
+
return `${baseName}_${n}`;
|
|
1449
|
+
}
|
|
1450
|
+
// For files, keep extension stable: "a.txt" -> "a_1.txt".
|
|
1451
|
+
const parsed = path.parse(baseName);
|
|
1452
|
+
return `${parsed.name || "item"}_${n}${parsed.ext || ""}`;
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
let target = path.join(workspaceDir, makeCandidate(0));
|
|
1425
1456
|
let seq = 1;
|
|
1426
1457
|
while (await fileExists(target)) {
|
|
1427
|
-
target = path.join(workspaceDir,
|
|
1458
|
+
target = path.join(workspaceDir, makeCandidate(seq));
|
|
1428
1459
|
seq += 1;
|
|
1429
1460
|
}
|
|
1430
1461
|
|