pulsemcp-cms-admin-mcp-server 0.7.2 → 0.7.4

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.
@@ -7,7 +7,7 @@ export async function saveResultsForMirror(apiKey, baseUrl, params) {
7
7
  exam_id: r.exam_id,
8
8
  result: {
9
9
  status: r.status,
10
- ...(r.data && { data: r.data }),
10
+ ...(r.data || {}),
11
11
  },
12
12
  })),
13
13
  };
@@ -95,26 +95,41 @@ Typical workflow:
95
95
  };
96
96
  }
97
97
  // Extract exam_result lines from stored data.
98
- // The exam_id may live at the top level of the stream line OR inside
99
- // line.data (the actual result payload). Prefer the data payload to
100
- // avoid reading from potentially incomplete display metadata.
101
98
  //
102
- // The real proctor API returns line.data as a metadata wrapper:
103
- // { mirror_id, exam_id, status, result: { status, output: {...} } }
104
- // The actual output lives inside line.data.result. When we pass the
105
- // entire line.data as `data`, the output ends up nested too deeply
106
- // (result.data.result.output) and the backend saves empty output.
107
- // Use line.data.result when present so that `output` is at the
108
- // expected depth (result.data.output).
99
+ // The real proctor API returns a deeply nested structure:
100
+ // line.data = {
101
+ // mirror_id, server_slug, exam_id, ...,
102
+ // result: { ← envelope
103
+ // exam_id, machine_id, status,
104
+ // result: { ← actual payload
105
+ // input: {...}, output: {...}, processedBy: {...}
106
+ // },
107
+ // error, logs
108
+ // }
109
+ // }
110
+ //
111
+ // The PulseMCP API expects the actual payload { input, output,
112
+ // processedBy } at the top level of the saved results column.
113
+ // We must unwrap through data.result.result to reach it.
109
114
  results = stored.lines
110
115
  .filter((line) => line.type === 'exam_result')
111
116
  .map((line) => {
112
117
  const data = line.data;
113
- // Prefer the nested result object (contains output, input, etc.)
114
- // over the full data wrapper (contains metadata like mirror_id)
115
- const resultData = data?.result && typeof data.result === 'object' && !Array.isArray(data.result)
116
- ? data.result
117
- : data;
118
+ // Unwrap nested result objects to find the exam payload
119
+ // containing { input, output, processedBy }.
120
+ let resultData = data;
121
+ // Level 1: data.result (envelope with exam_id, machine_id, logs, etc.)
122
+ if (resultData?.result &&
123
+ typeof resultData.result === 'object' &&
124
+ !Array.isArray(resultData.result)) {
125
+ resultData = resultData.result;
126
+ // Level 2: data.result.result (actual payload with input, output, processedBy)
127
+ if (resultData.result &&
128
+ typeof resultData.result === 'object' &&
129
+ !Array.isArray(resultData.result)) {
130
+ resultData = resultData.result;
131
+ }
132
+ }
118
133
  return {
119
134
  exam_id: extractExamId(line),
120
135
  status: extractStatus(line),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsemcp-cms-admin-mcp-server",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Local implementation of PulseMCP CMS Admin MCP server",
5
5
  "mcpName": "com.pulsemcp.servers/pulsemcp-cms-admin",
6
6
  "main": "build/index.js",
@@ -7,7 +7,7 @@ export async function saveResultsForMirror(apiKey, baseUrl, params) {
7
7
  exam_id: r.exam_id,
8
8
  result: {
9
9
  status: r.status,
10
- ...(r.data && { data: r.data }),
10
+ ...(r.data || {}),
11
11
  },
12
12
  })),
13
13
  };
@@ -95,26 +95,41 @@ Typical workflow:
95
95
  };
96
96
  }
97
97
  // Extract exam_result lines from stored data.
98
- // The exam_id may live at the top level of the stream line OR inside
99
- // line.data (the actual result payload). Prefer the data payload to
100
- // avoid reading from potentially incomplete display metadata.
101
98
  //
102
- // The real proctor API returns line.data as a metadata wrapper:
103
- // { mirror_id, exam_id, status, result: { status, output: {...} } }
104
- // The actual output lives inside line.data.result. When we pass the
105
- // entire line.data as `data`, the output ends up nested too deeply
106
- // (result.data.result.output) and the backend saves empty output.
107
- // Use line.data.result when present so that `output` is at the
108
- // expected depth (result.data.output).
99
+ // The real proctor API returns a deeply nested structure:
100
+ // line.data = {
101
+ // mirror_id, server_slug, exam_id, ...,
102
+ // result: { ← envelope
103
+ // exam_id, machine_id, status,
104
+ // result: { ← actual payload
105
+ // input: {...}, output: {...}, processedBy: {...}
106
+ // },
107
+ // error, logs
108
+ // }
109
+ // }
110
+ //
111
+ // The PulseMCP API expects the actual payload { input, output,
112
+ // processedBy } at the top level of the saved results column.
113
+ // We must unwrap through data.result.result to reach it.
109
114
  results = stored.lines
110
115
  .filter((line) => line.type === 'exam_result')
111
116
  .map((line) => {
112
117
  const data = line.data;
113
- // Prefer the nested result object (contains output, input, etc.)
114
- // over the full data wrapper (contains metadata like mirror_id)
115
- const resultData = data?.result && typeof data.result === 'object' && !Array.isArray(data.result)
116
- ? data.result
117
- : data;
118
+ // Unwrap nested result objects to find the exam payload
119
+ // containing { input, output, processedBy }.
120
+ let resultData = data;
121
+ // Level 1: data.result (envelope with exam_id, machine_id, logs, etc.)
122
+ if (resultData?.result &&
123
+ typeof resultData.result === 'object' &&
124
+ !Array.isArray(resultData.result)) {
125
+ resultData = resultData.result;
126
+ // Level 2: data.result.result (actual payload with input, output, processedBy)
127
+ if (resultData.result &&
128
+ typeof resultData.result === 'object' &&
129
+ !Array.isArray(resultData.result)) {
130
+ resultData = resultData.result;
131
+ }
132
+ }
118
133
  return {
119
134
  exam_id: extractExamId(line),
120
135
  status: extractStatus(line),