brightspace-mcp-server 5.0.4 → 5.0.5
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/update.js +107 -14
- package/package.json +1 -1
package/build/update.js
CHANGED
|
@@ -50,6 +50,74 @@ export function samePath(a, b) {
|
|
|
50
50
|
};
|
|
51
51
|
return canonical(a) === canonical(b);
|
|
52
52
|
}
|
|
53
|
+
const STABLE_VERSION = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
54
|
+
const COMMIT_SHA = /^[0-9a-f]{40}$/;
|
|
55
|
+
function versionTriple(version) {
|
|
56
|
+
const m = STABLE_VERSION.exec(version.trim().replace(/^v/, ""));
|
|
57
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
|
|
58
|
+
}
|
|
59
|
+
function compareTriples(a, b) {
|
|
60
|
+
for (let i = 0; i < 3; i++) {
|
|
61
|
+
if (a[i] !== b[i])
|
|
62
|
+
return a[i] - b[i];
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Whether `nodeVersion` meets an `engines.node` range. Only plain
|
|
68
|
+
* comparator sets (">=20.0.0", ">=20 <23") are understood; anything else
|
|
69
|
+
* yields null so the caller refuses instead of guessing.
|
|
70
|
+
*/
|
|
71
|
+
function satisfiesNodeRange(range, nodeVersion) {
|
|
72
|
+
const have = versionTriple(nodeVersion);
|
|
73
|
+
const comparators = range.trim().split(/\s+/);
|
|
74
|
+
if (!have || comparators.length === 0)
|
|
75
|
+
return null;
|
|
76
|
+
for (const comparator of comparators) {
|
|
77
|
+
const m = /^(>=|<=|>|<|=)?v?(\d+)(?:\.(\d+))?(?:\.(\d+))?$/.exec(comparator);
|
|
78
|
+
if (!m)
|
|
79
|
+
return null;
|
|
80
|
+
const want = [Number(m[2]), Number(m[3] ?? 0), Number(m[4] ?? 0)];
|
|
81
|
+
const cmp = compareTriples(have, want);
|
|
82
|
+
const ok = { ">=": cmp >= 0, "<=": cmp <= 0, ">": cmp > 0, "<": cmp < 0, "=": cmp === 0 }[m[1] ?? "="];
|
|
83
|
+
if (!ok)
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Decide which commit a checkout should move to, from what npm reports as the
|
|
90
|
+
* `latest` release. Only a stable version, published from a known commit, whose
|
|
91
|
+
* Node.js requirement this runtime meets, is a target; anything else is refused
|
|
92
|
+
* so the update fails closed.
|
|
93
|
+
*/
|
|
94
|
+
export function chooseRelease(registry, nodeVersion) {
|
|
95
|
+
const info = (registry ?? {});
|
|
96
|
+
const { version, gitHead } = info;
|
|
97
|
+
if (typeof version !== "string" || !versionTriple(version)) {
|
|
98
|
+
return { ok: false, reason: "npm did not report a stable release version." };
|
|
99
|
+
}
|
|
100
|
+
if (typeof gitHead !== "string" || !COMMIT_SHA.test(gitHead)) {
|
|
101
|
+
return { ok: false, reason: `npm does not record which commit ${version} was published from.` };
|
|
102
|
+
}
|
|
103
|
+
const nodeRange = info.engines?.node;
|
|
104
|
+
if (nodeRange !== undefined) {
|
|
105
|
+
const satisfied = typeof nodeRange === "string" ? satisfiesNodeRange(nodeRange, nodeVersion) : null;
|
|
106
|
+
if (satisfied === null) {
|
|
107
|
+
return { ok: false, reason: `Cannot check ${version}'s Node.js requirement (${String(nodeRange)}).` };
|
|
108
|
+
}
|
|
109
|
+
if (!satisfied) {
|
|
110
|
+
return { ok: false, reason: `${version} requires Node.js ${nodeRange}; this is Node.js ${nodeVersion}.` };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { ok: true, version, commit: gitHead };
|
|
114
|
+
}
|
|
115
|
+
function fail(...lines) {
|
|
116
|
+
console.error(red(` Error: ${lines[0]}`));
|
|
117
|
+
for (const line of lines.slice(1))
|
|
118
|
+
console.error(` ${line}`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
53
121
|
export function main() {
|
|
54
122
|
console.log("");
|
|
55
123
|
console.log(bold("=== Brightspace MCP Server — Update ==="));
|
|
@@ -88,18 +156,44 @@ export function main() {
|
|
|
88
156
|
console.log(dim(" The update will proceed, but your local changes may conflict."));
|
|
89
157
|
console.log("");
|
|
90
158
|
}
|
|
91
|
-
//
|
|
92
|
-
|
|
159
|
+
// Resolve the latest published release: the checkout follows what npm
|
|
160
|
+
// ships, never the unreleased tip of main.
|
|
161
|
+
console.log(dim(" Checking the latest release on npm..."));
|
|
162
|
+
let registry;
|
|
163
|
+
try {
|
|
164
|
+
registry = JSON.parse(run("npm view brightspace-mcp-server@latest version gitHead engines --json", { silent: true }));
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
fail("Could not read the latest release from npm.", "Check your network connection and try again.");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const release = chooseRelease(registry, process.version);
|
|
171
|
+
if (!release.ok) {
|
|
172
|
+
fail("No release this checkout can safely update to.", release.reason);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const { version: targetVersion, commit } = release;
|
|
176
|
+
// Fetch, then confirm the published commit really is that release on main.
|
|
177
|
+
console.log(dim(` Fetching release ${targetVersion}...`));
|
|
93
178
|
try {
|
|
94
179
|
run("git fetch origin main", { silent: true });
|
|
95
180
|
}
|
|
96
181
|
catch {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
182
|
+
fail("Failed to fetch from remote.", "Check your network connection and try again.");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
run(`git merge-base --is-ancestor ${commit} origin/main`, { silent: true });
|
|
187
|
+
const released = JSON.parse(run(`git show ${commit}:package.json`, { silent: true }));
|
|
188
|
+
if (released.version !== targetVersion)
|
|
189
|
+
throw new Error("version mismatch");
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
fail(`Could not verify release ${targetVersion} (commit ${commit.slice(0, 7)}) on origin/main.`, "Nothing was changed.");
|
|
193
|
+
return;
|
|
100
194
|
}
|
|
101
195
|
// Check if we're behind
|
|
102
|
-
const behindCount = run(
|
|
196
|
+
const behindCount = run(`git rev-list --count HEAD..${commit}`, { silent: true });
|
|
103
197
|
if (behindCount === "0") {
|
|
104
198
|
console.log("");
|
|
105
199
|
console.log(green(" Already up to date!"));
|
|
@@ -108,22 +202,21 @@ export function main() {
|
|
|
108
202
|
}
|
|
109
203
|
// Show what's new
|
|
110
204
|
console.log("");
|
|
111
|
-
console.log(bold(` ${behindCount} new commit${behindCount === "1" ? "" : "s"}:`));
|
|
205
|
+
console.log(bold(` ${behindCount} new commit${behindCount === "1" ? "" : "s"} in ${targetVersion}:`));
|
|
112
206
|
console.log("");
|
|
113
|
-
const log = run(
|
|
207
|
+
const log = run(`git log HEAD..${commit} --oneline`, { silent: true });
|
|
114
208
|
for (const line of log.split("\n")) {
|
|
115
209
|
console.log(` ${dim("•")} ${line}`);
|
|
116
210
|
}
|
|
117
211
|
console.log("");
|
|
118
|
-
//
|
|
119
|
-
console.log(dim(
|
|
212
|
+
// Move to the release
|
|
213
|
+
console.log(dim(` Updating to ${targetVersion}...`));
|
|
120
214
|
try {
|
|
121
|
-
run(
|
|
215
|
+
run(`git merge --ff-only ${commit}`, { silent: true });
|
|
122
216
|
}
|
|
123
217
|
catch {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
process.exit(1);
|
|
218
|
+
fail(`Failed to update to ${targetVersion}.`, "Your checkout has local commits or changes in the way. Resolve them and try again.");
|
|
219
|
+
return;
|
|
127
220
|
}
|
|
128
221
|
// Install dependencies
|
|
129
222
|
console.log(dim(" Installing dependencies..."));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brightspace-mcp-server",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.5",
|
|
4
4
|
"mcpName": "io.github.RohanMuppa/brightspace",
|
|
5
5
|
"description": "MCP server for Brightspace (D2L). Check grades, due dates, assignments, announcements, syllabus, rosters and more via Claude, ChatGPT, Cursor, Windsurf, or any MCP client.",
|
|
6
6
|
"type": "module",
|