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/server/page/page.js
CHANGED
|
@@ -8,7 +8,7 @@ import { aiNameOf } from "../../core/index.js";
|
|
|
8
8
|
import { gameStamp, tableTalkStamp } from "../../games/index.js";
|
|
9
9
|
import { outdatedHostFiles } from "../../host-files/index.js";
|
|
10
10
|
import { gameFolder } from "../../profiles/index.js";
|
|
11
|
-
import { Bell, bellProbe, pagePorts } from "../bell.js";
|
|
11
|
+
import { Bell, bellProbe, pagePorts } from "../bell/index.js";
|
|
12
12
|
import { analysesOf, answerAnalyses } from "./analyses.js";
|
|
13
13
|
import { answerChat } from "./attach.js";
|
|
14
14
|
import { attachedSeen, chatSeenOf, pageContext } from "./chat.js";
|
|
@@ -17,7 +17,8 @@ import { sendFile, sendHtml } from "./files.js";
|
|
|
17
17
|
import { answerGame, chatCalls } from "./game.js";
|
|
18
18
|
import { json, send } from "./http.js";
|
|
19
19
|
import { answerProfiles, readRatingsOf } from "./profiles.js";
|
|
20
|
-
import { answerTable } from "./table.js";
|
|
20
|
+
import { answerTable, restartWhenAtRest, updateWhenAtRest } from "./table.js";
|
|
21
|
+
import { watchForUpdates } from "./update.js";
|
|
21
22
|
/**
|
|
22
23
|
* 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
|
|
23
24
|
* table's on its own ports alone, which keep two tables apart. The page reads the chat from the context in the chat's process, and on the table from
|
|
@@ -33,7 +34,12 @@ export async function startPage(context, options = {}) {
|
|
|
33
34
|
context: pageContext(context),
|
|
34
35
|
chat,
|
|
35
36
|
opponent: options.opponent ?? (() => aiNameOf(chat.host())),
|
|
36
|
-
|
|
37
|
+
// A start again asked while the chat was at work comes once it has ended its answer (D-107), as an update installed meanwhile (D-108).
|
|
38
|
+
bell: new Bell(() => hasNews(context, chat), () => {
|
|
39
|
+
restartWhenAtRest(served);
|
|
40
|
+
updateWhenAtRest(served);
|
|
41
|
+
tellWatchers(watchers);
|
|
42
|
+
}),
|
|
37
43
|
watchers,
|
|
38
44
|
port: 0,
|
|
39
45
|
outdated: outdatedHostFiles(folder, context.platform).length > 0,
|
|
@@ -45,7 +51,12 @@ export async function startPage(context, options = {}) {
|
|
|
45
51
|
if (await listened(server, port)) {
|
|
46
52
|
server.unref();
|
|
47
53
|
served.port = portOf(server);
|
|
48
|
-
const
|
|
54
|
+
const stopWatchingGame = watchGame(served);
|
|
55
|
+
const stopAskingNpm = watchForUpdates(served);
|
|
56
|
+
const stopWatching = () => {
|
|
57
|
+
stopWatchingGame();
|
|
58
|
+
stopAskingNpm();
|
|
59
|
+
};
|
|
49
60
|
return {
|
|
50
61
|
url: `http://127.0.0.1:${served.port}/`,
|
|
51
62
|
heard: () => tellWatchers(watchers),
|
|
@@ -77,6 +88,7 @@ export function chatHasRead(context, showed) {
|
|
|
77
88
|
catch {
|
|
78
89
|
context.positionSeen = null;
|
|
79
90
|
}
|
|
91
|
+
context.positionFirstSeen ??= context.positionSeen ?? undefined;
|
|
80
92
|
// The chat on another position may now be thinking on its move: the page hears it, which no file tells when no bell woke the chat.
|
|
81
93
|
if (!sameSeen(before, context.positionSeen)) {
|
|
82
94
|
context.heard?.();
|
|
@@ -183,6 +195,8 @@ function watchGame(served) {
|
|
|
183
195
|
waiting = undefined;
|
|
184
196
|
watchAll();
|
|
185
197
|
tellWatchers(served.watchers);
|
|
198
|
+
// A game that has ended lets an update installed meanwhile start the table again (D-108).
|
|
199
|
+
updateWhenAtRest(served);
|
|
186
200
|
}, 30);
|
|
187
201
|
}
|
|
188
202
|
};
|
|
@@ -9,31 +9,56 @@ export interface ChatHost {
|
|
|
9
9
|
readonly command: string;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* How the table opens a chat: the hosts it offers, and a terminal with one of them, whether one opened;
|
|
13
|
-
* and how it is asked to start it again.
|
|
12
|
+
* How the table opens a chat: the hosts it offers, and a terminal with one of them, whether one opened; the chat `chesspal play` holds in a folder, with
|
|
13
|
+
* the model and effort it started with, and how it is asked to start it again.
|
|
14
14
|
*/
|
|
15
15
|
export interface TableChats {
|
|
16
16
|
hosts(): readonly ChatHost[];
|
|
17
17
|
open(host: string): Promise<boolean>;
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
held(folder: string): HeldChat | undefined;
|
|
19
|
+
/** Asks for the chat again: with another host, or `updated`, from the Chesspal just installed (D-108). */
|
|
20
|
+
relaunch(folder: string, host?: string, updated?: boolean): boolean;
|
|
20
21
|
}
|
|
21
|
-
/**
|
|
22
|
-
export
|
|
23
|
-
|
|
22
|
+
/** The chat `chesspal play` holds: the model and effort its host started with, none for the host's own. */
|
|
23
|
+
export interface HeldChat {
|
|
24
|
+
readonly model?: string | undefined;
|
|
25
|
+
readonly effort?: string | undefined;
|
|
26
|
+
}
|
|
27
|
+
/** A chat opening at the table: one the page asked for, the one started again for a new game, or with another model or host (D-107). */
|
|
28
|
+
export type Opening = "chat" | "again" | "restart";
|
|
29
|
+
/** What the table's page shows of its chat (D-104, D-107). */
|
|
30
|
+
export interface TableShown {
|
|
31
|
+
/** Whether a chat is at the table, and its host among those offered, when it says one. */
|
|
32
|
+
readonly chat: boolean;
|
|
33
|
+
readonly host?: string;
|
|
34
|
+
/** Whether `chesspal play` holds the chat, which the page can then start again; one opened by hand it cannot. With the model and effort it started with. */
|
|
35
|
+
readonly held: boolean;
|
|
36
|
+
readonly started?: HeldChat;
|
|
37
|
+
readonly hosts: readonly ChatHost[];
|
|
38
|
+
readonly opening?: Opening;
|
|
39
|
+
/** A start again asked while the chat was at work, waiting for it to end its answer, or to be started at once or let go from the page. */
|
|
40
|
+
readonly waiting?: true;
|
|
41
|
+
}
|
|
42
|
+
/** What the table's page shows of its chat: whether one is at the table, with which host, the hosts it can open one in, and one opening. */
|
|
24
43
|
export declare function tableShown(served: Served): {
|
|
25
|
-
table?:
|
|
26
|
-
chat: boolean;
|
|
27
|
-
hosts: readonly ChatHost[];
|
|
28
|
-
opening?: Opening;
|
|
29
|
-
};
|
|
44
|
+
table?: TableShown;
|
|
30
45
|
};
|
|
31
46
|
/** Answers the table's own routes, under /api/table/; false for any other, and for every request to a page a chat serves itself. */
|
|
32
47
|
export declare function answerTable(request: IncomingMessage, response: ServerResponse, url: URL, served: Served): boolean;
|
|
33
48
|
/**
|
|
34
49
|
* Whether a new game starts the chat at the table again, clean (D-57): `chesspal play` holds it, it waits for the bell, no analyst of it is at work, and it
|
|
35
|
-
* has seen a game; one that only greeted the player stays.
|
|
50
|
+
* has seen a game move since it was first shown one; one that only greeted the player stays, as one opened from the chat's window before a new game.
|
|
36
51
|
*/
|
|
37
52
|
export declare function chatToRelaunch(served: Served): boolean;
|
|
38
|
-
/**
|
|
39
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Asks `chesspal play` to start the chat at the table again: once the new game has started, or with another model or host in its place (D-107). Whether
|
|
55
|
+
* it was asked; the pages then show it opening.
|
|
56
|
+
*/
|
|
57
|
+
export declare function relaunchChat(served: Served, how?: "again" | "restart", host?: string): boolean;
|
|
58
|
+
/** Starts the chat again as the page asked while it was at work, now that it has ended its answer; a chat gone meanwhile takes the request with it. */
|
|
59
|
+
export declare function restartWhenAtRest(served: Served): void;
|
|
60
|
+
/**
|
|
61
|
+
* Once npm has installed the newer Chesspal (D-108), and no game goes on and the chat is at rest, as a game or a chat may have started while npm worked:
|
|
62
|
+
* the chat `chesspal play` holds starts again from it, clean, and once it has left the table, the table closes to start again from it too.
|
|
63
|
+
*/
|
|
64
|
+
export declare function updateWhenAtRest(served: Served): void;
|
|
@@ -1,15 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import { gameAt, samePosition } from "../../commands/index.js";
|
|
3
|
+
import { endOf, gameInAnalysis } from "../../games/index.js";
|
|
2
4
|
import { gameFolder } from "../../profiles/index.js";
|
|
3
5
|
import { tellWatchers } from "./events.js";
|
|
4
6
|
import { bodyOf, isJson, jsonOf, runRoute, sendJson } from "./http.js";
|
|
5
|
-
/** What the table's page shows of its chat: whether one is at the table, the hosts it can open one in, and one opening. */
|
|
7
|
+
/** What the table's page shows of its chat: whether one is at the table, with which host, the hosts it can open one in, and one opening. */
|
|
6
8
|
export function tableShown(served) {
|
|
7
|
-
const { table } = served;
|
|
9
|
+
const { table, attached } = served;
|
|
8
10
|
if (table === undefined) {
|
|
9
11
|
return {};
|
|
10
12
|
}
|
|
13
|
+
const host = hostAtTable(served);
|
|
14
|
+
const held = heldChat(served);
|
|
11
15
|
const now = opening(served);
|
|
12
|
-
return {
|
|
16
|
+
return {
|
|
17
|
+
table: {
|
|
18
|
+
chat: attached !== undefined,
|
|
19
|
+
...(host === undefined ? {} : { host }),
|
|
20
|
+
held: held !== undefined,
|
|
21
|
+
...(held === undefined ? {} : { started: held }),
|
|
22
|
+
hosts: table.chats?.hosts() ?? [],
|
|
23
|
+
...(now === undefined ? {} : { opening: now }),
|
|
24
|
+
...(served.restartWanted === undefined ? {} : { waiting: true }),
|
|
25
|
+
},
|
|
26
|
+
};
|
|
13
27
|
}
|
|
14
28
|
/** Answers the table's own routes, under /api/table/; false for any other, and for every request to a page a chat serves itself. */
|
|
15
29
|
export function answerTable(request, response, url, served) {
|
|
@@ -25,30 +39,59 @@ export function answerTable(request, response, url, served) {
|
|
|
25
39
|
else if (path === "/api/table/chat") {
|
|
26
40
|
runRoute(response, () => openChat(request, response, served));
|
|
27
41
|
}
|
|
42
|
+
else if (path === "/api/table/restart") {
|
|
43
|
+
runRoute(response, () => restartChat(request, response, served));
|
|
44
|
+
}
|
|
45
|
+
else if (path === "/api/table/waiting") {
|
|
46
|
+
runRoute(response, () => endWaiting(request, response, served));
|
|
47
|
+
}
|
|
48
|
+
else if (path === "/api/table/update") {
|
|
49
|
+
runRoute(response, () => updateChesspal(request, response, served));
|
|
50
|
+
}
|
|
28
51
|
else {
|
|
29
|
-
sendJson(response, 404, {
|
|
52
|
+
sendJson(response, 404, {
|
|
53
|
+
error: `${path} is no route of the table's: it answers POST /api/table/chat, /api/table/restart, /api/table/waiting, /api/table/update and /api/table/quit.`,
|
|
54
|
+
});
|
|
30
55
|
}
|
|
31
56
|
return true;
|
|
32
57
|
}
|
|
33
58
|
/**
|
|
34
59
|
* Whether a new game starts the chat at the table again, clean (D-57): `chesspal play` holds it, it waits for the bell, no analyst of it is at work, and it
|
|
35
|
-
* has seen a game; one that only greeted the player stays.
|
|
60
|
+
* has seen a game move since it was first shown one; one that only greeted the player stays, as one opened from the chat's window before a new game.
|
|
36
61
|
*/
|
|
37
62
|
export function chatToRelaunch(served) {
|
|
38
|
-
const {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
return attached !== undefined && stopped && !analysing && served.chat.positionSeen?.started !== undefined && served.table?.chats?.holds(attached.chat.folder) === true;
|
|
63
|
+
const { positionSeen, positionFirstSeen } = served.chat;
|
|
64
|
+
const played = positionSeen?.started !== undefined && (positionFirstSeen === undefined || !samePosition(positionSeen, positionFirstSeen));
|
|
65
|
+
return played && heldChat(served) !== undefined && chatAtRest(served);
|
|
42
66
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Asks `chesspal play` to start the chat at the table again: once the new game has started, or with another model or host in its place (D-107). Whether
|
|
69
|
+
* it was asked; the pages then show it opening.
|
|
70
|
+
*/
|
|
71
|
+
export function relaunchChat(served, how = "again", host) {
|
|
45
72
|
const folder = served.attached?.chat.folder;
|
|
46
|
-
|
|
73
|
+
// Another host may first ask whether it trusts the table's folder: the pages say so, as for a chat opened.
|
|
74
|
+
const switching = how === "restart" && host !== undefined && host !== hostAtTable(served);
|
|
75
|
+
if (folder === undefined || served.table?.chats?.relaunch(folder, host) !== true) {
|
|
47
76
|
return false;
|
|
48
77
|
}
|
|
49
|
-
noteOpening(served, "
|
|
78
|
+
noteOpening(served, switching ? "chat" : how);
|
|
50
79
|
return true;
|
|
51
80
|
}
|
|
81
|
+
/** Starts the chat again as the page asked while it was at work, now that it has ended its answer; a chat gone meanwhile takes the request with it. */
|
|
82
|
+
export function restartWhenAtRest(served) {
|
|
83
|
+
const wanted = served.restartWanted;
|
|
84
|
+
if (wanted === undefined) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (heldChat(served) === undefined) {
|
|
88
|
+
served.restartWanted = undefined;
|
|
89
|
+
}
|
|
90
|
+
else if (chatAtRest(served)) {
|
|
91
|
+
served.restartWanted = undefined;
|
|
92
|
+
relaunchChat(served, "restart", wanted.host);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
52
95
|
// A terminal takes a few seconds to open and its chat to attach: a second click meanwhile would open a second chat, which serves a page of its own.
|
|
53
96
|
const openingFor = 30_000;
|
|
54
97
|
/**
|
|
@@ -56,13 +99,12 @@ const openingFor = 30_000;
|
|
|
56
99
|
* opening. Whether it opened; else the page shows the command to type.
|
|
57
100
|
*/
|
|
58
101
|
async function openChat(request, response, served) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (request.headers.origin !== `http://127.0.0.1:${served.port}` && request.headers.origin !== `http://localhost:${served.port}`) {
|
|
102
|
+
const offered = hostOffered(served, jsonOf(await bodyOf(request))?.host);
|
|
103
|
+
if (!fromTablePage(request, served)) {
|
|
62
104
|
sendJson(response, 403, { error: "Only the table's own page opens a chat." });
|
|
63
105
|
}
|
|
64
106
|
else if (offered === undefined || served.table?.chats === undefined) {
|
|
65
|
-
sendJson(response, 400, { error:
|
|
107
|
+
sendJson(response, 400, { error: hostsOffered(served) });
|
|
66
108
|
}
|
|
67
109
|
else if (served.attached !== undefined || opening(served) !== undefined) {
|
|
68
110
|
sendJson(response, 409, { error: "A chat is at the table, or opening: play there." });
|
|
@@ -77,6 +119,148 @@ async function openChat(request, response, served) {
|
|
|
77
119
|
tellWatchers(served.watchers);
|
|
78
120
|
}
|
|
79
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Starts the chat `chesspal play` holds again, clean, with the host the page names and the model and effort it keeps for it (D-107): at once when it is at
|
|
124
|
+
* rest, else once it has ended its answer. Asked by the table's own page alone; a chat opened by hand changes its model with /model.
|
|
125
|
+
*/
|
|
126
|
+
async function restartChat(request, response, served) {
|
|
127
|
+
const offered = hostOffered(served, jsonOf(await bodyOf(request))?.host);
|
|
128
|
+
if (!fromTablePage(request, served)) {
|
|
129
|
+
sendJson(response, 403, { error: "Only the table's own page starts the chat again." });
|
|
130
|
+
}
|
|
131
|
+
else if (offered === undefined) {
|
|
132
|
+
sendJson(response, 400, { error: hostsOffered(served) });
|
|
133
|
+
}
|
|
134
|
+
else if (heldChat(served) === undefined) {
|
|
135
|
+
sendJson(response, 409, { error: "No chat the table opened is at it: open one from the page, or change the model with /model in a chat opened by hand." });
|
|
136
|
+
}
|
|
137
|
+
else if (chatAtRest(served)) {
|
|
138
|
+
sendJson(response, 200, { restarting: relaunchChat(served, "restart", offered.name) });
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
served.restartWanted = { host: offered.name };
|
|
142
|
+
tellWatchers(served.watchers);
|
|
143
|
+
sendJson(response, 200, { waiting: true });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Ends a start again the page asked while the chat was at work (D-107): `now` starts it at once, cutting the answer it gives, as after an Esc, when it would
|
|
148
|
+
* never end; else the request is let go. Asked by the table's own page alone.
|
|
149
|
+
*/
|
|
150
|
+
async function endWaiting(request, response, served) {
|
|
151
|
+
const now = jsonOf(await bodyOf(request))?.now;
|
|
152
|
+
const wanted = served.restartWanted;
|
|
153
|
+
if (!fromTablePage(request, served)) {
|
|
154
|
+
sendJson(response, 403, { error: "Only the table's own page ends a start again that waits." });
|
|
155
|
+
}
|
|
156
|
+
else if (typeof now !== "boolean") {
|
|
157
|
+
sendJson(response, 400, { error: "Say now: true to start the chat again at once, cutting its answer, or now: false to let the request go." });
|
|
158
|
+
}
|
|
159
|
+
else if (wanted === undefined) {
|
|
160
|
+
sendJson(response, 409, { error: "No start again waits: ask for one from the chat's window." });
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
served.restartWanted = undefined;
|
|
164
|
+
const restarting = now && heldChat(served) !== undefined && relaunchChat(served, "restart", wanted.host);
|
|
165
|
+
tellWatchers(served.watchers);
|
|
166
|
+
sendJson(response, 200, now ? { restarting } : { waiting: false });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Once npm has installed the newer Chesspal (D-108), and no game goes on and the chat is at rest, as a game or a chat may have started while npm worked:
|
|
171
|
+
* the chat `chesspal play` holds starts again from it, clean, and once it has left the table, the table closes to start again from it too.
|
|
172
|
+
*/
|
|
173
|
+
export function updateWhenAtRest(served) {
|
|
174
|
+
if (served.updating !== "installed" || gameGoingOn(served) || !tableAtRest(served)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
served.updating = "restarting";
|
|
178
|
+
tellWatchers(served.watchers);
|
|
179
|
+
const relaunched = served.table?.chats?.relaunch(served.folder, undefined, true) === true;
|
|
180
|
+
void restartOnceLeft(served, relaunched);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Installs the newer Chesspal npm has (D-108), asked by the table's own page alone, never while a game goes on, the chat is at work or one is opening;
|
|
184
|
+
* the table then starts again from it as soon as it is at rest. Whether npm installed it; when it did not, the page gives the command to type.
|
|
185
|
+
*/
|
|
186
|
+
async function updateChesspal(request, response, served) {
|
|
187
|
+
await bodyOf(request);
|
|
188
|
+
const { newer, table } = served;
|
|
189
|
+
if (!fromTablePage(request, served)) {
|
|
190
|
+
sendJson(response, 403, { error: "Only the table's own page updates Chesspal." });
|
|
191
|
+
}
|
|
192
|
+
else if (newer === undefined || table?.update === undefined) {
|
|
193
|
+
sendJson(response, 409, { error: "No newer Chesspal to install: this one is the latest npm has." });
|
|
194
|
+
}
|
|
195
|
+
else if (served.updating !== undefined) {
|
|
196
|
+
sendJson(response, 409, { error: "Chesspal is being updated already: wait for the table to start again." });
|
|
197
|
+
}
|
|
198
|
+
else if (gameGoingOn(served)) {
|
|
199
|
+
sendJson(response, 409, { error: "A game is going on: finish it, then update Chesspal.", refusal: "update-game" });
|
|
200
|
+
}
|
|
201
|
+
else if (!tableAtRest(served)) {
|
|
202
|
+
sendJson(response, 409, { error: "The chat is at work, or opening: update Chesspal once it is at rest.", refusal: "update-chat" });
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
served.updating = "installing";
|
|
206
|
+
tellWatchers(served.watchers);
|
|
207
|
+
let installed = false;
|
|
208
|
+
try {
|
|
209
|
+
installed = await table.update.install(newer);
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
served.updating = installed ? "installed" : undefined;
|
|
213
|
+
}
|
|
214
|
+
// Starting again ends every connection: once this answer has gone, or the page that asked has.
|
|
215
|
+
response.once("close", () => updateWhenAtRest(served));
|
|
216
|
+
tellWatchers(served.watchers);
|
|
217
|
+
sendJson(response, 200, { installed });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// The chat started again leaves the table as `chesspal play` ends its host: a table closed before would leave its server to serve its own page on the
|
|
221
|
+
// table's ports, where the new table would then find them taken (Priya). One that does not leave in time is left to it.
|
|
222
|
+
async function restartOnceLeft(served, relaunched) {
|
|
223
|
+
for (let tries = 0; relaunched && served.attached !== undefined && tries < leaveTries; tries++) {
|
|
224
|
+
await delay(100);
|
|
225
|
+
}
|
|
226
|
+
served.table?.update?.restart();
|
|
227
|
+
}
|
|
228
|
+
// `chesspal play` sees the request within half a second and ends its host in a few more.
|
|
229
|
+
const leaveTries = 100;
|
|
230
|
+
// A game with moves still to come, a new one too: never an update meanwhile (D-108).
|
|
231
|
+
function gameGoingOn(served) {
|
|
232
|
+
const current = gameAt(gameFolder(served.context.home()), served.context.now());
|
|
233
|
+
return current !== undefined && endOf(current.game) === undefined;
|
|
234
|
+
}
|
|
235
|
+
// No chat is at work at the table, and none is opening.
|
|
236
|
+
function tableAtRest(served) {
|
|
237
|
+
return (served.attached === undefined || chatAtRest(served)) && opening(served) === undefined;
|
|
238
|
+
}
|
|
239
|
+
// The browser marks a request of the table's own page with its origin.
|
|
240
|
+
function fromTablePage(request, served) {
|
|
241
|
+
return request.headers.origin === `http://127.0.0.1:${served.port}` || request.headers.origin === `http://localhost:${served.port}`;
|
|
242
|
+
}
|
|
243
|
+
function hostOffered(served, host) {
|
|
244
|
+
return served.table?.chats?.hosts().find((one) => one.name === host && one.installed);
|
|
245
|
+
}
|
|
246
|
+
function hostsOffered(served) {
|
|
247
|
+
return `Name a host the table offers and this computer has: ${served.table?.chats?.hosts().filter((one) => one.installed).map((one) => one.name).join(", ") || "none"}.`;
|
|
248
|
+
}
|
|
249
|
+
// The host of the chat at the table, among those offered: it says its name as its MCP client does, «claude-code» or «codex-mcp-client».
|
|
250
|
+
function hostAtTable(served) {
|
|
251
|
+
const said = served.chat.host()?.toLowerCase() ?? "";
|
|
252
|
+
return served.attached === undefined ? undefined : served.table?.chats?.hosts().find((one) => said.includes(one.name))?.name;
|
|
253
|
+
}
|
|
254
|
+
// The chat at the table when `chesspal play` holds it, which the table can start again: the model and effort it started with.
|
|
255
|
+
function heldChat(served) {
|
|
256
|
+
const { attached } = served;
|
|
257
|
+
return attached === undefined ? undefined : served.table?.chats?.held(attached.chat.folder);
|
|
258
|
+
}
|
|
259
|
+
// The chat waits for the doorbell, out of a turn, and no analyst of it is at work: starting it again loses nothing.
|
|
260
|
+
function chatAtRest(served) {
|
|
261
|
+
const { bell } = served;
|
|
262
|
+
return bell.listening && !bell.inTurn && gameInAnalysis(gameFolder(served.context.home()))?.analyst === undefined;
|
|
263
|
+
}
|
|
80
264
|
// The pages show a chat opening from now until it attaches; one that has not by then lets them open another. The opening noted.
|
|
81
265
|
function noteOpening(served, how) {
|
|
82
266
|
const opened = { at: served.context.now().getTime(), how };
|
|
@@ -98,5 +282,5 @@ function opening(served) {
|
|
|
98
282
|
if (chatOpened !== undefined && context.now().getTime() - chatOpened.at < openingFor) {
|
|
99
283
|
return chatOpened.how;
|
|
100
284
|
}
|
|
101
|
-
return served.table?.chats?.
|
|
285
|
+
return served.table?.chats?.held(context.folder) === undefined ? undefined : "chat";
|
|
102
286
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Served } from "./page.ts";
|
|
2
|
+
/**
|
|
3
|
+
* What the page shows of a newer Chesspal: its version, and on the table whether it is being installed, or installed and waiting for the game to end and
|
|
4
|
+
* the chat to be at rest.
|
|
5
|
+
*/
|
|
6
|
+
export interface UpdateShown {
|
|
7
|
+
readonly version: string;
|
|
8
|
+
readonly installing?: true;
|
|
9
|
+
readonly installed?: true;
|
|
10
|
+
}
|
|
11
|
+
/** Asks npm for Chesspal's latest version now and once a day after, the pages told when it is newer than this one; how to stop. None in the tests. */
|
|
12
|
+
export declare function watchForUpdates(served: Served, every?: number): () => void;
|
|
13
|
+
/** The newer Chesspal the page shows, when npm has one. */
|
|
14
|
+
export declare function updateShown(served: Served): {
|
|
15
|
+
update?: UpdateShown;
|
|
16
|
+
};
|
|
17
|
+
/** Chesspal's latest version on npm, none when npm cannot be reached in time or answers something else. */
|
|
18
|
+
export declare function latestVersion(fetch: typeof globalThis.fetch): Promise<string | undefined>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// A newer Chesspal on npm (D-108): the page's server asks as it starts and once a day after; the table's page offers to install it, a chat's own page says
|
|
2
|
+
// the command to type.
|
|
3
|
+
import { answerTime, askSite } from "../../sites/index.js";
|
|
4
|
+
import { isOlder, version } from "../../version.js";
|
|
5
|
+
import { tellWatchers } from "./events.js";
|
|
6
|
+
/** Asks npm for Chesspal's latest version now and once a day after, the pages told when it is newer than this one; how to stop. None in the tests. */
|
|
7
|
+
export function watchForUpdates(served, every = aDay) {
|
|
8
|
+
const fetch = served.context.fetch;
|
|
9
|
+
if (fetch === undefined) {
|
|
10
|
+
return () => undefined;
|
|
11
|
+
}
|
|
12
|
+
const ask = async () => {
|
|
13
|
+
const latest = await latestVersion(fetch);
|
|
14
|
+
if (latest !== undefined && isOlder(version, latest) && latest !== served.newer) {
|
|
15
|
+
served.newer = latest;
|
|
16
|
+
tellWatchers(served.watchers);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
void ask();
|
|
20
|
+
const timer = setInterval(() => void ask(), every);
|
|
21
|
+
timer.unref();
|
|
22
|
+
return () => clearInterval(timer);
|
|
23
|
+
}
|
|
24
|
+
/** The newer Chesspal the page shows, when npm has one. */
|
|
25
|
+
export function updateShown(served) {
|
|
26
|
+
const { newer, updating } = served;
|
|
27
|
+
if (newer === undefined) {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
return { update: { version: newer, ...(updating === "installed" ? { installed: true } : updating === undefined ? {} : { installing: true }) } };
|
|
31
|
+
}
|
|
32
|
+
/** Chesspal's latest version on npm, none when npm cannot be reached in time or answers something else. */
|
|
33
|
+
export async function latestVersion(fetch) {
|
|
34
|
+
const answer = await askSite(latestUrl, fetch, AbortSignal.timeout(answerTime));
|
|
35
|
+
const said = answer?.body?.version;
|
|
36
|
+
// Only a plain release: the version goes into npm's command line.
|
|
37
|
+
return answer?.status === 200 && typeof said === "string" && /^\d+\.\d+\.\d+$/.test(said) ? said : undefined;
|
|
38
|
+
}
|
|
39
|
+
const latestUrl = "https://registry.npmjs.org/chesspal/latest";
|
|
40
|
+
const aDay = 24 * 60 * 60 * 1000;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Opens an address in a window of its own, else in a tab of the default browser, without waiting for it: whether a browser started. */
|
|
2
2
|
export declare function openInBrowser(url: string, platform: string): Promise<boolean>;
|
|
3
|
-
/** The address of the window the table opens, marked so that the page sizes it
|
|
3
|
+
/** The address of the window the table opens, marked so that the page sizes it as it opens (page/layout/window.ts). */
|
|
4
4
|
export declare function openedAddress(url: string): string;
|
|
5
5
|
/** Chrome or Edge, where each system installs them: the first there is; none when neither is. */
|
|
6
6
|
export declare function appBrowser(platform: string, env: NodeJS.ProcessEnv, exists?: (path: string) => boolean): string | undefined;
|
|
@@ -10,7 +10,7 @@ export async function openInBrowser(url, platform) {
|
|
|
10
10
|
// Explorer, open and xdg-open take an address as they take a folder, and hand it to the default browser.
|
|
11
11
|
return (browser !== undefined && await started(browser, [`--app=${openedAddress(url)}`])) || openFolder(url, platform);
|
|
12
12
|
}
|
|
13
|
-
/** The address of the window the table opens, marked so that the page sizes it
|
|
13
|
+
/** The address of the window the table opens, marked so that the page sizes it as it opens (page/layout/window.ts). */
|
|
14
14
|
export function openedAddress(url) {
|
|
15
15
|
const address = new URL(url);
|
|
16
16
|
address.searchParams.set("opened", "");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context } from "../../../commands/index.ts";
|
|
2
|
-
import type { TableChats } from "../../page/
|
|
2
|
+
import type { TableChats } from "../../page/index.ts";
|
|
3
3
|
/**
|
|
4
4
|
* The chats of a real table: the hosts installed, looked for again once a while has passed, since the player may install one with the page open; a
|
|
5
5
|
* terminal opened with `chesspal play`, run by `chesspal`, the same Node and script as the table's.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { tableFolder } from "../../../home/index.js";
|
|
2
|
-
import { samePath } from "../../bell.js";
|
|
2
|
+
import { samePath } from "../../bell/index.js";
|
|
3
3
|
import { programPath } from "./find.js";
|
|
4
4
|
import { hostChoices, hostNames, isHostName } from "./hosts.js";
|
|
5
|
-
import { askAgain,
|
|
5
|
+
import { askAgain, seatHeld } from "./seat.js";
|
|
6
6
|
import { openTerminal } from "./terminal.js";
|
|
7
7
|
/**
|
|
8
8
|
* The chats of a real table: the hosts installed, looked for again once a while has passed, since the player may install one with the page open; a
|
|
@@ -20,8 +20,11 @@ export function terminalChats(context, chesspal = [process.execPath, ...process.
|
|
|
20
20
|
},
|
|
21
21
|
open: async (host) => isHostName(host) && await openTerminal(tableFolder(context.home()), [...chesspal, "play", host], context.platform, env),
|
|
22
22
|
// Only a chat in the table's folder can be the one chesspal play holds.
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
held: (folder) => {
|
|
24
|
+
const seat = samePath(folder, tableFolder(context.home())) ? seatHeld(folder, context.now()) : undefined;
|
|
25
|
+
return seat === undefined ? undefined : { model: seat.model, effort: seat.effort };
|
|
26
|
+
},
|
|
27
|
+
relaunch: (folder, host, updated) => samePath(folder, tableFolder(context.home())) && askAgain(folder, context.now(), { ...(host === undefined ? {} : { host }), ...(updated === true ? { updated } : {}) }),
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
30
|
// Looking on the PATH takes a few milliseconds, and the page asks at every change of the game.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// The AI hosts a table opens a chat in (D-104): their choices, the terminal they open in, and `chesspal play`, which starts one there.
|
|
2
2
|
export { terminalChats } from "./chats.js";
|
|
3
3
|
export { isHostName } from "./hosts.js";
|
|
4
|
-
export { hostLaunch, playHost } from "./play.js";
|
|
4
|
+
export { endTree, hostLaunch, playHost } from "./play.js";
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
1
2
|
import type { Context } from "../../../commands/index.ts";
|
|
2
|
-
import { type HostName } from "./hosts.ts";
|
|
3
|
-
/**
|
|
3
|
+
import { type HostChoice, type HostName } from "./hosts.ts";
|
|
4
|
+
/**
|
|
5
|
+
* What `chesspal play` starts: the host's program, its arguments, folder and environment, whether it needs cmd, as a .cmd shim does on Windows, and the
|
|
6
|
+
* model and effort it is given, which the seat notes for the page (D-107).
|
|
7
|
+
*/
|
|
4
8
|
export interface HostLaunch {
|
|
5
9
|
readonly program: string;
|
|
6
10
|
readonly args: readonly string[];
|
|
7
11
|
readonly folder: string;
|
|
8
12
|
readonly env: NodeJS.ProcessEnv;
|
|
9
13
|
readonly shell: boolean;
|
|
14
|
+
readonly choice: HostChoice;
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
|
-
* Runs the host in the table's folder, in this terminal, until it ends: its exit code; started again, clean, when the table asks for a new game (D-57)
|
|
13
|
-
*
|
|
17
|
+
* Runs the host in the table's folder, in this terminal, until it ends: its exit code; started again, clean, when the table asks for a new game (D-57),
|
|
18
|
+
* or for another model or host, which then takes its place (D-107); after an update, by the Chesspal installed (D-108). Ctrl+C is the host's: this
|
|
19
|
+
* process ignores it, or the terminal would close with the chat.
|
|
14
20
|
*/
|
|
15
21
|
export declare function playHost(context: Context, host: HostName): Promise<number>;
|
|
16
22
|
/**
|
|
@@ -23,3 +29,8 @@ export declare function runHost(launch: HostLaunch, again: () => boolean, platfo
|
|
|
23
29
|
}>;
|
|
24
30
|
/** How the host starts for the profile in use: found on the PATH, with its choice; it throws, saying how to install it, when it is not there. */
|
|
25
31
|
export declare function hostLaunch(context: Context, host: HostName, env?: NodeJS.ProcessEnv, exists?: (path: string) => boolean): HostLaunch;
|
|
32
|
+
/**
|
|
33
|
+
* Ends a process and what it started, a host's MCP server among them: on Windows its whole tree, which taskkill ends, never the console (Priya); else the
|
|
34
|
+
* process, which ends its own. A taskkill that failed leaves it to a kill.
|
|
35
|
+
*/
|
|
36
|
+
export declare function endTree(chat: ChildProcess, platform: string): void;
|