chitin-openclaw-plugin 0.2.1 → 0.2.2

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 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 hooks
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
@@ -32,43 +32,42 @@ function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress,
32
32
  function connect() {
33
33
  if (aborted) return;
34
34
  const wsUrl = gameServerUrl.replace(/^http/, "ws") + `/parties/poker/${roomCode}`;
35
- logger.info(`[chitin] Connecting WebSocket to ${wsUrl}`);
35
+ logger.info(`[chitin] WS connecting to ${wsUrl}`);
36
36
  ws = new WebSocket(wsUrl);
37
37
  ws.on("open", () => {
38
- logger.info(`[chitin] WebSocket connected to table ${roomCode}`);
38
+ logger.info(`[chitin] WS connected to ${roomCode}`);
39
39
  wsStore.set(roomCode, ws);
40
- ws.send(JSON.stringify({
41
- type: "enter",
42
- playerId,
43
- name,
44
- walletAddress
45
- }));
40
+ const enterMsg = { type: "enter", playerId, name, walletAddress };
41
+ logger.info(`[chitin] WS sending enter: ${JSON.stringify(enterMsg)}`);
42
+ ws.send(JSON.stringify(enterMsg));
46
43
  });
47
44
  ws.on("message", (data) => {
48
45
  try {
49
46
  const msg = JSON.parse(data.toString());
50
47
  handleMessage(msg, roomCode, logger);
51
48
  } catch (err) {
52
- logger.warn(`[chitin] Failed to parse message: ${err.message}`);
49
+ logger.warn(`[chitin] WS parse error: ${err.message}`);
53
50
  }
54
51
  });
55
- ws.on("close", () => {
52
+ ws.on("close", (code) => {
56
53
  if (aborted) return;
57
- logger.info(`[chitin] WebSocket closed for table ${roomCode}, reconnecting in 3s...`);
54
+ logger.info(`[chitin] WS closed (code ${code}), reconnecting in 3s...`);
58
55
  setTimeout(connect, 3e3);
59
56
  });
60
57
  ws.on("error", (err) => {
61
- logger.warn(`[chitin] WebSocket error: ${err.message}`);
58
+ logger.error(`[chitin] WS error: ${err.message}`);
62
59
  });
63
60
  }
64
61
  const latestState = /* @__PURE__ */ new Map();
65
62
  function handleMessage(msg, roomCode2, logger2) {
66
63
  if (msg.type === "game_state") {
67
64
  latestState.set(roomCode2, msg);
65
+ logger2.info(`[chitin] game_state: players=${msg.players?.length || 0} hand=${msg.isHandInProgress ? "yes" : "no"}`);
68
66
  } else if (msg.type === "your_turn") {
69
67
  const state = latestState.get(roomCode2);
70
68
  const legalActions = msg.legalActions?.join(", ") || "";
71
69
  const chipRange = msg.chipRange ? `${msg.chipRange.min}-${msg.chipRange.max}` : "";
70
+ logger2.info(`[chitin] YOUR TURN: actions=[${legalActions}] range=${chipRange}`);
72
71
  const parts = [`POKER: It's your turn at table ${roomCode2}.`];
73
72
  if (state?.holeCards) {
74
73
  const cards = state.holeCards.map((c) => `${c.rank}${c.suit[0]}`).join(" ");
@@ -92,25 +91,24 @@ function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress,
92
91
  } else if (msg.type === "hand_result") {
93
92
  const winners = msg.result?.winners?.flat() || [];
94
93
  const winnerNames = winners.map((w) => `${w.playerId}(${w.amount})`).join(", ");
94
+ logger2.info(`[chitin] HAND RESULT: winners=${winnerNames} rake=${msg.result?.rake || 0}`);
95
95
  const text = `POKER HAND RESULT at table ${roomCode2}: Winners: ${winnerNames}. Rake: ${msg.result?.rake || 0}.`;
96
96
  promptAgent(text, logger2);
97
+ } else {
98
+ logger2.info(`[chitin] WS msg: type=${msg.type}`);
97
99
  }
98
100
  }
99
101
  function promptAgent(text, logger2) {
102
+ logger2.info(`[chitin] Prompting agent: ${text.slice(0, 100)}...`);
100
103
  execFile("openclaw", ["agent", "--local", "--message", text], (err, _stdout, stderr) => {
101
104
  if (err) {
102
- logger2.error(`[chitin] Failed to prompt agent: ${err.message}`);
105
+ logger2.error(`[chitin] Agent prompt failed: ${err.message}`);
103
106
  return;
104
107
  }
105
- if (stderr) logger2.warn(`[chitin] Agent stderr: ${stderr}`);
106
- logger2.info(`[chitin] Agent prompted successfully`);
108
+ if (stderr) logger2.warn(`[chitin] Agent stderr: ${stderr.slice(0, 200)}`);
109
+ logger2.info(`[chitin] Agent prompted ok`);
107
110
  });
108
111
  }
109
- const sendAction = (action) => {
110
- if (ws?.readyState === WebSocket.OPEN) {
111
- ws.send(JSON.stringify({ type: "action", action }));
112
- }
113
- };
114
112
  connect();
115
113
  return () => {
116
114
  aborted = true;
@@ -123,29 +121,22 @@ var plugin = {
123
121
  description: "Play poker at Chitin Casino \u2014 wallet management and real-time game connection",
124
122
  configSchema: {
125
123
  type: "object",
126
- additionalProperties: false,
124
+ additionalProperties: true,
127
125
  properties: {}
128
126
  },
129
127
  register(api) {
130
128
  api.logger.info("[chitin] Chitin Casino plugin loaded");
131
129
  const gameServerUrl = process.env.GAME_SERVER_URL || "http://localhost:3665";
130
+ const adminServerUrl = process.env.ADMIN_SERVER_URL || "http://localhost:3667";
132
131
  const activeConnections = /* @__PURE__ */ new Map();
133
132
  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
133
  api.registerTool({
144
134
  name: "chitin_wallet_address",
145
135
  description: "Get your Chitin Casino wallet address",
146
136
  parameters: {},
147
- execute: async (_toolCallId) => {
137
+ execute: async () => {
148
138
  const { account } = getWalletClients();
139
+ api.logger.info(`[chitin] wallet_address: ${account.address}`);
149
140
  return { address: account.address };
150
141
  }
151
142
  });
@@ -160,7 +151,9 @@ var plugin = {
160
151
  },
161
152
  execute: async (_toolCallId, params) => {
162
153
  const { account, publicClient } = getWalletClients();
154
+ api.logger.info(`[chitin] wallet_balance: checking ${account.address}`);
163
155
  const ethBalance = await publicClient.getBalance({ address: account.address });
156
+ api.logger.info(`[chitin] wallet_balance: ETH=${formatEther(ethBalance)}`);
164
157
  let tokenBalance = BigInt(0);
165
158
  let tokenAddr = params.tokenAddress;
166
159
  if (!tokenAddr) {
@@ -168,7 +161,9 @@ var plugin = {
168
161
  const res = await fetch(`${gameServerUrl}/contracts`);
169
162
  const data = await res.json();
170
163
  tokenAddr = data.token;
171
- } catch {
164
+ api.logger.info(`[chitin] wallet_balance: token=${tokenAddr}`);
165
+ } catch (err) {
166
+ api.logger.error(`[chitin] wallet_balance: failed to fetch token address: ${err.message}`);
172
167
  }
173
168
  }
174
169
  if (tokenAddr) {
@@ -178,6 +173,7 @@ var plugin = {
178
173
  functionName: "balanceOf",
179
174
  args: [account.address]
180
175
  });
176
+ api.logger.info(`[chitin] wallet_balance: NUMERO=${formatEther(tokenBalance)}`);
181
177
  }
182
178
  return {
183
179
  address: account.address,
@@ -188,21 +184,18 @@ var plugin = {
188
184
  });
189
185
  api.registerTool({
190
186
  name: "chitin_faucet_claim",
191
- description: "Claim NUMERO tokens from the faucet. This is a free server-side operation \u2014 no gas needed.",
187
+ description: "Claim NUMERO tokens from the faucet. Free \u2014 no gas needed.",
192
188
  parameters: {},
193
- execute: async (_toolCallId) => {
189
+ execute: async () => {
194
190
  const { account } = getWalletClients();
195
- const adminServerUrl = process.env.ADMIN_SERVER_URL || "http://localhost:3667";
196
- const serviceKey = process.env.SERVICE_KEY || "";
191
+ api.logger.info(`[chitin] faucet_claim: wallet=${account.address} server=${adminServerUrl}`);
197
192
  const res = await fetch(`${adminServerUrl}/faucet/claim`, {
198
193
  method: "POST",
199
- headers: {
200
- "Content-Type": "application/json",
201
- "x-service-key": serviceKey
202
- },
194
+ headers: { "Content-Type": "application/json" },
203
195
  body: JSON.stringify({ walletAddress: account.address })
204
196
  });
205
197
  const data = await res.json();
198
+ api.logger.info(`[chitin] faucet_claim: status=${res.status} response=${JSON.stringify(data)}`);
206
199
  if (!res.ok) throw new Error(data.error || "Faucet claim failed");
207
200
  return data;
208
201
  }
@@ -220,21 +213,27 @@ var plugin = {
220
213
  required: ["amount", "tableId", "gameId"]
221
214
  },
222
215
  execute: async (_toolCallId, params) => {
216
+ api.logger.info(`[chitin] deposit: amount=${params.amount} tableId=${params.tableId} gameId=${params.gameId}`);
223
217
  const { publicClient, walletClient } = getWalletClients();
218
+ api.logger.info(`[chitin] deposit: fetching contracts from ${gameServerUrl}/contracts`);
224
219
  const res = await fetch(`${gameServerUrl}/contracts`);
225
220
  const contracts = await res.json();
221
+ api.logger.info(`[chitin] deposit: token=${contracts.token} diamond=${contracts.diamond}`);
226
222
  const amountWei = parseEther(params.amount);
227
223
  const data = encodeAbiParameters(
228
224
  [{ type: "bytes32" }, { type: "bytes32" }],
229
225
  [params.tableId, params.gameId]
230
226
  );
227
+ api.logger.info(`[chitin] deposit: sending transferAndCall amount=${amountWei} to=${contracts.diamond}`);
231
228
  const hash = await walletClient.writeContract({
232
229
  address: contracts.token,
233
230
  abi: ERC20_ABI,
234
231
  functionName: "transferAndCall",
235
232
  args: [contracts.diamond, amountWei, data]
236
233
  });
234
+ api.logger.info(`[chitin] deposit: tx sent hash=${hash}`);
237
235
  const receipt = await publicClient.waitForTransactionReceipt({ hash });
236
+ api.logger.info(`[chitin] deposit: confirmed block=${receipt.blockNumber} status=${receipt.status}`);
238
237
  return { txHash: hash, blockNumber: Number(receipt.blockNumber) };
239
238
  }
240
239
  });
@@ -242,18 +241,24 @@ var plugin = {
242
241
  name: "chitin_discover",
243
242
  description: "Discover Chitin Casino \u2014 games, contracts, faucet info",
244
243
  parameters: {},
245
- execute: async (_toolCallId) => {
244
+ execute: async () => {
245
+ api.logger.info(`[chitin] discover: ${gameServerUrl}/discover`);
246
246
  const res = await fetch(`${gameServerUrl}/discover`);
247
- return await res.json();
247
+ const data = await res.json();
248
+ api.logger.info(`[chitin] discover: status=${res.status}`);
249
+ return data;
248
250
  }
249
251
  });
250
252
  api.registerTool({
251
253
  name: "chitin_lobby",
252
254
  description: "List poker tables with open seats",
253
255
  parameters: {},
254
- execute: async (_toolCallId) => {
256
+ execute: async () => {
257
+ api.logger.info(`[chitin] lobby: ${gameServerUrl}/parties/pokerlobby/main/tables`);
255
258
  const res = await fetch(`${gameServerUrl}/parties/pokerlobby/main/tables`);
256
- return await res.json();
259
+ const data = await res.json();
260
+ api.logger.info(`[chitin] lobby: status=${res.status} tables=${Array.isArray(data) ? data.length : "?"}`);
261
+ return data;
257
262
  }
258
263
  });
259
264
  api.registerTool({
@@ -269,19 +274,21 @@ var plugin = {
269
274
  }
270
275
  },
271
276
  execute: async (_toolCallId, params) => {
277
+ const settings = {
278
+ smallBlind: params.smallBlind || 1,
279
+ bigBlind: params.bigBlind || 2,
280
+ minBuyIn: params.minBuyIn || 50,
281
+ maxBuyIn: params.maxBuyIn || 200
282
+ };
283
+ api.logger.info(`[chitin] create_table: ${JSON.stringify(settings)}`);
272
284
  const res = await fetch(`${gameServerUrl}/parties/poker/create`, {
273
285
  method: "POST",
274
286
  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
- })
287
+ body: JSON.stringify({ settings })
283
288
  });
284
- return await res.json();
289
+ const data = await res.json();
290
+ api.logger.info(`[chitin] create_table: status=${res.status} response=${JSON.stringify(data)}`);
291
+ return data;
285
292
  }
286
293
  });
287
294
  api.registerTool({
@@ -299,6 +306,7 @@ var plugin = {
299
306
  execute: async (_toolCallId, params) => {
300
307
  const { account } = getWalletClients();
301
308
  const botName = params.name || "ClawBot";
309
+ api.logger.info(`[chitin] register: room=${params.roomCode} name=${botName} buyIn=${params.buyIn || 200} wallet=${account.address}`);
302
310
  const res = await fetch(`${gameServerUrl}/parties/poker/${params.roomCode}/register`, {
303
311
  method: "POST",
304
312
  headers: { "Content-Type": "application/json" },
@@ -309,6 +317,7 @@ var plugin = {
309
317
  })
310
318
  });
311
319
  const result = await res.json();
320
+ api.logger.info(`[chitin] register: status=${res.status} response=${JSON.stringify(result)}`);
312
321
  if (!res.ok) return result;
313
322
  const cleanup = connectToTable(
314
323
  gameServerUrl,
@@ -319,8 +328,7 @@ var plugin = {
319
328
  api.logger,
320
329
  wsInstances
321
330
  );
322
- activeConnections.set(params.roomCode, { cleanup, ws: null });
323
- api.logger.info(`[chitin] Registered at ${params.roomCode}, WebSocket connected`);
331
+ activeConnections.set(params.roomCode, { cleanup });
324
332
  return { ...result, wsConnected: true };
325
333
  }
326
334
  });
@@ -337,13 +345,16 @@ var plugin = {
337
345
  required: ["roomCode", "action"]
338
346
  },
339
347
  execute: async (_toolCallId, params) => {
348
+ api.logger.info(`[chitin] poker_action: room=${params.roomCode} action=${params.action} amount=${params.amount ?? "n/a"}`);
340
349
  const ws = wsInstances.get(params.roomCode);
341
350
  if (!ws || ws.readyState !== WebSocket.OPEN) {
351
+ api.logger.error(`[chitin] poker_action: NOT CONNECTED to ${params.roomCode} (ws=${ws ? "exists" : "null"} state=${ws?.readyState})`);
342
352
  return { error: "Not connected to table. Call chitin_register first." };
343
353
  }
344
354
  const action = { type: params.action };
345
355
  if (params.amount !== void 0) action.amount = params.amount;
346
356
  ws.send(JSON.stringify({ type: "action", action }));
357
+ api.logger.info(`[chitin] poker_action: sent ${JSON.stringify(action)}`);
347
358
  return { ok: true, sent: action };
348
359
  }
349
360
  });
@@ -359,22 +370,27 @@ var plugin = {
359
370
  required: ["roomCode", "token"]
360
371
  },
361
372
  execute: async (_toolCallId, params) => {
373
+ api.logger.info(`[chitin] leave_table: room=${params.roomCode}`);
374
+ const ws = wsInstances.get(params.roomCode);
375
+ if (ws?.readyState === WebSocket.OPEN) {
376
+ ws.send(JSON.stringify({ type: "leave" }));
377
+ api.logger.info(`[chitin] leave_table: sent leave via WS`);
378
+ }
362
379
  const conn = activeConnections.get(params.roomCode);
363
380
  if (conn) {
364
381
  conn.cleanup();
365
382
  activeConnections.delete(params.roomCode);
366
383
  }
367
384
  wsInstances.delete(params.roomCode);
368
- const ws = wsInstances.get(params.roomCode);
369
- if (ws?.readyState === WebSocket.OPEN) {
370
- ws.send(JSON.stringify({ type: "leave" }));
371
- return { ok: true };
385
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
386
+ api.logger.info(`[chitin] leave_table: fallback to HTTP leave`);
387
+ const res = await fetch(`${gameServerUrl}/parties/poker/${params.roomCode}/leave`, {
388
+ method: "POST",
389
+ headers: { "Authorization": `Bearer ${params.token}` }
390
+ });
391
+ return await res.json();
372
392
  }
373
- const res = await fetch(`${gameServerUrl}/parties/poker/${params.roomCode}/leave`, {
374
- method: "POST",
375
- headers: { "Authorization": `Bearer ${params.token}` }
376
- });
377
- return await res.json();
393
+ return { ok: true };
378
394
  }
379
395
  });
380
396
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "chitin-openclaw-plugin",
3
3
  "name": "Chitin Casino",
4
- "version": "0.1.0",
4
+ "version": "0.2.2",
5
5
  "description": "Play poker at Chitin Casino — wallet management and real-time game connection",
6
6
  "author": "Chitin Casino",
7
7
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chitin-openclaw-plugin",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "OpenClaw plugin for Chitin Casino — wallet management and poker game connection",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",