chesspal 0.0.1 → 0.1.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.
Files changed (225) hide show
  1. package/README.md +136 -2
  2. package/dist/cli/chat-hook.d.ts +2 -0
  3. package/dist/cli/chat-hook.js +33 -0
  4. package/dist/cli/cli.d.ts +2 -0
  5. package/dist/cli/cli.js +28 -0
  6. package/dist/cli/command-line.d.ts +8 -0
  7. package/dist/cli/command-line.js +178 -0
  8. package/dist/commands/ai-move.d.ts +37 -0
  9. package/dist/commands/ai-move.js +92 -0
  10. package/dist/commands/ai-say.d.ts +20 -0
  11. package/dist/commands/ai-say.js +40 -0
  12. package/dist/commands/analyse-game.d.ts +61 -0
  13. package/dist/commands/analyse-game.js +238 -0
  14. package/dist/commands/annotate-game.d.ts +35 -0
  15. package/dist/commands/annotate-game.js +78 -0
  16. package/dist/commands/clock.d.ts +15 -0
  17. package/dist/commands/clock.js +45 -0
  18. package/dist/commands/context.d.ts +56 -0
  19. package/dist/commands/context.js +36 -0
  20. package/dist/commands/draw-offer.d.ts +10 -0
  21. package/dist/commands/draw-offer.js +43 -0
  22. package/dist/commands/drawings.d.ts +15 -0
  23. package/dist/commands/drawings.js +23 -0
  24. package/dist/commands/end-game.d.ts +23 -0
  25. package/dist/commands/end-game.js +64 -0
  26. package/dist/commands/export-game.d.ts +14 -0
  27. package/dist/commands/export-game.js +26 -0
  28. package/dist/commands/game-summary.d.ts +95 -0
  29. package/dist/commands/game-summary.js +239 -0
  30. package/dist/commands/index.d.ts +3 -0
  31. package/dist/commands/index.js +19 -0
  32. package/dist/commands/init.d.ts +15 -0
  33. package/dist/commands/init.js +73 -0
  34. package/dist/commands/levels.d.ts +9 -0
  35. package/dist/commands/levels.js +25 -0
  36. package/dist/commands/look.d.ts +31 -0
  37. package/dist/commands/look.js +61 -0
  38. package/dist/commands/new-game.d.ts +69 -0
  39. package/dist/commands/new-game.js +215 -0
  40. package/dist/commands/opening-book.d.ts +13 -0
  41. package/dist/commands/opening-book.js +84 -0
  42. package/dist/commands/page-link.d.ts +11 -0
  43. package/dist/commands/page-link.js +28 -0
  44. package/dist/commands/past-games.d.ts +11 -0
  45. package/dist/commands/past-games.js +47 -0
  46. package/dist/commands/play-move.d.ts +44 -0
  47. package/dist/commands/play-move.js +102 -0
  48. package/dist/commands/player-move.d.ts +17 -0
  49. package/dist/commands/player-move.js +44 -0
  50. package/dist/commands/player-say.d.ts +5 -0
  51. package/dist/commands/player-say.js +16 -0
  52. package/dist/commands/ponder.d.ts +42 -0
  53. package/dist/commands/ponder.js +167 -0
  54. package/dist/commands/position.d.ts +14 -0
  55. package/dist/commands/position.js +128 -0
  56. package/dist/commands/profiles.d.ts +60 -0
  57. package/dist/commands/profiles.js +129 -0
  58. package/dist/commands/registry.d.ts +54 -0
  59. package/dist/commands/registry.js +61 -0
  60. package/dist/commands/say.d.ts +16 -0
  61. package/dist/commands/say.js +84 -0
  62. package/dist/commands/status.d.ts +29 -0
  63. package/dist/commands/status.js +103 -0
  64. package/dist/commands/study-games.d.ts +5 -0
  65. package/dist/commands/study-games.js +40 -0
  66. package/dist/commands/study.d.ts +38 -0
  67. package/dist/commands/study.js +122 -0
  68. package/dist/commands/view.d.ts +14 -0
  69. package/dist/commands/view.js +125 -0
  70. package/dist/core/board-text.d.ts +7 -0
  71. package/dist/core/board-text.js +18 -0
  72. package/dist/core/book.json +1 -0
  73. package/dist/core/clock.d.ts +45 -0
  74. package/dist/core/clock.js +109 -0
  75. package/dist/core/facts.d.ts +55 -0
  76. package/dist/core/facts.js +175 -0
  77. package/dist/core/game.d.ts +93 -0
  78. package/dist/core/game.js +348 -0
  79. package/dist/core/illegal.d.ts +19 -0
  80. package/dist/core/illegal.js +141 -0
  81. package/dist/core/index.d.ts +19 -0
  82. package/dist/core/index.js +11 -0
  83. package/dist/core/levels.d.ts +20 -0
  84. package/dist/core/levels.js +33 -0
  85. package/dist/core/material.d.ts +9 -0
  86. package/dist/core/material.js +12 -0
  87. package/dist/core/moods.d.ts +23 -0
  88. package/dist/core/moods.js +45 -0
  89. package/dist/core/openings.d.ts +37 -0
  90. package/dist/core/openings.js +98 -0
  91. package/dist/core/openings.json +1 -0
  92. package/dist/core/pgn.d.ts +10 -0
  93. package/dist/core/pgn.js +213 -0
  94. package/dist/core/profile.d.ts +117 -0
  95. package/dist/core/profile.js +232 -0
  96. package/dist/core/record.d.ts +21 -0
  97. package/dist/core/record.js +25 -0
  98. package/dist/core/review.d.ts +74 -0
  99. package/dist/core/review.js +126 -0
  100. package/dist/games/ai-model.d.ts +5 -0
  101. package/dist/games/ai-model.js +15 -0
  102. package/dist/games/analysis.d.ts +12 -0
  103. package/dist/games/analysis.js +26 -0
  104. package/dist/games/archive.d.ts +42 -0
  105. package/dist/games/archive.js +168 -0
  106. package/dist/games/chat-start.d.ts +16 -0
  107. package/dist/games/chat-start.js +26 -0
  108. package/dist/games/current-game.d.ts +54 -0
  109. package/dist/games/current-game.js +128 -0
  110. package/dist/games/files.d.ts +9 -0
  111. package/dist/games/files.js +52 -0
  112. package/dist/games/index.d.ts +10 -0
  113. package/dist/games/index.js +11 -0
  114. package/dist/games/plans.d.ts +9 -0
  115. package/dist/games/plans.js +23 -0
  116. package/dist/games/table-talk.d.ts +12 -0
  117. package/dist/games/table-talk.js +25 -0
  118. package/dist/games/talk.d.ts +40 -0
  119. package/dist/games/talk.js +131 -0
  120. package/dist/games/thoughts.d.ts +15 -0
  121. package/dist/games/thoughts.js +60 -0
  122. package/dist/home/data-folder.d.ts +12 -0
  123. package/dist/home/data-folder.js +55 -0
  124. package/dist/home/index.d.ts +2 -0
  125. package/dist/home/index.js +3 -0
  126. package/dist/home/open-folder.d.ts +2 -0
  127. package/dist/home/open-folder.js +14 -0
  128. package/dist/host-files/host-files.d.ts +10 -0
  129. package/dist/host-files/host-files.js +167 -0
  130. package/dist/host-files/index.d.ts +2 -0
  131. package/dist/host-files/index.js +3 -0
  132. package/dist/host-files/ponder-agents.d.ts +12 -0
  133. package/dist/host-files/ponder-agents.js +40 -0
  134. package/dist/index.d.ts +4 -0
  135. package/dist/index.js +2 -0
  136. package/dist/page/app.js +576 -0
  137. package/dist/page/avatars/beanie.webp +0 -0
  138. package/dist/page/avatars/beard.webp +0 -0
  139. package/dist/page/avatars/bun.webp +0 -0
  140. package/dist/page/avatars/cat.webp +0 -0
  141. package/dist/page/avatars/curls.webp +0 -0
  142. package/dist/page/avatars/glasses.webp +0 -0
  143. package/dist/page/avatars/moustache.webp +0 -0
  144. package/dist/page/avatars/owl.webp +0 -0
  145. package/dist/page/avatars/short-hair.webp +0 -0
  146. package/dist/page/avatars/silver-bob.webp +0 -0
  147. package/dist/page/avatars.js +16 -0
  148. package/dist/page/badges.js +50 -0
  149. package/dist/page/board.js +566 -0
  150. package/dist/page/browse.js +17 -0
  151. package/dist/page/clock-time.js +12 -0
  152. package/dist/page/dialog.js +26 -0
  153. package/dist/page/ending.js +73 -0
  154. package/dist/page/explain.js +58 -0
  155. package/dist/page/fold-tab.js +9 -0
  156. package/dist/page/folds.js +43 -0
  157. package/dist/page/game-column.js +44 -0
  158. package/dist/page/header.js +27 -0
  159. package/dist/page/helps-view.js +51 -0
  160. package/dist/page/helps.js +90 -0
  161. package/dist/page/main.js +8 -0
  162. package/dist/page/model-name.js +20 -0
  163. package/dist/page/move-list.js +68 -0
  164. package/dist/page/new-game-dialog.js +42 -0
  165. package/dist/page/opening-book.js +14 -0
  166. package/dist/page/pieces/CREDITS.md +36 -0
  167. package/dist/page/pieces/cburnett-small.svg +20 -0
  168. package/dist/page/pieces/cburnett.svg +20 -0
  169. package/dist/page/pieces/nitida-small.svg +19 -0
  170. package/dist/page/pieces/nitida.svg +20 -0
  171. package/dist/page/pieces/torretta-small.svg +19 -0
  172. package/dist/page/pieces/torretta.svg +19 -0
  173. package/dist/page/pieces.js +28 -0
  174. package/dist/page/player-card.js +60 -0
  175. package/dist/page/plies.js +62 -0
  176. package/dist/page/profile-dialogs.js +123 -0
  177. package/dist/page/profile.js +95 -0
  178. package/dist/page/settings-panel.js +32 -0
  179. package/dist/page/settings.js +76 -0
  180. package/dist/page/sounds/capture.ogg +0 -0
  181. package/dist/page/sounds/check.ogg +0 -0
  182. package/dist/page/sounds/draw.ogg +0 -0
  183. package/dist/page/sounds/flag.ogg +0 -0
  184. package/dist/page/sounds/mate.ogg +0 -0
  185. package/dist/page/sounds/move.ogg +0 -0
  186. package/dist/page/sounds/offer.ogg +0 -0
  187. package/dist/page/sounds/resign.ogg +0 -0
  188. package/dist/page/sounds.js +105 -0
  189. package/dist/page/studied.js +14 -0
  190. package/dist/page/study-dialog.js +58 -0
  191. package/dist/page/style.css +4398 -0
  192. package/dist/page/talk.js +172 -0
  193. package/dist/page/text.js +593 -0
  194. package/dist/page/torretta.js +38 -0
  195. package/dist/page/voice.js +38 -0
  196. package/dist/profiles/avatar.d.ts +23 -0
  197. package/dist/profiles/avatar.js +84 -0
  198. package/dist/profiles/front-matter.d.ts +9 -0
  199. package/dist/profiles/front-matter.js +33 -0
  200. package/dist/profiles/index.d.ts +3 -0
  201. package/dist/profiles/index.js +5 -0
  202. package/dist/profiles/profiles.d.ts +58 -0
  203. package/dist/profiles/profiles.js +237 -0
  204. package/dist/profiles/settings.d.ts +12 -0
  205. package/dist/profiles/settings.js +46 -0
  206. package/dist/server/analyses.d.ts +17 -0
  207. package/dist/server/analyses.js +46 -0
  208. package/dist/server/bell.d.ts +60 -0
  209. package/dist/server/bell.js +209 -0
  210. package/dist/server/caller.d.ts +10 -0
  211. package/dist/server/caller.js +99 -0
  212. package/dist/server/http.d.ts +16 -0
  213. package/dist/server/http.js +57 -0
  214. package/dist/server/mcp.d.ts +14 -0
  215. package/dist/server/mcp.js +179 -0
  216. package/dist/server/page.d.ts +46 -0
  217. package/dist/server/page.js +657 -0
  218. package/dist/server/profile-routes.d.ts +19 -0
  219. package/dist/server/profile-routes.js +186 -0
  220. package/dist/version.d.ts +2 -0
  221. package/dist/version.js +3 -0
  222. package/instructions/analyst.md +8 -0
  223. package/instructions/opponent.md +15 -0
  224. package/instructions/ponder.md +9 -0
  225. package/package.json +66 -5
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sets up the player's folder for Claude Code and Codex (D-31): .mcp.json with the chesspal server, AGENTS.md with the opponent's instructions between
3
+ * Chesspal's marks, CLAUDE.md importing it, the hosts' settings with the server approved, and their hooks. What the player wrote there stays; it returns
4
+ * the files written.
5
+ */
6
+ export declare function setUpHosts(folder: string, platform: string): string[];
7
+ /** Where Codex reads a folder's hooks, which it runs only once the player allows them in /hooks (T-125). */
8
+ export declare function codexHooksPath(folder: string): string;
9
+ /** The instructions of the AI opponent, read from the package wherever it is installed (T-8). */
10
+ export declare function opponentInstructions(): string;
@@ -0,0 +1,167 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { makeFolder, writeAtomically } from "../games/index.js";
4
+ import { ponderAgentFiles } from "./ponder-agents.js";
5
+ /**
6
+ * Sets up the player's folder for Claude Code and Codex (D-31): .mcp.json with the chesspal server, AGENTS.md with the opponent's instructions between
7
+ * Chesspal's marks, CLAUDE.md importing it, the hosts' settings with the server approved, and their hooks. What the player wrote there stays; it returns
8
+ * the files written.
9
+ */
10
+ export function setUpHosts(folder, platform) {
11
+ makeFolder(folder);
12
+ const changes = [mcpFile(folder, platform), agentsFile(folder), claudeFile(folder), claudeSettingsFile(folder), ...ponderAgentChanges(folder), codexConfigFile(folder, platform), codexHooksFile(folder)];
13
+ const written = changes.filter((change) => change !== undefined);
14
+ for (const { path, text } of written) {
15
+ makeFolder(join(path, ".."));
16
+ writeAtomically(path, text);
17
+ }
18
+ return written.map(({ path }) => path);
19
+ }
20
+ /** Where Codex reads a folder's hooks, which it runs only once the player allows them in /hooks (T-125). */
21
+ export function codexHooksPath(folder) {
22
+ return join(folder, ".codex", "hooks.json");
23
+ }
24
+ /** The instructions of the AI opponent, read from the package wherever it is installed (T-8). */
25
+ export function opponentInstructions() {
26
+ return readFileSync(new URL("../../instructions/opponent.md", import.meta.url), "utf8").trim();
27
+ }
28
+ // The marks around Chesspal's lines in AGENTS.md: init rewrites what lies between them, and the player's own text stays around them.
29
+ const startMark = "<!-- chesspal: these lines up to the end mark are Chesspal's, and chesspal init rewrites them; write your own after it. -->";
30
+ const endMark = "<!-- chesspal: end -->";
31
+ const markedBlock = /<!-- chesspal: (?!end)[^\n]*\n[\s\S]*?<!-- chesspal: end -->/;
32
+ /** How a host starts the server: on Windows through cmd, which finds npm's shim. */
33
+ function chesspalServer(platform) {
34
+ return platform === "win32" ? { command: "cmd", args: ["/c", "chesspal", "mcp"] } : { command: "chesspal", args: ["mcp"] };
35
+ }
36
+ /** Claude Code's agents that think on the player's time, Chesspal's whole: written when they are missing or changed. */
37
+ function ponderAgentChanges(folder) {
38
+ return ponderAgentFiles(folder).filter(({ path, text }) => textOf(path) !== text);
39
+ }
40
+ /** .mcp.json with the chesspal server, beside the servers already there, keeping the environment the player gave it, as CHESSPAL_HOME in a playtest. */
41
+ function mcpFile(folder, platform) {
42
+ const path = join(folder, ".mcp.json");
43
+ const config = jsonOf(path);
44
+ const servers = isObject(config.mcpServers) ? config.mcpServers : {};
45
+ const before = isObject(servers.chesspal) ? servers.chesspal : {};
46
+ return changed(path, { ...config, mcpServers: { ...servers, chesspal: { ...chesspalServer(platform), ...(isObject(before.env) ? { env: before.env } : {}) } } });
47
+ }
48
+ /** AGENTS.md with the opponent's instructions between Chesspal's marks: rewritten when they changed, put first in a file that has none. */
49
+ function agentsFile(folder) {
50
+ const path = join(folder, "AGENTS.md");
51
+ const before = textOf(path);
52
+ const block = [startMark, opponentInstructions(), endMark].join("\n");
53
+ if (before === undefined) {
54
+ return { path, text: `${block}\n` };
55
+ }
56
+ const text = markedBlock.test(before) ? before.replace(markedBlock, () => block) : `${block}\n\n${before}`;
57
+ return text === before ? undefined : { path, text };
58
+ }
59
+ /** CLAUDE.md, which Claude Code reads, importing AGENTS.md: the import put first in a file without it. */
60
+ function claudeFile(folder) {
61
+ const path = join(folder, "CLAUDE.md");
62
+ const before = textOf(path);
63
+ if (before === undefined) {
64
+ return { path, text: "@AGENTS.md\n" };
65
+ }
66
+ return before.split(/\r?\n/).some((line) => line.trim() === "@AGENTS.md") ? undefined : { path, text: `@AGENTS.md\n${before}` };
67
+ }
68
+ /**
69
+ * Claude Code's settings: the chesspal server of .mcp.json approved and its tools allowed, so that the first chat asks for neither, and the doorbell of the
70
+ * moves on the page (D-47), and the note of how each chat starts (D-57); the player's own stay.
71
+ */
72
+ function claudeSettingsFile(folder) {
73
+ const path = join(folder, ".claude", "settings.json");
74
+ const settings = jsonOf(path);
75
+ const permissions = isObject(settings.permissions) ? settings.permissions : {};
76
+ const hooks = isObject(settings.hooks) ? settings.hooks : {};
77
+ return changed(path, {
78
+ ...settings,
79
+ enabledMcpjsonServers: withItem(settings.enabledMcpjsonServers, "chesspal"),
80
+ permissions: { ...permissions, allow: withItem(permissions.allow, "mcp__chesspal") },
81
+ hooks: withHook(withHook(hooks, "Stop", bellHook), "SessionStart", chatHook),
82
+ });
83
+ }
84
+ /** The hooks with one of Chesspal's put back beside the player's own whenever it is missing; an event of theirs that is no list stays theirs. */
85
+ function withHook(hooks, event, ours) {
86
+ const entries = hooks[event];
87
+ if (entries !== undefined && !Array.isArray(entries)) {
88
+ return hooks;
89
+ }
90
+ const list = (entries ?? []);
91
+ const there = list.some((entry) => isObject(entry) && Array.isArray(entry.hooks) && entry.hooks.some((hook) => isObject(hook) && hook.command === ours.command));
92
+ return there ? hooks : { ...hooks, [event]: [...list, { hooks: [ours] }] };
93
+ }
94
+ // Claude Code's Stop hook for the doorbell (D-47): it waits in the background from the end of each turn, and wakes the chat only when the player moves on
95
+ // the page; a day at most, until the next turn starts another.
96
+ const bellHook = { type: "command", command: "chesspal listen", asyncRewake: true, timeout: 86_400 };
97
+ // Claude Code's SessionStart hook (D-57): it notes how each chat starts, so that a new game waits for a clean one.
98
+ const chatHook = { type: "command", command: "chesspal chat" };
99
+ /**
100
+ * Codex's settings, read once the player trusts the folder: the chesspal server with its tools approved, a table of Chesspal's rewritten but for the
101
+ * environment the player gave it, as CHESSPAL_HOME in a playtest; the rest stays.
102
+ */
103
+ function codexConfigFile(folder, platform) {
104
+ const path = join(folder, ".codex", "config.toml");
105
+ const before = textOf(path) ?? "";
106
+ const { command, args } = chesspalServer(platform);
107
+ // The table runs up to the next one, or to the end; a header with a comment after it is the same table.
108
+ const ours = /^\s*\[mcp_servers\.chesspal\]\s*(#.*)?\r?\n[\s\S]*?(?=^\s*\[|(?![\s\S]))/m;
109
+ const environment = (ours.exec(before)?.[0].match(/^\s*env(?:_vars)?\s*=.*$/gm) ?? []).map((line) => `${line.trim()}\n`).join("");
110
+ const table = `[mcp_servers.chesspal]\ncommand = ${JSON.stringify(command)}\nargs = [${args.map((arg) => JSON.stringify(arg)).join(", ")}]\ndefault_tools_approval_mode = "approve"\n${environment}`;
111
+ const rest = before.replace(ours, "").trim();
112
+ const text = rest === "" ? table : `${rest}\n\n${table}`;
113
+ return text === before ? undefined : { path, text };
114
+ }
115
+ /** Codex's hooks, read once the player has reviewed them in /hooks: the doorbell of the moves on the page (T-62) and how each chat starts (T-104), beside the player's own. */
116
+ function codexHooksFile(folder) {
117
+ const path = codexHooksPath(folder);
118
+ const config = jsonOf(path);
119
+ const hooks = isObject(config.hooks) ? config.hooks : {};
120
+ return changed(path, { ...config, hooks: withHook(withHook(hooks, "Stop", codexBellHook), "SessionStart", codexChatHook) });
121
+ }
122
+ // Codex's Stop hook for the doorbell (T-62): it holds the turn until the player acts on the page, then Codex goes on; a day at most. On Windows Codex runs
123
+ // it in PowerShell, where `chesspal` would be npm's .ps1 shim, which a strict execution policy stops.
124
+ const codexBellHook = {
125
+ type: "command",
126
+ command: "chesspal listen --codex",
127
+ commandWindows: "chesspal.cmd listen --codex",
128
+ timeout: 86_400,
129
+ statusMessage: "Waiting for your move on the board page",
130
+ };
131
+ // Codex's SessionStart hook (T-104): it notes how each chat starts, as Claude Code's does (D-57).
132
+ const codexChatHook = { type: "command", command: "chesspal chat", commandWindows: "chesspal.cmd chat" };
133
+ /** A JSON file's new content, when it differs from what is there. */
134
+ function changed(path, value) {
135
+ const text = `${JSON.stringify(value, null, 2)}\n`;
136
+ return textOf(path) === text ? undefined : { path, text };
137
+ }
138
+ /** A list with an item added when it is missing; a value that is no list becomes one. */
139
+ function withItem(list, item) {
140
+ const items = Array.isArray(list) ? list : [];
141
+ return items.includes(item) ? items : [...items, item];
142
+ }
143
+ /** The object a JSON file holds, empty when there is no file; a file that is not a JSON object stops init with how to fix it. */
144
+ function jsonOf(path) {
145
+ const text = textOf(path);
146
+ if (text === undefined) {
147
+ return {};
148
+ }
149
+ let value;
150
+ try {
151
+ value = JSON.parse(text);
152
+ }
153
+ catch {
154
+ value = undefined;
155
+ }
156
+ if (!isObject(value)) {
157
+ throw new Error(`${path} is not a JSON object, so Chesspal cannot add itself to it: fix it or remove it, then run chesspal init again.`);
158
+ }
159
+ return value;
160
+ }
161
+ function textOf(path) {
162
+ // Windows PowerShell and Notepad may start a file with a byte order mark, which JSON.parse refuses.
163
+ return existsSync(path) ? readFileSync(path, "utf8").replace(/^/, "") : undefined;
164
+ }
165
+ function isObject(value) {
166
+ return typeof value === "object" && value !== null && !Array.isArray(value);
167
+ }
@@ -0,0 +1,2 @@
1
+ export { codexHooksPath, opponentInstructions, setUpHosts } from "./host-files.ts";
2
+ export { hasPonderAgent, onQuickModel, ponderAgentFor } from "./ponder-agents.ts";
@@ -0,0 +1,3 @@
1
+ // The files through which an AI host finds Chesspal in the player's folder (T-7): the server, the opponent's instructions, the hosts' settings.
2
+ export { codexHooksPath, opponentInstructions, setUpHosts } from "./host-files.js";
3
+ export { hasPonderAgent, onQuickModel, ponderAgentFor } from "./ponder-agents.js";
@@ -0,0 +1,12 @@
1
+ import type { AiLevel } from "../core/index.ts";
2
+ /** The agent that thinks for the AI at a level: on the quick model at the beginner and club levels, on the AI's own above. */
3
+ export declare function ponderAgentFor(level: AiLevel): string;
4
+ /** Whether the AI's thoughts on the player's time come from a quicker model than its own at a level. */
5
+ export declare function onQuickModel(level: AiLevel): boolean;
6
+ /** Whether the player's folder has the agent, as init writes it: a folder set up before it has none, and the AI then plays as before. */
7
+ export declare function hasPonderAgent(folder: string, agent: string): boolean;
8
+ /** The agents' files, as Claude Code reads them from .claude/agents: Chesspal's whole, rewritten by init. */
9
+ export declare function ponderAgentFiles(folder: string): {
10
+ path: string;
11
+ text: string;
12
+ }[];
@@ -0,0 +1,40 @@
1
+ // The agents that think on the player's time in Claude Code (D-72): one on the host's quick model for the lower levels, one on the AI's own for the higher.
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ /** The agent that thinks for the AI at a level: on the quick model at the beginner and club levels, on the AI's own above. */
5
+ export function ponderAgentFor(level) {
6
+ return onQuickModel(level) ? quickAgent : ownAgent;
7
+ }
8
+ /** Whether the AI's thoughts on the player's time come from a quicker model than its own at a level. */
9
+ export function onQuickModel(level) {
10
+ return level === "beginner" || level === "club";
11
+ }
12
+ /** Whether the player's folder has the agent, as init writes it: a folder set up before it has none, and the AI then plays as before. */
13
+ export function hasPonderAgent(folder, agent) {
14
+ return existsSync(agentPath(folder, agent));
15
+ }
16
+ /** The agents' files, as Claude Code reads them from .claude/agents: Chesspal's whole, rewritten by init. */
17
+ export function ponderAgentFiles(folder) {
18
+ const instructions = readFileSync(new URL("../../instructions/ponder.md", import.meta.url), "utf8").trim();
19
+ return [{ agent: quickAgent, model: "haiku" }, { agent: ownAgent, model: "inherit" }].map(({ agent, model }) => ({
20
+ path: agentPath(folder, agent),
21
+ text: [
22
+ "---",
23
+ `name: ${agent}`,
24
+ "description: Chesspal's opponent thinking on the player's time. Started by the AI in the background after its move, as ai_move says.",
25
+ `tools: ${tools.join(", ")}`,
26
+ `model: ${model}`,
27
+ "---",
28
+ "",
29
+ instructions,
30
+ "",
31
+ ].join("\n"),
32
+ }));
33
+ }
34
+ const quickAgent = "chesspal-ponder-quick";
35
+ const ownAgent = "chesspal-ponder";
36
+ // The one tool it works with: Claude Code gives an agent its MCP tools loaded, with no search first (Priya, round of T-109).
37
+ const tools = ["mcp__chesspal__ponder"];
38
+ function agentPath(folder, agent) {
39
+ return join(folder, ".claude", "agents", `${agent}.md`);
40
+ }
@@ -0,0 +1,4 @@
1
+ export type { Context } from "./commands/context.ts";
2
+ export { commands } from "./commands/index.ts";
3
+ export type { AnyCommand, Command } from "./commands/registry.ts";
4
+ export { version } from "./version.ts";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { commands } from "./commands/index.js";
2
+ export { version } from "./version.js";