@dyno181cm.nexsoft/zentao_mcp 1.2.11 → 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 -12
- package/package.json +1 -1
package/build/tools.js
CHANGED
|
@@ -54,32 +54,38 @@ function toFileUrl(filePath) {
|
|
|
54
54
|
return `file:///${normalized}`;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* Find all <img src="...">
|
|
57
|
+
* Find all <img src="..."> tags in an HTML string, download each image
|
|
58
58
|
* to the local tmp directory using the authenticated ZenTao client,
|
|
59
|
-
* and replace the
|
|
60
|
-
*
|
|
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.
|
|
61
61
|
*/
|
|
62
62
|
async function localizeImages(html) {
|
|
63
63
|
if (!html)
|
|
64
64
|
return html;
|
|
65
|
-
const
|
|
66
|
-
const matches = [...html.matchAll(
|
|
65
|
+
const imgTagRegex = /<img[^>]+src=["']([^"']+)["'][^>]*>/gi;
|
|
66
|
+
const matches = [...html.matchAll(imgTagRegex)];
|
|
67
67
|
if (matches.length === 0)
|
|
68
68
|
return html;
|
|
69
69
|
let result = html;
|
|
70
70
|
await Promise.all(matches.map(async (match) => {
|
|
71
|
+
const fullTag = match[0];
|
|
71
72
|
const remoteUrl = match[1];
|
|
72
|
-
|
|
73
|
-
const filename =
|
|
74
|
-
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);
|
|
75
78
|
try {
|
|
76
79
|
if (!fs.existsSync(localPath)) {
|
|
77
80
|
await client.downloadImageToLocal(remoteUrl, localPath);
|
|
78
81
|
}
|
|
79
|
-
|
|
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);
|
|
80
86
|
}
|
|
81
87
|
catch {
|
|
82
|
-
//
|
|
88
|
+
// Keep original tag if download fails
|
|
83
89
|
}
|
|
84
90
|
}));
|
|
85
91
|
return result;
|
|
@@ -133,8 +139,6 @@ async function renderAttachments(files) {
|
|
|
133
139
|
if (!f.localPath)
|
|
134
140
|
return `- 📎 ${f.title} — *(download failed, Size: ${formatSize(f.size)})*`;
|
|
135
141
|
const fileUrl = toFileUrl(f.localPath);
|
|
136
|
-
if (IMAGE_EXTS.has(f.ext))
|
|
137
|
-
return `- 📎  *(Size: ${formatSize(f.size)})*`;
|
|
138
142
|
return `- 📎 [${f.title}](${fileUrl}) *(Size: ${formatSize(f.size)})*`;
|
|
139
143
|
});
|
|
140
144
|
return `\n## Files 📎${headerHint}\n${lines.join('\n')}\n`;
|