chesspal 0.3.0 → 0.3.2
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/README.md +1 -1
- package/dist/cli/cli.js +6 -6
- package/dist/commands/{analyse-game.d.ts → analysis/analyse.d.ts} +2 -2
- package/dist/commands/{analyse-game.js → analysis/analyse.js} +7 -11
- package/dist/commands/{annotate-game.d.ts → analysis/annotate.d.ts} +1 -1
- package/dist/commands/{annotate-game.js → analysis/annotate.js} +6 -9
- package/dist/commands/{delete-review.d.ts → analysis/delete-review.d.ts} +1 -1
- package/dist/commands/{delete-review.js → analysis/delete-review.js} +5 -5
- package/dist/commands/analysis/index.d.ts +4 -0
- package/dist/commands/analysis/index.js +5 -0
- package/dist/commands/{study-games.d.ts → analysis/study-games.d.ts} +1 -1
- package/dist/commands/{study-games.js → analysis/study-games.js} +4 -5
- package/dist/commands/{agents.d.ts → answers/agents.d.ts} +3 -3
- package/dist/commands/{agents.js → answers/agents.js} +5 -5
- package/dist/commands/{clock.d.ts → answers/clock.d.ts} +2 -2
- package/dist/commands/{clock.js → answers/clock.js} +2 -2
- package/dist/commands/{drawings.d.ts → answers/drawings.d.ts} +1 -1
- package/dist/commands/{drawings.js → answers/drawings.js} +1 -1
- package/dist/commands/answers/index.d.ts +12 -0
- package/dist/commands/answers/index.js +14 -0
- package/dist/commands/{lead-input.d.ts → answers/lead-input.d.ts} +1 -1
- package/dist/commands/{lead-input.js → answers/lead-input.js} +1 -1
- package/dist/commands/{answer-lines.d.ts → answers/lines.d.ts} +2 -2
- package/dist/commands/{answer-lines.js → answers/lines.js} +4 -4
- package/dist/commands/{opening-book.d.ts → answers/opening-book.d.ts} +1 -1
- package/dist/commands/{opening-book.js → answers/opening-book.js} +3 -3
- package/dist/commands/{play-move.d.ts → answers/play-move.d.ts} +2 -2
- package/dist/commands/{play-move.js → answers/play-move.js} +3 -3
- package/dist/commands/{say.d.ts → answers/say.d.ts} +3 -3
- package/dist/commands/{say.js → answers/say.js} +4 -4
- package/dist/commands/{speech.js → answers/speech.js} +1 -1
- package/dist/commands/{study.d.ts → answers/study.d.ts} +3 -3
- package/dist/commands/{study.js → answers/study.js} +3 -3
- package/dist/commands/{game-summary.d.ts → answers/summary.d.ts} +2 -2
- package/dist/commands/{game-summary.js → answers/summary.js} +4 -4
- package/dist/commands/{view.d.ts → answers/view.d.ts} +1 -1
- package/dist/commands/{ai-move.d.ts → game/ai-move.d.ts} +2 -2
- package/dist/commands/{ai-move.js → game/ai-move.js} +6 -11
- package/dist/commands/{coach.d.ts → game/coach.d.ts} +1 -1
- package/dist/commands/{coach.js → game/coach.js} +7 -13
- package/dist/commands/{draw-offer.d.ts → game/draw-offer.d.ts} +1 -1
- package/dist/commands/{draw-offer.js → game/draw-offer.js} +4 -4
- package/dist/commands/{end-game.d.ts → game/end.d.ts} +2 -2
- package/dist/commands/{end-game.js → game/end.js} +5 -9
- package/dist/commands/{export-game.d.ts → game/export.d.ts} +1 -1
- package/dist/commands/{export-game.js → game/export.js} +4 -4
- package/dist/commands/game/index.d.ts +11 -0
- package/dist/commands/game/index.js +13 -0
- package/dist/commands/{levels.d.ts → game/levels.d.ts} +3 -3
- package/dist/commands/{levels.js → game/levels.js} +3 -3
- package/dist/commands/{look.d.ts → game/look.d.ts} +3 -4
- package/dist/commands/{look.js → game/look.js} +5 -10
- package/dist/commands/{new-game.d.ts → game/new.d.ts} +3 -4
- package/dist/commands/{new-game.js → game/new.js} +17 -13
- package/dist/commands/{page-link.d.ts → game/page-link.d.ts} +1 -1
- package/dist/commands/{player-move.d.ts → game/player-move.d.ts} +2 -2
- package/dist/commands/{player-move.js → game/player-move.js} +4 -8
- package/dist/commands/{ponder.d.ts → game/ponder.d.ts} +3 -3
- package/dist/commands/{ponder.js → game/ponder.js} +6 -9
- package/dist/commands/{position.d.ts → game/position.d.ts} +2 -2
- package/dist/commands/{position.js → game/position.js} +5 -7
- package/dist/commands/{status.d.ts → game/status.d.ts} +2 -4
- package/dist/commands/{status.js → game/status.js} +12 -17
- package/dist/commands/index.d.ts +6 -17
- package/dist/commands/index.js +11 -38
- package/dist/commands/{delete-game.d.ts → profiles/delete-game.d.ts} +1 -1
- package/dist/commands/{delete-game.js → profiles/delete-game.js} +3 -3
- package/dist/commands/profiles/index.d.ts +4 -0
- package/dist/commands/profiles/index.js +5 -0
- package/dist/commands/{past-games.d.ts → profiles/past-games.d.ts} +1 -1
- package/dist/commands/{past-games.js → profiles/past-games.js} +5 -5
- package/dist/commands/{profiles.d.ts → profiles/profiles.d.ts} +7 -7
- package/dist/commands/{profiles.js → profiles/profiles.js} +4 -4
- package/dist/commands/{ratings.d.ts → profiles/ratings.d.ts} +1 -1
- package/dist/commands/{ratings.js → profiles/ratings.js} +2 -2
- package/dist/commands/{context.d.ts → registry/context.d.ts} +2 -0
- package/dist/commands/{context.js → registry/context.js} +2 -2
- package/dist/commands/registry/index.d.ts +2 -0
- package/dist/commands/registry/index.js +3 -0
- package/dist/commands/setup/index.d.ts +2 -0
- package/dist/commands/setup/index.js +3 -0
- package/dist/commands/{init.d.ts → setup/init.d.ts} +1 -1
- package/dist/commands/{init.js → setup/init.js} +2 -3
- package/dist/commands/{instructions.d.ts → setup/instructions.d.ts} +2 -2
- package/dist/commands/{instructions.js → setup/instructions.js} +3 -3
- package/dist/commands/{ai-say.d.ts → talk/ai-say.d.ts} +2 -3
- package/dist/commands/{ai-say.js → talk/ai-say.js} +5 -9
- package/dist/commands/talk/index.d.ts +2 -0
- package/dist/commands/talk/index.js +3 -0
- package/dist/commands/{player-say.d.ts → talk/player-say.d.ts} +1 -1
- package/dist/commands/{player-say.js → talk/player-say.js} +4 -4
- package/dist/page/app/app.js +44 -20
- package/dist/page/app/served.js +7 -0
- package/dist/page/avatars/torretta.js +10 -3
- package/dist/page/dialogs/dialogs.css +10 -0
- package/dist/page/dialogs/profiles.js +3 -7
- package/dist/page/dialogs/settings.js +18 -4
- package/dist/page/game/column.js +1 -1
- package/dist/page/game/game.css +1 -1
- package/dist/page/guide/blocks.js +13 -2
- package/dist/page/guide/credits.js +6 -0
- package/dist/page/guide/drawings/analysis.js +13 -0
- package/dist/page/guide/drawings/drawings.css +329 -0
- package/dist/page/guide/drawings/drawings.js +15 -0
- package/dist/page/guide/drawings/game.js +15 -0
- package/dist/page/guide/drawings/helps.js +13 -0
- package/dist/page/guide/drawings/how-it-works.js +13 -0
- package/dist/page/guide/drawings/parts.js +103 -0
- package/dist/page/guide/drawings/players.js +19 -0
- package/dist/page/guide/drawings/talk.js +9 -0
- package/dist/page/guide/en.md +39 -25
- package/dist/page/guide/guide.css +123 -91
- package/dist/page/guide/guide.js +47 -25
- package/dist/page/guide/it.md +39 -25
- package/dist/page/guide/markdown.js +5 -0
- package/dist/page/helps/helps.css +127 -83
- package/dist/page/helps/helps.js +45 -26
- package/dist/page/helps/view.js +13 -3
- package/dist/page/{guide/foot.js → layout/footer.js} +7 -8
- package/dist/page/layout/header.js +5 -3
- package/dist/page/layout/layout.css +114 -36
- package/dist/page/layout/window.js +6 -26
- package/dist/page/main.js +1 -1
- package/dist/page/pieces/pieces.js +5 -2
- package/dist/page/style.css +2 -1
- package/dist/page/table/table.css +192 -0
- package/dist/page/table/update.js +82 -0
- package/dist/page/table/window.js +130 -0
- package/dist/page/talk/chat.css +19 -8
- package/dist/page/talk/talk.css +17 -67
- package/dist/page/talk/talk.js +7 -7
- package/dist/page/talk/voice.js +47 -9
- package/dist/page/text.js +118 -22
- package/dist/page/theme.css +2 -0
- package/dist/server/{bell.js → bell/bell.js} +3 -3
- package/dist/server/bell/index.d.ts +1 -0
- package/dist/server/bell/index.js +2 -0
- package/dist/server/{caller.d.ts → mcp/caller.d.ts} +1 -1
- package/dist/server/{caller.js → mcp/caller.js} +1 -1
- package/dist/server/mcp/index.d.ts +1 -0
- package/dist/server/mcp/index.js +2 -0
- package/dist/server/{mcp.d.ts → mcp/mcp.d.ts} +1 -1
- package/dist/server/{mcp.js → mcp/mcp.js} +9 -9
- package/dist/server/page/chat.d.ts +5 -0
- package/dist/server/page/chat.js +9 -1
- package/dist/server/page/game.js +16 -3
- package/dist/server/page/http.d.ts +1 -1
- package/dist/server/page/index.d.ts +3 -0
- package/dist/server/page/index.js +3 -0
- package/dist/server/page/page.d.ts +16 -3
- package/dist/server/page/page.js +18 -4
- package/dist/server/page/table.d.ts +40 -15
- package/dist/server/page/table.js +203 -19
- package/dist/server/page/update.d.ts +18 -0
- package/dist/server/page/update.js +40 -0
- package/dist/server/table/browser.d.ts +1 -1
- package/dist/server/table/browser.js +1 -1
- package/dist/server/table/hosts/chats.d.ts +1 -1
- package/dist/server/table/hosts/chats.js +7 -4
- package/dist/server/table/hosts/index.d.ts +1 -1
- package/dist/server/table/hosts/index.js +1 -1
- package/dist/server/table/hosts/play.d.ts +15 -4
- package/dist/server/table/hosts/play.js +75 -11
- package/dist/server/table/hosts/seat.d.ts +17 -5
- package/dist/server/table/hosts/seat.js +21 -15
- package/dist/server/table/index.d.ts +3 -2
- package/dist/server/table/index.js +3 -2
- package/dist/server/table/launch.d.ts +5 -2
- package/dist/server/table/launch.js +6 -3
- package/dist/server/table/link.d.ts +1 -1
- package/dist/server/table/link.js +4 -3
- package/dist/server/table/table.d.ts +4 -5
- package/dist/server/table/table.js +15 -12
- package/dist/server/table/update.d.ts +17 -0
- package/dist/server/table/update.js +77 -0
- package/dist/sites/index.d.ts +1 -1
- package/dist/sites/index.js +2 -2
- package/dist/version.d.ts +4 -0
- package/dist/version.js +12 -1
- package/package.json +1 -1
- package/dist/page/table/opener.css +0 -65
- package/dist/page/table/opener.js +0 -59
- /package/dist/commands/{speech.d.ts → answers/speech.d.ts} +0 -0
- /package/dist/commands/{view.js → answers/view.js} +0 -0
- /package/dist/commands/{page-link.js → game/page-link.js} +0 -0
- /package/dist/commands/{registry.d.ts → registry/registry.d.ts} +0 -0
- /package/dist/commands/{registry.js → registry/registry.js} +0 -0
- /package/dist/server/{bell.d.ts → bell/bell.d.ts} +0 -0
package/dist/page/text.js
CHANGED
|
@@ -5,12 +5,32 @@ export function textFor(languages) {
|
|
|
5
5
|
}
|
|
6
6
|
const englishNames = { K: "king", Q: "queen", R: "rook", B: "bishop", N: "knight", P: "pawn" };
|
|
7
7
|
const italianNames = { K: "re", Q: "donna", R: "torre", B: "alfiere", N: "cavallo", P: "pedone" };
|
|
8
|
+
const englishMoveWords = {
|
|
9
|
+
names: englishNames,
|
|
10
|
+
castles: { short: "castles short", long: "castles long" },
|
|
11
|
+
from: "from",
|
|
12
|
+
to: "to",
|
|
13
|
+
takes: "takes",
|
|
14
|
+
promotes: "promotes to",
|
|
15
|
+
check: { check: "check", mate: "checkmate" },
|
|
16
|
+
};
|
|
17
|
+
const italianMoveWords = {
|
|
18
|
+
names: italianNames,
|
|
19
|
+
castles: { short: "arrocco corto", long: "arrocco lungo" },
|
|
20
|
+
from: "da",
|
|
21
|
+
to: "in",
|
|
22
|
+
takes: "prende",
|
|
23
|
+
promotes: "promuove a",
|
|
24
|
+
check: { check: "scacco", mate: "scacco matto" },
|
|
25
|
+
};
|
|
8
26
|
const english = {
|
|
9
27
|
language: "en",
|
|
10
28
|
flip: "Flip",
|
|
11
29
|
theme: "Light or dark theme",
|
|
12
30
|
sounds: "Sounds",
|
|
13
31
|
voice: "Read the AI's words aloud",
|
|
32
|
+
noVoice: "This browser has no voice for this language: add one in your system's settings",
|
|
33
|
+
saidMove: (move) => moveInWords(englishMoveWords, move),
|
|
14
34
|
newGame: "New game",
|
|
15
35
|
offerDraw: "Offer a draw",
|
|
16
36
|
offerDrawWhen: "Offer a draw: on your turn, once each side has moved",
|
|
@@ -128,21 +148,45 @@ const english = {
|
|
|
128
148
|
boardLabel: (turn, lastMove) => `Chessboard, ${english.toMove(turn)}${lastMove === undefined ? "" : `, last move ${lastMove}`}`,
|
|
129
149
|
clearChat: (name) => `Before a new game, clear your chat with ${name}: in the window where you opened ${name}, not here, write /clear, then a message such as "new game". A clean chat plays faster.`,
|
|
130
150
|
outdated: (name) => `Chesspal has been updated, but this folder still has its old files: close the chat with ${name}, run chesspal init in this folder, and open a new chat.`,
|
|
151
|
+
update: {
|
|
152
|
+
mark: (version) => `Chesspal ${version} is out: update`,
|
|
153
|
+
title: "Update Chesspal",
|
|
154
|
+
offer: (version, current) => `Chesspal ${version} is out${current === undefined ? "" : `; this is ${current}`}. The table installs it and starts again by itself.`,
|
|
155
|
+
chatAgain: (name) => `The chat with ${name} starts again too, clean.`,
|
|
156
|
+
byHand: (name) => `You opened the chat with ${name} yourself: afterwards, close it and open a new one.`,
|
|
157
|
+
whilePlaying: "A game is going on: finish it, then update.",
|
|
158
|
+
install: "Update",
|
|
159
|
+
installing: (version) => `Installing ${version}…`,
|
|
160
|
+
installed: "Installed: the table starts again by itself once the game is over.",
|
|
161
|
+
failed: "Chesspal was not updated: close the chat, then type in a terminal, one after the other:",
|
|
162
|
+
notice: (version, name) => `Chesspal ${version} is out: close the chat with ${name}, type this command in a terminal, then open a new chat.`,
|
|
163
|
+
hide: "Hide until the next version",
|
|
164
|
+
},
|
|
131
165
|
offline: (name) => `${name} is not connected. Write it a message in the window where you opened ${name}, not in this page's chat: the page connects again by itself.`,
|
|
132
166
|
startClocks: "Start",
|
|
133
167
|
thinking: { move: "Thinking about its move", ponder: "Thinking while you play" },
|
|
134
168
|
asleep: (name) => `${name} is not listening: write a message, such as "hi", in the window where you opened ${name}, not here. Its clock waits until it answers.`,
|
|
135
169
|
asleepInAnalysis: (name) => `${name} is not listening: write to it in the window where you opened it, not here.`,
|
|
136
170
|
table: {
|
|
137
|
-
|
|
138
|
-
|
|
171
|
+
title: "Who are you playing?",
|
|
172
|
+
choose: "Choose the chat to play with: it opens in a window of its own, to keep open.",
|
|
173
|
+
restartHint: "Choose the model and effort, then press Claude Code or Codex: the chat starts again, clean, in the same window, once it has ended its answer. The game stays as it is.",
|
|
174
|
+
byHand: (name) => `You opened this chat yourself: change ${name}'s model with /model in its window, or close it and open one from here, with the choices below.`,
|
|
175
|
+
noChat: "No chat at the table: choose one",
|
|
176
|
+
change: "Change the chat or its model",
|
|
139
177
|
install: (name) => `To play with ${name}, install Claude Code or Codex, then open this page again.`,
|
|
140
178
|
model: "Model",
|
|
141
179
|
effort: "Effort",
|
|
142
180
|
asHost: (host) => `as set in ${host}`,
|
|
143
181
|
opening: "Opening the chat… In the terminal, if it asks whether you trust the folder, choose Yes with the arrow keys and press Enter.",
|
|
144
182
|
again: (name) => `${name} starts again with a clean chat for the new game…`,
|
|
183
|
+
restart: "The chat starts again, clean…",
|
|
184
|
+
waiting: (name) => `${name} starts again once it has ended its answer…`,
|
|
185
|
+
restartChanged: "Starts again, clean, with the new choices",
|
|
186
|
+
restartNow: "Start again now: it cuts the answer it is giving",
|
|
187
|
+
cancel: "Do not start again",
|
|
145
188
|
failed: "The terminal did not open: type the command below in a terminal.",
|
|
189
|
+
notRestarted: "The chat did not start again: close its window, then open another from here.",
|
|
146
190
|
typeIt: "Or type in a terminal:",
|
|
147
191
|
},
|
|
148
192
|
commandHere: (name) => `/clear and the other commands go in the window where you opened ${name}, not here.`,
|
|
@@ -161,6 +205,8 @@ const english = {
|
|
|
161
205
|
"profile-game": () => english.profile.whilePlaying,
|
|
162
206
|
"game-going": () => "A game is going on: finish it before you bring another to analyse.",
|
|
163
207
|
"pgn-unreadable": () => "Chesspal cannot read this PGN: check you copied the whole game, its tags and its moves.",
|
|
208
|
+
"update-game": () => english.update.whilePlaying,
|
|
209
|
+
"update-chat": (most, name) => `${name} is answering: update once it has done.`,
|
|
164
210
|
},
|
|
165
211
|
piece: (letter, side) => `${side} ${englishNames[letter]}`,
|
|
166
212
|
taken: (pieces, ahead) => `Pieces taken: ${pieces.length === 0 ? "none" : pieces.join(", ")}${ahead > 0 ? `; ahead by ${ahead}` : ""}`,
|
|
@@ -218,7 +264,6 @@ const english = {
|
|
|
218
264
|
back: "Back",
|
|
219
265
|
yourProfile: "Your profile",
|
|
220
266
|
editProfile: "Edit your profile",
|
|
221
|
-
yourPicture: "Your picture: edit your profile",
|
|
222
267
|
avatars: { "short-hair": "Short hair", bun: "Bun", glasses: "Glasses", beanie: "Beanie", beard: "Beard", curls: "Curls", moustache: "Moustache", "silver-bob": "Silver bob", cat: "Cat", owl: "Owl" },
|
|
223
268
|
whilePlaying: "Finish the game, or resign, before changing player.",
|
|
224
269
|
accounts: "Do you play on Lichess, Chess.com or in FIDE tournaments?",
|
|
@@ -323,25 +368,29 @@ const english = {
|
|
|
323
368
|
backward: ["Backward pawns", "A pawn left behind the pawns beside it, with the square in front of it attacked by an enemy pawn."],
|
|
324
369
|
passed: ["Passed pawns", "No enemy pawn in front of it, on its file or the files beside it."],
|
|
325
370
|
islands: ["Pawn islands", "Groups of pawns on neighbouring files, apart from each other."],
|
|
371
|
+
openFiles: ["Open files", "Files with no pawn of either side."],
|
|
326
372
|
halfOpen: ["Half-open files", "Files with enemy pawns and none of one's own."],
|
|
327
373
|
heavyOnFiles: ["Rooks and queens on open files", "Rooks and queens on open or half-open files."],
|
|
328
374
|
onSeventh: ["Rooks and queens on the seventh", "Rooks and queens on the enemy's second rank: the seventh for White, the second for Black."],
|
|
329
375
|
outposts: ["Outposts", "Squares on one's ranks 4 to 6, defended by a pawn, that no enemy pawn can ever attack."],
|
|
330
376
|
bishopPair: ["Bishop pair", "Both bishops still on the board."],
|
|
331
|
-
space: ["Space
|
|
377
|
+
space: ["Space", "How many squares of the enemy's half one's pieces attack."],
|
|
332
378
|
undeveloped: ["Minor pieces not developed", "Knights and bishops still on their first squares."],
|
|
333
379
|
castled: ["Castling", "How it castled; a dash while it still can, a cross once the king or the rooks have moved."],
|
|
334
380
|
kingAttacks: ["Enemy attacks around the king", "How many enemy attacks fall on the squares next to the king."],
|
|
335
381
|
},
|
|
336
|
-
groups: { pawns: "Pawns", pieces: "Pieces", king: "King" },
|
|
337
382
|
yes: "yes",
|
|
338
383
|
notYet: "not yet",
|
|
339
384
|
noMore: "no more",
|
|
340
385
|
phases: { opening: "Opening", middlegame: "Middlegame", endgame: "Endgame" },
|
|
341
|
-
openFiles: "Open files",
|
|
342
|
-
control: "Squares controlled",
|
|
343
|
-
both: "both",
|
|
344
386
|
controlled: (white, black, both) => `Squares only White's ${white}, only Black's ${black}, both ${both}`,
|
|
387
|
+
controlledBy: (who, count, you) => {
|
|
388
|
+
if (who === "both") {
|
|
389
|
+
return `Squares both control: ${count}`;
|
|
390
|
+
}
|
|
391
|
+
return `Squares only ${who === "white" ? "White" : "Black"}${you ? " (you)" : ""} controls: ${count}`;
|
|
392
|
+
},
|
|
393
|
+
bothSides: "both sides",
|
|
345
394
|
oppositeBishops: "Bishops of opposite colours",
|
|
346
395
|
repetitions: (times) => `This position has stood ${times} times`,
|
|
347
396
|
fiftyMoves: (halfMoves) => `${halfMoves} half-moves left before the fifty-move draw`,
|
|
@@ -365,9 +414,8 @@ const english = {
|
|
|
365
414
|
guide: {
|
|
366
415
|
title: "Guide",
|
|
367
416
|
contents: "Contents",
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
support: "Support Chesspal",
|
|
417
|
+
previous: "Previous page",
|
|
418
|
+
next: "Next page",
|
|
371
419
|
credits: "Credits",
|
|
372
420
|
creditLines: [
|
|
373
421
|
"The rules: [chess.js](https://github.com/jhlywa/chess.js), under the BSD 2-Clause license.",
|
|
@@ -376,6 +424,11 @@ const english = {
|
|
|
376
424
|
"The sounds: Chesspal's own.",
|
|
377
425
|
],
|
|
378
426
|
},
|
|
427
|
+
foot: {
|
|
428
|
+
onGitHub: "Chesspal on GitHub",
|
|
429
|
+
onNpm: "Chesspal on npm",
|
|
430
|
+
support: "Support Chesspal",
|
|
431
|
+
},
|
|
379
432
|
};
|
|
380
433
|
const italian = {
|
|
381
434
|
language: "it",
|
|
@@ -383,6 +436,8 @@ const italian = {
|
|
|
383
436
|
theme: "Tema chiaro o scuro",
|
|
384
437
|
sounds: "Suoni",
|
|
385
438
|
voice: "Leggi ad alta voce le parole dell'AI",
|
|
439
|
+
noVoice: "Questo browser non ha una voce per questa lingua: aggiungila nelle impostazioni del sistema",
|
|
440
|
+
saidMove: (move) => moveInWords(italianMoveWords, move),
|
|
386
441
|
newGame: "Nuova partita",
|
|
387
442
|
offerDraw: "Proponi patta",
|
|
388
443
|
offerDrawWhen: "Proponi patta: nel tuo turno, dopo una mossa a testa",
|
|
@@ -500,21 +555,45 @@ const italian = {
|
|
|
500
555
|
boardLabel: (turn, lastMove) => `Scacchiera, ${italian.toMove(turn)}${lastMove === undefined ? "" : `, ultima mossa ${lastMove}`}`,
|
|
501
556
|
clearChat: (name) => `Prima di una nuova partita azzera la conversazione con ${name}: nella finestra dove hai aperto ${name}, non qui, scrivi /clear e poi un messaggio, per esempio "nuova partita". Con la chat pulita l'AI gioca più veloce.`,
|
|
502
557
|
outdated: (name) => `Chesspal è stato aggiornato, ma questa cartella ha ancora i file di prima: chiudi la chat con ${name}, esegui chesspal init in questa cartella e apri una chat nuova.`,
|
|
558
|
+
update: {
|
|
559
|
+
mark: (version) => `È uscito Chesspal ${version}: aggiorna`,
|
|
560
|
+
title: "Aggiorna Chesspal",
|
|
561
|
+
offer: (version, current) => `È uscita la versione ${version} di Chesspal${current === undefined ? "" : `; questa è la ${current}`}. Il tavolo la installa e riparte da solo.`,
|
|
562
|
+
chatAgain: (name) => `Anche la chat con ${name} riparte pulita.`,
|
|
563
|
+
byHand: (name) => `La chat con ${name} l'hai aperta tu: dopo, chiudila e aprine una nuova.`,
|
|
564
|
+
whilePlaying: "C'è una partita in corso: finiscila, poi aggiorna.",
|
|
565
|
+
install: "Aggiorna",
|
|
566
|
+
installing: (version) => `Installo la ${version}…`,
|
|
567
|
+
installed: "Installata: il tavolo riparte da solo a fine partita.",
|
|
568
|
+
failed: "Chesspal non si è aggiornato: chiudi la chat, poi scrivi in un terminale, uno dopo l'altro:",
|
|
569
|
+
notice: (version, name) => `È uscita la versione ${version} di Chesspal: chiudi la chat con ${name}, scrivi questo comando in un terminale e apri una chat nuova.`,
|
|
570
|
+
hide: "Nascondi fino alla prossima versione",
|
|
571
|
+
},
|
|
503
572
|
offline: (name) => `${name} è scollegato. Scrivigli un messaggio nella finestra dove hai aperto ${name}, non nella chat di questa pagina: la pagina si ricollega da sola.`,
|
|
504
573
|
startClocks: "Inizia",
|
|
505
574
|
thinking: { move: "Sta pensando alla sua mossa", ponder: "Pensa mentre giochi tu" },
|
|
506
575
|
asleep: (name) => `${name} non ti sta ascoltando: scrivi un messaggio, per esempio "ciao", nella finestra dove hai aperto ${name}, non qui. Il suo orologio aspetta che risponda.`,
|
|
507
576
|
asleepInAnalysis: (name) => `${name} non ti sta ascoltando: scrivigli nella finestra dove l'hai aperto, non qui.`,
|
|
508
577
|
table: {
|
|
509
|
-
|
|
510
|
-
|
|
578
|
+
title: "Contro chi giochi?",
|
|
579
|
+
choose: "Scegli la chat con cui giocare: parte in una finestra a parte, da tenere aperta.",
|
|
580
|
+
restartHint: "Scegli modello e ragionamento, poi premi Claude Code o Codex: la chat riparte pulita nella stessa finestra, appena ha finito di rispondere. La partita resta com'è.",
|
|
581
|
+
byHand: (name) => `Questa chat l'hai aperta tu: cambia il modello di ${name} con /model nella sua finestra, oppure chiudila e aprine una da qui, con le scelte qui sotto.`,
|
|
582
|
+
noChat: "Nessuna chat al tavolo: scegline una",
|
|
583
|
+
change: "Cambia la chat o il modello",
|
|
511
584
|
install: (name) => `Per giocare con ${name}, installa Claude Code o Codex, poi apri di nuovo questa pagina.`,
|
|
512
585
|
model: "Modello",
|
|
513
586
|
effort: "Ragionamento",
|
|
514
587
|
asHost: (host) => `come è impostato in ${host}`,
|
|
515
588
|
opening: "Apro la chat… Nel terminale, se ti chiede se ti fidi della cartella, scegli Yes con le frecce e premi Invio.",
|
|
516
589
|
again: (name) => `${name} riparte con una chat pulita per la nuova partita…`,
|
|
590
|
+
restart: "La chat riparte pulita…",
|
|
591
|
+
waiting: (name) => `${name} riparte appena ha finito di rispondere…`,
|
|
592
|
+
restartChanged: "Riparte pulita con le nuove scelte",
|
|
593
|
+
restartNow: "Riparti adesso: interrompe la risposta in corso",
|
|
594
|
+
cancel: "Non ripartire",
|
|
517
595
|
failed: "Il terminale non si è aperto: scrivi il comando qui sotto in un terminale.",
|
|
596
|
+
notRestarted: "La chat non è ripartita: chiudi la sua finestra, poi aprine un'altra da qui.",
|
|
518
597
|
typeIt: "Oppure scrivi in un terminale:",
|
|
519
598
|
},
|
|
520
599
|
commandHere: (name) => `/clear e gli altri comandi vanno scritti nella finestra dove hai aperto ${name}, non qui.`,
|
|
@@ -533,6 +612,8 @@ const italian = {
|
|
|
533
612
|
"profile-game": () => italian.profile.whilePlaying,
|
|
534
613
|
"game-going": () => "C'è una partita in corso: finiscila prima di portarne un'altra da analizzare.",
|
|
535
614
|
"pgn-unreadable": () => "Chesspal non riesce a leggere questo PGN: controlla di aver copiato la partita intera, intestazioni e mosse.",
|
|
615
|
+
"update-game": () => italian.update.whilePlaying,
|
|
616
|
+
"update-chat": (most, name) => `${name} sta rispondendo: aggiorna quando ha finito.`,
|
|
536
617
|
},
|
|
537
618
|
// Queen and rook are feminine in Italian.
|
|
538
619
|
piece: (letter, side) => `${italianNames[letter]} ${side === "white" ? (letter === "Q" || letter === "R" ? "bianca" : "bianco") : (letter === "Q" || letter === "R" ? "nera" : "nero")}`,
|
|
@@ -591,7 +672,6 @@ const italian = {
|
|
|
591
672
|
back: "Indietro",
|
|
592
673
|
yourProfile: "Il tuo profilo",
|
|
593
674
|
editProfile: "Modifica il profilo",
|
|
594
|
-
yourPicture: "La tua immagine: modifica il profilo",
|
|
595
675
|
avatars: { "short-hair": "Capelli corti", bun: "Chignon", glasses: "Occhiali", beanie: "Berretto", beard: "Barba", curls: "Ricci", moustache: "Baffi", "silver-bob": "Caschetto grigio", cat: "Gatto", owl: "Gufo" },
|
|
596
676
|
whilePlaying: "Finisci la partita, o abbandona, prima di cambiare giocatore.",
|
|
597
677
|
accounts: "Giochi su Lichess, Chess.com o nei tornei FIDE?",
|
|
@@ -696,25 +776,29 @@ const italian = {
|
|
|
696
776
|
backward: ["Pedoni arretrati", "Un pedone rimasto indietro rispetto a quelli accanto, con la casa davanti attaccata da un pedone nemico."],
|
|
697
777
|
passed: ["Pedoni passati", "Nessun pedone nemico davanti a lui, né sulla sua colonna né su quelle accanto."],
|
|
698
778
|
islands: ["Isole di pedoni", "Gruppi di pedoni su colonne vicine, separati fra loro."],
|
|
779
|
+
openFiles: ["Colonne aperte", "Colonne senza pedoni di nessuno dei due."],
|
|
699
780
|
halfOpen: ["Colonne semiaperte", "Colonne con pedoni nemici e nessuno dei propri."],
|
|
700
781
|
heavyOnFiles: ["Torri e donna su colonne aperte", "Torri e donna su colonne aperte o semiaperte."],
|
|
701
782
|
onSeventh: ["Torri e donna in settima", "Torri e donna sulla seconda traversa del nemico: la settima per il Bianco, la seconda per il Nero."],
|
|
702
783
|
outposts: ["Avamposti", "Case sulle proprie traverse dalla quarta alla sesta, difese da un pedone, che nessun pedone nemico potrà mai attaccare."],
|
|
703
784
|
bishopPair: ["Coppia degli alfieri", "Tutti e due gli alfieri ancora sulla scacchiera."],
|
|
704
|
-
space: ["Spazio
|
|
785
|
+
space: ["Spazio", "Quante case della metà avversaria attaccano i propri pezzi."],
|
|
705
786
|
undeveloped: ["Pezzi minori non sviluppati", "Cavalli e alfieri ancora sulle case di partenza."],
|
|
706
787
|
castled: ["Arrocco", "Come ha arroccato; un trattino finché può ancora farlo, una croce quando il re o le torri si sono già mossi."],
|
|
707
788
|
kingAttacks: ["Attacchi nemici attorno al re", "Quanti attacchi nemici cadono sulle case accanto al re."],
|
|
708
789
|
},
|
|
709
|
-
groups: { pawns: "Pedoni", pieces: "Pezzi", king: "Re" },
|
|
710
790
|
yes: "sì",
|
|
711
791
|
notYet: "non ancora",
|
|
712
792
|
noMore: "non più",
|
|
713
793
|
phases: { opening: "Apertura", middlegame: "Mediogioco", endgame: "Finale" },
|
|
714
|
-
openFiles: "Colonne aperte",
|
|
715
|
-
control: "Case controllate",
|
|
716
|
-
both: "tutti e due",
|
|
717
794
|
controlled: (white, black, both) => `Case solo del Bianco ${white}, solo del Nero ${black}, di tutti e due ${both}`,
|
|
795
|
+
controlledBy: (who, count, you) => {
|
|
796
|
+
if (who === "both") {
|
|
797
|
+
return `Case controllate da tutti e due: ${count}`;
|
|
798
|
+
}
|
|
799
|
+
return `Case controllate solo dal ${who === "white" ? "Bianco" : "Nero"}${you ? " (tu)" : ""}: ${count}`;
|
|
800
|
+
},
|
|
801
|
+
bothSides: "tutti e due",
|
|
718
802
|
oppositeBishops: "Alfieri di colore contrario",
|
|
719
803
|
repetitions: (times) => `Questa posizione si è vista ${times} volte`,
|
|
720
804
|
fiftyMoves: (halfMoves) => `Mancano ${halfMoves} semimosse alla patta delle cinquanta mosse`,
|
|
@@ -738,9 +822,8 @@ const italian = {
|
|
|
738
822
|
guide: {
|
|
739
823
|
title: "Guida",
|
|
740
824
|
contents: "Indice",
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
support: "Sostieni Chesspal",
|
|
825
|
+
previous: "Pagina precedente",
|
|
826
|
+
next: "Pagina seguente",
|
|
744
827
|
credits: "Crediti",
|
|
745
828
|
creditLines: [
|
|
746
829
|
"Le regole: [chess.js](https://github.com/jhlywa/chess.js), con licenza BSD 2-Clause.",
|
|
@@ -749,6 +832,11 @@ const italian = {
|
|
|
749
832
|
"I suoni: di Chesspal.",
|
|
750
833
|
],
|
|
751
834
|
},
|
|
835
|
+
foot: {
|
|
836
|
+
onGitHub: "Chesspal su GitHub",
|
|
837
|
+
onNpm: "Chesspal su npm",
|
|
838
|
+
support: "Sostieni Chesspal",
|
|
839
|
+
},
|
|
752
840
|
};
|
|
753
841
|
// How each piece moves, said when it was taken where it cannot go (Anatolij's words).
|
|
754
842
|
const englishMoves = {
|
|
@@ -811,6 +899,14 @@ function italianCulprit(by) {
|
|
|
811
899
|
function italianWith(preposition, letter) {
|
|
812
900
|
return italianThe[letter].replace(/^il /, `${preposition}l `).replace(/^la /, `${preposition}lla `).replace(/^l'/, `${preposition}ll'`);
|
|
813
901
|
}
|
|
902
|
+
/** A move in words: "knight from b takes d7, check", "cavallo in f3", "arrocco corto". */
|
|
903
|
+
function moveInWords(words, move) {
|
|
904
|
+
const promotion = "castles" in move || move.promotion === undefined ? undefined : `${words.promotes} ${words.names[move.promotion]}`;
|
|
905
|
+
const played = "castles" in move
|
|
906
|
+
? words.castles[move.castles]
|
|
907
|
+
: [words.names[move.piece], ...(move.from === undefined ? [] : [words.from, move.from]), move.takes ? words.takes : words.to, move.square].join(" ");
|
|
908
|
+
return [played, promotion, move.check === undefined ? undefined : words.check[move.check]].filter((part) => part !== undefined).join(", ");
|
|
909
|
+
}
|
|
814
910
|
/** The words with their first letter capital, to open a sentence. */
|
|
815
911
|
function capital(words) {
|
|
816
912
|
return words.charAt(0).toUpperCase() + words.slice(1);
|
package/dist/page/theme.css
CHANGED
|
@@ -4,9 +4,9 @@ import { createHash } from "node:crypto";
|
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { get } from "node:http";
|
|
6
6
|
import { join, resolve } from "node:path";
|
|
7
|
-
import { writeAtomically } from "
|
|
8
|
-
import { dataFolder, tableFolder } from "
|
|
9
|
-
import { version } from "
|
|
7
|
+
import { writeAtomically } from "../../games/index.js";
|
|
8
|
+
import { dataFolder, tableFolder } from "../../home/index.js";
|
|
9
|
+
import { version } from "../../version.js";
|
|
10
10
|
/** What the chat hears from the doorbell: one line for whatever the player did, never what, only where to read it. */
|
|
11
11
|
export const bellLine = "The player acted on the board page: call status to see it.";
|
|
12
12
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Bell, bellProbe, listen, pageAt, pagePorts, samePath, type TableChat } from "./bell.ts";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { closeSync, openSync, readdirSync, readFileSync, readSync, statSync } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { basename, dirname, join } from "node:path";
|
|
6
|
-
import { lastChatStart } from "
|
|
6
|
+
import { lastChatStart } from "../../games/index.js";
|
|
7
7
|
/** Who made the call with these metadata: the model and effort the host ties to it, else the host's name; undefined without a host. */
|
|
8
8
|
export async function callerOf(meta, client, folder, wait = 50) {
|
|
9
9
|
const turn = objectOf(meta?.["x-codex-turn-metadata"]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { startMcpServer } from "./mcp.ts";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { type AnyCommand, type Context } from "
|
|
2
|
+
import { type AnyCommand, type Context } from "../../commands/index.ts";
|
|
3
3
|
/**
|
|
4
4
|
* What the host reads as the server starts, before any tool: the lines that start a chat, `instructions` then `status`, and the rule of every move (D-27,
|
|
5
5
|
* D-102). Short, since hosts cut them or copy them into every tool.
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { aiMove, commands, defaultContext, inputProblems, isBoolean, PositionChanged } from "
|
|
7
|
-
import { aiNameOf } from "
|
|
8
|
-
import { endOf, loadGame, noteAiHost, noteAiModel, rerunIfChanged } from "
|
|
9
|
-
import { agentTools, hasAgent, startInstructions } from "
|
|
10
|
-
import { gameFolder } from "
|
|
11
|
-
import { version } from "
|
|
12
|
-
import { pagePorts } from "
|
|
6
|
+
import { aiMove, commands, defaultContext, inputProblems, isBoolean, PositionChanged } from "../../commands/index.js";
|
|
7
|
+
import { aiNameOf } from "../../core/index.js";
|
|
8
|
+
import { endOf, loadGame, noteAiHost, noteAiModel, rerunIfChanged } from "../../games/index.js";
|
|
9
|
+
import { agentTools, hasAgent, startInstructions } from "../../host-files/index.js";
|
|
10
|
+
import { gameFolder } from "../../profiles/index.js";
|
|
11
|
+
import { version } from "../../version.js";
|
|
12
|
+
import { pagePorts } from "../bell/index.js";
|
|
13
|
+
import { chatHasRead, startPage } from "../page/index.js";
|
|
14
|
+
import { attachTable, tableToJoin } from "../table/index.js";
|
|
13
15
|
import { allowedCaller, callerOf, callingAgent, fromCodexAgent } from "./caller.js";
|
|
14
|
-
import { chatHasRead, startPage } from "./page/page.js";
|
|
15
|
-
import { attachTable, tableToJoin } from "./table/index.js";
|
|
16
16
|
/**
|
|
17
17
|
* What the host reads as the server starts, before any tool: the lines that start a chat, `instructions` then `status`, and the rule of every move (D-27,
|
|
18
18
|
* D-102). Short, since hosts cut them or copy them into every tool.
|
|
@@ -8,6 +8,7 @@ export interface ChatSeen {
|
|
|
8
8
|
readonly given: ReadonlySet<string>;
|
|
9
9
|
readonly seen: string | undefined;
|
|
10
10
|
readonly positionSeen: SeenPosition | null | undefined;
|
|
11
|
+
readonly positionFirstSeen: SeenPosition | undefined;
|
|
11
12
|
host(): string | undefined;
|
|
12
13
|
}
|
|
13
14
|
/** The chat as the page reads it, in the chat's own process: read from its context at each request, so always as the chat left it. */
|
|
@@ -39,6 +40,10 @@ export declare const chatCopy: z.ZodObject<{
|
|
|
39
40
|
started: z.ZodOptional<z.ZodString>;
|
|
40
41
|
plies: z.ZodInt;
|
|
41
42
|
}, z.core.$strip>>>;
|
|
43
|
+
positionFirstSeen: z.ZodOptional<z.ZodObject<{
|
|
44
|
+
started: z.ZodOptional<z.ZodString>;
|
|
45
|
+
plies: z.ZodInt;
|
|
46
|
+
}, z.core.$strip>>;
|
|
42
47
|
given: z.ZodArray<z.ZodString>;
|
|
43
48
|
host: z.ZodOptional<z.ZodString>;
|
|
44
49
|
aiModel: z.ZodOptional<z.ZodObject<{
|
package/dist/server/page/chat.js
CHANGED
|
@@ -13,6 +13,9 @@ export function chatSeenOf(chat) {
|
|
|
13
13
|
get positionSeen() {
|
|
14
14
|
return chat.positionSeen;
|
|
15
15
|
},
|
|
16
|
+
get positionFirstSeen() {
|
|
17
|
+
return chat.positionFirstSeen;
|
|
18
|
+
},
|
|
16
19
|
host: () => chat.host?.(),
|
|
17
20
|
};
|
|
18
21
|
}
|
|
@@ -47,6 +50,7 @@ export const chatAttach = z.object({
|
|
|
47
50
|
host: z.string().optional(),
|
|
48
51
|
outdated: z.boolean(),
|
|
49
52
|
});
|
|
53
|
+
const seenPosition = z.object({ started: z.string().optional(), plies: z.int().min(0) });
|
|
50
54
|
/**
|
|
51
55
|
* What the chat attached to the table tells it after each tool, and when the page has news no file holds (`news`): what it saw, the words it was given,
|
|
52
56
|
* its host, and the AI's model and host, which the table notes for a game that ends on the page (D-82, D-97).
|
|
@@ -54,7 +58,8 @@ export const chatAttach = z.object({
|
|
|
54
58
|
export const chatCopy = z.object({
|
|
55
59
|
token: z.string(),
|
|
56
60
|
seen: z.string().optional(),
|
|
57
|
-
positionSeen:
|
|
61
|
+
positionSeen: seenPosition.nullable().optional(),
|
|
62
|
+
positionFirstSeen: seenPosition.optional(),
|
|
58
63
|
given: z.array(z.string()),
|
|
59
64
|
host: z.string().optional(),
|
|
60
65
|
aiModel: z.object({ model: z.string(), effort: z.string().optional() }).optional(),
|
|
@@ -74,6 +79,9 @@ export function attachedSeen(attached) {
|
|
|
74
79
|
get positionSeen() {
|
|
75
80
|
return attached()?.copy?.positionSeen;
|
|
76
81
|
},
|
|
82
|
+
get positionFirstSeen() {
|
|
83
|
+
return attached()?.copy?.positionFirstSeen;
|
|
84
|
+
},
|
|
77
85
|
host: () => attached()?.copy?.host ?? attached()?.chat.host,
|
|
78
86
|
};
|
|
79
87
|
}
|
package/dist/server/page/game.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { analyseGame, answerDraw, bookPlies, ChatNotClear, DrawRefused, endGame, gameAt, gameToStudy, namedGame, newGame, offerDraw, playMove, samePosition, say, shownPosition, startNewGame, } from "../../commands/index.js";
|
|
1
|
+
import { analyseGame, analystOf, answerDraw, bookPlies, ChatNotClear, DrawRefused, endGame, gameAt, gameToStudy, namedGame, newGame, offerDraw, playMove, samePosition, say, shownPosition, startNewGame, } from "../../commands/index.js";
|
|
2
2
|
import { clockStarted, isReviewed, writePgn } from "../../core/index.js";
|
|
3
3
|
import { aiModelOf, archiveName, coachShown, coachWords, drawOfferOf, endOf, gameInAnalysis, heardLines, loadGame, loadTableTalk, playerPgn, ponderingOn, rerunIfChanged, saveGame, startAnalysis, talkLimits, thoughtKey, wakesTheChat, WordsRefused, } from "../../games/index.js";
|
|
4
4
|
import { gameFolder, helpsIn } from "../../profiles/index.js";
|
|
5
|
+
import { version } from "../../version.js";
|
|
5
6
|
import { asTheChatSees } from "./chat.js";
|
|
6
7
|
import { bodyOf, bytesOf, isJson, json, jsonOf, runRoute, send, textOf } from "./http.js";
|
|
7
8
|
import { profilesShown } from "./profiles.js";
|
|
8
9
|
import { chatToRelaunch, relaunchChat, tableShown } from "./table.js";
|
|
10
|
+
import { updateShown } from "./update.js";
|
|
9
11
|
/** Answers the page's requests about the game: true when the request was one. */
|
|
10
12
|
export function answerGame(request, response, url, served) {
|
|
11
13
|
const route = routes[`${request.method ?? ""} ${url.pathname}`];
|
|
@@ -295,6 +297,8 @@ function sendGame(response, served) {
|
|
|
295
297
|
const analysis = current === undefined || endOf(current.game) !== undefined ? analysisShown(served) : undefined;
|
|
296
298
|
const aiModel = aiModelOf(folder);
|
|
297
299
|
const body = {
|
|
300
|
+
// The page loaded from another version loads again, its files and all (Federico).
|
|
301
|
+
version,
|
|
298
302
|
game,
|
|
299
303
|
...(game === null && talk.length > 0 ? { talk } : {}),
|
|
300
304
|
...(analysis === undefined ? {} : { analysis }),
|
|
@@ -303,6 +307,7 @@ function sendGame(response, served) {
|
|
|
303
307
|
listening: served.bell.listening,
|
|
304
308
|
...thinkingShown(served, current),
|
|
305
309
|
...(served.outdated ? { outdated: true } : {}),
|
|
310
|
+
...updateShown(served),
|
|
306
311
|
...tableShown(served),
|
|
307
312
|
...profilesShown(served.context.home()),
|
|
308
313
|
};
|
|
@@ -336,7 +341,10 @@ function coachOn(folder, current) {
|
|
|
336
341
|
const shown = coachShown(coachWords(folder, current), current);
|
|
337
342
|
return shown.judgments.length === 0 && shown.hint === undefined && shown.leads === undefined ? undefined : shown;
|
|
338
343
|
}
|
|
339
|
-
/**
|
|
344
|
+
/**
|
|
345
|
+
* The game in analysis, once no game goes on (D-69): its name and its PGN with the AI's review, and whether an AI is going over it now; none without one,
|
|
346
|
+
* or when it cannot be read.
|
|
347
|
+
*/
|
|
340
348
|
function analysisShown(served) {
|
|
341
349
|
const analysis = gameInAnalysis(gameFolder(served.context.home()));
|
|
342
350
|
if (analysis === undefined) {
|
|
@@ -344,8 +352,13 @@ function analysisShown(served) {
|
|
|
344
352
|
}
|
|
345
353
|
try {
|
|
346
354
|
const { name, record } = namedGame(served.context, analysis.game);
|
|
355
|
+
// Without a review, an AI is at it only while the chat is in a turn, or hears the player while its analyst holds the game (D-89): one the chat has
|
|
356
|
+
// started again since is gone (Priya). On the table the chat's start is in the chat's own folder.
|
|
357
|
+
const { bell } = served;
|
|
358
|
+
const chat = { ...served.context, folder: served.attached?.chat.folder ?? served.folder };
|
|
359
|
+
const reviewing = !isReviewed(record) && (bell.inTurn || (bell.listening && analystOf(chat, analysis.game) !== undefined));
|
|
347
360
|
// How far the book goes, which the page cannot tell without the book's moves: its card names the opening on those moves.
|
|
348
|
-
return { name, pgn: writePgn(record), book: bookPlies(record) };
|
|
361
|
+
return { name, pgn: writePgn(record), book: bookPlies(record), ...(reviewing ? { reviewing: true } : {}) };
|
|
349
362
|
}
|
|
350
363
|
catch {
|
|
351
364
|
// A game gone from the archive is no longer shown.
|
|
@@ -8,7 +8,7 @@ export declare const json = "application/json; charset=utf-8";
|
|
|
8
8
|
*/
|
|
9
9
|
export interface Refused {
|
|
10
10
|
readonly error: string;
|
|
11
|
-
readonly refusal?: "no-game" | "ai-to-move" | "illegal" | "clear-chat" | `words-${WordsRefused["reason"]}` | `draw-${DrawRefused["reason"]}` | "profile-game" | "game-going" | "pgn-unreadable";
|
|
11
|
+
readonly refusal?: "no-game" | "ai-to-move" | "illegal" | "clear-chat" | `words-${WordsRefused["reason"]}` | `draw-${DrawRefused["reason"]}` | "profile-game" | "game-going" | "pgn-unreadable" | "update-game" | "update-chat";
|
|
12
12
|
readonly most?: number;
|
|
13
13
|
}
|
|
14
14
|
/** Answers a request, with nothing cached, sniffed or referred, and the page's policy unless the headers give another. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ServerResponse } from "node:http";
|
|
2
2
|
import { type Context } from "../../commands/index.ts";
|
|
3
|
-
import { Bell } from "../bell.ts";
|
|
3
|
+
import { Bell } from "../bell/index.ts";
|
|
4
4
|
import { type Attached, type ChatSeen } from "./chat.ts";
|
|
5
5
|
import { type Opening, type TableChats } from "./table.ts";
|
|
6
6
|
/**
|
|
@@ -29,13 +29,19 @@ export interface PageOptions {
|
|
|
29
29
|
readonly table?: TableEnd;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
* What the page tells the table that serves it: a request came, so the table is in use, or another Chesspal version asked it to quit;
|
|
33
|
-
* opens a chat, which the page offers while none is at the table.
|
|
32
|
+
* What the page tells the table that serves it: a request came, so the table is in use, or another Chesspal version asked it to quit; how the table
|
|
33
|
+
* opens a chat, which the page offers while none is at the table, and how it updates Chesspal.
|
|
34
34
|
*/
|
|
35
35
|
export interface TableEnd {
|
|
36
36
|
used(): void;
|
|
37
37
|
quit(): void;
|
|
38
38
|
readonly chats?: TableChats | undefined;
|
|
39
|
+
readonly update?: TableUpdate | undefined;
|
|
40
|
+
}
|
|
41
|
+
/** How the table updates Chesspal (D-108): npm installs a version, whether it did, and the table closes to start again from it. */
|
|
42
|
+
export interface TableUpdate {
|
|
43
|
+
install(version: string): Promise<boolean>;
|
|
44
|
+
restart(): void;
|
|
39
45
|
}
|
|
40
46
|
/**
|
|
41
47
|
* Serves the page of the context's folder on 127.0.0.1, on a port of its own when free, else on any free one, where the doorbell cannot find it; the
|
|
@@ -69,6 +75,13 @@ export interface Served {
|
|
|
69
75
|
readonly at: number;
|
|
70
76
|
readonly how: Opening;
|
|
71
77
|
} | undefined;
|
|
78
|
+
/** The host the page asked the chat to start again with while it was at work (D-107). */
|
|
79
|
+
restartWanted?: {
|
|
80
|
+
readonly host: string;
|
|
81
|
+
} | undefined;
|
|
82
|
+
/** The newer Chesspal npm has (D-108); the table installing it, installed and waiting to be at rest, or starting again from it. */
|
|
83
|
+
newer?: string;
|
|
84
|
+
updating?: "installing" | "installed" | "restarting" | undefined;
|
|
72
85
|
}
|
|
73
86
|
/**
|
|
74
87
|
* The chat has read the game as it is now, at the end of a tool's call: the doorbell wakes it only for what changes it after; and, when the tool `showed` it
|