llm-chess-mcp 0.4.9 → 0.4.10
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/dist/chess-copy.js +83 -5
- package/dist/pgn.js +8 -6
- package/package.json +1 -1
package/dist/chess-copy.js
CHANGED
|
@@ -5,6 +5,42 @@ const ORIGINAL_PIECES = {
|
|
|
5
5
|
r: 2,
|
|
6
6
|
n: 2,
|
|
7
7
|
};
|
|
8
|
+
const CANONICAL_PGN_HEADERS = new Map([
|
|
9
|
+
"Event",
|
|
10
|
+
"Site",
|
|
11
|
+
"Date",
|
|
12
|
+
"Round",
|
|
13
|
+
"White",
|
|
14
|
+
"Black",
|
|
15
|
+
"Result",
|
|
16
|
+
"SetUp",
|
|
17
|
+
"FEN",
|
|
18
|
+
].map((name) => [name.toLowerCase(), name]));
|
|
19
|
+
function restoreHeaders(chess, sourceHeaders) {
|
|
20
|
+
const sourceNames = new Set(sourceHeaders.map(([key]) => key.toLowerCase()));
|
|
21
|
+
for (const key of Object.keys(chess.getHeaders())) {
|
|
22
|
+
if (!sourceNames.has(key.toLowerCase()))
|
|
23
|
+
chess.removeHeader(key);
|
|
24
|
+
}
|
|
25
|
+
const names = new Map();
|
|
26
|
+
for (const key of Object.keys(chess.getHeaders())) {
|
|
27
|
+
const existing = names.get(key.toLowerCase());
|
|
28
|
+
if (existing)
|
|
29
|
+
existing.push(key);
|
|
30
|
+
else
|
|
31
|
+
names.set(key.toLowerCase(), [key]);
|
|
32
|
+
}
|
|
33
|
+
for (const [key, value] of sourceHeaders) {
|
|
34
|
+
const lower = key.toLowerCase();
|
|
35
|
+
const canonical = CANONICAL_PGN_HEADERS.get(lower) ?? key;
|
|
36
|
+
for (const existing of names.get(lower) ?? []) {
|
|
37
|
+
if (existing !== canonical)
|
|
38
|
+
chess.removeHeader(existing);
|
|
39
|
+
}
|
|
40
|
+
chess.setHeader(canonical, value);
|
|
41
|
+
names.set(lower, [canonical]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
8
44
|
function squareColor(square) {
|
|
9
45
|
return ((square.charCodeAt(0) - 97 + Number(square[1])) % 2);
|
|
10
46
|
}
|
|
@@ -146,14 +182,30 @@ export function snapshotChess(chess) {
|
|
|
146
182
|
assertSafeFenCounters(initialFen);
|
|
147
183
|
const snapshot = new Chess(initialFen);
|
|
148
184
|
assertLegalPosition(snapshot);
|
|
149
|
-
const comments = new Map(chess.getComments().map(({ fen, comment }) => [
|
|
150
|
-
|
|
151
|
-
|
|
185
|
+
const comments = new Map(chess.getComments().map(({ fen, comment }) => [
|
|
186
|
+
fen,
|
|
187
|
+
/[{}]/.test(comment) ? comment.replace(/[\r\n]+/g, " ") : comment,
|
|
188
|
+
]));
|
|
189
|
+
const sourceHeaders = Object.entries(chess.getHeaders());
|
|
190
|
+
const unsafeComments = [...comments.values()].some((comment) => /[{}]/.test(comment));
|
|
191
|
+
let markerPrefix = "\uE000";
|
|
192
|
+
if (unsafeComments) {
|
|
193
|
+
const occupied = [...sourceHeaders.flat(), ...comments.values()].join("\u0000");
|
|
194
|
+
while (occupied.includes(markerPrefix))
|
|
195
|
+
markerPrefix += "\uE001";
|
|
152
196
|
}
|
|
197
|
+
const markerComments = [];
|
|
153
198
|
const restoreComment = () => {
|
|
154
199
|
const comment = comments.get(snapshot.fen());
|
|
155
|
-
if (comment
|
|
200
|
+
if (comment === undefined)
|
|
201
|
+
return;
|
|
202
|
+
if (!unsafeComments || !/[{}]/.test(comment)) {
|
|
156
203
|
snapshot.setComment(comment);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const marker = `${markerPrefix}${markerComments.length}${markerPrefix}`;
|
|
207
|
+
markerComments.push(comment);
|
|
208
|
+
snapshot.setComment(marker);
|
|
157
209
|
};
|
|
158
210
|
restoreComment();
|
|
159
211
|
for (const move of history) {
|
|
@@ -161,5 +213,31 @@ export function snapshotChess(chess) {
|
|
|
161
213
|
restoreComment();
|
|
162
214
|
}
|
|
163
215
|
assertSafeFenCounters(snapshot.fen());
|
|
164
|
-
|
|
216
|
+
if (!unsafeComments) {
|
|
217
|
+
restoreHeaders(snapshot, sourceHeaders);
|
|
218
|
+
return snapshot;
|
|
219
|
+
}
|
|
220
|
+
const escapedPrefix = markerPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
221
|
+
const marker = new RegExp(`\\{${escapedPrefix}(\\d+)${escapedPrefix}\\}`, "g");
|
|
222
|
+
const pgn = snapshot.pgn().replace(marker, (_match, index) => {
|
|
223
|
+
return `;${markerComments[Number(index)]}\n`;
|
|
224
|
+
});
|
|
225
|
+
const restored = new Chess();
|
|
226
|
+
restored.loadPgn(pgn);
|
|
227
|
+
const restoredHistory = restored.history({ verbose: true });
|
|
228
|
+
while (restored.undo()) { }
|
|
229
|
+
const restoreSafeComment = () => {
|
|
230
|
+
const comment = comments.get(restored.fen());
|
|
231
|
+
if (comment !== undefined && !/[{}]/.test(comment)) {
|
|
232
|
+
restored.setComment(comment);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
restoreSafeComment();
|
|
236
|
+
for (const move of restoredHistory) {
|
|
237
|
+
restored.move(moveDescriptor(move));
|
|
238
|
+
restoreSafeComment();
|
|
239
|
+
}
|
|
240
|
+
restoreHeaders(restored, sourceHeaders);
|
|
241
|
+
assertSafeFenCounters(restored.fen());
|
|
242
|
+
return restored;
|
|
165
243
|
}
|
package/dist/pgn.js
CHANGED
|
@@ -278,12 +278,14 @@ function pgnText(chess) {
|
|
|
278
278
|
for (const { comment } of comments)
|
|
279
279
|
assertPgnTokenSize(comment);
|
|
280
280
|
const raw = chess.pgn();
|
|
281
|
-
|
|
282
|
-
let
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
281
|
+
let movetextStart = 0;
|
|
282
|
+
for (let index = 0; index < headers.length; index += 1) {
|
|
283
|
+
const lineEnd = raw.indexOf("\n", movetextStart);
|
|
284
|
+
movetextStart = lineEnd < 0 ? raw.length : lineEnd + 1;
|
|
285
|
+
}
|
|
286
|
+
if (headers.length > 0 && raw[movetextStart] === "\n")
|
|
287
|
+
movetextStart += 1;
|
|
288
|
+
let movetext = raw.slice(movetextStart);
|
|
287
289
|
const unsafeComments = [
|
|
288
290
|
...new Set(comments
|
|
289
291
|
.map(({ comment }) => comment)
|