chitin-openclaw-plugin 0.2.1 → 0.3.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/dist/index.d.ts +1 -1
- package/dist/index.js +128 -65
- package/openclaw.plugin.json +1 -1
- package/package.json +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 1. Wallet tools — check balance, claim faucet, deposit to table
|
|
6
6
|
* 2. Game tools — discover, lobby, create table, register, send action
|
|
7
7
|
* 3. WebSocket connection — persistent connection to poker table, your_turn events
|
|
8
|
-
* injected into agent session via
|
|
8
|
+
* injected into agent session via openclaw agent --message
|
|
9
9
|
*/
|
|
10
10
|
declare const plugin: {
|
|
11
11
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,12 @@ import { privateKeyToAccount } from "viem/accounts";
|
|
|
12
12
|
import { baseSepolia } from "viem/chains";
|
|
13
13
|
import WebSocket from "ws";
|
|
14
14
|
import { execFile } from "child_process";
|
|
15
|
+
import { trace, SpanStatusCode } from "@opentelemetry/api";
|
|
16
|
+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
17
|
+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
|
|
18
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
19
|
+
import { Resource } from "@opentelemetry/resources";
|
|
20
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
15
21
|
var ERC20_ABI = parseAbi([
|
|
16
22
|
"function balanceOf(address) view returns (uint256)",
|
|
17
23
|
"function transferAndCall(address to, uint256 amount, bytes data) returns (bool)",
|
|
@@ -32,43 +38,42 @@ function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress,
|
|
|
32
38
|
function connect() {
|
|
33
39
|
if (aborted) return;
|
|
34
40
|
const wsUrl = gameServerUrl.replace(/^http/, "ws") + `/parties/poker/${roomCode}`;
|
|
35
|
-
logger.info(`[chitin]
|
|
41
|
+
logger.info(`[chitin] WS connecting to ${wsUrl}`);
|
|
36
42
|
ws = new WebSocket(wsUrl);
|
|
37
43
|
ws.on("open", () => {
|
|
38
|
-
logger.info(`[chitin]
|
|
44
|
+
logger.info(`[chitin] WS connected to ${roomCode}`);
|
|
39
45
|
wsStore.set(roomCode, ws);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
name,
|
|
44
|
-
walletAddress
|
|
45
|
-
}));
|
|
46
|
+
const enterMsg = { type: "enter", playerId, name, walletAddress };
|
|
47
|
+
logger.info(`[chitin] WS sending enter: ${JSON.stringify(enterMsg)}`);
|
|
48
|
+
ws.send(JSON.stringify(enterMsg));
|
|
46
49
|
});
|
|
47
50
|
ws.on("message", (data) => {
|
|
48
51
|
try {
|
|
49
52
|
const msg = JSON.parse(data.toString());
|
|
50
53
|
handleMessage(msg, roomCode, logger);
|
|
51
54
|
} catch (err) {
|
|
52
|
-
logger.warn(`[chitin]
|
|
55
|
+
logger.warn(`[chitin] WS parse error: ${err.message}`);
|
|
53
56
|
}
|
|
54
57
|
});
|
|
55
|
-
ws.on("close", () => {
|
|
58
|
+
ws.on("close", (code) => {
|
|
56
59
|
if (aborted) return;
|
|
57
|
-
logger.info(`[chitin]
|
|
60
|
+
logger.info(`[chitin] WS closed (code ${code}), reconnecting in 3s...`);
|
|
58
61
|
setTimeout(connect, 3e3);
|
|
59
62
|
});
|
|
60
63
|
ws.on("error", (err) => {
|
|
61
|
-
logger.
|
|
64
|
+
logger.error(`[chitin] WS error: ${err.message}`);
|
|
62
65
|
});
|
|
63
66
|
}
|
|
64
67
|
const latestState = /* @__PURE__ */ new Map();
|
|
65
68
|
function handleMessage(msg, roomCode2, logger2) {
|
|
66
69
|
if (msg.type === "game_state") {
|
|
67
70
|
latestState.set(roomCode2, msg);
|
|
71
|
+
logger2.info(`[chitin] game_state: players=${msg.players?.length || 0} hand=${msg.isHandInProgress ? "yes" : "no"}`);
|
|
68
72
|
} else if (msg.type === "your_turn") {
|
|
69
73
|
const state = latestState.get(roomCode2);
|
|
70
74
|
const legalActions = msg.legalActions?.join(", ") || "";
|
|
71
75
|
const chipRange = msg.chipRange ? `${msg.chipRange.min}-${msg.chipRange.max}` : "";
|
|
76
|
+
logger2.info(`[chitin] YOUR TURN: actions=[${legalActions}] range=${chipRange}`);
|
|
72
77
|
const parts = [`POKER: It's your turn at table ${roomCode2}.`];
|
|
73
78
|
if (state?.holeCards) {
|
|
74
79
|
const cards = state.holeCards.map((c) => `${c.rank}${c.suit[0]}`).join(" ");
|
|
@@ -92,25 +97,30 @@ function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress,
|
|
|
92
97
|
} else if (msg.type === "hand_result") {
|
|
93
98
|
const winners = msg.result?.winners?.flat() || [];
|
|
94
99
|
const winnerNames = winners.map((w) => `${w.playerId}(${w.amount})`).join(", ");
|
|
100
|
+
logger2.info(`[chitin] HAND RESULT: winners=${winnerNames} rake=${msg.result?.rake || 0}`);
|
|
95
101
|
const text = `POKER HAND RESULT at table ${roomCode2}: Winners: ${winnerNames}. Rake: ${msg.result?.rake || 0}.`;
|
|
96
102
|
promptAgent(text, logger2);
|
|
103
|
+
} else {
|
|
104
|
+
logger2.info(`[chitin] WS msg: type=${msg.type}`);
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
107
|
function promptAgent(text, logger2) {
|
|
100
|
-
|
|
108
|
+
logger2.info(`[chitin] Prompting agent: ${text.slice(0, 100)}...`);
|
|
109
|
+
const child = execFile("openclaw", ["agent", "--local", "--message", text], {
|
|
110
|
+
timeout: 12e4,
|
|
111
|
+
env: process.env
|
|
112
|
+
// Inherit HOME pointing to workspace
|
|
113
|
+
}, (err, stdout, stderr) => {
|
|
101
114
|
if (err) {
|
|
102
|
-
logger2.error(`[chitin]
|
|
115
|
+
logger2.error(`[chitin] Agent prompt failed: ${err.message}`);
|
|
116
|
+
if (stderr) logger2.error(`[chitin] Agent stderr: ${stderr.slice(0, 500)}`);
|
|
103
117
|
return;
|
|
104
118
|
}
|
|
105
|
-
if (
|
|
106
|
-
logger2.
|
|
119
|
+
if (stdout) logger2.info(`[chitin] Agent response: ${stdout.slice(0, 300)}`);
|
|
120
|
+
if (stderr) logger2.warn(`[chitin] Agent stderr: ${stderr.slice(0, 300)}`);
|
|
121
|
+
logger2.info(`[chitin] Agent prompted ok`);
|
|
107
122
|
});
|
|
108
123
|
}
|
|
109
|
-
const sendAction = (action) => {
|
|
110
|
-
if (ws?.readyState === WebSocket.OPEN) {
|
|
111
|
-
ws.send(JSON.stringify({ type: "action", action }));
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
124
|
connect();
|
|
115
125
|
return () => {
|
|
116
126
|
aborted = true;
|
|
@@ -123,29 +133,57 @@ var plugin = {
|
|
|
123
133
|
description: "Play poker at Chitin Casino \u2014 wallet management and real-time game connection",
|
|
124
134
|
configSchema: {
|
|
125
135
|
type: "object",
|
|
126
|
-
additionalProperties:
|
|
136
|
+
additionalProperties: true,
|
|
127
137
|
properties: {}
|
|
128
138
|
},
|
|
129
139
|
register(api) {
|
|
130
140
|
api.logger.info("[chitin] Chitin Casino plugin loaded");
|
|
141
|
+
let tracer = trace.getTracer("chitin-plugin");
|
|
142
|
+
try {
|
|
143
|
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
144
|
+
const headers = process.env.OTEL_EXPORTER_OTLP_HEADERS;
|
|
145
|
+
if (endpoint) {
|
|
146
|
+
const headerObj = {};
|
|
147
|
+
if (headers) {
|
|
148
|
+
for (const pair of headers.split(",")) {
|
|
149
|
+
const [k, ...v] = pair.split("=");
|
|
150
|
+
if (k) headerObj[k.trim()] = v.join("=").trim();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const provider = new NodeTracerProvider({
|
|
154
|
+
resource: new Resource({ [ATTR_SERVICE_NAME]: "chitin-plugin" }),
|
|
155
|
+
spanProcessors: [
|
|
156
|
+
new BatchSpanProcessor(new OTLPTraceExporter({
|
|
157
|
+
url: `${endpoint}/v1/traces`,
|
|
158
|
+
headers: headerObj
|
|
159
|
+
}))
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
provider.register();
|
|
163
|
+
tracer = trace.getTracer("chitin-plugin");
|
|
164
|
+
api.logger.info(`[chitin] OTel initialized \u2014 endpoint=${endpoint}`);
|
|
165
|
+
const span = tracer.startSpan("plugin.loaded");
|
|
166
|
+
span.setAttributes({ "plugin.name": "chitin-openclaw-plugin" });
|
|
167
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
168
|
+
span.end();
|
|
169
|
+
api.logger.info("[chitin] OTel test span emitted: plugin.loaded");
|
|
170
|
+
} else {
|
|
171
|
+
api.logger.info("[chitin] OTel skipped \u2014 no OTEL_EXPORTER_OTLP_ENDPOINT");
|
|
172
|
+
}
|
|
173
|
+
} catch (err) {
|
|
174
|
+
api.logger.warn(`[chitin] OTel init failed (non-fatal): ${err.message}`);
|
|
175
|
+
}
|
|
131
176
|
const gameServerUrl = process.env.GAME_SERVER_URL || "http://localhost:3665";
|
|
177
|
+
const adminServerUrl = process.env.ADMIN_SERVER_URL || "http://localhost:3667";
|
|
132
178
|
const activeConnections = /* @__PURE__ */ new Map();
|
|
133
179
|
const wsInstances = /* @__PURE__ */ new Map();
|
|
134
|
-
api.registerTool({
|
|
135
|
-
name: "chitin_test",
|
|
136
|
-
label: "Chitin Test",
|
|
137
|
-
description: "A test tool that returns hello world",
|
|
138
|
-
parameters: { type: "object", properties: {} },
|
|
139
|
-
execute: async (_toolCallId) => {
|
|
140
|
-
return { message: "Hello from Chitin Casino plugin!" };
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
180
|
api.registerTool({
|
|
144
181
|
name: "chitin_wallet_address",
|
|
145
182
|
description: "Get your Chitin Casino wallet address",
|
|
146
183
|
parameters: {},
|
|
147
|
-
execute: async (
|
|
184
|
+
execute: async () => {
|
|
148
185
|
const { account } = getWalletClients();
|
|
186
|
+
api.logger.info(`[chitin] wallet_address: ${account.address}`);
|
|
149
187
|
return { address: account.address };
|
|
150
188
|
}
|
|
151
189
|
});
|
|
@@ -160,7 +198,9 @@ var plugin = {
|
|
|
160
198
|
},
|
|
161
199
|
execute: async (_toolCallId, params) => {
|
|
162
200
|
const { account, publicClient } = getWalletClients();
|
|
201
|
+
api.logger.info(`[chitin] wallet_balance: checking ${account.address}`);
|
|
163
202
|
const ethBalance = await publicClient.getBalance({ address: account.address });
|
|
203
|
+
api.logger.info(`[chitin] wallet_balance: ETH=${formatEther(ethBalance)}`);
|
|
164
204
|
let tokenBalance = BigInt(0);
|
|
165
205
|
let tokenAddr = params.tokenAddress;
|
|
166
206
|
if (!tokenAddr) {
|
|
@@ -168,7 +208,9 @@ var plugin = {
|
|
|
168
208
|
const res = await fetch(`${gameServerUrl}/contracts`);
|
|
169
209
|
const data = await res.json();
|
|
170
210
|
tokenAddr = data.token;
|
|
171
|
-
|
|
211
|
+
api.logger.info(`[chitin] wallet_balance: token=${tokenAddr}`);
|
|
212
|
+
} catch (err) {
|
|
213
|
+
api.logger.error(`[chitin] wallet_balance: failed to fetch token address: ${err.message}`);
|
|
172
214
|
}
|
|
173
215
|
}
|
|
174
216
|
if (tokenAddr) {
|
|
@@ -178,6 +220,7 @@ var plugin = {
|
|
|
178
220
|
functionName: "balanceOf",
|
|
179
221
|
args: [account.address]
|
|
180
222
|
});
|
|
223
|
+
api.logger.info(`[chitin] wallet_balance: NUMERO=${formatEther(tokenBalance)}`);
|
|
181
224
|
}
|
|
182
225
|
return {
|
|
183
226
|
address: account.address,
|
|
@@ -188,21 +231,18 @@ var plugin = {
|
|
|
188
231
|
});
|
|
189
232
|
api.registerTool({
|
|
190
233
|
name: "chitin_faucet_claim",
|
|
191
|
-
description: "Claim NUMERO tokens from the faucet.
|
|
234
|
+
description: "Claim NUMERO tokens from the faucet. Free \u2014 no gas needed.",
|
|
192
235
|
parameters: {},
|
|
193
|
-
execute: async (
|
|
236
|
+
execute: async () => {
|
|
194
237
|
const { account } = getWalletClients();
|
|
195
|
-
|
|
196
|
-
const serviceKey = process.env.SERVICE_KEY || "";
|
|
238
|
+
api.logger.info(`[chitin] faucet_claim: wallet=${account.address} server=${adminServerUrl}`);
|
|
197
239
|
const res = await fetch(`${adminServerUrl}/faucet/claim`, {
|
|
198
240
|
method: "POST",
|
|
199
|
-
headers: {
|
|
200
|
-
"Content-Type": "application/json",
|
|
201
|
-
"x-service-key": serviceKey
|
|
202
|
-
},
|
|
241
|
+
headers: { "Content-Type": "application/json" },
|
|
203
242
|
body: JSON.stringify({ walletAddress: account.address })
|
|
204
243
|
});
|
|
205
244
|
const data = await res.json();
|
|
245
|
+
api.logger.info(`[chitin] faucet_claim: status=${res.status} response=${JSON.stringify(data)}`);
|
|
206
246
|
if (!res.ok) throw new Error(data.error || "Faucet claim failed");
|
|
207
247
|
return data;
|
|
208
248
|
}
|
|
@@ -220,21 +260,27 @@ var plugin = {
|
|
|
220
260
|
required: ["amount", "tableId", "gameId"]
|
|
221
261
|
},
|
|
222
262
|
execute: async (_toolCallId, params) => {
|
|
263
|
+
api.logger.info(`[chitin] deposit: amount=${params.amount} tableId=${params.tableId} gameId=${params.gameId}`);
|
|
223
264
|
const { publicClient, walletClient } = getWalletClients();
|
|
265
|
+
api.logger.info(`[chitin] deposit: fetching contracts from ${gameServerUrl}/contracts`);
|
|
224
266
|
const res = await fetch(`${gameServerUrl}/contracts`);
|
|
225
267
|
const contracts = await res.json();
|
|
268
|
+
api.logger.info(`[chitin] deposit: token=${contracts.token} diamond=${contracts.diamond}`);
|
|
226
269
|
const amountWei = parseEther(params.amount);
|
|
227
270
|
const data = encodeAbiParameters(
|
|
228
271
|
[{ type: "bytes32" }, { type: "bytes32" }],
|
|
229
272
|
[params.tableId, params.gameId]
|
|
230
273
|
);
|
|
274
|
+
api.logger.info(`[chitin] deposit: sending transferAndCall amount=${amountWei} to=${contracts.diamond}`);
|
|
231
275
|
const hash = await walletClient.writeContract({
|
|
232
276
|
address: contracts.token,
|
|
233
277
|
abi: ERC20_ABI,
|
|
234
278
|
functionName: "transferAndCall",
|
|
235
279
|
args: [contracts.diamond, amountWei, data]
|
|
236
280
|
});
|
|
281
|
+
api.logger.info(`[chitin] deposit: tx sent hash=${hash}`);
|
|
237
282
|
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
283
|
+
api.logger.info(`[chitin] deposit: confirmed block=${receipt.blockNumber} status=${receipt.status}`);
|
|
238
284
|
return { txHash: hash, blockNumber: Number(receipt.blockNumber) };
|
|
239
285
|
}
|
|
240
286
|
});
|
|
@@ -242,18 +288,24 @@ var plugin = {
|
|
|
242
288
|
name: "chitin_discover",
|
|
243
289
|
description: "Discover Chitin Casino \u2014 games, contracts, faucet info",
|
|
244
290
|
parameters: {},
|
|
245
|
-
execute: async (
|
|
291
|
+
execute: async () => {
|
|
292
|
+
api.logger.info(`[chitin] discover: ${gameServerUrl}/discover`);
|
|
246
293
|
const res = await fetch(`${gameServerUrl}/discover`);
|
|
247
|
-
|
|
294
|
+
const data = await res.json();
|
|
295
|
+
api.logger.info(`[chitin] discover: status=${res.status}`);
|
|
296
|
+
return data;
|
|
248
297
|
}
|
|
249
298
|
});
|
|
250
299
|
api.registerTool({
|
|
251
300
|
name: "chitin_lobby",
|
|
252
301
|
description: "List poker tables with open seats",
|
|
253
302
|
parameters: {},
|
|
254
|
-
execute: async (
|
|
303
|
+
execute: async () => {
|
|
304
|
+
api.logger.info(`[chitin] lobby: ${gameServerUrl}/parties/pokerlobby/main/tables`);
|
|
255
305
|
const res = await fetch(`${gameServerUrl}/parties/pokerlobby/main/tables`);
|
|
256
|
-
|
|
306
|
+
const data = await res.json();
|
|
307
|
+
api.logger.info(`[chitin] lobby: status=${res.status} tables=${Array.isArray(data) ? data.length : "?"}`);
|
|
308
|
+
return data;
|
|
257
309
|
}
|
|
258
310
|
});
|
|
259
311
|
api.registerTool({
|
|
@@ -269,19 +321,21 @@ var plugin = {
|
|
|
269
321
|
}
|
|
270
322
|
},
|
|
271
323
|
execute: async (_toolCallId, params) => {
|
|
324
|
+
const settings = {
|
|
325
|
+
smallBlind: params.smallBlind || 1,
|
|
326
|
+
bigBlind: params.bigBlind || 2,
|
|
327
|
+
minBuyIn: params.minBuyIn || 50,
|
|
328
|
+
maxBuyIn: params.maxBuyIn || 200
|
|
329
|
+
};
|
|
330
|
+
api.logger.info(`[chitin] create_table: ${JSON.stringify(settings)}`);
|
|
272
331
|
const res = await fetch(`${gameServerUrl}/parties/poker/create`, {
|
|
273
332
|
method: "POST",
|
|
274
333
|
headers: { "Content-Type": "application/json" },
|
|
275
|
-
body: JSON.stringify({
|
|
276
|
-
settings: {
|
|
277
|
-
smallBlind: params.smallBlind || 1,
|
|
278
|
-
bigBlind: params.bigBlind || 2,
|
|
279
|
-
minBuyIn: params.minBuyIn || 50,
|
|
280
|
-
maxBuyIn: params.maxBuyIn || 200
|
|
281
|
-
}
|
|
282
|
-
})
|
|
334
|
+
body: JSON.stringify({ settings })
|
|
283
335
|
});
|
|
284
|
-
|
|
336
|
+
const data = await res.json();
|
|
337
|
+
api.logger.info(`[chitin] create_table: status=${res.status} response=${JSON.stringify(data)}`);
|
|
338
|
+
return data;
|
|
285
339
|
}
|
|
286
340
|
});
|
|
287
341
|
api.registerTool({
|
|
@@ -299,6 +353,7 @@ var plugin = {
|
|
|
299
353
|
execute: async (_toolCallId, params) => {
|
|
300
354
|
const { account } = getWalletClients();
|
|
301
355
|
const botName = params.name || "ClawBot";
|
|
356
|
+
api.logger.info(`[chitin] register: room=${params.roomCode} name=${botName} buyIn=${params.buyIn || 200} wallet=${account.address}`);
|
|
302
357
|
const res = await fetch(`${gameServerUrl}/parties/poker/${params.roomCode}/register`, {
|
|
303
358
|
method: "POST",
|
|
304
359
|
headers: { "Content-Type": "application/json" },
|
|
@@ -309,6 +364,7 @@ var plugin = {
|
|
|
309
364
|
})
|
|
310
365
|
});
|
|
311
366
|
const result = await res.json();
|
|
367
|
+
api.logger.info(`[chitin] register: status=${res.status} response=${JSON.stringify(result)}`);
|
|
312
368
|
if (!res.ok) return result;
|
|
313
369
|
const cleanup = connectToTable(
|
|
314
370
|
gameServerUrl,
|
|
@@ -319,8 +375,7 @@ var plugin = {
|
|
|
319
375
|
api.logger,
|
|
320
376
|
wsInstances
|
|
321
377
|
);
|
|
322
|
-
activeConnections.set(params.roomCode, { cleanup
|
|
323
|
-
api.logger.info(`[chitin] Registered at ${params.roomCode}, WebSocket connected`);
|
|
378
|
+
activeConnections.set(params.roomCode, { cleanup });
|
|
324
379
|
return { ...result, wsConnected: true };
|
|
325
380
|
}
|
|
326
381
|
});
|
|
@@ -337,13 +392,16 @@ var plugin = {
|
|
|
337
392
|
required: ["roomCode", "action"]
|
|
338
393
|
},
|
|
339
394
|
execute: async (_toolCallId, params) => {
|
|
395
|
+
api.logger.info(`[chitin] poker_action: room=${params.roomCode} action=${params.action} amount=${params.amount ?? "n/a"}`);
|
|
340
396
|
const ws = wsInstances.get(params.roomCode);
|
|
341
397
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
398
|
+
api.logger.error(`[chitin] poker_action: NOT CONNECTED to ${params.roomCode} (ws=${ws ? "exists" : "null"} state=${ws?.readyState})`);
|
|
342
399
|
return { error: "Not connected to table. Call chitin_register first." };
|
|
343
400
|
}
|
|
344
401
|
const action = { type: params.action };
|
|
345
402
|
if (params.amount !== void 0) action.amount = params.amount;
|
|
346
403
|
ws.send(JSON.stringify({ type: "action", action }));
|
|
404
|
+
api.logger.info(`[chitin] poker_action: sent ${JSON.stringify(action)}`);
|
|
347
405
|
return { ok: true, sent: action };
|
|
348
406
|
}
|
|
349
407
|
});
|
|
@@ -359,22 +417,27 @@ var plugin = {
|
|
|
359
417
|
required: ["roomCode", "token"]
|
|
360
418
|
},
|
|
361
419
|
execute: async (_toolCallId, params) => {
|
|
420
|
+
api.logger.info(`[chitin] leave_table: room=${params.roomCode}`);
|
|
421
|
+
const ws = wsInstances.get(params.roomCode);
|
|
422
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
423
|
+
ws.send(JSON.stringify({ type: "leave" }));
|
|
424
|
+
api.logger.info(`[chitin] leave_table: sent leave via WS`);
|
|
425
|
+
}
|
|
362
426
|
const conn = activeConnections.get(params.roomCode);
|
|
363
427
|
if (conn) {
|
|
364
428
|
conn.cleanup();
|
|
365
429
|
activeConnections.delete(params.roomCode);
|
|
366
430
|
}
|
|
367
431
|
wsInstances.delete(params.roomCode);
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
432
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
433
|
+
api.logger.info(`[chitin] leave_table: fallback to HTTP leave`);
|
|
434
|
+
const res = await fetch(`${gameServerUrl}/parties/poker/${params.roomCode}/leave`, {
|
|
435
|
+
method: "POST",
|
|
436
|
+
headers: { "Authorization": `Bearer ${params.token}` }
|
|
437
|
+
});
|
|
438
|
+
return await res.json();
|
|
372
439
|
}
|
|
373
|
-
|
|
374
|
-
method: "POST",
|
|
375
|
-
headers: { "Authorization": `Bearer ${params.token}` }
|
|
376
|
-
});
|
|
377
|
-
return await res.json();
|
|
440
|
+
return { ok: true };
|
|
378
441
|
}
|
|
379
442
|
});
|
|
380
443
|
}
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chitin-openclaw-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "OpenClaw plugin for Chitin Casino — wallet management and poker game connection",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
"prepublishOnly": "npm run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@opentelemetry/api": "^1.9.0",
|
|
34
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.57.0",
|
|
35
|
+
"@opentelemetry/resources": "^1.30.0",
|
|
36
|
+
"@opentelemetry/sdk-trace-node": "^1.30.0",
|
|
37
|
+
"@opentelemetry/semantic-conventions": "^1.28.0",
|
|
33
38
|
"viem": "^2.0.0",
|
|
34
39
|
"ws": "^8.0.0"
|
|
35
40
|
},
|