@dyno181cm.nexsoft/zentao_mcp 1.2.12 → 1.2.13
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/build/tools.js +16 -26
- package/package.json +1 -1
package/build/tools.js
CHANGED
|
@@ -53,45 +53,39 @@ function toFileUrl(filePath) {
|
|
|
53
53
|
}
|
|
54
54
|
return `file:///${normalized}`;
|
|
55
55
|
}
|
|
56
|
-
/** Convert a local file to a Base64 data URI for safe rendering in browser/chat UI. */
|
|
57
|
-
function fileToBase64(filePath) {
|
|
58
|
-
try {
|
|
59
|
-
const data = fs.readFileSync(filePath);
|
|
60
|
-
const ext = path.extname(filePath).toLowerCase().replace('.', '');
|
|
61
|
-
const mime = ext === 'svg' ? 'image/svg+xml' : `image/${ext || 'png'}`;
|
|
62
|
-
return `data:${mime};base64,${data.toString('base64')}`;
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return toFileUrl(filePath); // fallback to file URL if read fails
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
56
|
/**
|
|
69
|
-
* Find all <img src="...">
|
|
57
|
+
* Find all <img src="..."> tags in an HTML string, download each image
|
|
70
58
|
* to the local tmp directory using the authenticated ZenTao client,
|
|
71
|
-
* and replace the
|
|
72
|
-
*
|
|
59
|
+
* and replace the entire <img> tag with an <a> link pointing to the local file:// URL.
|
|
60
|
+
* This saves AI tokens (no huge Base64 data) and avoids local file load errors in UI.
|
|
73
61
|
*/
|
|
74
62
|
async function localizeImages(html) {
|
|
75
63
|
if (!html)
|
|
76
64
|
return html;
|
|
77
|
-
const
|
|
78
|
-
const matches = [...html.matchAll(
|
|
65
|
+
const imgTagRegex = /<img[^>]+src=["']([^"']+)["'][^>]*>/gi;
|
|
66
|
+
const matches = [...html.matchAll(imgTagRegex)];
|
|
79
67
|
if (matches.length === 0)
|
|
80
68
|
return html;
|
|
81
69
|
let result = html;
|
|
82
70
|
await Promise.all(matches.map(async (match) => {
|
|
71
|
+
const fullTag = match[0];
|
|
83
72
|
const remoteUrl = match[1];
|
|
84
|
-
|
|
85
|
-
const filename =
|
|
86
|
-
const
|
|
73
|
+
const altMatch = fullTag.match(/alt=["']([^"']+)["']/i);
|
|
74
|
+
const filename = path.basename(remoteUrl.split('?')[0]);
|
|
75
|
+
const linkText = altMatch ? altMatch[1] : filename;
|
|
76
|
+
const localFilename = `zentao_img_${filename}`;
|
|
77
|
+
const localPath = path.join(os.tmpdir(), localFilename);
|
|
87
78
|
try {
|
|
88
79
|
if (!fs.existsSync(localPath)) {
|
|
89
80
|
await client.downloadImageToLocal(remoteUrl, localPath);
|
|
90
81
|
}
|
|
91
|
-
|
|
82
|
+
const fileUrl = toFileUrl(localPath);
|
|
83
|
+
// Replace img tag with a standard hyperlink (no inline rendering, saves tokens)
|
|
84
|
+
const linkTag = `<a href="${fileUrl}">📎 ${linkText}</a>`;
|
|
85
|
+
result = result.split(fullTag).join(linkTag);
|
|
92
86
|
}
|
|
93
87
|
catch {
|
|
94
|
-
//
|
|
88
|
+
// Keep original tag if download fails
|
|
95
89
|
}
|
|
96
90
|
}));
|
|
97
91
|
return result;
|
|
@@ -144,10 +138,6 @@ async function renderAttachments(files) {
|
|
|
144
138
|
const lines = enriched.map((f) => {
|
|
145
139
|
if (!f.localPath)
|
|
146
140
|
return `- 📎 ${f.title} — *(download failed, Size: ${formatSize(f.size)})*`;
|
|
147
|
-
if (IMAGE_EXTS.has(f.ext)) {
|
|
148
|
-
const base64 = fileToBase64(f.localPath);
|
|
149
|
-
return `- 📎  *(Size: ${formatSize(f.size)})*`;
|
|
150
|
-
}
|
|
151
141
|
const fileUrl = toFileUrl(f.localPath);
|
|
152
142
|
return `- 📎 [${f.title}](${fileUrl}) *(Size: ${formatSize(f.size)})*`;
|
|
153
143
|
});
|