chesspal 0.1.0 → 0.2.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 +45 -82
- package/dist/cli/chat-hook.js +1 -1
- package/dist/cli/command-line.d.ts +1 -2
- package/dist/cli/command-line.js +2 -3
- package/dist/commands/agents.d.ts +26 -0
- package/dist/commands/agents.js +72 -0
- package/dist/commands/ai-move.d.ts +5 -14
- package/dist/commands/ai-move.js +28 -35
- package/dist/commands/ai-say.d.ts +3 -1
- package/dist/commands/ai-say.js +24 -6
- package/dist/commands/analyse-game.d.ts +4 -0
- package/dist/commands/analyse-game.js +43 -16
- package/dist/commands/annotate-game.d.ts +4 -0
- package/dist/commands/annotate-game.js +65 -12
- package/dist/commands/answer-lines.d.ts +28 -0
- package/dist/commands/answer-lines.js +144 -0
- package/dist/commands/coach.d.ts +45 -0
- package/dist/commands/coach.js +344 -0
- package/dist/commands/context.d.ts +16 -5
- package/dist/commands/context.js +1 -0
- package/dist/commands/delete-game.d.ts +7 -0
- package/dist/commands/delete-game.js +30 -0
- package/dist/commands/delete-review.d.ts +8 -0
- package/dist/commands/delete-review.js +34 -0
- package/dist/commands/drawings.d.ts +0 -2
- package/dist/commands/drawings.js +5 -3
- package/dist/commands/end-game.js +5 -2
- package/dist/commands/export-game.d.ts +1 -1
- package/dist/commands/export-game.js +4 -3
- package/dist/commands/game-summary.d.ts +21 -38
- package/dist/commands/game-summary.js +30 -167
- package/dist/commands/index.d.ts +15 -0
- package/dist/commands/index.js +47 -2
- package/dist/commands/init.d.ts +3 -3
- package/dist/commands/init.js +4 -4
- package/dist/commands/lead-input.d.ts +8 -0
- package/dist/commands/lead-input.js +21 -0
- package/dist/commands/look.js +4 -1
- package/dist/commands/new-game.d.ts +2 -3
- package/dist/commands/new-game.js +7 -4
- package/dist/commands/play-move.d.ts +8 -15
- package/dist/commands/play-move.js +5 -13
- package/dist/commands/player-move.d.ts +2 -6
- package/dist/commands/player-move.js +13 -6
- package/dist/commands/player-say.d.ts +1 -1
- package/dist/commands/player-say.js +1 -1
- package/dist/commands/ponder.d.ts +10 -0
- package/dist/commands/ponder.js +33 -21
- package/dist/commands/position.d.ts +1 -1
- package/dist/commands/position.js +3 -1
- package/dist/commands/profiles.d.ts +13 -4
- package/dist/commands/profiles.js +49 -15
- package/dist/commands/registry.d.ts +8 -3
- package/dist/commands/registry.js +12 -11
- package/dist/commands/say.d.ts +1 -1
- package/dist/commands/say.js +16 -16
- package/dist/commands/speech.d.ts +8 -0
- package/dist/commands/speech.js +20 -0
- package/dist/commands/status.d.ts +9 -3
- package/dist/commands/status.js +40 -15
- package/dist/commands/study-games.js +1 -1
- package/dist/commands/study.js +3 -19
- package/dist/core/facts.js +15 -15
- package/dist/core/game.d.ts +3 -1
- package/dist/core/game.js +8 -4
- package/dist/core/illegal.js +1 -1
- package/dist/core/index.d.ts +5 -4
- package/dist/core/index.js +5 -4
- package/dist/core/lead.d.ts +15 -0
- package/dist/core/lead.js +40 -0
- package/dist/core/levels.d.ts +1 -1
- package/dist/core/levels.js +1 -1
- package/dist/core/moods.d.ts +0 -2
- package/dist/core/moods.js +2 -2
- package/dist/core/openings.d.ts +0 -2
- package/dist/core/openings.js +1 -1
- package/dist/core/profile.js +1 -1
- package/dist/core/record.d.ts +1 -1
- package/dist/core/record.js +1 -1
- package/dist/core/review.d.ts +9 -3
- package/dist/core/review.js +29 -9
- package/dist/games/analysis.d.ts +1 -1
- package/dist/games/archive.d.ts +24 -3
- package/dist/games/archive.js +96 -22
- package/dist/games/coach.d.ts +57 -0
- package/dist/games/coach.js +144 -0
- package/dist/games/current-game.d.ts +2 -0
- package/dist/games/current-game.js +7 -1
- package/dist/games/files.js +1 -0
- package/dist/games/index.d.ts +4 -3
- package/dist/games/index.js +4 -3
- package/dist/games/talk.d.ts +1 -5
- package/dist/games/talk.js +14 -14
- package/dist/home/open-folder.js +1 -1
- package/dist/host-files/{ponder-agents.d.ts → agents.d.ts} +10 -2
- package/dist/host-files/agents.js +53 -0
- package/dist/host-files/host-files.d.ts +7 -2
- package/dist/host-files/host-files.js +27 -12
- package/dist/host-files/index.d.ts +2 -2
- package/dist/host-files/index.js +3 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -0
- package/dist/page/app/anchor.js +88 -0
- package/dist/page/{app.js → app/app.js} +112 -230
- package/dist/page/app/keys.js +94 -0
- package/dist/page/app/phase.js +30 -0
- package/dist/page/app/served.js +73 -0
- package/dist/page/avatars/avatars.js +19 -0
- package/dist/page/avatars/thought.js +10 -0
- package/dist/page/base.css +160 -0
- package/dist/page/board/board.css +959 -0
- package/dist/page/board/board.js +125 -0
- package/dist/page/{explain.js → board/explain.js} +1 -1
- package/dist/page/board/marks.js +160 -0
- package/dist/page/board/motion.js +71 -0
- package/dist/page/board/pointer.js +239 -0
- package/dist/page/board/squares.js +26 -0
- package/dist/page/dialogs/analyses.js +195 -0
- package/dist/page/{dialog.js → dialogs/dialog.js} +1 -1
- package/dist/page/dialogs/dialogs.css +1228 -0
- package/dist/page/{new-game-dialog.js → dialogs/new-game.js} +3 -3
- package/dist/page/{profile-dialogs.js → dialogs/profiles.js} +40 -11
- package/dist/page/dialogs/search.js +31 -0
- package/dist/page/dialogs/settings.js +42 -0
- package/dist/page/dialogs/studied.js +39 -0
- package/dist/page/dialogs/study.js +51 -0
- package/dist/page/{badges.js → game/badges.js} +1 -1
- package/dist/page/{browse.js → game/browse.js} +1 -1
- package/dist/page/game/card-fold.js +40 -0
- package/dist/page/game/column.js +51 -0
- package/dist/page/{ending.js → game/ending.js} +2 -2
- package/dist/page/game/game.css +577 -0
- package/dist/page/{move-list.js → game/move-list.js} +10 -6
- package/dist/page/{plies.js → game/plies.js} +30 -10
- package/dist/page/game/result-tile.js +14 -0
- package/dist/page/helps/helps.css +689 -0
- package/dist/page/helps/helps.js +220 -0
- package/dist/page/helps/view.js +127 -0
- package/dist/page/layout/fold-tab.js +11 -0
- package/dist/page/{folds.js → layout/folds.js} +1 -1
- package/dist/page/{header.js → layout/header.js} +5 -4
- package/dist/page/layout/layout.css +834 -0
- package/dist/page/lead/lead.js +82 -0
- package/dist/page/lead/view.js +38 -0
- package/dist/page/main.js +2 -2
- package/dist/page/pieces/CREDITS.md +12 -29
- package/dist/page/pieces/capablanca-small.svg +20 -0
- package/dist/page/pieces/capablanca.svg +22 -0
- package/dist/page/pieces/nitida-small.svg +3 -2
- package/dist/page/pieces/nitida.svg +3 -2
- package/dist/page/{pieces.js → pieces/pieces.js} +2 -2
- package/dist/page/pieces/torretta-small.svg +15 -14
- package/dist/page/pieces/torretta.svg +17 -15
- package/dist/page/{player-card.js → players/card.js} +2 -6
- package/dist/page/{clock-time.js → players/clock-time.js} +2 -2
- package/dist/page/{profile.js → profile/profile.js} +9 -5
- package/dist/page/{settings.js → profile/settings.js} +5 -4
- package/dist/page/style.css +9 -4398
- package/dist/page/talk/talk.css +958 -0
- package/dist/page/{talk.js → talk/talk.js} +39 -46
- package/dist/page/text.js +137 -19
- package/dist/page/theme.css +292 -0
- package/dist/profiles/index.d.ts +1 -1
- package/dist/profiles/profiles.d.ts +15 -4
- package/dist/profiles/profiles.js +24 -7
- package/dist/server/bell.d.ts +10 -2
- package/dist/server/bell.js +28 -12
- package/dist/server/caller.d.ts +14 -3
- package/dist/server/caller.js +44 -11
- package/dist/server/mcp.d.ts +1 -2
- package/dist/server/mcp.js +42 -14
- package/dist/server/page/analyses.d.ts +23 -0
- package/dist/server/page/analyses.js +65 -0
- package/dist/server/page/files.d.ts +5 -0
- package/dist/server/page/files.js +92 -0
- package/dist/server/page/game.d.ts +6 -0
- package/dist/server/page/game.js +381 -0
- package/dist/server/{http.d.ts → page/http.d.ts} +13 -0
- package/dist/server/{http.js → page/http.js} +11 -0
- package/dist/server/{page.d.ts → page/page.d.ts} +8 -13
- package/dist/server/page/page.js +229 -0
- package/dist/server/{profile-routes.d.ts → page/profiles.d.ts} +2 -2
- package/dist/server/{profile-routes.js → page/profiles.js} +47 -18
- package/instructions/analysis.md +4 -0
- package/instructions/analyst-agent.md +8 -0
- package/instructions/analyst.md +3 -7
- package/instructions/coach.md +11 -0
- package/instructions/opponent.md +4 -4
- package/package.json +1 -1
- package/dist/host-files/ponder-agents.js +0 -40
- package/dist/page/avatars.js +0 -16
- package/dist/page/board.js +0 -566
- package/dist/page/fold-tab.js +0 -9
- package/dist/page/game-column.js +0 -44
- package/dist/page/helps-view.js +0 -51
- package/dist/page/helps.js +0 -90
- package/dist/page/pieces/cburnett-small.svg +0 -20
- package/dist/page/pieces/cburnett.svg +0 -20
- package/dist/page/settings-panel.js +0 -32
- package/dist/page/studied.js +0 -14
- package/dist/page/study-dialog.js +0 -58
- package/dist/server/analyses.d.ts +0 -17
- package/dist/server/analyses.js +0 -46
- package/dist/server/page.js +0 -657
- /package/dist/page/{torretta.js → avatars/torretta.js} +0 -0
- /package/dist/page/{opening-book.js → game/opening-book.js} +0 -0
- /package/dist/page/{model-name.js → players/model-name.js} +0 -0
- /package/dist/page/{sounds.js → sounds/sounds.js} +0 -0
- /package/dist/page/{voice.js → talk/voice.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AiLevel, type Facts, type MoodNow, type Side, type Square } from "../core/index.ts";
|
|
1
|
+
import { type AiLevel, type Facts, type GameRecord, type MoodNow, type Side, type Square } from "../core/index.ts";
|
|
2
2
|
import { type CurrentGame, type Speaker, type Thought } from "../games/index.ts";
|
|
3
3
|
import { type ClockSummary } from "./clock.ts";
|
|
4
4
|
/** The current game, as the commands give it. */
|
|
@@ -23,19 +23,23 @@ export interface GameSummary {
|
|
|
23
23
|
plan?: string;
|
|
24
24
|
/** When the AI is to move: what it thought of the player's move on their time (D-72). */
|
|
25
25
|
thought?: Thought;
|
|
26
|
-
/** When the AI is to move: the helps on, so it may teach (D-78), or turned off since it
|
|
27
|
-
helps?: "on" | "off now";
|
|
26
|
+
/** When the AI is to move: the helps on, so it may teach (D-78), with a coach that judges the player's moves (D-88), or turned off since it drew on a move. */
|
|
27
|
+
helps?: "on" | "coached" | "off now";
|
|
28
28
|
/** In a game with a time control: the time each side had left when the command ran (D-13). */
|
|
29
29
|
clock?: ClockSummary;
|
|
30
30
|
/** Who offered a draw, while the offer stands (D-65). */
|
|
31
31
|
drawOffer?: Speaker;
|
|
32
32
|
/** The AI's mood while it lasts, in a game going on (D-70). */
|
|
33
33
|
mood?: MoodNow;
|
|
34
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* When the game is over: how it ended, its name in the archive once it is there, and, where an analyst agent runs (D-89), whether the chat offers it or
|
|
36
|
+
* goes over the review it did.
|
|
37
|
+
*/
|
|
35
38
|
end?: {
|
|
36
39
|
result: string;
|
|
37
40
|
termination?: string;
|
|
38
41
|
archive?: string;
|
|
42
|
+
analyst?: "offer" | "done";
|
|
39
43
|
};
|
|
40
44
|
}
|
|
41
45
|
/** A move numbered as in the game (4.Ng5, 4...d5), with the squares it went from and to. */
|
|
@@ -53,43 +57,22 @@ export interface MovePlayed {
|
|
|
53
57
|
game: GameSummary;
|
|
54
58
|
/** What went wrong after the move was saved, such as the archive not written. */
|
|
55
59
|
warning?: string;
|
|
56
|
-
/** What the player wrote on the board page that the AI has not been given yet
|
|
60
|
+
/** What the player wrote on the board page that the AI has not been given yet. */
|
|
57
61
|
words?: string[];
|
|
58
62
|
}
|
|
59
63
|
/** The game as the commands tell it; a game over with the name it has in the archive, when it is there. */
|
|
60
64
|
export declare function summaryOf(current: CurrentGame, now: Date, archive?: string): GameSummary;
|
|
61
|
-
/** The summary with what the AI reads when it is to move: what it thought of the player's last move on their time (D-72), and whether the helps are on (D-78). */
|
|
62
|
-
export declare function withThought(summary: GameSummary, folder: string, current: CurrentGame): GameSummary;
|
|
63
|
-
/** The current game `now`, refused when there is none or when it is over, on time too. */
|
|
64
|
-
export declare function gameGoingOn(folder: string, now: Date): CurrentGame;
|
|
65
|
-
/** Where the game stands: the AI's position to decide on, with its last move unless the lines before named it; the player's turn; or how it ended. */
|
|
66
|
-
export declare function positionLines(game: GameSummary, withLastMove?: boolean): string[];
|
|
67
|
-
/** The head of a view: where the game stands, the last move unless the lines before named it, the opening, the material as the player sees it, and the FEN. */
|
|
68
|
-
export declare function headLines(game: GameSummary, withLastMove?: boolean): string[];
|
|
69
|
-
/** The last move, as the player is shown it, with its squares: 4.♞g5 (f3-g5). */
|
|
70
|
-
export declare function lastMoveText({ move, from, to }: LastMove): string;
|
|
71
65
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
66
|
+
* The summary with what the AI reads when it is to move: what it thought of the player's last move on their time (D-72), and whether the helps are on (D-78),
|
|
67
|
+
* with a coach when `coached`.
|
|
74
68
|
*/
|
|
75
|
-
export declare function
|
|
76
|
-
/** The
|
|
77
|
-
export
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
export declare function moveLines({ note, game, warning }: MovePlayed): string[];
|
|
86
|
-
/** The last lines of a tool's answer: the player's words from the board page, then the next step, which stays the last line. */
|
|
87
|
-
export declare function closingLines(game: GameSummary | undefined, words?: readonly string[]): string[];
|
|
88
|
-
/** The player's words from the board page, one line each: lines they broke are joined, so no line of theirs reads as one of Chesspal's. */
|
|
89
|
-
export declare function wordLines(words: readonly string[]): string[];
|
|
90
|
-
/** What the AI does next: the one line every host reads, even where the server's instructions are not shown. Words of the player's ask for an answer. */
|
|
91
|
-
export declare function nextStep(game: GameSummary | undefined, words?: readonly string[]): string;
|
|
92
|
-
/** How a new game starts: the player chooses it in the board page's window, which new_game without choices opens; in the chat only where there is no page (D-85). */
|
|
93
|
-
export declare const newGameStep: string;
|
|
94
|
-
/** Who plays what, from the AI's side. */
|
|
95
|
-
export declare function sidesLine(ai: Side): string;
|
|
69
|
+
export declare function withThought(summary: GameSummary, folder: string, current: CurrentGame, coached: boolean): GameSummary;
|
|
70
|
+
/** The current game `now`, refused when there is none or when it is over, on time too. */
|
|
71
|
+
export declare function gameGoingOn(folder: string, now: Date): CurrentGame;
|
|
72
|
+
/** How a game ended, in words: its result, and how it came when known. */
|
|
73
|
+
export declare function endText({ result, termination }: {
|
|
74
|
+
result: string;
|
|
75
|
+
termination?: string;
|
|
76
|
+
}): string;
|
|
77
|
+
/** The last plies of a record, numbered as a player writes them, from the move number and side of its FEN. */
|
|
78
|
+
export declare function lastMoves(record: GameRecord, count: number): string;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
//
|
|
2
|
-
import {
|
|
3
|
-
import { currentPlan, drawOfferOf, endOf,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { clockLine, clockSummaryOf, gameAt } from "./clock.js";
|
|
1
|
+
// The current game as the commands give it: plain data for the command line's JSON, from which answer-lines.ts writes the lines an AI reads.
|
|
2
|
+
import { levelOf, moodAt, sees } from "../core/index.js";
|
|
3
|
+
import { currentPlan, drawOfferOf, endOf, thoughtForLastMove } from "../games/index.js";
|
|
4
|
+
import { helpsIn } from "../profiles/index.js";
|
|
5
|
+
import { clockSummaryOf, gameAt } from "./clock.js";
|
|
7
6
|
import { knownMoves, openingLine } from "./opening-book.js";
|
|
8
|
-
import { boardView, colourName, compactView, materialText } from "./view.js";
|
|
9
7
|
/** The game as the commands tell it; a game over with the name it has in the archive, when it is there. */
|
|
10
8
|
export function summaryOf(current, now, archive) {
|
|
11
9
|
const { game, ai } = current;
|
|
@@ -40,13 +38,16 @@ export function summaryOf(current, now, archive) {
|
|
|
40
38
|
}
|
|
41
39
|
return summary;
|
|
42
40
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The summary with what the AI reads when it is to move: what it thought of the player's last move on their time (D-72), and whether the helps are on (D-78),
|
|
43
|
+
* with a coach when `coached`.
|
|
44
|
+
*/
|
|
45
|
+
export function withThought(summary, folder, current, coached) {
|
|
45
46
|
if (summary.turn !== summary.ai || summary.end !== undefined) {
|
|
46
47
|
return summary;
|
|
47
48
|
}
|
|
48
49
|
const thought = thoughtForLastMove(folder, current);
|
|
49
|
-
const helps = helpsIn(folder) ? "on" : judgedBefore(current) ? "off now" : undefined;
|
|
50
|
+
const helps = helpsIn(folder) ? (coached ? "coached" : "on") : judgedBefore(current) ? "off now" : undefined;
|
|
50
51
|
return { ...summary, ...(thought === undefined ? {} : { thought }), ...(helps === undefined ? {} : { helps }) };
|
|
51
52
|
}
|
|
52
53
|
/** The current game `now`, refused when there is none or when it is over, on time too. */
|
|
@@ -61,159 +62,12 @@ export function gameGoingOn(folder, now) {
|
|
|
61
62
|
}
|
|
62
63
|
return current;
|
|
63
64
|
}
|
|
64
|
-
/**
|
|
65
|
-
export function
|
|
66
|
-
if (game.end !== undefined || game.turn !== game.ai) {
|
|
67
|
-
return [whereLine(game), ...offerLines(game), ...clockLines(game), ...moodLines(game)];
|
|
68
|
-
}
|
|
69
|
-
return [
|
|
70
|
-
...headLines(game, withLastMove),
|
|
71
|
-
...(game.facts === undefined ? [] : (sees(game.level, "tactics") ? compactView : boardView)(game.facts, game.turn)),
|
|
72
|
-
...(game.book === undefined ? [] : [`Book moves, most named lines first: ${game.book.join(", ")}`]),
|
|
73
|
-
...(game.plan === undefined ? [] : [`Plan: ${game.plan}`]),
|
|
74
|
-
...(game.thought === undefined ? [] : [thoughtLine(game.thought, game.level)]),
|
|
75
|
-
...moodLines(game),
|
|
76
|
-
...(game.helps === "on" ? [helpsLine] : game.helps === "off now" ? [helpsOffLine] : []),
|
|
77
|
-
];
|
|
78
|
-
}
|
|
79
|
-
/** The helps turned on: the AI may teach as the analyst does (D-62, D-78), never playing for the player. */
|
|
80
|
-
const helpsLine = "Helps on: the player wants to learn. Tell your intentions, never their best move; after their move judge it when it stands out (ai_move's badge "
|
|
81
|
-
+ `and note), draw arrows and squares to show what you say, and write up to ${talkLimits.aiHelps} characters.`;
|
|
82
|
-
/** The helps turned off during a game: what the AI said and drew before no longer holds (Priya, round of D-78). */
|
|
83
|
-
const helpsOffLine = `Helps off now: play as at a tournament again: no intentions, badges or arrows, comments of ${talkLimits.ai} characters at most.`;
|
|
84
|
-
/** Whether the AI judged or drew on a move of this game, which only the helps allow: a sign they were on. */
|
|
85
|
-
function judgedBefore(current) {
|
|
86
|
-
return current.game.record.moves.some((move) => /\[%(badge|review|cal|csl) /.test(move.comment ?? ""));
|
|
87
|
-
}
|
|
88
|
-
/** The head of a view: where the game stands, the last move unless the lines before named it, the opening, the material as the player sees it, and the FEN. */
|
|
89
|
-
export function headLines(game, withLastMove = true) {
|
|
90
|
-
return [
|
|
91
|
-
whereLine(game),
|
|
92
|
-
...offerLines(game),
|
|
93
|
-
...(withLastMove && game.lastMove !== undefined ? [`Last move: ${lastMoveText(game.lastMove)}.`] : []),
|
|
94
|
-
...(game.opening === undefined ? [] : [`Opening: ${game.opening}`]),
|
|
95
|
-
`Material: ${materialText(materialOf(game.fen))}`,
|
|
96
|
-
...clockLines(game),
|
|
97
|
-
`FEN: ${game.fen}`,
|
|
98
|
-
];
|
|
99
|
-
}
|
|
100
|
-
/** The last move, as the player is shown it, with its squares: 4.♞g5 (f3-g5). */
|
|
101
|
-
export function lastMoveText({ move, from, to }) {
|
|
102
|
-
return `${shownMove(move)} (${from}-${to})`;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* A numbered move as the player is shown it, with the pieces' figurines (D-86): the form alone, without the SAN, which the AI copied into its message
|
|
106
|
-
* (Priya, test of D-86): 4.Ng5 is 4.♞g5.
|
|
107
|
-
*/
|
|
108
|
-
export function shownMove(move) {
|
|
109
|
-
const [, number = "", san = move] = /^(\d+\.+)(.+)$/.exec(move) ?? [];
|
|
110
|
-
return `${number}${figurinesOf(san)}`;
|
|
111
|
-
}
|
|
112
|
-
/** The player's speech, from the page's settings or the system's language; undefined in English, which the AI speaks unless told. */
|
|
113
|
-
export function speechOf(folder, systemLanguage) {
|
|
114
|
-
const language = languageName(languageIn(folder, systemLanguage));
|
|
115
|
-
return language === undefined ? undefined : { language };
|
|
116
|
-
}
|
|
117
|
-
/** What the AI is told of the player's speech once a chat (Priya, retest of T-54); the moves are SAN in every language (D-87). */
|
|
118
|
-
export function speechLine({ language }) {
|
|
119
|
-
return `The player speaks ${language}.`;
|
|
120
|
-
}
|
|
121
|
-
/** The lines after a move, which the line before named: its note, where the game stands, a warning. closingLines end them. */
|
|
122
|
-
export function moveLines({ note, game, warning }) {
|
|
123
|
-
return [...(note === undefined ? [] : [`Note: ${note}`]), ...positionLines(game, false), ...(warning === undefined ? [] : [warning])];
|
|
124
|
-
}
|
|
125
|
-
/** The last lines of a tool's answer: the player's words from the board page, then the next step, which stays the last line. */
|
|
126
|
-
export function closingLines(game, words = []) {
|
|
127
|
-
return [...wordLines(words), nextStep(game, words)];
|
|
128
|
-
}
|
|
129
|
-
/** The player's words from the board page, one line each: lines they broke are joined, so no line of theirs reads as one of Chesspal's. */
|
|
130
|
-
export function wordLines(words) {
|
|
131
|
-
return words.map((text) => `Player wrote on the board page: «${text.replace(/\s+/g, " ")}»`);
|
|
132
|
-
}
|
|
133
|
-
/** What the AI does next: the one line every host reads, even where the server's instructions are not shown. Words of the player's ask for an answer. */
|
|
134
|
-
export function nextStep(game, words = []) {
|
|
135
|
-
if (game === undefined) {
|
|
136
|
-
return words.length === 0 ? `Next: when the player wants a game, ${newGameStep}` : `Next: answer the player with ai_say. When they want a game, ${newGameStep}`;
|
|
137
|
-
}
|
|
138
|
-
if (game.end !== undefined) {
|
|
139
|
-
return words.length === 0
|
|
140
|
-
? "Next: tell the player how the game ended, with ai_say and how you feel as its mood if they play on the board page; then offer them, in words, another game or "
|
|
141
|
-
+ "to go over this one "
|
|
142
|
-
+ `(analyse_game). For another, ${newGameStep}`
|
|
143
|
-
: `Next: answer the player with ai_say. When they want another game, ${newGameStep}`;
|
|
144
|
-
}
|
|
145
|
-
if (game.turn === game.ai && game.clock?.waiting === true) {
|
|
146
|
-
return "Next: don't move yet: the player starts the game with Start on the board page, and the doorbell wakes you then. End your turn.";
|
|
147
|
-
}
|
|
148
|
-
if (game.turn === game.ai) {
|
|
149
|
-
return words.length === 0
|
|
150
|
-
? "Next: choose your move, then call ai_move with it, your plan and any comment."
|
|
151
|
-
: "Next: choose your move, then call ai_move with it, your plan and a comment that answers the player.";
|
|
152
|
-
}
|
|
153
|
-
if (game.drawOffer === "player") {
|
|
154
|
-
return "Next: accept the draw with end_game draw_agreed, or answer with ai_say and wait for the player's move.";
|
|
155
|
-
}
|
|
156
|
-
return words.length === 0 ? "Next: wait for the player's move, then call player_move with it." : "Next: answer the player with ai_say, then wait for their move.";
|
|
157
|
-
}
|
|
158
|
-
/** How a new game starts: the player chooses it in the board page's window, which new_game without choices opens; in the chat only where there is no page (D-85). */
|
|
159
|
-
export const newGameStep = "call new_game without choices: it opens the board page's New game window, where the player chooses the colour, the clock and the "
|
|
160
|
-
+ "level; where there is no board page, it tells you to ask them in the chat.";
|
|
161
|
-
/** Who plays what, from the AI's side. */
|
|
162
|
-
export function sidesLine(ai) {
|
|
163
|
-
return `you play ${colourName(ai)}, the player ${colourName(ai === "white" ? "black" : "white")}`;
|
|
164
|
-
}
|
|
165
|
-
/** What the AI gets when it is to move: the facts its level sees (D-60), and its plan. */
|
|
166
|
-
function addAiFacts(summary, { game }) {
|
|
167
|
-
const plan = currentPlan(game.record);
|
|
168
|
-
summary.facts = game.facts;
|
|
169
|
-
if (sees(summary.level, "theory")) {
|
|
170
|
-
const book = knownMoves(summary.fen);
|
|
171
|
-
if (book.length > 0) {
|
|
172
|
-
summary.book = book;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (plan !== undefined) {
|
|
176
|
-
summary.plan = plan;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
/** The draw offer that stands, and how to answer it or what becomes of it (D-65). */
|
|
180
|
-
function offerLines({ drawOffer, turn, ai }) {
|
|
181
|
-
if (drawOffer === "ai") {
|
|
182
|
-
return ["Your draw offer stands until the player moves; if they accept it in the chat, end_game draw_agreed ends the game."];
|
|
183
|
-
}
|
|
184
|
-
if (drawOffer === "player") {
|
|
185
|
-
return [turn === ai ? "The player offers a draw: end_game draw_agreed accepts it; your move declines it." : "The player offers a draw before their move; your next move declines it."];
|
|
186
|
-
}
|
|
187
|
-
return [];
|
|
188
|
-
}
|
|
189
|
-
/** What the AI thought on the player's time, saying by which model and that Chesspal checked only that it is legal: the facts do not cover every blunder (Anatolij, round of T-109). */
|
|
190
|
-
function thoughtLine({ move, why }, level) {
|
|
191
|
-
return `Thought on their time ${onQuickModel(level) ? "by a quicker model" : "by your model"} (legal, not checked): ${move}, ${why}`;
|
|
192
|
-
}
|
|
193
|
-
/** The AI's mood while it lasts, and how long its face shows it (D-70). */
|
|
194
|
-
function moodLines({ mood }) {
|
|
195
|
-
if (mood === undefined) {
|
|
196
|
-
return [];
|
|
197
|
-
}
|
|
198
|
-
const shown = mood.left === 0 ? "until your next move" : `for ${mood.left} more of your moves`;
|
|
199
|
-
return [`Your mood: ${mood.mood}, on your face ${shown}, then neutral by itself.`];
|
|
200
|
-
}
|
|
201
|
-
/** Who is to move, or how the game ended. */
|
|
202
|
-
function clockLines(game) {
|
|
203
|
-
return game.clock === undefined ? [] : [clockLine(game.clock, game.ai)];
|
|
204
|
-
}
|
|
205
|
-
function whereLine(game) {
|
|
206
|
-
if (game.end !== undefined) {
|
|
207
|
-
const archived = game.end.archive === undefined ? "" : ` Archived in ${game.end.archive}.`;
|
|
208
|
-
return `Game over: ${endText(game.end)}.${archived}`;
|
|
209
|
-
}
|
|
210
|
-
return `${game.turn === game.ai ? "You" : "Player"} (${colourName(game.turn)}) to move, move ${game.moveNumber}.`;
|
|
211
|
-
}
|
|
212
|
-
function endText({ result, termination }) {
|
|
65
|
+
/** How a game ended, in words: its result, and how it came when known. */
|
|
66
|
+
export function endText({ result, termination }) {
|
|
213
67
|
return termination === undefined ? result : `${result}, ${termination}`;
|
|
214
68
|
}
|
|
215
69
|
/** The last plies of a record, numbered as a player writes them, from the move number and side of its FEN. */
|
|
216
|
-
function lastMoves(record, count) {
|
|
70
|
+
export function lastMoves(record, count) {
|
|
217
71
|
const [, turn, , , , number] = (record.tags.FEN ?? "").split(" ");
|
|
218
72
|
const startNumber = Number(number) || 1;
|
|
219
73
|
// The ply count from white's move of the first move number: 1 when black moves first.
|
|
@@ -228,12 +82,21 @@ function lastMoves(record, count) {
|
|
|
228
82
|
return index === 0 ? `${moveNumber}...${move.san}` : move.san;
|
|
229
83
|
}).join(" ");
|
|
230
84
|
}
|
|
231
|
-
/**
|
|
232
|
-
function
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
85
|
+
/** Whether the AI judged or drew on a move of this game, which only the helps allow: a sign they were on. */
|
|
86
|
+
function judgedBefore(current) {
|
|
87
|
+
return current.game.record.moves.some((move) => /\[%(badge|review|cal|csl) /.test(move.comment ?? ""));
|
|
88
|
+
}
|
|
89
|
+
/** What the AI gets when it is to move: the facts its level sees (D-60), and its plan. */
|
|
90
|
+
function addAiFacts(summary, { game }) {
|
|
91
|
+
const plan = currentPlan(game.record);
|
|
92
|
+
summary.facts = game.facts;
|
|
93
|
+
if (sees(summary.level, "theory")) {
|
|
94
|
+
const book = knownMoves(summary.fen);
|
|
95
|
+
if (book.length > 0) {
|
|
96
|
+
summary.book = book;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (plan !== undefined) {
|
|
100
|
+
summary.plan = plan;
|
|
236
101
|
}
|
|
237
|
-
const name = new Intl.DisplayNames(["en"], { type: "language" }).of(code);
|
|
238
|
-
return name === undefined || name === code ? undefined : name;
|
|
239
102
|
}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
1
|
import type { AnyCommand } from "./registry.ts";
|
|
2
|
+
export { aiMove } from "./ai-move.ts";
|
|
3
|
+
export { analyseGame } from "./analyse-game.ts";
|
|
4
|
+
export { gameAt } from "./clock.ts";
|
|
5
|
+
export { type Caller, type Context, defaultContext, type SeenPosition } from "./context.ts";
|
|
6
|
+
export { deleteGame } from "./delete-game.ts";
|
|
7
|
+
export { deleteReview } from "./delete-review.ts";
|
|
8
|
+
export { answerDraw, DrawRefused, offerDraw } from "./draw-offer.ts";
|
|
9
|
+
export { endGame } from "./end-game.ts";
|
|
10
|
+
export { ChatNotClear, newGame, startNewGame } from "./new-game.ts";
|
|
11
|
+
export { bookOpening, bookPlies } from "./opening-book.ts";
|
|
12
|
+
export { playMove, PositionChanged, positionIn, samePosition } from "./play-move.ts";
|
|
13
|
+
export { chooseDrawnAvatar, GameGoingOn, newProfile, setAccounts, useProfile } from "./profiles.ts";
|
|
14
|
+
export { type AnyCommand, baseType, type Command, commandLineFieldProblem, inputProblems, isBoolean, isList, takesNumbers } from "./registry.ts";
|
|
15
|
+
export { say } from "./say.ts";
|
|
16
|
+
export { gameToStudy, namedGame } from "./study.ts";
|
|
2
17
|
/** Every command of Chesspal, in the order the command line lists them and the MCP server offers them. */
|
|
3
18
|
export declare const commands: AnyCommand[];
|
package/dist/commands/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
// The commands: the only way the AI, the command line and the page change a game (D-5, D-27), each defined once in the file named as its tool.
|
|
1
2
|
import { aiMove } from "./ai-move.js";
|
|
2
3
|
import { aiSay } from "./ai-say.js";
|
|
3
4
|
import { analyseGame } from "./analyse-game.js";
|
|
4
5
|
import { annotateGame } from "./annotate-game.js";
|
|
6
|
+
import { coach } from "./coach.js";
|
|
7
|
+
import { deleteGame } from "./delete-game.js";
|
|
8
|
+
import { deleteReview } from "./delete-review.js";
|
|
5
9
|
import { endGame } from "./end-game.js";
|
|
6
10
|
import { exportGame } from "./export-game.js";
|
|
7
11
|
import { init } from "./init.js";
|
|
@@ -12,8 +16,49 @@ import { playerMove } from "./player-move.js";
|
|
|
12
16
|
import { playerSay } from "./player-say.js";
|
|
13
17
|
import { ponder } from "./ponder.js";
|
|
14
18
|
import { position } from "./position.js";
|
|
15
|
-
import { newProfile, profiles, setAvatar, useProfile } from "./profiles.js";
|
|
19
|
+
import { newProfile, profiles, setAccounts, setAvatar, useProfile } from "./profiles.js";
|
|
16
20
|
import { status } from "./status.js";
|
|
17
21
|
import { studyGames } from "./study-games.js";
|
|
22
|
+
// What the server and the command line use besides the list: the context, the reading of an input, and the operations the page shares with the tools.
|
|
23
|
+
export { aiMove } from "./ai-move.js";
|
|
24
|
+
export { analyseGame } from "./analyse-game.js";
|
|
25
|
+
export { gameAt } from "./clock.js";
|
|
26
|
+
export { defaultContext } from "./context.js";
|
|
27
|
+
export { deleteGame } from "./delete-game.js";
|
|
28
|
+
export { deleteReview } from "./delete-review.js";
|
|
29
|
+
export { answerDraw, DrawRefused, offerDraw } from "./draw-offer.js";
|
|
30
|
+
export { endGame } from "./end-game.js";
|
|
31
|
+
export { ChatNotClear, newGame, startNewGame } from "./new-game.js";
|
|
32
|
+
export { bookOpening, bookPlies } from "./opening-book.js";
|
|
33
|
+
export { playMove, PositionChanged, positionIn, samePosition } from "./play-move.js";
|
|
34
|
+
export { chooseDrawnAvatar, GameGoingOn, newProfile, setAccounts, useProfile } from "./profiles.js";
|
|
35
|
+
export { baseType, commandLineFieldProblem, inputProblems, isBoolean, isList, takesNumbers } from "./registry.js";
|
|
36
|
+
export { say } from "./say.js";
|
|
37
|
+
export { gameToStudy, namedGame } from "./study.js";
|
|
18
38
|
/** Every command of Chesspal, in the order the command line lists them and the MCP server offers them. */
|
|
19
|
-
export const commands = [
|
|
39
|
+
export const commands = [
|
|
40
|
+
init,
|
|
41
|
+
status,
|
|
42
|
+
newGame,
|
|
43
|
+
playerMove,
|
|
44
|
+
playerSay,
|
|
45
|
+
aiMove,
|
|
46
|
+
aiSay,
|
|
47
|
+
ponder,
|
|
48
|
+
coach,
|
|
49
|
+
look,
|
|
50
|
+
position,
|
|
51
|
+
endGame,
|
|
52
|
+
exportGame,
|
|
53
|
+
pastGames,
|
|
54
|
+
analyseGame,
|
|
55
|
+
annotateGame,
|
|
56
|
+
studyGames,
|
|
57
|
+
deleteReview,
|
|
58
|
+
deleteGame,
|
|
59
|
+
profiles,
|
|
60
|
+
newProfile,
|
|
61
|
+
useProfile,
|
|
62
|
+
setAvatar,
|
|
63
|
+
setAccounts,
|
|
64
|
+
];
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
/** The player's folder set up for the AI hosts
|
|
2
|
+
/** The player's folder set up for the AI hosts: the folder, and the files written there. */
|
|
3
3
|
interface FolderSetUp {
|
|
4
4
|
folder: string;
|
|
5
5
|
written: string[];
|
|
6
|
-
/** The folder as the player goes into it from where init ran, when it is not that one
|
|
6
|
+
/** The folder as the player goes into it from where init ran, when it is not that one: chess. */
|
|
7
7
|
enter?: string;
|
|
8
|
-
/** Codex's hooks changed in a folder that had them: Codex runs them only once
|
|
8
|
+
/** Codex's hooks changed in a folder that had them: Codex runs them only once the player trusts them again. */
|
|
9
9
|
hooksChanged?: true;
|
|
10
10
|
}
|
|
11
11
|
/** Makes a folder the player's chess table: the files through which Claude Code and Codex find Chesspal and the opponent's instructions (D-31). */
|
package/dist/commands/init.js
CHANGED
|
@@ -46,10 +46,10 @@ const english = {
|
|
|
46
46
|
toPlay: "To play:",
|
|
47
47
|
open: (enter) => enter === undefined ? ["Open Claude Code or Codex in this folder."] : [`Go into the folder: cd ${enter}`, "then open Claude Code (claude) or Codex (codex)."],
|
|
48
48
|
steps: [
|
|
49
|
-
["The first time, it asks whether to trust the folder: say yes.", "
|
|
49
|
+
["The first time, it asks whether to trust the folder: say yes.", "Codex also asks about Chesspal's two hooks: choose Trust all.", "They are small helpers that let it notice your moves on the board."],
|
|
50
50
|
["Say hello: the AI gives you the link to the board."],
|
|
51
51
|
],
|
|
52
|
-
hooksChanged: "Chesspal's hooks for Codex have changed:
|
|
52
|
+
hooksChanged: "Chesspal's hooks for Codex have changed: when Codex asks about them, choose Trust all again.",
|
|
53
53
|
updated: (count) => `Updated ${count} ${count === 1 ? "file" : "files"}.`,
|
|
54
54
|
};
|
|
55
55
|
const italian = {
|
|
@@ -58,10 +58,10 @@ const italian = {
|
|
|
58
58
|
toPlay: "Per giocare:",
|
|
59
59
|
open: (enter) => enter === undefined ? ["Apri Claude Code o Codex in questa cartella."] : [`Entra nella cartella: cd ${enter}`, "poi apri Claude Code (claude) o Codex (codex)."],
|
|
60
60
|
steps: [
|
|
61
|
-
["La prima volta ti chiede se fidarti della cartella: rispondi sì.", "
|
|
61
|
+
["La prima volta ti chiede se fidarti della cartella: rispondi sì.", "Codex chiede anche dei due «hook» di Chesspal: scegli Trust all.", "Sono piccoli aiuti che gli fanno vedere le tue mosse sulla scacchiera."],
|
|
62
62
|
["Saluta: l'AI ti dà il link della scacchiera."],
|
|
63
63
|
],
|
|
64
|
-
hooksChanged: "Gli «hook» di Chesspal per Codex sono cambiati:
|
|
64
|
+
hooksChanged: "Gli «hook» di Chesspal per Codex sono cambiati: quando Codex te lo chiede, scegli di nuovo Trust all.",
|
|
65
65
|
updated: (count) => count === 1 ? "Aggiornato 1 file." : `Aggiornati ${count} file.`,
|
|
66
66
|
};
|
|
67
67
|
function wordsFor(language) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type Lead } from "../core/index.ts";
|
|
3
|
+
/** A lead as its input reads it: pawns from White's side as a number, +1.5 or -3, or a mate it sees, "#3" White's or "#-3" Black's. */
|
|
4
|
+
export declare const leadInput: z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>;
|
|
5
|
+
/** Who is ahead in words, the side and by how much, so that the AI reads its own sign back (Anatolij). */
|
|
6
|
+
export declare function aheadWords(lead: Lead): string;
|
|
7
|
+
/** The lead an input gave, checked by leadInput. */
|
|
8
|
+
export declare function leadFrom(value: number | string): Lead;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Who is ahead as the AI gives it (D-90): the analyst after each move of a game over, the coach in the position the player is to move in.
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { readLead } from "../core/index.js";
|
|
4
|
+
/** A lead as its input reads it: pawns from White's side as a number, +1.5 or -3, or a mate it sees, "#3" White's or "#-3" Black's. */
|
|
5
|
+
export const leadInput = z.union([z.number(), z.string()]).refine((value) => readLead(String(value)) !== undefined, 'who is ahead is a number of pawns from White\'s side, 1.5 or -3, or a mate you see in moves of the side that mates, "#3" for White\'s or "#-3" for Black\'s, '
|
|
6
|
+
+ "up to 99");
|
|
7
|
+
/** Who is ahead in words, the side and by how much, so that the AI reads its own sign back (Anatolij). */
|
|
8
|
+
export function aheadWords(lead) {
|
|
9
|
+
if ("mate" in lead) {
|
|
10
|
+
return `${lead.mate > 0 ? "White" : "Black"} mates in ${Math.abs(lead.mate)}`;
|
|
11
|
+
}
|
|
12
|
+
return lead.pawns === 0 ? "even" : `${lead.pawns > 0 ? "White" : "Black"} ahead by ${Math.abs(lead.pawns)}`;
|
|
13
|
+
}
|
|
14
|
+
/** The lead an input gave, checked by leadInput. */
|
|
15
|
+
export function leadFrom(value) {
|
|
16
|
+
const lead = readLead(String(value));
|
|
17
|
+
if (lead === undefined) {
|
|
18
|
+
throw new Error(`${value} is not who is ahead: give a number of pawns from White's side, 1.5 or -3, or a mate you see, "#3" or "#-3". Nothing changed.`);
|
|
19
|
+
}
|
|
20
|
+
return lead;
|
|
21
|
+
}
|
package/dist/commands/look.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { boardText, materialOf } from "../core/index.js";
|
|
3
|
+
import { analystAgent } from "../host-files/index.js";
|
|
3
4
|
import { gameFolder } from "../profiles/index.js";
|
|
5
|
+
import { headLines, wordLines } from "./answer-lines.js";
|
|
4
6
|
import { gameAt } from "./clock.js";
|
|
5
|
-
import {
|
|
7
|
+
import { summaryOf } from "./game-summary.js";
|
|
6
8
|
import { refuseUnseen } from "./levels.js";
|
|
7
9
|
import { defineCommand } from "./registry.js";
|
|
8
10
|
import { newWords } from "./say.js";
|
|
@@ -20,6 +22,7 @@ export const look = defineCommand({
|
|
|
20
22
|
// Read only for the host: a flag that has fallen is written, as the time already decided.
|
|
21
23
|
readOnly: true,
|
|
22
24
|
idempotent: true,
|
|
25
|
+
sharedWith: [analystAgent],
|
|
23
26
|
run: ({ only, game, move }, context) => {
|
|
24
27
|
if (game !== undefined || move !== undefined) {
|
|
25
28
|
return studyLook(context, only, game, move);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { Context } from "./context.ts";
|
|
3
|
-
import { type GameSummary
|
|
3
|
+
import { type GameSummary } from "./game-summary.ts";
|
|
4
|
+
import { type Speech } from "./speech.ts";
|
|
4
5
|
interface NewGame {
|
|
5
6
|
game: GameSummary;
|
|
6
7
|
/** Where the game before went: one going on, unfinished; one over, when its archive could not be written at its end. */
|
|
@@ -64,6 +65,4 @@ export declare function startNewGame({ ai_colour: colour, from, clock, level: ch
|
|
|
64
65
|
export declare class ChatNotClear extends Error {
|
|
65
66
|
constructor();
|
|
66
67
|
}
|
|
67
|
-
/** From how many plies a game played in a chat asks for a clean one before the next (D-57): one left after a few moves does not. */
|
|
68
|
-
export declare const pliesBeforeClearing = 20;
|
|
69
68
|
export {};
|
|
@@ -2,14 +2,17 @@ import { z } from "zod";
|
|
|
2
2
|
import { aiLevels, Game, levelTag, pgnDate, readPgn, startClock, timeControlOf, timeControlTag, withoutMoods } from "../core/index.js";
|
|
3
3
|
import { archivedName, archiveGame, cleanSince, endAnalysis, endOf, endTableTalk, lastChatStart, loadGame, saveGame, startOfNewGame, withoutPlans } from "../games/index.js";
|
|
4
4
|
import { gameFolder, gameFolders } from "../profiles/index.js";
|
|
5
|
+
import { coachRuns } from "./agents.js";
|
|
6
|
+
import { nextStep, positionLines, sidesLine } from "./answer-lines.js";
|
|
5
7
|
import { gameAt } from "./clock.js";
|
|
6
|
-
import {
|
|
8
|
+
import { summaryOf, withThought } from "./game-summary.js";
|
|
7
9
|
import { levelText, levelToPlay } from "./levels.js";
|
|
8
10
|
import { closedPage, pageGiven, pageLine } from "./page-link.js";
|
|
9
11
|
import { pastGameLines } from "./past-games.js";
|
|
10
12
|
import { refuseUnseenPosition } from "./play-move.js";
|
|
11
13
|
import { playerLine } from "./profiles.js";
|
|
12
14
|
import { defineCommand } from "./registry.js";
|
|
15
|
+
import { speechLine, speechOf } from "./speech.js";
|
|
13
16
|
const newGameInput = z.object({
|
|
14
17
|
ai_colour: z.enum(["white", "black", "random"]).optional().describe("the colour you play: random draws it; left out with the rest, the page's window asks"),
|
|
15
18
|
from: z.string().optional().describe("a FEN or a PGN to go on from, instead of the standard position"),
|
|
@@ -86,7 +89,7 @@ export function startNewGame({ ai_colour: colour, from, clock, level: chosen, re
|
|
|
86
89
|
pageGiven(context, current.started);
|
|
87
90
|
}
|
|
88
91
|
return {
|
|
89
|
-
game: withThought(summaryOf(current, now), folder, current),
|
|
92
|
+
game: withThought(summaryOf(current, now), folder, current, coachRuns(context)),
|
|
90
93
|
...(archived === undefined ? {} : { archived: { name: archived, finished: going === undefined } }),
|
|
91
94
|
past,
|
|
92
95
|
...(player === undefined ? {} : { player }),
|
|
@@ -140,12 +143,12 @@ export class ChatNotClear extends Error {
|
|
|
140
143
|
/** How many of the last games new_game recalls. */
|
|
141
144
|
const remembered = 3;
|
|
142
145
|
/** From how many plies a game played in a chat asks for a clean one before the next (D-57): one left after a few moves does not. */
|
|
143
|
-
|
|
146
|
+
const pliesBeforeClearing = 20;
|
|
144
147
|
// A FEN's board: eight ranks of pieces and empty counts.
|
|
145
148
|
const fenPattern = /^[pnbrqkPNBRQK1-8]+(?:\/[pnbrqkPNBRQK1-8]+){7}(?:\s|$)/;
|
|
146
149
|
/**
|
|
147
150
|
* Whether the chat must be cleared first: the last game begun, in any profile, was played in it at some length, and the host says how chats start (the hook
|
|
148
|
-
* of Claude Code and Codex
|
|
151
|
+
* of Claude Code and Codex). Another profile does not clear the chat (D-66), nor a game another chat played, which this one was never shown (D-71).
|
|
149
152
|
*/
|
|
150
153
|
function chatToClear(context) {
|
|
151
154
|
const start = lastChatStart(context.folder);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Context } from "./context.ts";
|
|
1
|
+
import type { Context, SeenPosition } from "./context.ts";
|
|
3
2
|
import { type MovePlayed } from "./game-summary.ts";
|
|
4
3
|
/** Who plays a move: the AI, or the player through the AI. */
|
|
5
4
|
export type Mover = "ai" | "player";
|
|
6
|
-
/** What comes with a move: the AI's comment, or the player's words from the board page, saved with it
|
|
5
|
+
/** What comes with a move: the AI's comment, or the player's words from the board page, saved with it, and a draw offer (D-65). */
|
|
7
6
|
export interface WithMove {
|
|
8
7
|
comment?: string;
|
|
9
8
|
offerDraw?: boolean;
|
|
@@ -13,28 +12,20 @@ export interface WithMove {
|
|
|
13
12
|
};
|
|
14
13
|
/** Milliseconds of the mover's turn that were not theirs, not taken off their clock (D-36). */
|
|
15
14
|
allowance?: number;
|
|
16
|
-
/**
|
|
17
|
-
|
|
15
|
+
/** A coach judges the player's moves with the helps on (D-88): the AI reads it after the player's move. */
|
|
16
|
+
coached?: boolean;
|
|
18
17
|
}
|
|
19
18
|
/**
|
|
20
19
|
* Plays a move for one side `now` and saves the game, with the time it took and the clock after it in its comment ([%clk]). A refused move, or words refused
|
|
21
20
|
* with it, change nothing: it throws the message `refused` writes from the core's.
|
|
22
21
|
*/
|
|
23
|
-
export declare function playMove(folder: string, now: Date, mover: Mover, text: string, refused: (message: string, legal: readonly string[]) => string, { comment, said, offerDraw, allowance,
|
|
24
|
-
/**
|
|
25
|
-
* Where the game a chat sees stands: the game by its start, none when there is none, and how many plies it has. Not by its folder, which a profile
|
|
26
|
-
* completed renames (D-71); a game in another profile started at another time.
|
|
27
|
-
*/
|
|
28
|
-
export interface Position {
|
|
29
|
-
readonly started?: string;
|
|
30
|
-
readonly plies: number;
|
|
31
|
-
}
|
|
22
|
+
export declare function playMove(folder: string, now: Date, mover: Mover, text: string, refused: (message: string, legal: readonly string[]) => string, { comment, said, offerDraw, allowance, coached }?: WithMove): MovePlayed;
|
|
32
23
|
/** A chat's move, resignation or game replaced on a position it has not seen (D-71): it was decided on another. */
|
|
33
24
|
export declare class PositionChanged extends Error {
|
|
34
25
|
constructor();
|
|
35
26
|
}
|
|
36
27
|
/** The position of the profile's game now. */
|
|
37
|
-
export declare function positionIn(folder: string):
|
|
28
|
+
export declare function positionIn(folder: string): SeenPosition;
|
|
38
29
|
/**
|
|
39
30
|
* Refuses a chat's move or ending on a position it has not seen, changed by another chat or on the board page, or before any tool showed it the game
|
|
40
31
|
* (D-71). Words and the clock change no position; the command line and the page, which have no chat, are never refused.
|
|
@@ -42,3 +33,5 @@ export declare function positionIn(folder: string): Position;
|
|
|
42
33
|
export declare function refuseUnseenPosition(context: Context, folder: string): void;
|
|
43
34
|
/** Refuses a chat's words on a game it has not seen, which another chat or the page started: words on a later move of the same game do no harm. */
|
|
44
35
|
export declare function refuseOtherGame(context: Context, folder: string): void;
|
|
36
|
+
/** Whether two positions a chat may see are the same: the same game, as many plies. */
|
|
37
|
+
export declare function samePosition(one: SeenPosition, other: SeenPosition): boolean;
|