pog-mcp 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Proof of Goal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # pog-mcp — play Proof of Goal as an agent
2
+
3
+ An MCP server that turns [pog.soccer](https://pog.soccer) into fourteen tools. The
4
+ API has always been reachable over plain HTTP (see the repo's `AGENTS.md`); what
5
+ this adds is that the agent no longer has to read a runbook, hold a Solana
6
+ keypair, or guess payload shapes.
7
+
8
+ ```
9
+ login → get_game_rules → create_squad → play_friendly → get_match
10
+ ↑ │
11
+ └─── update_squad ───┘
12
+ ```
13
+
14
+ That loop back is the game. A wallet holds one squad; you improve it by playing
15
+ friendlies and rewriting the lineup, not by building new teams.
16
+
17
+ Across sessions the wallet file is the account, so the agent returns as the same
18
+ manager. Cups and league fixtures resolve on a scheduler, hours after they start,
19
+ which means an agent's own results normally arrive while it is away — `catch_up`
20
+ is the one call that closes that gap.
21
+
22
+ ## Install
23
+
24
+ Nothing to clone or build. For Claude Code:
25
+
26
+ ```bash
27
+ claude mcp add proof-of-goal -- npx -y pog-mcp
28
+ ```
29
+
30
+ For any client that reads a JSON config:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "proof-of-goal": {
36
+ "command": "npx",
37
+ "args": ["-y", "pog-mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ### From a checkout
44
+
45
+ Working on the server itself, or running it against your own API:
46
+
47
+ ```bash
48
+ pnpm --filter pog-mcp build
49
+ claude mcp add proof-of-goal -- node /absolute/path/to/packages/mcp/dist/index.js
50
+ ```
51
+
52
+ ## Releasing
53
+
54
+ Publishing is automated: merge to `main` with a new `version` in `package.json`
55
+ and `.github/workflows/publish-mcp.yml` puts it on npm. A pull request that
56
+ changes shipped files (`src/`, `skill/`, `README.md`, the manifest) while the
57
+ version is already on npm fails the check — npm cannot overwrite a version, so
58
+ without the bump the merge would publish nothing and `npx -y pog-mcp` would keep
59
+ handing out the old server.
60
+
61
+ Two things are set up once, by hand:
62
+
63
+ - **The first publish.** A granular token can only be scoped to a package that
64
+ exists, so the order is: `npm publish --access public` from this directory,
65
+ then create the token. Nothing to decide first — the licence is in place.
66
+ - **`NPM_TOKEN`.** A granular npm access token with read-and-write rights on
67
+ this package, stored as the repository secret `NPM_TOKEN`. Nothing in CI can
68
+ create it.
69
+
70
+ ## Licence
71
+
72
+ MIT — see `LICENSE`, which covers **this package only**. It is the client you
73
+ run; the game it talks to is not open source, and the repository this package
74
+ is built from is private.
75
+
76
+ ## Configuration
77
+
78
+ Everything is optional for the default deployment. Pointing somewhere else is
79
+ not: the client refuses to sign a login for any host it was not built to trust,
80
+ so a staging or self-hosted API needs `POG_SIWS_DOMAIN` as well.
81
+
82
+ ```bash
83
+ POG_API_URL=https://api.staging.example \
84
+ POG_SIWS_DOMAIN=staging.example \
85
+ node packages/mcp/dist/index.js
86
+ ```
87
+
88
+ Loopback (`localhost`, `127.0.0.1`) is trusted automatically, so a local API
89
+ needs nothing beyond `POG_API_URL`. Without the override you get a refusal that
90
+ names both the host it saw and the variable to set — it fails closed rather than
91
+ signing for whatever answered.
92
+
93
+ | Variable | Default | Purpose |
94
+ | --- | --- | --- |
95
+ | `POG_API_URL` | `https://api.pog.soccer` | Point at a local API (`http://localhost:3001`) or another deployment. |
96
+ | `POG_SIWS_DOMAIN` | — | **Required** with a non-loopback `POG_API_URL`. The site that deployment signs people in to. |
97
+ | `POG_SIWS_CHAIN` | `solana:devnet` | The chain the deployment binds sign-in to. |
98
+ | `POG_API_HOST` | `<siws domain>` or `api.<siws domain>` | The host this client will TALK TO. Declaring `POG_SIWS_DOMAIN` already authorizes that domain and its `api.` subdomain — set this only when the API lives somewhere else entirely. It replaces the relation, it does not add to it. |
99
+ | `POG_SIWS_URI` | `https://<siws domain>` | The exact URI the message may name. The whole URI is bound, not just its host — set this if your deployment signs for a path or a non-https scheme. Ignored for a loopback API. |
100
+ | `POG_API_TIMEOUT_MS` | `30000` | Per-request ceiling. |
101
+ | `POG_MCP_WALLET_FILE` | `~/.pog-mcp/wallet.json` | Where the recovery phrase lives. **Set this when the host only persists specific directories** — containers, sandboxes and agent runtimes often wipe `$HOME` between runs, and a missing file means a NEW phrase and a new account, silently. Absolute paths only: `~` is not expanded, and an MCP config `env` block has no shell to expand it. The directory must not be writable by other users. |
102
+ | `POG_MCP_MNEMONIC` | — | Import an existing phrase instead of generating one. Refuses to start if a DIFFERENT wallet is already stored — move that file first, or point `POG_MCP_WALLET_FILE` elsewhere. One-time import, not steady-state config: the process environment is readable by anything running as you, and MCP clients keep it in a config file on disk.|
103
+
104
+ ## The wallet
105
+
106
+ `login` generates a BIP39 phrase on first use and derives a Solana keypair on
107
+ `m/44'/501'/0'/0'` — the same path Phantom and Solflare use, so the phrase can be
108
+ imported into either and the agent's squad shows up in a normal wallet.
109
+
110
+ The file is written `0600` inside a `0700` directory. It is a real key: whatever
111
+ the agent earns is held by it, and anyone who reads the file is that manager.
112
+
113
+ Nothing is written until a tool actually needs the wallet, so starting the server
114
+ and listing its tools does not mint a key. That property has a test
115
+ (`server.test.ts` → "constructs without touching the wallet file") because it is
116
+ the kind of thing a refactor breaks silently.
117
+
118
+ ## Tools
119
+
120
+ | Tool | Auth | Notes |
121
+ | --- | --- | --- |
122
+ | `login` | — | SIWS handshake. Call once; sessions last ~30 days. |
123
+ | `catch_up` | ✓ | Everything since last time, in one call. Start every return with it. |
124
+ | `whoami` | — | Wallet address and session state. Never reveals the phrase. |
125
+ | `get_game_rules` | — | Squad constraints and how the daily cup works. Read before building. |
126
+ | `list_nations` | — | Code→name map. Pass `nationCode` for that nation's name pools. |
127
+ | `create_squad` | ✓ | 11 players, 212 points. One squad per wallet — a second attempt redirects you to `update_squad`. |
128
+ | `update_squad` | ✓ | Rewrite the lineup you own. Applies to the next unsimulated match. |
129
+ | `my_squads` | ✓ | Squads owned by this wallet. |
130
+ | `get_squad` | — | Any squad by id — scout an opponent. |
131
+ | `play_friendly` | ✓ | Instant match. You must own `homeTeamId`. Standings-neutral. |
132
+ | `play_playoff` | ✓ | One RANKED ladder match. Nothing schedules these — you start them. |
133
+ | `get_match` | — | Result and event stream. Replays are deterministic. |
134
+ | `get_cup` | — | Bracket for a date (UTC). The cup opens 04:00 UTC. |
135
+ | `get_leaderboard` | — | Top 20 by default. Skip rows marked `playable: false` — their team was deleted and `topTeamId` is null. |
136
+
137
+ ## The Skill
138
+
139
+ MCP gives an agent the ability to act; it does not give it judgment. An agent
140
+ with only these tools builds a squad by splitting 212 points evenly across
141
+ eleven players, which is measurably the worst thing you can build.
142
+
143
+ `skill/SKILL.md` is the other half: what the engine actually rewards, and how
144
+ many friendlies a conclusion needs before it means anything. Install it for
145
+ Claude Code with
146
+
147
+ ```bash
148
+ mkdir -p ~/.claude/skills && cp -r packages/mcp/skill ~/.claude/skills/play-proof-of-goal
149
+ ```
150
+
151
+ Every strategy claim in it was measured by running the engine over tens of
152
+ thousands of matches. The probes that produced those tables live in this
153
+ repository at `packages/mcp/skill/reference/probes/`. They are **not** in the
154
+ published package: they import the game engine from the workspace, so they run
155
+ from a checkout and would fail with module-not-found anywhere else.
156
+
157
+ ```bash
158
+ npx tsx packages/mcp/skill/reference/probes/gk-sweep.mts
159
+ ```
160
+
161
+ Re-run them after any engine change — a rebalance invalidates the advice.
162
+
163
+ ## Notes for anyone extending this
164
+
165
+ **Responses are billed as context.** `list_nations` originally returned the raw
166
+ 55 kB payload — ~14k tokens, almost all of it name pools nobody asked for. It now
167
+ projects to a code→name map (~760 tokens) and `get_leaderboard` returns a window.
168
+ Before adding a tool, look at what its endpoint actually returns.
169
+
170
+ **Tool descriptions are read as fact.** An agent can't see the validator; it reads
171
+ `get_game_rules` and reasons on top of it. A wrong rule doesn't cost a retry — it
172
+ makes the agent exclude squads that are legal, and nothing ever tells it why.
173
+ `__tests__/gameFacts.test.ts` pins every published number to
174
+ `packages/engine/src/validator.ts` and fails when either side moves.
175
+
176
+ **Derivation is duplicated, not shared.** `@sws26/shared` is dependency-free by
177
+ design and can't host crypto libraries, so this package re-implements SLIP-0010.
178
+ Both halves assert the same fixed vectors (`__tests__/derivationVectors.ts`) —
179
+ change one alone and its own suite fails. A silent break here doesn't throw, it
180
+ hands the same phrase a different address.
181
+
182
+ **Both real bugs found so far were invisible in code review**, and both are now
183
+ regression tests in `client.test.ts`: preferring Fastify's `error` field over
184
+ `message` threw away the only actionable half of a 400, and omitting `auth` on
185
+ the friendly route 401'd every match while every read still worked — so the
186
+ surface looked healthy.
@@ -0,0 +1,319 @@
1
+ /**
2
+ * client — typed HTTP access to the Proof of Goal API, with SIWS handled here.
3
+ *
4
+ * The whole point of this layer is that `login()` is one call. The real flow is
5
+ * four round-trips and an ed25519 signature:
6
+ *
7
+ * 1. GET /api/auth/nonce?wallet=… → single-use nonce
8
+ * 2. GET /api/auth/message?wallet=…&nonce=… → the exact text to sign
9
+ * 3. sign it locally
10
+ * 4. POST /api/auth/signin → bearer session
11
+ *
12
+ * Step 2 matters: the server builds the SIWS text (domain, URI, statement) and
13
+ * checks the parsed result on the way back in. Rebuilding that string here would
14
+ * work right up until SIWS_DOMAIN changes on a deploy and every login started
15
+ * failing signature verification for no visible reason. Ask, don't guess.
16
+ */
17
+ /**
18
+ * Largest page GET /api/leaderboard will serve (its MAX_LIMIT). Asking for it
19
+ * makes truncation detectable: a full page means there may be more.
20
+ */
21
+ export declare const LEADERBOARD_MAX_LIMIT = 500;
22
+ /** Public deployment. Override with POG_API_URL to point at a local server. */
23
+ export declare const DEFAULT_API_URL = "https://api.pog.soccer";
24
+ export interface Session {
25
+ sessionId: string;
26
+ walletAddress: string;
27
+ expiresAt: string;
28
+ }
29
+ /**
30
+ * A selectable nation. `givenNames`/`surnames` are the pools the web UI's
31
+ * randomise button draws from — they are big (174 nations ≈ 55 kB all told) and
32
+ * irrelevant to picking a nation, so the MCP layer projects them away by
33
+ * default. See `list_nations`.
34
+ */
35
+ export interface Nation {
36
+ code: string;
37
+ name: string;
38
+ givenNames: string[];
39
+ surnames: string[];
40
+ }
41
+ /** One manager's standing. The board is a flat array, already rank-ordered. */
42
+ export interface LeaderboardRow {
43
+ rank: number;
44
+ ownerAddress: string;
45
+ managerScore: number;
46
+ /**
47
+ * Null when the manager's team was deleted after its matches were played —
48
+ * the row stays on the board, the opponent does not exist. Typed nullable so
49
+ * the tool cannot hand an agent a `null` to pass as awayTeamId.
50
+ */
51
+ topTeamId: string | null;
52
+ topTeamName: string | null;
53
+ [k: string]: unknown;
54
+ }
55
+ /** GET /api/cups/:date — no fixtures, despite the name. */
56
+ export interface CupSummary {
57
+ date: string;
58
+ tournamentId: string;
59
+ status: string;
60
+ matchCount: number;
61
+ [k: string]: unknown;
62
+ }
63
+ /** One fixture from the bracket. */
64
+ export interface BracketMatch {
65
+ matchId: string;
66
+ matchType: string;
67
+ [k: string]: unknown;
68
+ }
69
+ /** GET /api/tournaments/:id/bracket — 104 fixtures for a full cup. */
70
+ export interface CupBracket {
71
+ tournamentId: string;
72
+ matches: BracketMatch[];
73
+ /** Duplicates every `matches[].matchId`; projected away by the MCP layer. */
74
+ matchIds?: string[];
75
+ [k: string]: unknown;
76
+ }
77
+ /** One finished match from a team's history. */
78
+ export interface HistoryMatch {
79
+ matchId: string;
80
+ finishedAt: string;
81
+ result: 'W' | 'D' | 'L';
82
+ score: {
83
+ home: number;
84
+ away: number;
85
+ };
86
+ opponent: string;
87
+ homeTeamId: string;
88
+ /** False when a level score is definitive: 90 minutes, draws allowed. */
89
+ shootoutPossible?: boolean;
90
+ [k: string]: unknown;
91
+ }
92
+ export declare class ApiError extends Error {
93
+ readonly status: number;
94
+ readonly path: string;
95
+ /**
96
+ * The `teamId` some rejections carry alongside the error. POST /api/teams
97
+ * answers 409 `{error:"team_exists", teamId}` — the id is the whole point of
98
+ * that response, so it must not be flattened away into the message.
99
+ */
100
+ readonly teamId?: string;
101
+ /**
102
+ * When to try again, in seconds — the whole point of a 429.
103
+ *
104
+ * The server always says this, twice over: `retry-after` on the response and,
105
+ * for the playoff cooldown, `retryAfterMs`/`nextMatchAt` in the body. Both
106
+ * used to be dropped on the floor, so an agent that woke a minute early got a
107
+ * sentence to read instead of a time to sleep until, and had to spend another
108
+ * call working out what the rejection already contained.
109
+ */
110
+ readonly retryAfterSeconds?: number;
111
+ /** The exact instant the next attempt is allowed, when the server names one. */
112
+ readonly retryAt?: string;
113
+ /** Requests left in this window, so an agent can PACE instead of only backing off. */
114
+ readonly remaining?: number;
115
+ constructor(status: number, path: string, message: string, teamId?: string, extra?: {
116
+ retryAfterSeconds?: number;
117
+ retryAt?: string;
118
+ remaining?: number;
119
+ });
120
+ }
121
+ /**
122
+ * Hosts this client will sign a sign-in for.
123
+ *
124
+ * The anchor is BUILT IN, not derived from POG_API_URL. Deriving it from the
125
+ * URL under suspicion was the flaw: point the client at evil.example and it
126
+ * would serve a message for evil.example, satisfy every field check, and get a
127
+ * signature from the persistent wallet. Thorough validation of a self-consistent
128
+ * forgery is still a forgery — the check has to start from something the
129
+ * attacker does not control.
130
+ *
131
+ * So: the known Proof of Goal domains by default; loopback automatically,
132
+ * because a local dev server is not a phishing target; anything else only with
133
+ * an explicit POG_SIWS_DOMAIN. A mistyped host therefore fails closed and says
134
+ * what to set.
135
+ *
136
+ * The ORIGIN has to clear that bar too, not just the domain in the message.
137
+ * Returning the production hosts for an arbitrary API URL left one attack whole:
138
+ * a hostile HTTPS host does not have to forge anything — it proxies the nonce
139
+ * and message straight from api.pog.soccer, hands back the genuine pog.soccer
140
+ * text, and every field check passes because every field is real. Then it keeps
141
+ * the signature and the session. HTTPS authenticates the relay, not the service
142
+ * behind it. So an origin we do not know is refused before a message is fetched.
143
+ */
144
+ export declare function expectedSiwsHosts(apiOrigin: string, env?: NodeJS.ProcessEnv): string[];
145
+ /**
146
+ * Hosts this client will send a wallet address to.
147
+ *
148
+ * Separate from the domains a MESSAGE may name, because they answer different
149
+ * questions and a deployment can legitimately split them: the product's own API
150
+ * lives at api.pog.soccer and signs for pog.soccer. So an operator who declares
151
+ * their domain gets that same relation for free — the domain itself, or `api.`
152
+ * in front of it — and POG_API_HOST is there for the topologies that are neither.
153
+ */
154
+ export declare function expectedApiHosts(env?: NodeJS.ProcessEnv): string[];
155
+ /**
156
+ * The product's own domains, derived from DEFAULT_API_URL so the two cannot
157
+ * drift: the API host and the site it signs people in to.
158
+ */
159
+ export declare const TRUSTED_SIWS_HOSTS: string[];
160
+ /**
161
+ * Refuse to run the sign-in flow over plaintext to a remote host.
162
+ *
163
+ * Loopback is exempt: there is no path for anyone to sit on.
164
+ */
165
+ export declare function assertTransportIsSafe(origin: string): void;
166
+ /**
167
+ * The exact `domain` a message may name, or `null` to check only the host.
168
+ *
169
+ * Loopback stays host-only: the local API signs "localhost" whichever spelling
170
+ * and port you dialled it by, and pinning that would refuse a perfectly good
171
+ * local login — the same exemption the host and URI checks already make.
172
+ */
173
+ export declare function expectedSiwsDomain(apiOrigin: string, env?: NodeJS.ProcessEnv): string | null;
174
+ /**
175
+ * The exact URI(s) a message may name, or `null` to check only the host.
176
+ *
177
+ * The API builds this as `https://{SIWS_DOMAIN}` unless SIWS_URI overrides it,
178
+ * so the expected value is derivable and worth pinning: a compromised endpoint
179
+ * that can only vary scheme and path still gets a signature over a resource the
180
+ * operator never agreed to.
181
+ *
182
+ * Loopback stays host-only. Ports and schemes vary freely on a dev box, it is
183
+ * not a phishing target — the same exemption the host check already makes — and
184
+ * pinning it would only teach people to set an override they do not need.
185
+ */
186
+ export declare function expectedSiwsUris(apiOrigin: string, env?: NodeJS.ProcessEnv): string[] | null;
187
+ /**
188
+ * The one chain id this client will sign a sign-in for.
189
+ *
190
+ * The API binds auth to a single chain (SOLANA_DEVNET_CHAIN_ID today), so this
191
+ * is an exact match, not a family. Moving the deployment to another chain means
192
+ * setting POG_SIWS_CHAIN — logins fail closed until then, and the refusal names
193
+ * both chains so the cause is obvious.
194
+ */
195
+ export declare function expectedSiwsChain(env?: NodeJS.ProcessEnv): string;
196
+ /**
197
+ * Refuse to sign anything that is not a login to THIS service, for THIS wallet,
198
+ * with the nonce we just asked for.
199
+ *
200
+ * Every field is bound, not sampled. A message we cannot fully parse is a
201
+ * refusal: there is no safe way to sign text we could not read, and the only
202
+ * party who benefits from a lenient parser here is whoever served the message.
203
+ */
204
+ export declare function assertSiwsMatchesRequest(message: string, expected: {
205
+ walletAddress: string;
206
+ nonce: string;
207
+ origin: string;
208
+ }, env?: NodeJS.ProcessEnv): void;
209
+ export declare class PogClient {
210
+ private readonly baseUrl;
211
+ private readonly fetchImpl;
212
+ /** Per-request ceiling. Generous: a cup-day bracket is a large response. */
213
+ private readonly timeoutMs;
214
+ private session;
215
+ constructor(baseUrl?: string, fetchImpl?: typeof fetch,
216
+ /** Per-request ceiling. Generous: a cup-day bracket is a large response. */
217
+ timeoutMs?: number);
218
+ /**
219
+ * The active session, or null when there is none or it has expired.
220
+ *
221
+ * Expiry is checked on read rather than trusted from when it was issued: this
222
+ * process can outlive a session, and returning a stale one made `whoami`
223
+ * report "signed in" while every authenticated call 401'd.
224
+ */
225
+ currentSession(): Session | null;
226
+ private request;
227
+ /** Run the full SIWS handshake and hold the resulting bearer session. */
228
+ login(mnemonic: string, walletAddress: string): Promise<Session>;
229
+ /**
230
+ * Liveness. Deliberately /healthz and not /api/ops/status — the ops routes are
231
+ * operator surface and answer 401 without OPS_API_KEY on any real deployment,
232
+ * so exposing them here would ship a tool that never works for a player.
233
+ */
234
+ health(): Promise<unknown>;
235
+ /** Whether the FA market is open on this deployment (public, ungated). */
236
+ marketStatus(): Promise<unknown>;
237
+ nations(): Promise<{
238
+ nations: Nation[];
239
+ }>;
240
+ myTeams(): Promise<unknown>;
241
+ /**
242
+ * Everything about this manager in one authenticated call: squads, league
243
+ * rank, playoff entry and cooldown, finished-match history, next fixture,
244
+ * honours, career record.
245
+ *
246
+ * This is the endpoint that makes the game playable across sessions. Cups run
247
+ * daily and finish hours after they open, so an agent that only ever looks at
248
+ * what it did inside one session never sees its own results — and never has a
249
+ * reason to change the squad. The alternative is six separate calls the agent
250
+ * has to know to make and stitch together itself.
251
+ */
252
+ dashboard(): Promise<unknown>;
253
+ /**
254
+ * A team's finished matches, newest first, up to `limit` (the API caps at 200).
255
+ *
256
+ * Lives under /api/playoff/ but is not playoff-only — it lists every completed
257
+ * match for the team, friendlies included. Needed because the dashboard's own
258
+ * `teamHistory` is capped at five rows, which is fewer than a single cup day
259
+ * produces.
260
+ */
261
+ teamHistory(teamId: string, limit: number): Promise<{
262
+ matches: HistoryMatch[];
263
+ }>;
264
+ team(teamId: string): Promise<unknown>;
265
+ match(matchId: string): Promise<unknown>;
266
+ /**
267
+ * Cup SUMMARY only: status, champion, final score, match count. No fixtures —
268
+ * see `cupBracket` for those.
269
+ */
270
+ cup(date: string): Promise<CupSummary>;
271
+ /**
272
+ * The fixtures. A cup date maps to tournament id `wc-${date}`, and the bracket
273
+ * lives on the tournament, not the cup — /api/cups/:date returns a summary
274
+ * with a `matchCount` and no matches at all.
275
+ */
276
+ cupBracket(date: string): Promise<CupBracket>;
277
+ /**
278
+ * The board's top `limit` rows. The API defaults to 100 and caps at
279
+ * MAX_LIMIT=500, so a request without an explicit limit silently truncates on
280
+ * any deployment with more managers than that — and `rows.length` is then the
281
+ * page size, not the population.
282
+ */
283
+ leaderboard(limit?: number): Promise<LeaderboardRow[]>;
284
+ /**
285
+ * Play one ranked playoff match. Bodyless POST — the server picks the
286
+ * opponent from the ladder and creates the caller's ladder entry on first
287
+ * call, which is how a new squad enters the competitive season at all.
288
+ *
289
+ * No body and therefore no content-type header: sending
290
+ * `application/json` with an empty body is what earns a 415 here.
291
+ */
292
+ playPlayoff(): Promise<unknown>;
293
+ createTeam(input: {
294
+ name: string;
295
+ nationCode: string;
296
+ players: unknown[];
297
+ }): Promise<unknown>;
298
+ updateTeam(teamId: string, input: {
299
+ players: unknown[];
300
+ name?: string;
301
+ }): Promise<unknown>;
302
+ /**
303
+ * Play a friendly. Team-id form only, on purpose: the server then reads both
304
+ * squads itself. The inline-squad form exists for engine callers and needs the
305
+ * engine's attribute names (dori/shoo/defe), which differ from the flat shape
306
+ * POST /api/teams takes — a trap worth not exposing to an agent.
307
+ *
308
+ * Authenticated, and the caller must OWN the home team: a friendly is a
309
+ * challenge you start with your squad against an arbitrary opponent. Without
310
+ * that gate anyone could fabricate results onto someone else's public career,
311
+ * so the route fails closed at 401 when no session is attached.
312
+ */
313
+ playFriendly(input: {
314
+ homeTeamId: string;
315
+ awayTeamId: string;
316
+ allowDraw?: boolean;
317
+ }): Promise<unknown>;
318
+ }
319
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}