chesspal 0.3.5 → 0.4.0
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 -0
- package/dist/cli/cli.js +17 -4
- package/dist/cli/command-line.js +22 -12
- package/dist/cli/icon.d.ts +2 -0
- package/dist/cli/icon.js +11 -1
- package/dist/cli/prompt-hook.d.ts +17 -0
- package/dist/cli/prompt-hook.js +100 -0
- package/dist/commands/analysis/analyse.d.ts +2 -2
- package/dist/commands/analysis/analyse.js +10 -16
- package/dist/commands/analysis/annotate.d.ts +8 -0
- package/dist/commands/analysis/annotate.js +19 -3
- package/dist/commands/answers/agents.d.ts +17 -7
- package/dist/commands/answers/agents.js +46 -16
- package/dist/commands/answers/clock.js +2 -1
- package/dist/commands/answers/drawings.js +6 -2
- package/dist/commands/answers/index.d.ts +4 -3
- package/dist/commands/answers/index.js +4 -3
- package/dist/commands/answers/lines.d.ts +5 -3
- package/dist/commands/answers/lines.js +17 -9
- package/dist/commands/answers/opening-book.d.ts +13 -7
- package/dist/commands/answers/opening-book.js +34 -38
- package/dist/commands/answers/opening-tags.d.ts +4 -0
- package/dist/commands/answers/opening-tags.js +11 -0
- package/dist/commands/answers/play-move.d.ts +3 -1
- package/dist/commands/answers/play-move.js +9 -6
- package/dist/commands/answers/say.js +2 -1
- package/dist/commands/answers/summary.d.ts +7 -3
- package/dist/commands/answers/summary.js +16 -5
- package/dist/commands/answers/view.d.ts +1 -1
- package/dist/commands/answers/view.js +2 -2
- package/dist/commands/game/ai-move.js +4 -4
- package/dist/commands/game/coach.js +7 -6
- package/dist/commands/game/end.js +2 -2
- package/dist/commands/game/export.d.ts +1 -1
- package/dist/commands/game/index.d.ts +1 -1
- package/dist/commands/game/index.js +1 -1
- package/dist/commands/game/look.d.ts +7 -3
- package/dist/commands/game/look.js +9 -4
- package/dist/commands/game/new.js +42 -12
- package/dist/commands/game/player-move.d.ts +16 -0
- package/dist/commands/game/player-move.js +69 -19
- package/dist/commands/game/ponder.js +7 -4
- package/dist/commands/game/position.d.ts +2 -1
- package/dist/commands/game/position.js +9 -4
- package/dist/commands/game/status.d.ts +4 -2
- package/dist/commands/game/status.js +24 -14
- package/dist/commands/index.d.ts +3 -3
- package/dist/commands/index.js +3 -3
- package/dist/commands/profiles/past-games.d.ts +7 -2
- package/dist/commands/profiles/past-games.js +45 -18
- package/dist/commands/registry/context.d.ts +2 -0
- package/dist/commands/registry/context.js +5 -0
- package/dist/commands/registry/index.d.ts +1 -1
- package/dist/commands/registry/index.js +1 -1
- package/dist/commands/talk/ai-say.d.ts +1 -1
- package/dist/commands/talk/ai-say.js +7 -6
- package/dist/core/game.d.ts +13 -0
- package/dist/core/game.js +29 -3
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +3 -3
- package/dist/core/openings.d.ts +20 -6
- package/dist/core/openings.js +45 -22
- package/dist/core/pgn.d.ts +4 -0
- package/dist/core/pgn.js +35 -6
- package/dist/games/analysis.d.ts +7 -4
- package/dist/games/analysis.js +5 -3
- package/dist/games/archive.d.ts +25 -5
- package/dist/games/archive.js +52 -19
- package/dist/games/chat-start.d.ts +2 -2
- package/dist/games/chat-start.js +6 -1
- package/dist/games/current-game.d.ts +2 -2
- package/dist/games/current-game.js +3 -2
- package/dist/games/index.d.ts +3 -2
- package/dist/games/index.js +3 -2
- package/dist/games/position-shown.d.ts +24 -0
- package/dist/games/position-shown.js +51 -0
- package/dist/games/thoughts.d.ts +12 -4
- package/dist/games/thoughts.js +27 -10
- package/dist/home/index.d.ts +1 -0
- package/dist/home/index.js +1 -0
- package/dist/home/same-path.d.ts +7 -0
- package/dist/home/same-path.js +24 -0
- package/dist/host-files/host-files.d.ts +5 -0
- package/dist/host-files/host-files.js +21 -7
- package/dist/host-files/index.d.ts +1 -1
- package/dist/host-files/index.js +1 -1
- package/dist/page/app/anchor.js +15 -11
- package/dist/page/app/app.js +49 -14
- package/dist/page/app/served.js +30 -38
- package/dist/page/app/watch.js +97 -0
- package/dist/page/avatars/torretta.css +108 -0
- package/dist/page/base.css +1 -1
- package/dist/page/board/board.css +11 -8
- package/dist/page/board/marks.js +2 -2
- package/dist/page/board/pointer.js +2 -2
- package/dist/page/dialogs/analyses.js +5 -3
- package/dist/page/dialogs/dialogs.css +3 -1
- package/dist/page/dialogs/rows.js +72 -0
- package/dist/page/dialogs/site-games.js +3 -1
- package/dist/page/game/column.js +10 -8
- package/dist/page/game/game.css +137 -16
- package/dist/page/game/move-list.js +7 -5
- package/dist/page/game/plies.js +4 -0
- package/dist/page/game/review-progress.js +11 -0
- package/dist/page/guide/drawings/drawings.css +0 -1
- package/dist/page/guide/en.md +2 -2
- package/dist/page/guide/it.md +2 -2
- package/dist/page/helps/helps.css +5 -5
- package/dist/page/helps/helps.js +3 -181
- package/dist/page/helps/rows.js +16 -0
- package/dist/page/helps/strategy.js +105 -0
- package/dist/page/helps/tactics.js +69 -0
- package/dist/page/layout/header.js +49 -6
- package/dist/page/layout/icon.ico +0 -0
- package/dist/page/layout/layout.css +49 -17
- package/dist/page/layout/window.js +45 -6
- package/dist/page/lead/lead.js +41 -4
- package/dist/page/legend/legend.css +4 -16
- package/dist/page/legend/legend.js +28 -15
- package/dist/page/profile/settings.js +1 -0
- package/dist/page/sounds/sounds.js +1 -1
- package/dist/page/style.css +1 -0
- package/dist/page/table/action.js +42 -0
- package/dist/page/table/table.css +57 -39
- package/dist/page/table/window.js +67 -67
- package/dist/page/talk/talk.css +52 -118
- package/dist/page/talk/talk.js +65 -20
- package/dist/page/talk/voice.js +92 -21
- package/dist/page/text.js +34 -8
- package/dist/page/theme.css +13 -0
- package/dist/profiles/profiles.js +5 -1
- package/dist/server/bell/bell.d.ts +24 -29
- package/dist/server/bell/bell.js +79 -133
- package/dist/server/bell/index.d.ts +1 -1
- package/dist/server/bell/index.js +2 -2
- package/dist/server/mcp/mcp.js +49 -7
- package/dist/server/page/analyses.js +15 -4
- package/dist/server/page/chat.d.ts +5 -1
- package/dist/server/page/chat.js +5 -1
- package/dist/server/page/files.js +3 -1
- package/dist/server/page/game.d.ts +5 -0
- package/dist/server/page/game.js +95 -15
- package/dist/server/page/http.d.ts +1 -1
- package/dist/server/page/page.d.ts +14 -9
- package/dist/server/page/page.js +111 -26
- package/dist/server/page/table.d.ts +40 -5
- package/dist/server/page/table.js +65 -25
- package/dist/server/page/update.d.ts +1 -1
- package/dist/server/page/update.js +4 -4
- package/dist/server/page/windows.d.ts +22 -0
- package/dist/server/page/windows.js +45 -0
- package/dist/server/ports/index.d.ts +1 -0
- package/dist/server/ports/index.js +2 -0
- package/dist/server/ports/ports.d.ts +78 -0
- package/dist/server/ports/ports.js +222 -0
- package/dist/server/table/browser.d.ts +22 -6
- package/dist/server/table/browser.js +98 -20
- package/dist/server/table/hosts/chats.d.ts +5 -0
- package/dist/server/table/hosts/chats.js +11 -4
- package/dist/server/table/hosts/hooks.d.ts +6 -0
- package/dist/server/table/hosts/hooks.js +38 -0
- package/dist/server/table/hosts/hosts.d.ts +13 -5
- package/dist/server/table/hosts/hosts.js +16 -10
- package/dist/server/table/hosts/index.d.ts +1 -0
- package/dist/server/table/hosts/index.js +1 -0
- package/dist/server/table/hosts/play.d.ts +7 -3
- package/dist/server/table/hosts/play.js +63 -9
- package/dist/server/table/icon/index.d.ts +2 -0
- package/dist/server/table/icon/index.js +16 -2
- package/dist/server/table/index.d.ts +2 -2
- package/dist/server/table/index.js +1 -1
- package/dist/server/table/launch.d.ts +5 -4
- package/dist/server/table/launch.js +18 -5
- package/dist/server/table/link.js +4 -1
- package/dist/server/table/table.d.ts +7 -0
- package/dist/server/table/table.js +40 -12
- package/dist/sites/index.d.ts +1 -1
- package/dist/sites/index.js +1 -1
- package/dist/sites/{chesscom.d.ts → ratings/chesscom.d.ts} +2 -2
- package/dist/sites/{chesscom.js → ratings/chesscom.js} +1 -1
- package/dist/sites/{choice.d.ts → ratings/choice.d.ts} +1 -1
- package/dist/sites/{choice.js → ratings/choice.js} +1 -1
- package/dist/sites/ratings/index.d.ts +1 -0
- package/dist/sites/ratings/index.js +2 -0
- package/dist/sites/{lichess.d.ts → ratings/lichess.d.ts} +2 -2
- package/dist/sites/{lichess.js → ratings/lichess.js} +1 -1
- package/dist/sites/{sites.d.ts → ratings/ratings.d.ts} +2 -2
- package/dist/sites/{sites.js → ratings/ratings.js} +1 -1
- package/instructions/opponent.md +1 -1
- package/instructions/start.md +1 -1
- package/package.json +1 -1
package/dist/page/talk/voice.js
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
|
-
/** Reads the
|
|
2
|
-
export function speak(
|
|
1
|
+
/** Reads the bubbles aloud one after the other in the voice's language, the moves in words, cutting short what was being read. */
|
|
2
|
+
export function speak(readings, voice) {
|
|
3
3
|
if (typeof speechSynthesis === "undefined") {
|
|
4
4
|
return;
|
|
5
5
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
stop();
|
|
7
|
+
queue = readings.map((reading) => ({ key: reading.key, said: spokenMoves(reading.words.replace(/\*\*/g, ""), voice.saidMove).trim() })).filter((reading) => reading.said !== "");
|
|
8
|
+
language = voice.language;
|
|
9
|
+
readNextSoon();
|
|
10
|
+
}
|
|
11
|
+
/** Stops reading the bubble the key names, when it is the one read, and goes on with the next. */
|
|
12
|
+
export function skip(key) {
|
|
13
|
+
if (current?.key === key) {
|
|
14
|
+
stop();
|
|
15
|
+
readNextSoon();
|
|
11
16
|
}
|
|
12
|
-
// Chrome drops words spoken right after a cancel, and lists its voices late the first time: the words wait a moment.
|
|
13
|
-
pending = setTimeout(() => {
|
|
14
|
-
const utterance = new SpeechSynthesisUtterance(said);
|
|
15
|
-
const reader = readerFor(voice.language);
|
|
16
|
-
utterance.lang = reader?.lang ?? voice.language;
|
|
17
|
-
if (reader !== undefined) {
|
|
18
|
-
utterance.voice = reader;
|
|
19
|
-
}
|
|
20
|
-
speechSynthesis.resume();
|
|
21
|
-
speechSynthesis.speak(utterance);
|
|
22
|
-
}, 150);
|
|
23
17
|
}
|
|
24
|
-
/** Stops reading. */
|
|
18
|
+
/** Stops reading, and forgets what was waiting. */
|
|
25
19
|
export function hush() {
|
|
26
20
|
if (typeof speechSynthesis !== "undefined") {
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
queue = [];
|
|
22
|
+
stop();
|
|
29
23
|
}
|
|
30
24
|
}
|
|
25
|
+
/** The key of the bubble being read, from the moment the voice starts it to its end; none while nothing is read. */
|
|
26
|
+
export function reading() {
|
|
27
|
+
return current?.started === true ? current.key : undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Calls the listener whenever the bubble being read changes: what it returns stops it. */
|
|
30
|
+
export function onReading(listener) {
|
|
31
|
+
listeners.add(listener);
|
|
32
|
+
return () => {
|
|
33
|
+
listeners.delete(listener);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
31
36
|
/** Whether the browser has a voice for the language: without one the words cannot be read. */
|
|
32
37
|
export function hasVoice(language) {
|
|
33
38
|
return typeof speechSynthesis !== "undefined" && readerFor(language) !== undefined;
|
|
@@ -61,7 +66,73 @@ export function spokenMoves(words, say) {
|
|
|
61
66
|
return say({ piece, ...said, takes: takes !== undefined, square, ...promoted, ...checked });
|
|
62
67
|
});
|
|
63
68
|
}
|
|
69
|
+
// What waits to be read, what is read and in which language, and who wants to know which bubble is read.
|
|
70
|
+
let queue = [];
|
|
71
|
+
let current;
|
|
72
|
+
let language = "";
|
|
64
73
|
let pending;
|
|
74
|
+
const listeners = new Set();
|
|
75
|
+
// Chrome drops words spoken right after a cancel, and lists its voices late the first time: the words wait a moment.
|
|
76
|
+
function readNextSoon() {
|
|
77
|
+
pending = setTimeout(readNext, 150);
|
|
78
|
+
}
|
|
79
|
+
function readNext() {
|
|
80
|
+
const next = queue.shift();
|
|
81
|
+
if (next === undefined) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const utterance = new SpeechSynthesisUtterance(next.said);
|
|
85
|
+
const reader = readerFor(language);
|
|
86
|
+
utterance.lang = reader?.lang ?? language;
|
|
87
|
+
if (reader !== undefined) {
|
|
88
|
+
utterance.voice = reader;
|
|
89
|
+
}
|
|
90
|
+
const reading = { key: next.key, utterance, started: false };
|
|
91
|
+
current = reading;
|
|
92
|
+
// A cancel fires end or error in some browsers and nothing in others: only the events of the utterance read now count, and the page drops its own at once.
|
|
93
|
+
utterance.onstart = () => {
|
|
94
|
+
if (current === reading) {
|
|
95
|
+
reading.started = true;
|
|
96
|
+
// The voice may stop with no event at all: a look each second at whether it still speaks, so no mark stays on a bubble nobody reads.
|
|
97
|
+
reading.watch = setInterval(() => {
|
|
98
|
+
if (current === reading && !speechSynthesis.speaking) {
|
|
99
|
+
finished(reading);
|
|
100
|
+
}
|
|
101
|
+
}, 1000);
|
|
102
|
+
tell();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
utterance.onend = () => finished(reading);
|
|
106
|
+
utterance.onerror = () => finished(reading);
|
|
107
|
+
speechSynthesis.resume();
|
|
108
|
+
speechSynthesis.speak(utterance);
|
|
109
|
+
}
|
|
110
|
+
function finished(reading) {
|
|
111
|
+
if (current === reading) {
|
|
112
|
+
drop();
|
|
113
|
+
readNext();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Cuts short what is read, keeping what waits.
|
|
117
|
+
function stop() {
|
|
118
|
+
clearTimeout(pending);
|
|
119
|
+
drop();
|
|
120
|
+
speechSynthesis.cancel();
|
|
121
|
+
}
|
|
122
|
+
function drop() {
|
|
123
|
+
const was = current;
|
|
124
|
+
clearInterval(was?.watch);
|
|
125
|
+
current = undefined;
|
|
126
|
+
if (was?.started === true) {
|
|
127
|
+
tell();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function tell() {
|
|
131
|
+
const key = reading();
|
|
132
|
+
for (const listener of listeners) {
|
|
133
|
+
listener(key);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
65
136
|
// A move in SAN, with the pieces' letters or figurines, as the AI writes it; the parts named, castling apart.
|
|
66
137
|
const movePattern = /(?<![\w♔-♟])(?:(?<castles>O-O(?:-O)?|0-0(?:-0)?)|(?:(?<figurine>[♔-♟])[\uFE0E\uFE0F]?|(?<letter>[KQRBN]))?(?<from>[a-h]?[1-8]?)(?<takes>[x×])?(?<square>[a-h][1-8])(?:=?(?<promotion>[QRBN]|[♔-♟]))?[\uFE0E\uFE0F]?)(?<check>\+\+|[+#])?(?![\w♔-♟])/gu;
|
|
67
138
|
// A piece's letter, or its figurine: White's run ♔♕♖♗♘♙ and Black's ♚♛♜♝♞♟, in SAN's order.
|
package/dist/page/text.js
CHANGED
|
@@ -30,6 +30,7 @@ const english = {
|
|
|
30
30
|
sounds: "Sounds",
|
|
31
31
|
voice: "Read the AI's words aloud",
|
|
32
32
|
noVoice: "This browser has no voice for this language: add one in your system's settings",
|
|
33
|
+
skipReading: "Stop reading this aloud",
|
|
33
34
|
saidMove: (move) => moveInWords(englishMoveWords, move),
|
|
34
35
|
newGame: "New game",
|
|
35
36
|
offerDraw: "Offer a draw",
|
|
@@ -40,6 +41,7 @@ const english = {
|
|
|
40
41
|
declineDrawTitle: "Decline: moving declines it too",
|
|
41
42
|
resign: "Resign",
|
|
42
43
|
resignGame: "Resign this game?",
|
|
44
|
+
keepPlaying: "Play on",
|
|
43
45
|
settings: "Settings",
|
|
44
46
|
close: "Close",
|
|
45
47
|
look: "Look",
|
|
@@ -175,31 +177,40 @@ const english = {
|
|
|
175
177
|
choose: "Choose the chat to play with: it opens in a window of its own, to keep open.",
|
|
176
178
|
reviewTitle: "Who reviews the game?",
|
|
177
179
|
reviewChoose: "Choose the chat that reviews the game: it opens in a window of its own, to keep open.",
|
|
178
|
-
restartHint: "
|
|
180
|
+
restartHint: "The chat starts again, clean, in the same window, once it has ended its answer, with the chat, model and effort chosen here. The game stays as it is.",
|
|
179
181
|
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.`,
|
|
180
182
|
noChat: "No chat at the table: choose one",
|
|
181
183
|
change: "Change the chat or its model",
|
|
182
184
|
install: (name) => `To play with ${name}, install Claude Code or Codex, then open this page again.`,
|
|
185
|
+
chat: "Chat",
|
|
183
186
|
model: "Model",
|
|
184
187
|
effort: "Effort",
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
atTable: "At the table",
|
|
189
|
+
act: { open: (host) => `Start ${host}`, review: (host) => `Review with ${host}`, restart: (host) => `Restart ${host}`, switch: (host) => `Switch to ${host}` },
|
|
190
|
+
opening: "Opening the chat… In the terminal, if it asks whether you trust the folder, say yes (in Claude Code, go down to Yes with the arrow keys) and press Enter; with Codex, on the hooks, choose Trust all and continue.",
|
|
187
191
|
again: (name) => `${name} starts again with a clean chat for the new game…`,
|
|
188
192
|
restart: "The chat starts again, clean…",
|
|
189
193
|
waiting: (name) => `${name} starts again once it has ended its answer…`,
|
|
190
|
-
|
|
194
|
+
newGameWaiting: (name) => `The new game starts once ${name} has ended its answer…`,
|
|
191
195
|
restartNow: "Start again now: it cuts the answer it is giving",
|
|
192
196
|
cancel: "Do not start again",
|
|
197
|
+
newGameNow: "Start the new game now: it cuts the answer it is giving",
|
|
198
|
+
newGameCancel: "Do not start the new game",
|
|
193
199
|
failed: "The terminal did not open: type the command below in a terminal.",
|
|
194
200
|
notRestarted: "The chat did not start again: close its window, then open another from here.",
|
|
195
201
|
typeIt: "Or type in a terminal:",
|
|
196
202
|
},
|
|
197
203
|
commandHere: (name) => `/clear and the other commands go in the window where you opened ${name}, not here.`,
|
|
204
|
+
link: {
|
|
205
|
+
going: "A game is going on: finish it, then open the link again.",
|
|
206
|
+
gone: "The game of this link is not here: it was deleted, or it is another profile's.",
|
|
207
|
+
},
|
|
198
208
|
refused: {
|
|
199
209
|
"no-game": () => "There is no game going on: press + to start one, or ask for one in the chat.",
|
|
200
210
|
"ai-to-move": () => "Wait for the AI's move.",
|
|
201
211
|
illegal: () => "That move is not legal here.",
|
|
202
212
|
"clear-chat": (most, name) => english.clearChat(name),
|
|
213
|
+
"new-game-profile": () => "The new game did not start: you changed profile while it waited. Start it again from this one.",
|
|
203
214
|
"words-empty": () => "Write something first.",
|
|
204
215
|
"words-spent": () => "You have used up your words for this move: write again after the AI's move.",
|
|
205
216
|
"words-long": (most) => `Write at most ${most} characters.`,
|
|
@@ -210,6 +221,8 @@ const english = {
|
|
|
210
221
|
"profile-game": () => english.profile.whilePlaying,
|
|
211
222
|
"game-going": () => "A game is going on: finish it before you bring another to analyse.",
|
|
212
223
|
"pgn-unreadable": () => "Chesspal cannot read this PGN: check you copied the whole game, its tags and its moves.",
|
|
224
|
+
"game-missing": () => "This game is no longer there: pick another.",
|
|
225
|
+
"game-not-archived": () => "The game just over is not saved yet: try again in a moment.",
|
|
213
226
|
"update-game": () => english.update.whilePlaying,
|
|
214
227
|
"update-chat": (most, name) => `${name} is answering: update once it has done.`,
|
|
215
228
|
},
|
|
@@ -455,6 +468,7 @@ const italian = {
|
|
|
455
468
|
sounds: "Suoni",
|
|
456
469
|
voice: "Leggi ad alta voce le parole dell'AI",
|
|
457
470
|
noVoice: "Questo browser non ha una voce per questa lingua: aggiungila nelle impostazioni del sistema",
|
|
471
|
+
skipReading: "Smetti di leggere questo a voce",
|
|
458
472
|
saidMove: (move) => moveInWords(italianMoveWords, move),
|
|
459
473
|
newGame: "Nuova partita",
|
|
460
474
|
offerDraw: "Proponi patta",
|
|
@@ -465,6 +479,7 @@ const italian = {
|
|
|
465
479
|
declineDrawTitle: "Rifiuta: anche muovere rifiuta",
|
|
466
480
|
resign: "Abbandona",
|
|
467
481
|
resignGame: "Abbandonare la partita?",
|
|
482
|
+
keepPlaying: "Continua",
|
|
468
483
|
settings: "Impostazioni",
|
|
469
484
|
close: "Chiudi",
|
|
470
485
|
look: "Aspetto",
|
|
@@ -600,31 +615,40 @@ const italian = {
|
|
|
600
615
|
choose: "Scegli la chat con cui giocare: parte in una finestra a parte, da tenere aperta.",
|
|
601
616
|
reviewTitle: "Chi analizza la partita?",
|
|
602
617
|
reviewChoose: "Scegli la chat che analizza la partita: parte in una finestra a parte, da tenere aperta.",
|
|
603
|
-
restartHint: "
|
|
618
|
+
restartHint: "La chat riparte pulita nella stessa finestra, appena ha finito di rispondere, con la chat, il modello e il ragionamento scelti qui. La partita resta com'è.",
|
|
604
619
|
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.`,
|
|
605
620
|
noChat: "Nessuna chat al tavolo: scegline una",
|
|
606
621
|
change: "Cambia la chat o il modello",
|
|
607
622
|
install: (name) => `Per giocare con ${name}, installa Claude Code o Codex, poi apri di nuovo questa pagina.`,
|
|
623
|
+
chat: "Chat",
|
|
608
624
|
model: "Modello",
|
|
609
625
|
effort: "Ragionamento",
|
|
610
|
-
|
|
611
|
-
|
|
626
|
+
atTable: "Al tavolo",
|
|
627
|
+
act: { open: (host) => `Avvia ${host}`, review: (host) => `Analizza con ${host}`, restart: (host) => `Riavvia ${host}`, switch: (host) => `Passa a ${host}` },
|
|
628
|
+
opening: "Apro la chat… Nel terminale, se ti chiede se ti fidi della cartella, rispondi sì (in Claude Code scendi su Yes con le frecce) e premi Invio; con Codex, sugli «hook», scegli Trust all and continue.",
|
|
612
629
|
again: (name) => `${name} riparte con una chat pulita per la nuova partita…`,
|
|
613
630
|
restart: "La chat riparte pulita…",
|
|
614
631
|
waiting: (name) => `${name} riparte appena ha finito di rispondere…`,
|
|
615
|
-
|
|
632
|
+
newGameWaiting: (name) => `La nuova partita comincia appena ${name} ha finito di rispondere…`,
|
|
616
633
|
restartNow: "Riparti adesso: interrompe la risposta in corso",
|
|
617
634
|
cancel: "Non ripartire",
|
|
635
|
+
newGameNow: "Comincia adesso la nuova partita: interrompe la risposta in corso",
|
|
636
|
+
newGameCancel: "Non cominciare la nuova partita",
|
|
618
637
|
failed: "Il terminale non si è aperto: scrivi il comando qui sotto in un terminale.",
|
|
619
638
|
notRestarted: "La chat non è ripartita: chiudi la sua finestra, poi aprine un'altra da qui.",
|
|
620
639
|
typeIt: "Oppure scrivi in un terminale:",
|
|
621
640
|
},
|
|
622
641
|
commandHere: (name) => `/clear e gli altri comandi vanno scritti nella finestra dove hai aperto ${name}, non qui.`,
|
|
642
|
+
link: {
|
|
643
|
+
going: "C'è una partita in corso: finiscila, poi riapri il link.",
|
|
644
|
+
gone: "La partita di questo link non c'è: è stata cancellata, o è di un altro profilo.",
|
|
645
|
+
},
|
|
623
646
|
refused: {
|
|
624
647
|
"no-game": () => "Nessuna partita in corso: premi + per iniziarne una, o chiedila nella chat.",
|
|
625
648
|
"ai-to-move": () => "Aspetta la mossa dell'AI.",
|
|
626
649
|
illegal: () => "Questa mossa qui non è legale.",
|
|
627
650
|
"clear-chat": (most, name) => italian.clearChat(name),
|
|
651
|
+
"new-game-profile": () => "La nuova partita non è cominciata: hai cambiato profilo mentre aspettava. Ricominciala da questo.",
|
|
628
652
|
"words-empty": () => "Scrivi prima qualcosa.",
|
|
629
653
|
"words-spent": () => "Hai finito le parole per questa mossa: scrivi di nuovo dopo quella dell'AI.",
|
|
630
654
|
"words-long": (most) => `Scrivi al massimo ${most} caratteri.`,
|
|
@@ -635,6 +659,8 @@ const italian = {
|
|
|
635
659
|
"profile-game": () => italian.profile.whilePlaying,
|
|
636
660
|
"game-going": () => "C'è una partita in corso: finiscila prima di portarne un'altra da analizzare.",
|
|
637
661
|
"pgn-unreadable": () => "Chesspal non riesce a leggere questo PGN: controlla di aver copiato la partita intera, intestazioni e mosse.",
|
|
662
|
+
"game-missing": () => "Questa partita non c'è più: scegline un'altra.",
|
|
663
|
+
"game-not-archived": () => "La partita appena finita non è ancora salvata: riprova fra un momento.",
|
|
638
664
|
"update-game": () => italian.update.whilePlaying,
|
|
639
665
|
"update-chat": (most, name) => `${name} sta rispondendo: aggiorna quando ha finito.`,
|
|
640
666
|
},
|
package/dist/page/theme.css
CHANGED
|
@@ -62,6 +62,19 @@
|
|
|
62
62
|
--badge-mistake: #d4650f;
|
|
63
63
|
--badge-miss: #c2407d;
|
|
64
64
|
--badge-blunder: #d22c2c;
|
|
65
|
+
/* The kings' badges on a game over, the same in both themes: the winner's gold crown, the mate in red on white, the flag that fell, the draw */
|
|
66
|
+
--king-crown: #e0a526;
|
|
67
|
+
--king-crown-ink: #3b2a00;
|
|
68
|
+
--king-mate: #c81e1e;
|
|
69
|
+
--king-flag: #4a4f57;
|
|
70
|
+
--king-draw: #69727d;
|
|
71
|
+
/* The two sides as the game's column draws them, in the bar and the chart of who is ahead and in the helps' bars and tiles, the same in both themes:
|
|
72
|
+
White, Black, and both, each half 3:1 at least with the tile's green tick; their edge keeps the white half in sight on a light card and the black one
|
|
73
|
+
on a dark card. The board's map and counts keep their own, darker on the squares (Zoe) */
|
|
74
|
+
--side-white: #f5f5f2;
|
|
75
|
+
--side-black: #33383f;
|
|
76
|
+
--side-both: #8a9099;
|
|
77
|
+
--side-edge: color-mix(in srgb, var(--side-both) 60%, transparent);
|
|
65
78
|
--shadow: 0 1px 2px rgba(29, 39, 51, 0.06), 0 6px 18px rgba(29, 39, 51, 0.06);
|
|
66
79
|
/* On a light page the board keeps a thin edge in its dark squares colour, and a deeper shadow, so its light squares do not melt into the page */
|
|
67
80
|
--board-shadow: 0 0 0 1px color-mix(in oklab, var(--dark-square) 55%, transparent), 0 2px 4px rgba(29, 39, 51, 0.1), 0 10px 28px rgba(29, 39, 51, 0.12);
|
|
@@ -23,8 +23,12 @@ export function listProfiles(root) {
|
|
|
23
23
|
* together make one: the second finds its folder taken.
|
|
24
24
|
*/
|
|
25
25
|
export function ensureProfile(root, account) {
|
|
26
|
+
// Every command asks, so the common answer comes first: a profile is there.
|
|
27
|
+
if (profileIds(root).length > 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
26
30
|
const id = freeId(root, slugOf(account));
|
|
27
|
-
if (
|
|
31
|
+
if (claimed(root, id)) {
|
|
28
32
|
fillProfile(root, id, { name: account }, true);
|
|
29
33
|
}
|
|
30
34
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
/** What the chat hears from the doorbell: one line for whatever the player did, never what, only where to read it. */
|
|
3
3
|
export declare const bellLine = "The player acted on the board page: call status to see it.";
|
|
4
4
|
/**
|
|
@@ -10,6 +10,7 @@ export declare class Bell {
|
|
|
10
10
|
private pending;
|
|
11
11
|
private busy;
|
|
12
12
|
private woken;
|
|
13
|
+
private hooked;
|
|
13
14
|
private readonly news;
|
|
14
15
|
private readonly changed;
|
|
15
16
|
/**
|
|
@@ -25,38 +26,34 @@ export declare class Bell {
|
|
|
25
26
|
get listening(): boolean;
|
|
26
27
|
/** The chat calls a tool, so it is in a turn: true when nobody was listening before. */
|
|
27
28
|
chatCalls(): boolean;
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The player's message, or one the host sent for the doorbell or an agent, starts the chat's turn, as the prompt hook says: the hook of the turn
|
|
31
|
+
* before is let go without a ring, and what the player does on the page meanwhile waits for the turn's end, as during a tool. A chat nobody heard
|
|
32
|
+
* stays unheard until its first tool, which starts the AI's clock, held till then: the message moves no clock.
|
|
33
|
+
*/
|
|
34
|
+
chatPrompted(): void;
|
|
35
|
+
/**
|
|
36
|
+
* The player acted on the page: the hook waiting hears it now, or the next one as soon as it comes. In a host that runs no hook nothing tells the end of
|
|
37
|
+
* a turn: an act the chat waits for finds it out of its turn, and nobody hears the player, unless the chat `mayBeAtWork` on the AI's move meanwhile.
|
|
38
|
+
*/
|
|
39
|
+
ring(mayBeAtWork?: boolean): void;
|
|
40
|
+
/**
|
|
41
|
+
* A hook waits for the bell, so the chat's turn has ended; the hook before it, of a turn already ended, is let go. A ring no hook heard is dropped when
|
|
42
|
+
* the chat is `told` all of it otherwise: by the player's message that came with the move the prompt hook played.
|
|
43
|
+
*/
|
|
44
|
+
listen(request: IncomingMessage, response: ServerResponse, told?: boolean): void;
|
|
32
45
|
/** The chat left the table (D-104): its process ended, and nobody is in a turn or waits for the bell; a ring no hook heard is no longer news for anyone. */
|
|
33
46
|
chatLeft(): void;
|
|
34
47
|
private tellIf;
|
|
35
48
|
}
|
|
36
49
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
50
|
+
* Notes in the data folder the port a chat's page took off its folder's usual ports, one file per page, for the hook to find it there; then forgets, off
|
|
51
|
+
* the caller's clock, the notes of its folder whose page is gone: nobody listens at the port, or another folder's page does. A page that answers late
|
|
52
|
+
* is busy, not gone, and keeps its note. It throws when the note cannot be written.
|
|
39
53
|
*/
|
|
40
|
-
export declare function
|
|
41
|
-
/**
|
|
42
|
-
export
|
|
43
|
-
session: string | null;
|
|
44
|
-
chat?: string;
|
|
45
|
-
}
|
|
46
|
-
/** What a page says of itself at `/api/bell?probe`. */
|
|
47
|
-
export interface BellProbe {
|
|
48
|
-
session: string | null;
|
|
49
|
-
folder: string;
|
|
50
|
-
open: boolean;
|
|
51
|
-
version?: string;
|
|
52
|
-
table?: true;
|
|
53
|
-
/** The folder of the chat attached to the table. */
|
|
54
|
-
chat?: string;
|
|
55
|
-
}
|
|
56
|
-
/** What the page at a port of this computer says of itself; undefined when none answers there. */
|
|
57
|
-
export declare function pageAt(port: number): Promise<BellProbe | undefined>;
|
|
58
|
-
/** The ports a folder's page tries first: one in each of a few ranges, by its path, since Windows may reserve a range. The hook looks for it there. */
|
|
59
|
-
export declare function pagePorts(folder: string): number[];
|
|
54
|
+
export declare function notePagePort(home: string, folder: string, port: number, wait?: number): Promise<void>;
|
|
55
|
+
/** Forgets the note of a page that closes, unless another folder's page took its port since; a note that cannot go is left for the next page to clear. */
|
|
56
|
+
export declare function forgetPagePort(home: string, folder: string, port: number): void;
|
|
60
57
|
/** What Codex's Stop hook answers to wake the chat: its turn goes on with the doorbell's line. */
|
|
61
58
|
export declare const codexBellAnswer: string;
|
|
62
59
|
/**
|
|
@@ -85,5 +82,3 @@ export type BellHeard = {
|
|
|
85
82
|
export declare function bellHeard(input: string, ports?: number[]): Promise<BellHeard>;
|
|
86
83
|
/** Adds a line to the log of the hooks that heard no bell, keeping its last lines; a log that cannot be written never stops the hook. */
|
|
87
84
|
export declare function noteSilence(folder: string, why: string, now?: Date): void;
|
|
88
|
-
/** Whether two paths name the same folder: without regard to case on Windows. */
|
|
89
|
-
export declare function samePath(one: string, other: string): boolean;
|