Skip to content

Commit abf15f2

Browse files
nocidenocide
authored andcommitted
Bundle chess gamelet UI assets
1 parent a2ac212 commit abf15f2

46 files changed

Lines changed: 3798 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

plugins/airi-plugin-game-chess/dist/index.d.mts

Lines changed: 641 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { defineGamelet, defineToolset } from "@proj-airi/plugin-sdk-tamagotchi";
2+
import * as v from "valibot";
3+
//#region src/tools/chessTools.ts
4+
/** Gamelet the tools forward requests to; must match the id in {@link ../index}. */
5+
const GAMELET_ID$1 = "chess";
6+
/** Search depth bounds keep LLM-triggered analysis responsive in the browser. */
7+
const MIN_DEPTH = 1;
8+
const MAX_DEPTH = 20;
9+
/** MultiPV bounds prevent huge candidate-line requests from monopolising Stockfish. */
10+
const MIN_MULTIPV = 1;
11+
const MAX_MULTIPV = 5;
12+
/** Input schema for the `analyze_position` tool. */
13+
const analyzePositionInput = v.object({
14+
fen: v.string(),
15+
depth: v.optional(v.number()),
16+
multipv: v.optional(v.number())
17+
});
18+
/** Input schema for the `explain_move` tool. */
19+
const explainMoveInput = v.object({
20+
fenBefore: v.string(),
21+
moveUci: v.string()
22+
});
23+
function boundedInteger(value, min, max, label) {
24+
if (value === void 0) return void 0;
25+
if (!Number.isInteger(value)) throw new Error(`${label} must be an integer.`);
26+
if (value < min || value > max) throw new Error(`${label} must be between ${min} and ${max}.`);
27+
return value;
28+
}
29+
/**
30+
* The coach's LLM-callable chess tools.
31+
*
32+
* Each tool is a thin forwarder: the real engine work runs inside the chess
33+
* gamelet (which owns the Stockfish worker and the board), so `execute` parses
34+
* its input and relays a request to the gamelet via `ctx.gamelets.request`.
35+
* The tools are only offered while the chess gamelet is open.
36+
*/
37+
const chessTools = [{
38+
id: "analyze_position",
39+
title: "Analyze chess position",
40+
description: "Runs the chess engine on a position and returns the best move, evaluation, and candidate lines. Call this before commenting on a position.",
41+
inputSchema: analyzePositionInput,
42+
isAvailable: (ctx) => ctx.gamelets.isOpen(GAMELET_ID$1),
43+
execute: async (input, ctx) => {
44+
const { fen, depth, multipv } = v.parse(analyzePositionInput, input);
45+
const safeDepth = boundedInteger(depth, MIN_DEPTH, MAX_DEPTH, "depth");
46+
const safeMultipv = boundedInteger(multipv, MIN_MULTIPV, MAX_MULTIPV, "multipv");
47+
return ctx.gamelets.request(GAMELET_ID$1, {
48+
type: "analyze_position",
49+
fen,
50+
...safeDepth === void 0 ? {} : { depth: safeDepth },
51+
...safeMultipv === void 0 ? {} : { multipv: safeMultipv }
52+
});
53+
}
54+
}, {
55+
id: "explain_move",
56+
title: "Explain a played move",
57+
description: "Compares a played move against the engine's best move and returns its classification (brilliant, blunder, ...) and centipawn loss. Call this to evaluate a move before commenting on it.",
58+
inputSchema: explainMoveInput,
59+
isAvailable: (ctx) => ctx.gamelets.isOpen(GAMELET_ID$1),
60+
execute: async (input, ctx) => {
61+
const { fenBefore, moveUci } = v.parse(explainMoveInput, input);
62+
return ctx.gamelets.request(GAMELET_ID$1, {
63+
type: "explain_move",
64+
fenBefore,
65+
moveUci
66+
});
67+
}
68+
}];
69+
//#endregion
70+
//#region src/index.ts
71+
/**
72+
* Stable gamelet identifier. The board UI is registered under this id and the
73+
* coach tools address the same gamelet through it.
74+
*/
75+
const GAMELET_ID = "chess";
76+
/** Plugin lifecycle hook — no eager work is needed before the host APIs exist. */
77+
async function init() {}
78+
/** Plugin lifecycle hook — the chess plugin has no host-configurable settings yet. */
79+
async function configure() {}
80+
/**
81+
* Registers the chess gamelet UI and the coach's analysis tools, then opens the
82+
* board.
83+
*
84+
* Use when:
85+
* - The plugin host reaches the module-setup lifecycle phase
86+
*
87+
* Expects:
88+
* - `apis` exposes the stage-tamagotchi gamelet kit and the tool registry
89+
*/
90+
async function setupModules({ apis }) {
91+
try {
92+
await defineGamelet({ apis }, {
93+
id: GAMELET_ID,
94+
title: "Chess",
95+
entrypoint: "./ui/index.html",
96+
widgets: [{
97+
id: "main-board",
98+
kind: "primary"
99+
}]
100+
});
101+
await defineToolset({ apis }, { tools: chessTools });
102+
await apis.gamelets?.open(GAMELET_ID);
103+
} catch (error) {
104+
console.error("[airi-plugin-game-chess] setupModules failed:", error);
105+
throw error;
106+
}
107+
}
108+
//#endregion
109+
export { configure, init, setupModules };
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script setup lang="ts">
2+
import ChessBoard from './components/ChessBoard.vue'
3+
</script>
4+
5+
<template>
6+
<div :class="['h-screen w-screen', 'flex items-center justify-center', 'bg-neutral-100']">
7+
<ChessBoard />
8+
</div>
9+
</template>
134 KB
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)