pulsemcp-cms-admin-mcp-server 0.9.11 → 0.9.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/shared/src/exam-result-store.js +2 -1
- package/build/shared/src/pulsemcp-admin-client/lib/upload-image.js +1 -1
- package/build/shared/src/tools/get-exam-result.js +9 -2
- package/build/shared/src/tools/run-exam-for-mirror.js +15 -16
- package/package.json +1 -1
- package/shared/exam-result-store.js +2 -1
- package/shared/pulsemcp-admin-client/lib/upload-image.js +1 -1
- package/shared/tools/get-exam-result.js +9 -2
- package/shared/tools/run-exam-for-mirror.js +15 -16
|
@@ -21,7 +21,8 @@ export function extractExamId(line) {
|
|
|
21
21
|
*/
|
|
22
22
|
export function extractStatus(line) {
|
|
23
23
|
const data = line.data;
|
|
24
|
-
|
|
24
|
+
const result = data?.result;
|
|
25
|
+
return (result?.status || data?.status || line.status || 'unknown');
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
28
|
* Maximum number of results to keep on disk. Oldest results are evicted
|
|
@@ -3,7 +3,7 @@ export async function uploadImage(apiKey, baseUrl, postSlug, fileName, fileData)
|
|
|
3
3
|
// Create form data for multipart upload
|
|
4
4
|
const formData = new FormData();
|
|
5
5
|
// Create a blob from the buffer
|
|
6
|
-
const blob = new Blob([fileData], { type: 'image/png' });
|
|
6
|
+
const blob = new Blob([new Uint8Array(fileData)], { type: 'image/png' });
|
|
7
7
|
// Add file to form data
|
|
8
8
|
formData.append('file', blob, fileName);
|
|
9
9
|
// Add folder and filepath as documented in the API
|
|
@@ -67,9 +67,16 @@ Typical usage:
|
|
|
67
67
|
const targetType = typeMap[validatedArgs.section];
|
|
68
68
|
lines = lines.filter((line) => line.type === targetType);
|
|
69
69
|
}
|
|
70
|
-
// Filter by mirror_id
|
|
70
|
+
// Filter by mirror_id — check both top-level and data.mirror_id
|
|
71
|
+
// since the backend nests mirror_id inside the data payload.
|
|
71
72
|
if (validatedArgs.mirror_id !== undefined) {
|
|
72
|
-
lines = lines.filter((line) =>
|
|
73
|
+
lines = lines.filter((line) => {
|
|
74
|
+
if (line.type !== 'exam_result')
|
|
75
|
+
return true;
|
|
76
|
+
const data = line.data;
|
|
77
|
+
const mirrorId = line.mirror_id ?? data?.mirror_id;
|
|
78
|
+
return mirrorId === validatedArgs.mirror_id;
|
|
79
|
+
});
|
|
73
80
|
}
|
|
74
81
|
let content = `**Exam Result Details**\n\n`;
|
|
75
82
|
content += `Result ID: ${stored.result_id}\n`;
|
|
@@ -24,7 +24,6 @@ function truncateExamResultData(data) {
|
|
|
24
24
|
const truncated = {};
|
|
25
25
|
for (const [key, value] of Object.entries(data)) {
|
|
26
26
|
if (key === 'tools' && Array.isArray(value)) {
|
|
27
|
-
// For tool listings, include only name and description, omit inputSchema
|
|
28
27
|
truncated[key] = value.map((tool) => ({
|
|
29
28
|
name: tool.name,
|
|
30
29
|
...(tool.description ? { description: String(tool.description).slice(0, 100) } : {}),
|
|
@@ -33,20 +32,18 @@ function truncateExamResultData(data) {
|
|
|
33
32
|
truncated['tools_truncated'] = true;
|
|
34
33
|
}
|
|
35
34
|
else if (key === 'inputSchema' || key === 'input_schema') {
|
|
36
|
-
// Omit full input schemas
|
|
37
35
|
truncated[key] = '(truncated — use get_exam_result to see full data)';
|
|
38
36
|
}
|
|
39
|
-
else if (typeof value === 'string' && value.length >
|
|
40
|
-
truncated[key] = value.slice(0,
|
|
37
|
+
else if (typeof value === 'string' && value.length > 2000) {
|
|
38
|
+
truncated[key] = value.slice(0, 2000) + '... (truncated)';
|
|
39
|
+
}
|
|
40
|
+
else if (Array.isArray(value)) {
|
|
41
|
+
truncated[key] = value.map((item) => typeof item === 'object' && item !== null
|
|
42
|
+
? truncateExamResultData(item)
|
|
43
|
+
: item);
|
|
41
44
|
}
|
|
42
45
|
else if (typeof value === 'object' && value !== null) {
|
|
43
|
-
|
|
44
|
-
if (serialized.length > 1000) {
|
|
45
|
-
truncated[key] = '(truncated — use get_exam_result to see full data)';
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
truncated[key] = value;
|
|
49
|
-
}
|
|
46
|
+
truncated[key] = truncateExamResultData(value);
|
|
50
47
|
}
|
|
51
48
|
else {
|
|
52
49
|
truncated[key] = value;
|
|
@@ -131,13 +128,15 @@ Use cases:
|
|
|
131
128
|
}
|
|
132
129
|
break;
|
|
133
130
|
}
|
|
134
|
-
case 'summary':
|
|
131
|
+
case 'summary': {
|
|
132
|
+
const summaryData = line.data;
|
|
135
133
|
content += `\n**Summary**\n`;
|
|
136
|
-
content += ` Total: ${line.total
|
|
137
|
-
content += ` Passed: ${line.passed
|
|
138
|
-
content += ` Failed: ${line.failed
|
|
139
|
-
content += ` Skipped: ${line.skipped
|
|
134
|
+
content += ` Total: ${summaryData?.total_exams ?? line.total ?? 0}\n`;
|
|
135
|
+
content += ` Passed: ${summaryData?.successful ?? line.passed ?? 0}\n`;
|
|
136
|
+
content += ` Failed: ${summaryData?.failed ?? line.failed ?? 0}\n`;
|
|
137
|
+
content += ` Skipped: ${summaryData?.skipped ?? line.skipped ?? 0}\n`;
|
|
140
138
|
break;
|
|
139
|
+
}
|
|
141
140
|
case 'error':
|
|
142
141
|
content += `\n**Error**: ${line.message || line.error || JSON.stringify(line)}\n`;
|
|
143
142
|
break;
|
package/package.json
CHANGED
|
@@ -21,7 +21,8 @@ export function extractExamId(line) {
|
|
|
21
21
|
*/
|
|
22
22
|
export function extractStatus(line) {
|
|
23
23
|
const data = line.data;
|
|
24
|
-
|
|
24
|
+
const result = data?.result;
|
|
25
|
+
return (result?.status || data?.status || line.status || 'unknown');
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
28
|
* Maximum number of results to keep on disk. Oldest results are evicted
|
|
@@ -3,7 +3,7 @@ export async function uploadImage(apiKey, baseUrl, postSlug, fileName, fileData)
|
|
|
3
3
|
// Create form data for multipart upload
|
|
4
4
|
const formData = new FormData();
|
|
5
5
|
// Create a blob from the buffer
|
|
6
|
-
const blob = new Blob([fileData], { type: 'image/png' });
|
|
6
|
+
const blob = new Blob([new Uint8Array(fileData)], { type: 'image/png' });
|
|
7
7
|
// Add file to form data
|
|
8
8
|
formData.append('file', blob, fileName);
|
|
9
9
|
// Add folder and filepath as documented in the API
|
|
@@ -67,9 +67,16 @@ Typical usage:
|
|
|
67
67
|
const targetType = typeMap[validatedArgs.section];
|
|
68
68
|
lines = lines.filter((line) => line.type === targetType);
|
|
69
69
|
}
|
|
70
|
-
// Filter by mirror_id
|
|
70
|
+
// Filter by mirror_id — check both top-level and data.mirror_id
|
|
71
|
+
// since the backend nests mirror_id inside the data payload.
|
|
71
72
|
if (validatedArgs.mirror_id !== undefined) {
|
|
72
|
-
lines = lines.filter((line) =>
|
|
73
|
+
lines = lines.filter((line) => {
|
|
74
|
+
if (line.type !== 'exam_result')
|
|
75
|
+
return true;
|
|
76
|
+
const data = line.data;
|
|
77
|
+
const mirrorId = line.mirror_id ?? data?.mirror_id;
|
|
78
|
+
return mirrorId === validatedArgs.mirror_id;
|
|
79
|
+
});
|
|
73
80
|
}
|
|
74
81
|
let content = `**Exam Result Details**\n\n`;
|
|
75
82
|
content += `Result ID: ${stored.result_id}\n`;
|
|
@@ -24,7 +24,6 @@ function truncateExamResultData(data) {
|
|
|
24
24
|
const truncated = {};
|
|
25
25
|
for (const [key, value] of Object.entries(data)) {
|
|
26
26
|
if (key === 'tools' && Array.isArray(value)) {
|
|
27
|
-
// For tool listings, include only name and description, omit inputSchema
|
|
28
27
|
truncated[key] = value.map((tool) => ({
|
|
29
28
|
name: tool.name,
|
|
30
29
|
...(tool.description ? { description: String(tool.description).slice(0, 100) } : {}),
|
|
@@ -33,20 +32,18 @@ function truncateExamResultData(data) {
|
|
|
33
32
|
truncated['tools_truncated'] = true;
|
|
34
33
|
}
|
|
35
34
|
else if (key === 'inputSchema' || key === 'input_schema') {
|
|
36
|
-
// Omit full input schemas
|
|
37
35
|
truncated[key] = '(truncated — use get_exam_result to see full data)';
|
|
38
36
|
}
|
|
39
|
-
else if (typeof value === 'string' && value.length >
|
|
40
|
-
truncated[key] = value.slice(0,
|
|
37
|
+
else if (typeof value === 'string' && value.length > 2000) {
|
|
38
|
+
truncated[key] = value.slice(0, 2000) + '... (truncated)';
|
|
39
|
+
}
|
|
40
|
+
else if (Array.isArray(value)) {
|
|
41
|
+
truncated[key] = value.map((item) => typeof item === 'object' && item !== null
|
|
42
|
+
? truncateExamResultData(item)
|
|
43
|
+
: item);
|
|
41
44
|
}
|
|
42
45
|
else if (typeof value === 'object' && value !== null) {
|
|
43
|
-
|
|
44
|
-
if (serialized.length > 1000) {
|
|
45
|
-
truncated[key] = '(truncated — use get_exam_result to see full data)';
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
truncated[key] = value;
|
|
49
|
-
}
|
|
46
|
+
truncated[key] = truncateExamResultData(value);
|
|
50
47
|
}
|
|
51
48
|
else {
|
|
52
49
|
truncated[key] = value;
|
|
@@ -131,13 +128,15 @@ Use cases:
|
|
|
131
128
|
}
|
|
132
129
|
break;
|
|
133
130
|
}
|
|
134
|
-
case 'summary':
|
|
131
|
+
case 'summary': {
|
|
132
|
+
const summaryData = line.data;
|
|
135
133
|
content += `\n**Summary**\n`;
|
|
136
|
-
content += ` Total: ${line.total
|
|
137
|
-
content += ` Passed: ${line.passed
|
|
138
|
-
content += ` Failed: ${line.failed
|
|
139
|
-
content += ` Skipped: ${line.skipped
|
|
134
|
+
content += ` Total: ${summaryData?.total_exams ?? line.total ?? 0}\n`;
|
|
135
|
+
content += ` Passed: ${summaryData?.successful ?? line.passed ?? 0}\n`;
|
|
136
|
+
content += ` Failed: ${summaryData?.failed ?? line.failed ?? 0}\n`;
|
|
137
|
+
content += ` Skipped: ${summaryData?.skipped ?? line.skipped ?? 0}\n`;
|
|
140
138
|
break;
|
|
139
|
+
}
|
|
141
140
|
case 'error':
|
|
142
141
|
content += `\n**Error**: ${line.message || line.error || JSON.stringify(line)}\n`;
|
|
143
142
|
break;
|