@aifight/aifight 0.1.0-alpha.1
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 +160 -0
- package/dist/bin.mjs +291 -0
- package/dist/index.mjs +107 -0
- package/dist/schemas/README.md +57 -0
- package/dist/schemas/common/README.md +40 -0
- package/dist/schemas/common/action.schema.json +19 -0
- package/dist/schemas/common/error.schema.json +23 -0
- package/dist/schemas/common/event.schema.json +33 -0
- package/dist/schemas/common/game_result.schema.json +31 -0
- package/dist/schemas/common/player_identity.schema.json +29 -0
- package/dist/schemas/common/player_info.schema.json +27 -0
- package/dist/schemas/common/rules.schema.json +34 -0
- package/dist/schemas/games/README.md +43 -0
- package/dist/schemas/games/coup/README.md +104 -0
- package/dist/schemas/games/coup/action.schema.json +198 -0
- package/dist/schemas/games/coup/event.schema.json +249 -0
- package/dist/schemas/games/coup/rules.schema.json +46 -0
- package/dist/schemas/games/coup/state.schema.json +123 -0
- package/dist/schemas/games/liars_dice/README.md +59 -0
- package/dist/schemas/games/liars_dice/action.schema.json +45 -0
- package/dist/schemas/games/liars_dice/event.schema.json +120 -0
- package/dist/schemas/games/liars_dice/rules.schema.json +36 -0
- package/dist/schemas/games/liars_dice/state.schema.json +72 -0
- package/dist/schemas/games/texas_holdem/README.md +58 -0
- package/dist/schemas/games/texas_holdem/action.schema.json +88 -0
- package/dist/schemas/games/texas_holdem/config.schema.json +30 -0
- package/dist/schemas/games/texas_holdem/event.schema.json +135 -0
- package/dist/schemas/games/texas_holdem/rules.schema.json +39 -0
- package/dist/schemas/games/texas_holdem/state.schema.json +98 -0
- package/dist/schemas/messages/README.md +98 -0
- package/dist/schemas/messages/client_action.schema.json +20 -0
- package/dist/schemas/messages/client_join_queue.schema.json +39 -0
- package/dist/schemas/messages/client_leave_queue.schema.json +18 -0
- package/dist/schemas/messages/client_match_confirm.schema.json +25 -0
- package/dist/schemas/messages/client_runtime_status.schema.json +46 -0
- package/dist/schemas/messages/server_action_request.schema.json +71 -0
- package/dist/schemas/messages/server_error.schema.json +16 -0
- package/dist/schemas/messages/server_event.schema.json +30 -0
- package/dist/schemas/messages/server_game_over.schema.json +49 -0
- package/dist/schemas/messages/server_game_start.schema.json +99 -0
- package/dist/schemas/messages/server_game_state.schema.json +33 -0
- package/dist/schemas/messages/server_match_cancelled.schema.json +51 -0
- package/dist/schemas/messages/server_match_confirm_request.schema.json +37 -0
- package/dist/schemas/messages/server_queue_joined.schema.json +26 -0
- package/dist/schemas/messages/server_queue_left.schema.json +24 -0
- package/dist/schemas/messages/server_readiness_check.schema.json +42 -0
- package/dist/schemas/messages/server_welcome.schema.json +49 -0
- package/dist/schemas/rest/README.md +85 -0
- package/dist/schemas/rest/agent_status_response.schema.json +34 -0
- package/dist/schemas/rest/claim_request.schema.json +20 -0
- package/dist/schemas/rest/claim_response.schema.json +24 -0
- package/dist/schemas/rest/error_response.schema.json +15 -0
- package/dist/schemas/rest/register_request.schema.json +35 -0
- package/dist/schemas/rest/register_response.schema.json +54 -0
- package/dist/types/account/credentials.d.ts +29 -0
- package/dist/types/account/errors.d.ts +61 -0
- package/dist/types/account/registration.d.ts +26 -0
- package/dist/types/agents/agent.d.ts +82 -0
- package/dist/types/agents/state-machine.d.ts +96 -0
- package/dist/types/bridge/config.d.ts +35 -0
- package/dist/types/bridge/hermes-provider.d.ts +9 -0
- package/dist/types/bridge/openclaw-provider.d.ts +9 -0
- package/dist/types/bridge/pairing.d.ts +18 -0
- package/dist/types/bridge/provider.d.ts +18 -0
- package/dist/types/bridge/runner.d.ts +30 -0
- package/dist/types/bridge/service.d.ts +55 -0
- package/dist/types/bridge/update-check.d.ts +23 -0
- package/dist/types/cli/agent-resolver.d.ts +25 -0
- package/dist/types/cli/argv.d.ts +13 -0
- package/dist/types/cli/commands/agent-list.d.ts +2 -0
- package/dist/types/cli/commands/agent-status.d.ts +2 -0
- package/dist/types/cli/commands/bridge-accept.d.ts +2 -0
- package/dist/types/cli/commands/bridge-challenge.d.ts +2 -0
- package/dist/types/cli/commands/bridge-connect.d.ts +2 -0
- package/dist/types/cli/commands/bridge-register.d.ts +2 -0
- package/dist/types/cli/commands/bridge-run.d.ts +7 -0
- package/dist/types/cli/commands/bridge-service.d.ts +3 -0
- package/dist/types/cli/commands/bridge-set.d.ts +2 -0
- package/dist/types/cli/commands/bridge-start.d.ts +2 -0
- package/dist/types/cli/commands/bridge-status.d.ts +2 -0
- package/dist/types/cli/commands/bridge-uninstall.d.ts +4 -0
- package/dist/types/cli/commands/config-init.d.ts +2 -0
- package/dist/types/cli/commands/config-probe.d.ts +2 -0
- package/dist/types/cli/commands/config-validate.d.ts +2 -0
- package/dist/types/cli/commands/daily-off.d.ts +2 -0
- package/dist/types/cli/commands/daily-on.d.ts +2 -0
- package/dist/types/cli/commands/daily-set.d.ts +2 -0
- package/dist/types/cli/commands/daily-show.d.ts +2 -0
- package/dist/types/cli/commands/doctor.d.ts +2 -0
- package/dist/types/cli/commands/init.d.ts +2 -0
- package/dist/types/cli/commands/join.d.ts +2 -0
- package/dist/types/cli/commands/leave.d.ts +2 -0
- package/dist/types/cli/commands/mcp.d.ts +2 -0
- package/dist/types/cli/commands/runtime-management.d.ts +16 -0
- package/dist/types/cli/commands/runtime-setup-state.d.ts +21 -0
- package/dist/types/cli/commands/runtime-setup.d.ts +23 -0
- package/dist/types/cli/commands/serve.d.ts +2 -0
- package/dist/types/cli/commands/service/launchd.d.ts +71 -0
- package/dist/types/cli/commands/service/platform.d.ts +69 -0
- package/dist/types/cli/commands/service/systemd.d.ts +55 -0
- package/dist/types/cli/commands/service/types.d.ts +64 -0
- package/dist/types/cli/commands/service-install.d.ts +29 -0
- package/dist/types/cli/commands/setup.d.ts +2 -0
- package/dist/types/cli/commands/shutdown.d.ts +2 -0
- package/dist/types/cli/commands/stubs.d.ts +24 -0
- package/dist/types/cli/commands/version.d.ts +2 -0
- package/dist/types/cli/control-client.d.ts +59 -0
- package/dist/types/cli/format.d.ts +52 -0
- package/dist/types/cli/main.d.ts +18 -0
- package/dist/types/cli/runtime-files.d.ts +11 -0
- package/dist/types/cli/shared.d.ts +74 -0
- package/dist/types/controlapi/profile-routes.d.ts +49 -0
- package/dist/types/controlapi/server.d.ts +3 -0
- package/dist/types/controlapi/types.d.ts +136 -0
- package/dist/types/daemon/agent-decision-adapter.d.ts +40 -0
- package/dist/types/daemon/lifecycle.d.ts +85 -0
- package/dist/types/daemon/router.d.ts +97 -0
- package/dist/types/daemon/runtime-files-write.d.ts +76 -0
- package/dist/types/decision/direct-model/anthropic.d.ts +12 -0
- package/dist/types/decision/direct-model/errors.d.ts +59 -0
- package/dist/types/decision/direct-model/openai.d.ts +12 -0
- package/dist/types/decision/direct-model/types.d.ts +20 -0
- package/dist/types/decision/parser-types.d.ts +31 -0
- package/dist/types/decision/prompt-builder.d.ts +10 -0
- package/dist/types/decision/provider.d.ts +50 -0
- package/dist/types/decision/types.d.ts +87 -0
- package/dist/types/games/_shared/player-info.d.ts +14 -0
- package/dist/types/games/coup/action-parser.d.ts +3 -0
- package/dist/types/games/coup/fallback.d.ts +8 -0
- package/dist/types/games/coup/state-formatter.d.ts +14 -0
- package/dist/types/games/liars_dice/action-parser.d.ts +3 -0
- package/dist/types/games/liars_dice/fallback.d.ts +8 -0
- package/dist/types/games/liars_dice/state-formatter.d.ts +14 -0
- package/dist/types/games/texas_holdem/action-parser.d.ts +3 -0
- package/dist/types/games/texas_holdem/fallback.d.ts +8 -0
- package/dist/types/games/texas_holdem/state-formatter.d.ts +14 -0
- package/dist/types/identity/identity-manager.d.ts +59 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/llm/adapter-registry.d.ts +27 -0
- package/dist/types/llm/adapters/anthropic-messages.d.ts +2 -0
- package/dist/types/llm/adapters/deepseek-chat-completions.d.ts +2 -0
- package/dist/types/llm/adapters/openai-chat-compat.d.ts +2 -0
- package/dist/types/llm/adapters/openai-chat-completions.d.ts +2 -0
- package/dist/types/llm/adapters/openai-responses.d.ts +2 -0
- package/dist/types/llm/adapters/types.d.ts +128 -0
- package/dist/types/llm/capabilities/validate-capabilities.d.ts +68 -0
- package/dist/types/mcp/control-client.d.ts +54 -0
- package/dist/types/mcp/profile-tools.d.ts +10 -0
- package/dist/types/mcp/server.d.ts +10 -0
- package/dist/types/mcp/tools.d.ts +31 -0
- package/dist/types/mcp/types.d.ts +27 -0
- package/dist/types/profile/config-schema.d.ts +199 -0
- package/dist/types/profile/identity-schema.d.ts +75 -0
- package/dist/types/profile/index.d.ts +7 -0
- package/dist/types/profile/migrate.d.ts +16 -0
- package/dist/types/profile/profile-loader.d.ts +64 -0
- package/dist/types/profile/secret-ref.d.ts +82 -0
- package/dist/types/profile/soul.d.ts +46 -0
- package/dist/types/profile/strategy-schema.d.ts +70 -0
- package/dist/types/protocol/schemas.d.ts +11 -0
- package/dist/types/protocol/types.d.ts +1333 -0
- package/dist/types/reflection/proposal-store.d.ts +50 -0
- package/dist/types/reflection/reflection-engine.d.ts +81 -0
- package/dist/types/scheduler/daily.d.ts +47 -0
- package/dist/types/scheduler/types.d.ts +42 -0
- package/dist/types/session/match-session-manager.d.ts +113 -0
- package/dist/types/session/session-context-builder.d.ts +68 -0
- package/dist/types/store/errors.d.ts +23 -0
- package/dist/types/store/paths.d.ts +3 -0
- package/dist/types/store/schema.generated.d.ts +1 -0
- package/dist/types/store/sqlite.d.ts +36 -0
- package/dist/types/wsclient/client.d.ts +220 -0
- package/dist/types/wsclient/errors.d.ts +106 -0
- package/dist/types/wsclient/frame-handler.d.ts +20 -0
- package/dist/types/wsclient/reconnect.d.ts +84 -0
- package/package.json +53 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/coup/event.schema.json",
|
|
4
|
+
"title": "CoupEvent",
|
|
5
|
+
"description": "Coup-specific event payload, describing the `data` field of common/event.schema.json when the event occurred in a Coup match. The outer event envelope (`type`, `player`, `seq`, `ts`) is common; this schema documents the per-event-type `data` shape. Discriminator is the outer `type` field. Mirrors games/coup/coup.go emission sites.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "object",
|
|
9
|
+
"description": "action — emitted when a player declares their turn action. Outer `player` is the actor. For income/tax/foreign_aid/exchange, no target. For coup/assassinate/steal, target is present. For tax/assassinate/steal/exchange, claimed_role is present.",
|
|
10
|
+
"required": ["action"],
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"properties": {
|
|
13
|
+
"action": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"enum": ["income", "foreign_aid", "coup", "tax", "assassinate", "steal", "exchange"]
|
|
16
|
+
},
|
|
17
|
+
"target": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Target player ID for coup/assassinate/steal."
|
|
20
|
+
},
|
|
21
|
+
"claimed_role": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador"],
|
|
24
|
+
"description": "Role claimed for tax/assassinate/steal/exchange. Absent for income/foreign_aid/coup."
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "object",
|
|
30
|
+
"description": "challenge_pass — emitted when a player declines to challenge the action claim. Outer `player` is the passer.",
|
|
31
|
+
"required": ["player"],
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"properties": {
|
|
34
|
+
"player": { "type": "string" }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "object",
|
|
39
|
+
"description": "challenge — emitted when a player challenges the action's role claim. Outer `player` is the challenger.",
|
|
40
|
+
"required": ["challenger", "actor", "claimed_role"],
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"properties": {
|
|
43
|
+
"challenger": { "type": "string" },
|
|
44
|
+
"actor": { "type": "string" },
|
|
45
|
+
"claimed_role": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"type": "object",
|
|
53
|
+
"description": "challenge_result — emitted after a challenge resolves. Outer `player` is the actor (whose claim was checked). result='fail' means actor was truthful (challenger loses influence + actor reshuffles and redraws — server reveals which card via revealed_card). result='success' means actor was lying (actor loses influence; action cancelled).",
|
|
54
|
+
"required": ["result", "actor", "challenger"],
|
|
55
|
+
"additionalProperties": true,
|
|
56
|
+
"properties": {
|
|
57
|
+
"result": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"enum": ["fail", "success"]
|
|
60
|
+
},
|
|
61
|
+
"revealed_card": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"],
|
|
64
|
+
"description": "Role name of the card briefly exposed during a failed-challenge reshuffle. Present only when result == 'fail'."
|
|
65
|
+
},
|
|
66
|
+
"actor": { "type": "string" },
|
|
67
|
+
"challenger": { "type": "string" }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"type": "object",
|
|
72
|
+
"description": "block_pass — emitted when an eligible player declines to block. Outer `player` is the passer. For foreign_aid, any non-actor alive player emits one; for assassinate/steal, only the target can block so at most one block_pass.",
|
|
73
|
+
"required": ["player"],
|
|
74
|
+
"additionalProperties": false,
|
|
75
|
+
"properties": {
|
|
76
|
+
"player": { "type": "string" }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "object",
|
|
81
|
+
"description": "block — emitted when a player declares a block. Outer `player` is the blocker.",
|
|
82
|
+
"required": ["blocker", "claimed_role", "action"],
|
|
83
|
+
"additionalProperties": false,
|
|
84
|
+
"properties": {
|
|
85
|
+
"blocker": { "type": "string" },
|
|
86
|
+
"claimed_role": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"enum": ["Duke", "Contessa", "Captain", "Ambassador"]
|
|
89
|
+
},
|
|
90
|
+
"action": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"enum": ["foreign_aid", "assassinate", "steal"],
|
|
93
|
+
"description": "The pending action being blocked."
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"type": "object",
|
|
99
|
+
"description": "block_challenge_pass — emitted when a player declines to challenge the block. Outer `player` is the passer.",
|
|
100
|
+
"required": ["player"],
|
|
101
|
+
"additionalProperties": false,
|
|
102
|
+
"properties": {
|
|
103
|
+
"player": { "type": "string" }
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "object",
|
|
108
|
+
"description": "block_accepted — emitted when all eligible players have passed on challenging the block. Outer `player` is the blocker. Action is cancelled; turn advances.",
|
|
109
|
+
"required": ["blocker"],
|
|
110
|
+
"additionalProperties": false,
|
|
111
|
+
"properties": {
|
|
112
|
+
"blocker": { "type": "string" }
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "object",
|
|
117
|
+
"description": "challenge_block — emitted when a player challenges the block claim. Outer `player` is the challenger.",
|
|
118
|
+
"required": ["challenger", "blocker", "claimed_role"],
|
|
119
|
+
"additionalProperties": false,
|
|
120
|
+
"properties": {
|
|
121
|
+
"challenger": { "type": "string" },
|
|
122
|
+
"blocker": { "type": "string" },
|
|
123
|
+
"claimed_role": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"enum": ["Duke", "Contessa", "Captain", "Ambassador"]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"type": "object",
|
|
131
|
+
"description": "challenge_block_result — emitted after a block-challenge resolves. Outer `player` is the blocker. result='fail' means blocker was truthful (challenger loses influence + blocker reshuffles and redraws); block stands, action cancelled. result='success' means blocker was lying (blocker loses influence); block fails, action executes.",
|
|
132
|
+
"required": ["result", "blocker", "challenger"],
|
|
133
|
+
"additionalProperties": true,
|
|
134
|
+
"properties": {
|
|
135
|
+
"result": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"enum": ["fail", "success"]
|
|
138
|
+
},
|
|
139
|
+
"revealed_card": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"enum": ["Duke", "Contessa", "Captain", "Ambassador"],
|
|
142
|
+
"description": "Role exposed during reshuffle on result=='fail'."
|
|
143
|
+
},
|
|
144
|
+
"blocker": { "type": "string" },
|
|
145
|
+
"challenger": { "type": "string" }
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"type": "object",
|
|
150
|
+
"description": "influence_lost — emitted when a player reveals one of their cards (losing influence). Outer `player` is the card owner. Public knowledge from here on.",
|
|
151
|
+
"required": ["player", "card", "card_index"],
|
|
152
|
+
"additionalProperties": false,
|
|
153
|
+
"properties": {
|
|
154
|
+
"player": { "type": "string" },
|
|
155
|
+
"card": {
|
|
156
|
+
"type": "string",
|
|
157
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"]
|
|
158
|
+
},
|
|
159
|
+
"card_index": {
|
|
160
|
+
"type": "number",
|
|
161
|
+
"minimum": 0
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"type": "object",
|
|
167
|
+
"description": "player_eliminated — emitted when a player has no face-down cards remaining. Outer `player` is the eliminated player.",
|
|
168
|
+
"required": ["player"],
|
|
169
|
+
"additionalProperties": false,
|
|
170
|
+
"properties": {
|
|
171
|
+
"player": { "type": "string" }
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"type": "object",
|
|
176
|
+
"description": "exchange_draw — emitted when the Exchange action resolves and the server draws 2 cards for the actor. Outer `player` is the actor. drawn_count is normally 2 but may be fewer if the deck is nearly empty.",
|
|
177
|
+
"required": ["action", "drawn_count"],
|
|
178
|
+
"additionalProperties": false,
|
|
179
|
+
"properties": {
|
|
180
|
+
"action": { "const": "exchange" },
|
|
181
|
+
"drawn_count": {
|
|
182
|
+
"type": "number",
|
|
183
|
+
"minimum": 0,
|
|
184
|
+
"maximum": 2
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"type": "object",
|
|
190
|
+
"description": "exchange_complete — emitted when the actor has returned their chosen cards to the deck, completing the Exchange. Outer `player` is the actor.",
|
|
191
|
+
"required": ["player", "returned_count"],
|
|
192
|
+
"additionalProperties": false,
|
|
193
|
+
"properties": {
|
|
194
|
+
"player": { "type": "string" },
|
|
195
|
+
"returned_count": {
|
|
196
|
+
"type": "number",
|
|
197
|
+
"minimum": 0
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"type": "object",
|
|
203
|
+
"description": "action_resolved — emitted when a non-coup action finally applies its effect (after all challenge/block phases completed). Outer `player` is the actor. Emitted for foreign_aid / tax / assassinate / steal (exchange uses exchange_draw + exchange_complete instead; coup skips this and goes straight to lose_influence).",
|
|
204
|
+
"required": ["action"],
|
|
205
|
+
"additionalProperties": true,
|
|
206
|
+
"properties": {
|
|
207
|
+
"action": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"enum": ["foreign_aid", "tax", "assassinate", "steal"]
|
|
210
|
+
},
|
|
211
|
+
"coins_now": {
|
|
212
|
+
"type": "number",
|
|
213
|
+
"minimum": 0,
|
|
214
|
+
"description": "Actor's coin count after the action. Present for foreign_aid/tax/steal."
|
|
215
|
+
},
|
|
216
|
+
"target": {
|
|
217
|
+
"type": "string",
|
|
218
|
+
"description": "Target player ID. Present for assassinate/steal."
|
|
219
|
+
},
|
|
220
|
+
"stolen": {
|
|
221
|
+
"type": "number",
|
|
222
|
+
"minimum": 0,
|
|
223
|
+
"description": "Coins actually stolen (capped at target's pre-steal balance). Present for steal."
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"type": "object",
|
|
229
|
+
"description": "game_over — emitted when only one (or zero, degenerate) alive player remains. No outer `player`.",
|
|
230
|
+
"required": ["winner"],
|
|
231
|
+
"additionalProperties": false,
|
|
232
|
+
"properties": {
|
|
233
|
+
"winner": {
|
|
234
|
+
"type": "string",
|
|
235
|
+
"description": "Player ID of the winner. Empty string if zero alive players remained."
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"type": "object",
|
|
241
|
+
"description": "player_disconnected — emitted when a player is removed mid-match due to timeout/disconnect. Outer `player` is the disconnected player. All their cards are force-revealed; usually followed by player_eliminated and a state-flow continuation (advanceTurn / executeAction).",
|
|
242
|
+
"required": ["player"],
|
|
243
|
+
"additionalProperties": false,
|
|
244
|
+
"properties": {
|
|
245
|
+
"player": { "type": "string" }
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/coup/rules.schema.json",
|
|
4
|
+
"title": "CoupRules",
|
|
5
|
+
"description": "Rules payload for Coup, delivered in server_game_start.data.rules when game == 'coup'. Mirrors games/coup/coup.go Game.Rules(). Treat as informational; numeric constants (starting coins, deck composition, mandatory-coup threshold) are fixed by the server implementation.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "summary", "available_actions", "key_rules"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": {
|
|
11
|
+
"const": "Coup"
|
|
12
|
+
},
|
|
13
|
+
"summary": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Free-form summary paragraph; treat as informational."
|
|
16
|
+
},
|
|
17
|
+
"phases": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": { "type": "string" },
|
|
20
|
+
"description": "Human-readable phase descriptions (action, challenge_action, block, challenge_block, lose_influence, exchange_return)."
|
|
21
|
+
},
|
|
22
|
+
"available_actions": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"required": ["income", "foreign_aid", "coup", "tax", "assassinate", "steal", "exchange", "challenge", "pass", "block", "lose_card", "return_cards"],
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"properties": {
|
|
27
|
+
"income": { "type": "string" },
|
|
28
|
+
"foreign_aid": { "type": "string" },
|
|
29
|
+
"coup": { "type": "string" },
|
|
30
|
+
"tax": { "type": "string" },
|
|
31
|
+
"assassinate": { "type": "string" },
|
|
32
|
+
"steal": { "type": "string" },
|
|
33
|
+
"exchange": { "type": "string" },
|
|
34
|
+
"challenge": { "type": "string" },
|
|
35
|
+
"pass": { "type": "string" },
|
|
36
|
+
"block": { "type": "string" },
|
|
37
|
+
"lose_card": { "type": "string" },
|
|
38
|
+
"return_cards": { "type": "string" }
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"key_rules": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": { "type": "string" }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/coup/state.schema.json",
|
|
4
|
+
"title": "CoupState",
|
|
5
|
+
"description": "Per-player state delivered in server_action_request.data.state when game == 'coup'. Built by games/coup/coup.go GetPlayerView() L1592. Mixes **public fields** (phase, current_turn, pending_action, pending_target, claimed_role, blocker, block_role, influence_loser, turn_log, winner) with **private fields** (your_cards, your_revealed, coins, exchange_cards, all_exchange_options). The outer PlayerView.players array carries coins + hidden_cards count + revealed cards for everyone (public); only the recipient sees their own hidden card roles via your_cards.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["phase", "current_turn"],
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"properties": {
|
|
10
|
+
"phase": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"enum": ["action", "challenge_action", "block", "challenge_block", "lose_influence", "exchange_return", "done"],
|
|
13
|
+
"description": "State machine phase. 'action' = actor chooses. 'challenge_action' = others may challenge role claim. 'block' = eligible players may block. 'challenge_block' = anyone may challenge the block. 'lose_influence' = a player reveals a card. 'exchange_return' = Ambassador picks cards to return."
|
|
14
|
+
},
|
|
15
|
+
"current_turn": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Player ID whose turn it is (i.e. the actor of this action). Not necessarily the player being prompted — see legal_actions in the message envelope."
|
|
18
|
+
},
|
|
19
|
+
"pending_action": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"enum": ["income", "foreign_aid", "coup", "tax", "assassinate", "steal", "exchange"],
|
|
22
|
+
"description": "The action being resolved. Present in all phases except 'action' (when the actor is picking) and 'done'."
|
|
23
|
+
},
|
|
24
|
+
"pending_target": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Player ID target of the pending action (coup/assassinate/steal). Omitted when action has no target."
|
|
27
|
+
},
|
|
28
|
+
"claimed_role": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"],
|
|
31
|
+
"description": "Role the actor claims for their action (Tax=Duke, Assassinate=Assassin, Steal=Captain, Exchange=Ambassador). Omitted for income / foreign_aid / coup (no role claim)."
|
|
32
|
+
},
|
|
33
|
+
"blocker": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Player ID who has declared a block. Present in 'challenge_block' phase; absent otherwise."
|
|
36
|
+
},
|
|
37
|
+
"block_role": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"enum": ["Duke", "Contessa", "Captain", "Ambassador"],
|
|
40
|
+
"description": "Role the blocker claims (Duke blocks foreign_aid; Contessa blocks assassinate; Captain or Ambassador blocks steal). Present in 'challenge_block' phase."
|
|
41
|
+
},
|
|
42
|
+
"influence_loser": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "Player ID who must choose a card to reveal. Present in 'lose_influence' phase."
|
|
45
|
+
},
|
|
46
|
+
"turn_log": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"description": "Narrative trace of this turn's resolution. Fields populate as the turn progresses. All entries refer to the current turn; cleared when advanceTurn() runs.",
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"properties": {
|
|
51
|
+
"action": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": ["income", "foreign_aid", "coup", "tax", "assassinate", "steal", "exchange"]
|
|
54
|
+
},
|
|
55
|
+
"actor": { "type": "string" },
|
|
56
|
+
"target": { "type": "string" },
|
|
57
|
+
"claimed_role": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"]
|
|
60
|
+
},
|
|
61
|
+
"challenger": { "type": "string" },
|
|
62
|
+
"challenge_result": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"enum": ["success", "fail"],
|
|
65
|
+
"description": "'success' = actor was lying, actor loses influence. 'fail' = actor was truthful, challenger loses influence."
|
|
66
|
+
},
|
|
67
|
+
"blocker": { "type": "string" },
|
|
68
|
+
"block_role": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"enum": ["Duke", "Contessa", "Captain", "Ambassador"]
|
|
71
|
+
},
|
|
72
|
+
"block_challenger": { "type": "string" },
|
|
73
|
+
"block_challenge_result": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"enum": ["success", "fail"],
|
|
76
|
+
"description": "'success' = blocker was lying, blocker loses influence. 'fail' = blocker was truthful, block_challenger loses influence."
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"your_cards": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"]
|
|
85
|
+
},
|
|
86
|
+
"maxItems": 2,
|
|
87
|
+
"description": "**PRIVATE.** Your unrevealed (face-down) cards. 1-2 entries. Replaced by server after a successful-claim challenge shuffle-and-redraw."
|
|
88
|
+
},
|
|
89
|
+
"your_revealed": {
|
|
90
|
+
"type": "array",
|
|
91
|
+
"items": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"]
|
|
94
|
+
},
|
|
95
|
+
"description": "Your face-up (revealed) cards. Public — opponents' equivalent appears in the players array's `revealed` field."
|
|
96
|
+
},
|
|
97
|
+
"coins": {
|
|
98
|
+
"type": "integer",
|
|
99
|
+
"minimum": 0,
|
|
100
|
+
"description": "**PRIVATE** convenience field (opponents' coins are in the players array's `coins`). Your current coin count."
|
|
101
|
+
},
|
|
102
|
+
"exchange_cards": {
|
|
103
|
+
"type": "array",
|
|
104
|
+
"items": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"]
|
|
107
|
+
},
|
|
108
|
+
"description": "**PRIVATE.** The 2 cards drawn from the deck for your pending Exchange. Present only when phase == 'exchange_return' AND you are the actor."
|
|
109
|
+
},
|
|
110
|
+
"all_exchange_options": {
|
|
111
|
+
"type": "array",
|
|
112
|
+
"items": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"enum": ["Duke", "Assassin", "Captain", "Ambassador", "Contessa"]
|
|
115
|
+
},
|
|
116
|
+
"description": "**PRIVATE.** Convenience view = your_cards ++ exchange_cards. Present only when phase == 'exchange_return' AND you are the actor. Indices here are the ones you pass to return_cards."
|
|
117
|
+
},
|
|
118
|
+
"winner": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"description": "Player ID of the match winner. Present only when phase == 'done'."
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# protocol/schema/games/liars_dice
|
|
2
|
+
|
|
3
|
+
Game-specific schemas for Liar's Dice. Source of truth:
|
|
4
|
+
[`games/liarsdice/liarsdice.go`](../../../../games/liarsdice/liarsdice.go).
|
|
5
|
+
|
|
6
|
+
## Files
|
|
7
|
+
|
|
8
|
+
| Schema | Mirrors | Used at |
|
|
9
|
+
|--------|---------|---------|
|
|
10
|
+
| [`rules.schema.json`](./rules.schema.json) | `Game.Rules()` L56 | `server_game_start.data.rules` |
|
|
11
|
+
| [`state.schema.json`](./state.schema.json) | `GetPlayerView()` L372 → `PlayerView.GameData` | `server_action_request.data.state`, `server_game_state.data.state` |
|
|
12
|
+
| [`action.schema.json`](./action.schema.json) | `GetLegalActions()` L121 + `ValidateAction()` L175 | `client_action.data`, `server_action_request.data.legal_actions[*]` |
|
|
13
|
+
| [`event.schema.json`](./event.schema.json) | All `events = append(..., Event{Type: ...})` emission sites | `server_action_request.data.new_events[*]`, `common/event.schema.json` `data` field when outer type is a Liar's Dice event |
|
|
14
|
+
|
|
15
|
+
No `config.schema.json`: `NewState()` ignores the `GameConfig` — dice count
|
|
16
|
+
(5 per player) and face range (1-6) are fixed by the Go implementation.
|
|
17
|
+
`server_game_start.data.config` for liars_dice is effectively an empty
|
|
18
|
+
object.
|
|
19
|
+
|
|
20
|
+
## Action enum
|
|
21
|
+
|
|
22
|
+
2 actions: `bid`, `challenge`. Legality:
|
|
23
|
+
|
|
24
|
+
- `challenge` — only legal when `current_bid` is set
|
|
25
|
+
- `bid` — always legal; must strictly beat `current_bid` (same quantity +
|
|
26
|
+
higher face, or higher quantity); quantity capped at `total_dice`
|
|
27
|
+
|
|
28
|
+
## Event types
|
|
29
|
+
|
|
30
|
+
6 event types:
|
|
31
|
+
|
|
32
|
+
- `bid` — a player places a bid
|
|
33
|
+
- `challenge` — a player calls 'Liar!'; reveals all alive players' dice
|
|
34
|
+
- `player_eliminated` — a player loses their last die
|
|
35
|
+
- `round_start` — new round starts after challenge (dice re-rolled) or
|
|
36
|
+
after a drop-induced reset; emitted only for round >= 2
|
|
37
|
+
- `game_over` — exactly one (or zero) alive players remain
|
|
38
|
+
- `player_disconnected` — timeout/disconnect removal
|
|
39
|
+
|
|
40
|
+
## Anonymization reminder
|
|
41
|
+
|
|
42
|
+
- `your_dice` and `your_dice_count` are **private**: only sent to the
|
|
43
|
+
owning recipient.
|
|
44
|
+
- The `all_dice` field in a `challenge` event **publicly reveals** all
|
|
45
|
+
alive players' dice — this is core to the game mechanic.
|
|
46
|
+
- Public state includes: phase, round, current_bid (quantity/face/bidder),
|
|
47
|
+
current_turn, total_dice.
|
|
48
|
+
|
|
49
|
+
## Scope notes
|
|
50
|
+
|
|
51
|
+
- `common/action.schema.json` is the generic envelope; `action.schema.json`
|
|
52
|
+
here uses `oneOf` to narrow.
|
|
53
|
+
- `common/event.schema.json` provides the outer envelope (`type`, `player?`,
|
|
54
|
+
`seq`, `ts`); the `data` field's narrowing per Liar's Dice event type is
|
|
55
|
+
what `event.schema.json` here describes.
|
|
56
|
+
- Ones-are-wild rule is a server-side resolution concern; the `face == 1`
|
|
57
|
+
exception (no wilds on bids-of-ones) is noted in schema descriptions but
|
|
58
|
+
not encoded as a validation rule (bid validity is purely quantity/face
|
|
59
|
+
monotonicity at the protocol layer).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/liars_dice/action.schema.json",
|
|
4
|
+
"title": "LiarsDiceAction",
|
|
5
|
+
"description": "Action payload for Liar's Dice, sent as client_action.data when game == 'liars_dice'. Two discriminated variants by `type`. `challenge` is only legal when there is a current bid. `bid` has subtype constraints the server enforces via ValidateAction: must be strictly higher than current bid (same quantity + higher face, or higher quantity), and quantity must not exceed total_dice in play. Mirrors games/liarsdice/liarsdice.go GetLegalActions() + ValidateAction().",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "object",
|
|
9
|
+
"required": ["type", "data"],
|
|
10
|
+
"additionalProperties": false,
|
|
11
|
+
"properties": {
|
|
12
|
+
"type": { "const": "bid" },
|
|
13
|
+
"data": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["quantity", "face"],
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"properties": {
|
|
18
|
+
"quantity": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 1,
|
|
21
|
+
"description": "Claimed total count of the face value across all alive players' dice. Must be <= total_dice in state."
|
|
22
|
+
},
|
|
23
|
+
"face": {
|
|
24
|
+
"type": "integer",
|
|
25
|
+
"minimum": 1,
|
|
26
|
+
"maximum": 6,
|
|
27
|
+
"description": "Face value you are bidding on (1-6). If face == 1, ones are NOT wild for this bid."
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"description": "Make a bid. First bid of a round can be any valid (quantity, face). Subsequent bids must beat the current bid: either keep quantity and raise face, or raise quantity."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "object",
|
|
36
|
+
"required": ["type"],
|
|
37
|
+
"additionalProperties": false,
|
|
38
|
+
"properties": {
|
|
39
|
+
"type": { "const": "challenge" },
|
|
40
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
41
|
+
},
|
|
42
|
+
"description": "Challenge the previous bid ('Liar!'). Only legal when current_bid is set. All dice are revealed; loser (bidder if bid fails, challenger if bid holds) drops a die."
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/liars_dice/event.schema.json",
|
|
4
|
+
"title": "LiarsDiceEvent",
|
|
5
|
+
"description": "Liar's Dice-specific event payload, describing the `data` field of common/event.schema.json when the event occurred in a Liar's Dice match. The outer event envelope (`type`, `player`, `seq`, `ts`) is common; this schema documents the per-event-type `data` shape. Discriminator is the outer `type` field. Mirrors games/liarsdice/liarsdice.go emission sites.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "object",
|
|
9
|
+
"description": "bid — emitted when a player places a bid. Outer envelope's `player` is the bidder.",
|
|
10
|
+
"required": ["quantity", "face"],
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"properties": {
|
|
13
|
+
"quantity": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"minimum": 1,
|
|
16
|
+
"description": "Claimed count of the face value across all alive players' dice."
|
|
17
|
+
},
|
|
18
|
+
"face": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 1,
|
|
21
|
+
"maximum": 6,
|
|
22
|
+
"description": "Face value bid upon."
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "object",
|
|
28
|
+
"description": "challenge — emitted when a player challenges the current bid. Outer envelope's `player` is the challenger. Reveals ALL alive players' dice in `all_dice`.",
|
|
29
|
+
"required": ["challenger", "bidder", "bid_quantity", "bid_face", "actual_count", "bid_met", "all_dice", "loser"],
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"properties": {
|
|
32
|
+
"challenger": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "Player ID of the challenger (same as outer `player`)."
|
|
35
|
+
},
|
|
36
|
+
"bidder": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Player ID who made the bid being challenged."
|
|
39
|
+
},
|
|
40
|
+
"bid_quantity": { "type": "integer", "minimum": 1 },
|
|
41
|
+
"bid_face": { "type": "integer", "minimum": 1, "maximum": 6 },
|
|
42
|
+
"actual_count": {
|
|
43
|
+
"type": "integer",
|
|
44
|
+
"minimum": 0,
|
|
45
|
+
"description": "Actual count of matching face values. If bid_face != 1, ones count as wild."
|
|
46
|
+
},
|
|
47
|
+
"bid_met": {
|
|
48
|
+
"type": "boolean",
|
|
49
|
+
"description": "True iff actual_count >= bid_quantity. When true, challenger loses a die; when false, bidder loses."
|
|
50
|
+
},
|
|
51
|
+
"all_dice": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"description": "Map of player_id -> array of their revealed dice face values (1-6). Only alive players at challenge time are included.",
|
|
54
|
+
"additionalProperties": {
|
|
55
|
+
"type": "array",
|
|
56
|
+
"items": { "type": "integer", "minimum": 1, "maximum": 6 }
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"loser": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"description": "Player ID who loses a die."
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "object",
|
|
67
|
+
"description": "player_eliminated — emitted when a player loses their last die. Outer envelope's `player` is the eliminated player.",
|
|
68
|
+
"required": ["player"],
|
|
69
|
+
"additionalProperties": false,
|
|
70
|
+
"properties": {
|
|
71
|
+
"player": {
|
|
72
|
+
"type": "string",
|
|
73
|
+
"description": "Player ID eliminated (same as outer `player`)."
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "object",
|
|
79
|
+
"description": "round_start — emitted at the start of each round after round 1 (or after a drop-induced reset). No `player`. Dice are re-rolled before this event.",
|
|
80
|
+
"required": ["round", "dice_counts"],
|
|
81
|
+
"additionalProperties": false,
|
|
82
|
+
"properties": {
|
|
83
|
+
"round": {
|
|
84
|
+
"type": "integer",
|
|
85
|
+
"minimum": 2,
|
|
86
|
+
"description": "New round number (>= 2)."
|
|
87
|
+
},
|
|
88
|
+
"dice_counts": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"description": "Map of player_id -> dice count for alive players only.",
|
|
91
|
+
"additionalProperties": { "type": "integer", "minimum": 1, "maximum": 5 }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "game_over — emitted when only one alive player remains (or zero, in degenerate cases). No `player`.",
|
|
98
|
+
"required": ["winner"],
|
|
99
|
+
"additionalProperties": false,
|
|
100
|
+
"properties": {
|
|
101
|
+
"winner": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"description": "Player ID of the winner. Empty string if no winner (e.g. simultaneous elimination)."
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"type": "object",
|
|
109
|
+
"description": "player_disconnected — emitted when a player is removed mid-match due to timeout/disconnect. Outer envelope's `player` is the disconnected player. Usually followed by player_eliminated and possibly round_start.",
|
|
110
|
+
"required": ["player"],
|
|
111
|
+
"additionalProperties": false,
|
|
112
|
+
"properties": {
|
|
113
|
+
"player": {
|
|
114
|
+
"type": "string",
|
|
115
|
+
"description": "Player ID disconnected (same as outer `player`)."
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|