@chitincasino/openclaw-plugin 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/dist/index.d.ts +22 -0
- package/dist/index.js +385 -0
- package/openclaw.plugin.json +17 -0
- package/package.json +42 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chitin Casino Plugin for OpenClaw
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* 1. Wallet tools — check balance, claim faucet, deposit to table
|
|
6
|
+
* 2. Game tools — discover, lobby, create table, register, send action
|
|
7
|
+
* 3. WebSocket connection — persistent connection to poker table, your_turn events
|
|
8
|
+
* injected into agent session via hooks
|
|
9
|
+
*/
|
|
10
|
+
declare const plugin: {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
configSchema: {
|
|
15
|
+
type: "object";
|
|
16
|
+
additionalProperties: boolean;
|
|
17
|
+
properties: {};
|
|
18
|
+
};
|
|
19
|
+
register(api: any): void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { plugin as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
createPublicClient,
|
|
4
|
+
createWalletClient,
|
|
5
|
+
http,
|
|
6
|
+
parseAbi,
|
|
7
|
+
parseEther,
|
|
8
|
+
formatEther,
|
|
9
|
+
encodeAbiParameters
|
|
10
|
+
} from "viem";
|
|
11
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
12
|
+
import { baseSepolia } from "viem/chains";
|
|
13
|
+
import WebSocket from "ws";
|
|
14
|
+
import { execFile } from "child_process";
|
|
15
|
+
var ERC20_ABI = parseAbi([
|
|
16
|
+
"function balanceOf(address) view returns (uint256)",
|
|
17
|
+
"function transferAndCall(address to, uint256 amount, bytes data) returns (bool)",
|
|
18
|
+
"function faucet() external"
|
|
19
|
+
]);
|
|
20
|
+
function getWalletClients() {
|
|
21
|
+
const privateKey = process.env.PRIVATE_KEY;
|
|
22
|
+
if (!privateKey) throw new Error("PRIVATE_KEY env var is required");
|
|
23
|
+
const rpcUrl = process.env.RPC_URL || "https://sepolia.base.org";
|
|
24
|
+
const account = privateKeyToAccount(privateKey);
|
|
25
|
+
const publicClient = createPublicClient({ chain: baseSepolia, transport: http(rpcUrl) });
|
|
26
|
+
const walletClient = createWalletClient({ account, chain: baseSepolia, transport: http(rpcUrl) });
|
|
27
|
+
return { account, publicClient, walletClient };
|
|
28
|
+
}
|
|
29
|
+
function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress, logger, wsStore) {
|
|
30
|
+
let ws = null;
|
|
31
|
+
let aborted = false;
|
|
32
|
+
function connect() {
|
|
33
|
+
if (aborted) return;
|
|
34
|
+
const wsUrl = gameServerUrl.replace(/^http/, "ws") + `/parties/poker/${roomCode}`;
|
|
35
|
+
logger.info(`[chitin] Connecting WebSocket to ${wsUrl}`);
|
|
36
|
+
ws = new WebSocket(wsUrl);
|
|
37
|
+
ws.on("open", () => {
|
|
38
|
+
logger.info(`[chitin] WebSocket connected to table ${roomCode}`);
|
|
39
|
+
wsStore.set(roomCode, ws);
|
|
40
|
+
ws.send(JSON.stringify({
|
|
41
|
+
type: "enter",
|
|
42
|
+
playerId,
|
|
43
|
+
name,
|
|
44
|
+
walletAddress
|
|
45
|
+
}));
|
|
46
|
+
});
|
|
47
|
+
ws.on("message", (data) => {
|
|
48
|
+
try {
|
|
49
|
+
const msg = JSON.parse(data.toString());
|
|
50
|
+
handleMessage(msg, roomCode, logger);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
logger.warn(`[chitin] Failed to parse message: ${err.message}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
ws.on("close", () => {
|
|
56
|
+
if (aborted) return;
|
|
57
|
+
logger.info(`[chitin] WebSocket closed for table ${roomCode}, reconnecting in 3s...`);
|
|
58
|
+
setTimeout(connect, 3e3);
|
|
59
|
+
});
|
|
60
|
+
ws.on("error", (err) => {
|
|
61
|
+
logger.warn(`[chitin] WebSocket error: ${err.message}`);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const latestState = /* @__PURE__ */ new Map();
|
|
65
|
+
function handleMessage(msg, roomCode2, logger2) {
|
|
66
|
+
if (msg.type === "game_state") {
|
|
67
|
+
latestState.set(roomCode2, msg);
|
|
68
|
+
} else if (msg.type === "your_turn") {
|
|
69
|
+
const state = latestState.get(roomCode2);
|
|
70
|
+
const legalActions = msg.legalActions?.join(", ") || "";
|
|
71
|
+
const chipRange = msg.chipRange ? `${msg.chipRange.min}-${msg.chipRange.max}` : "";
|
|
72
|
+
const parts = [`POKER: It's your turn at table ${roomCode2}.`];
|
|
73
|
+
if (state?.holeCards) {
|
|
74
|
+
const cards = state.holeCards.map((c) => `${c.rank}${c.suit[0]}`).join(" ");
|
|
75
|
+
parts.push(`Your cards: ${cards}.`);
|
|
76
|
+
}
|
|
77
|
+
if (state?.communityCards?.length > 0) {
|
|
78
|
+
const cards = state.communityCards.map((c) => `${c.rank}${c.suit[0]}`).join(" ");
|
|
79
|
+
parts.push(`Community: ${cards}.`);
|
|
80
|
+
}
|
|
81
|
+
if (state?.pots?.length > 0) {
|
|
82
|
+
const potSize = state.pots.reduce((s, p) => s + (p.size || 0), 0);
|
|
83
|
+
parts.push(`Pot: ${potSize}.`);
|
|
84
|
+
}
|
|
85
|
+
if (state?.yourStack !== void 0) {
|
|
86
|
+
parts.push(`Your stack: ${state.yourStack}.`);
|
|
87
|
+
}
|
|
88
|
+
parts.push(`Legal actions: ${legalActions}.`);
|
|
89
|
+
if (chipRange) parts.push(`Bet/raise range: ${chipRange}.`);
|
|
90
|
+
parts.push(`Use chitin_poker_action to respond with roomCode "${roomCode2}".`);
|
|
91
|
+
promptAgent(parts.join(" "), logger2);
|
|
92
|
+
} else if (msg.type === "hand_result") {
|
|
93
|
+
const winners = msg.result?.winners?.flat() || [];
|
|
94
|
+
const winnerNames = winners.map((w) => `${w.playerId}(${w.amount})`).join(", ");
|
|
95
|
+
const text = `POKER HAND RESULT at table ${roomCode2}: Winners: ${winnerNames}. Rake: ${msg.result?.rake || 0}.`;
|
|
96
|
+
promptAgent(text, logger2);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function promptAgent(text, logger2) {
|
|
100
|
+
execFile("openclaw", ["agent", "--local", "--message", text], (err, _stdout, stderr) => {
|
|
101
|
+
if (err) {
|
|
102
|
+
logger2.error(`[chitin] Failed to prompt agent: ${err.message}`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (stderr) logger2.warn(`[chitin] Agent stderr: ${stderr}`);
|
|
106
|
+
logger2.info(`[chitin] Agent prompted successfully`);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const sendAction = (action) => {
|
|
110
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
111
|
+
ws.send(JSON.stringify({ type: "action", action }));
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
connect();
|
|
115
|
+
return () => {
|
|
116
|
+
aborted = true;
|
|
117
|
+
ws?.close();
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
var plugin = {
|
|
121
|
+
id: "chitin-casino",
|
|
122
|
+
name: "Chitin Casino",
|
|
123
|
+
description: "Play poker at Chitin Casino \u2014 wallet management and real-time game connection",
|
|
124
|
+
configSchema: {
|
|
125
|
+
type: "object",
|
|
126
|
+
additionalProperties: false,
|
|
127
|
+
properties: {}
|
|
128
|
+
},
|
|
129
|
+
register(api) {
|
|
130
|
+
api.logger.info("[chitin] Chitin Casino plugin loaded");
|
|
131
|
+
const gameServerUrl = process.env.GAME_SERVER_URL || "http://localhost:3665";
|
|
132
|
+
const activeConnections = /* @__PURE__ */ new Map();
|
|
133
|
+
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
|
+
api.registerTool({
|
|
144
|
+
name: "chitin_wallet_address",
|
|
145
|
+
description: "Get your Chitin Casino wallet address",
|
|
146
|
+
parameters: {},
|
|
147
|
+
execute: async (_toolCallId) => {
|
|
148
|
+
const { account } = getWalletClients();
|
|
149
|
+
return { address: account.address };
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
api.registerTool({
|
|
153
|
+
name: "chitin_wallet_balance",
|
|
154
|
+
description: "Check ETH and NUMERO token balance",
|
|
155
|
+
parameters: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: {
|
|
158
|
+
tokenAddress: { type: "string", description: "Token address (auto-fetched if omitted)" }
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
execute: async (_toolCallId, params) => {
|
|
162
|
+
const { account, publicClient } = getWalletClients();
|
|
163
|
+
const ethBalance = await publicClient.getBalance({ address: account.address });
|
|
164
|
+
let tokenBalance = BigInt(0);
|
|
165
|
+
let tokenAddr = params.tokenAddress;
|
|
166
|
+
if (!tokenAddr) {
|
|
167
|
+
try {
|
|
168
|
+
const res = await fetch(`${gameServerUrl}/contracts`);
|
|
169
|
+
const data = await res.json();
|
|
170
|
+
tokenAddr = data.token;
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (tokenAddr) {
|
|
175
|
+
tokenBalance = await publicClient.readContract({
|
|
176
|
+
address: tokenAddr,
|
|
177
|
+
abi: ERC20_ABI,
|
|
178
|
+
functionName: "balanceOf",
|
|
179
|
+
args: [account.address]
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
address: account.address,
|
|
184
|
+
ethBalance: formatEther(ethBalance),
|
|
185
|
+
tokenBalance: formatEther(tokenBalance)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
api.registerTool({
|
|
190
|
+
name: "chitin_faucet_claim",
|
|
191
|
+
description: "Claim NUMERO tokens from the faucet. This is a free server-side operation \u2014 no gas needed.",
|
|
192
|
+
parameters: {},
|
|
193
|
+
execute: async (_toolCallId) => {
|
|
194
|
+
const { account } = getWalletClients();
|
|
195
|
+
const adminServerUrl = process.env.ADMIN_SERVER_URL || "http://localhost:3667";
|
|
196
|
+
const serviceKey = process.env.SERVICE_KEY || "";
|
|
197
|
+
const res = await fetch(`${adminServerUrl}/faucet/claim`, {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: {
|
|
200
|
+
"Content-Type": "application/json",
|
|
201
|
+
"x-service-key": serviceKey
|
|
202
|
+
},
|
|
203
|
+
body: JSON.stringify({ walletAddress: account.address })
|
|
204
|
+
});
|
|
205
|
+
const data = await res.json();
|
|
206
|
+
if (!res.ok) throw new Error(data.error || "Faucet claim failed");
|
|
207
|
+
return data;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
api.registerTool({
|
|
211
|
+
name: "chitin_deposit",
|
|
212
|
+
description: "Deposit NUMERO tokens to a poker table on-chain",
|
|
213
|
+
parameters: {
|
|
214
|
+
type: "object",
|
|
215
|
+
properties: {
|
|
216
|
+
amount: { type: "string", description: 'Amount to deposit (e.g. "200")' },
|
|
217
|
+
tableId: { type: "string", description: "Table ID (bytes32)" },
|
|
218
|
+
gameId: { type: "string", description: "Game ID (bytes32)" }
|
|
219
|
+
},
|
|
220
|
+
required: ["amount", "tableId", "gameId"]
|
|
221
|
+
},
|
|
222
|
+
execute: async (_toolCallId, params) => {
|
|
223
|
+
const { publicClient, walletClient } = getWalletClients();
|
|
224
|
+
const res = await fetch(`${gameServerUrl}/contracts`);
|
|
225
|
+
const contracts = await res.json();
|
|
226
|
+
const amountWei = parseEther(params.amount);
|
|
227
|
+
const data = encodeAbiParameters(
|
|
228
|
+
[{ type: "bytes32" }, { type: "bytes32" }],
|
|
229
|
+
[params.tableId, params.gameId]
|
|
230
|
+
);
|
|
231
|
+
const hash = await walletClient.writeContract({
|
|
232
|
+
address: contracts.token,
|
|
233
|
+
abi: ERC20_ABI,
|
|
234
|
+
functionName: "transferAndCall",
|
|
235
|
+
args: [contracts.diamond, amountWei, data]
|
|
236
|
+
});
|
|
237
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
238
|
+
return { txHash: hash, blockNumber: Number(receipt.blockNumber) };
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
api.registerTool({
|
|
242
|
+
name: "chitin_discover",
|
|
243
|
+
description: "Discover Chitin Casino \u2014 games, contracts, faucet info",
|
|
244
|
+
parameters: {},
|
|
245
|
+
execute: async (_toolCallId) => {
|
|
246
|
+
const res = await fetch(`${gameServerUrl}/discover`);
|
|
247
|
+
return await res.json();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
api.registerTool({
|
|
251
|
+
name: "chitin_lobby",
|
|
252
|
+
description: "List poker tables with open seats",
|
|
253
|
+
parameters: {},
|
|
254
|
+
execute: async (_toolCallId) => {
|
|
255
|
+
const res = await fetch(`${gameServerUrl}/parties/pokerlobby/main/tables`);
|
|
256
|
+
return await res.json();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
api.registerTool({
|
|
260
|
+
name: "chitin_create_table",
|
|
261
|
+
description: "Create a new poker table (fails if open seats exist elsewhere)",
|
|
262
|
+
parameters: {
|
|
263
|
+
type: "object",
|
|
264
|
+
properties: {
|
|
265
|
+
smallBlind: { type: "number" },
|
|
266
|
+
bigBlind: { type: "number" },
|
|
267
|
+
minBuyIn: { type: "number" },
|
|
268
|
+
maxBuyIn: { type: "number" }
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
execute: async (_toolCallId, params) => {
|
|
272
|
+
const res = await fetch(`${gameServerUrl}/parties/poker/create`, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
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
|
+
})
|
|
283
|
+
});
|
|
284
|
+
return await res.json();
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
api.registerTool({
|
|
288
|
+
name: "chitin_register",
|
|
289
|
+
description: "Register at a poker table and connect via WebSocket. Events will be delivered to your session automatically.",
|
|
290
|
+
parameters: {
|
|
291
|
+
type: "object",
|
|
292
|
+
properties: {
|
|
293
|
+
roomCode: { type: "string", description: "Table room code" },
|
|
294
|
+
name: { type: "string", description: "Display name" },
|
|
295
|
+
buyIn: { type: "number", description: "Buy-in amount (default: 200)" }
|
|
296
|
+
},
|
|
297
|
+
required: ["roomCode"]
|
|
298
|
+
},
|
|
299
|
+
execute: async (_toolCallId, params) => {
|
|
300
|
+
const { account } = getWalletClients();
|
|
301
|
+
const botName = params.name || "ClawBot";
|
|
302
|
+
const res = await fetch(`${gameServerUrl}/parties/poker/${params.roomCode}/register`, {
|
|
303
|
+
method: "POST",
|
|
304
|
+
headers: { "Content-Type": "application/json" },
|
|
305
|
+
body: JSON.stringify({
|
|
306
|
+
name: botName,
|
|
307
|
+
buyIn: params.buyIn || 200,
|
|
308
|
+
walletAddress: account.address
|
|
309
|
+
})
|
|
310
|
+
});
|
|
311
|
+
const result = await res.json();
|
|
312
|
+
if (!res.ok) return result;
|
|
313
|
+
const cleanup = connectToTable(
|
|
314
|
+
gameServerUrl,
|
|
315
|
+
params.roomCode,
|
|
316
|
+
result.playerId,
|
|
317
|
+
botName,
|
|
318
|
+
account.address,
|
|
319
|
+
api.logger,
|
|
320
|
+
wsInstances
|
|
321
|
+
);
|
|
322
|
+
activeConnections.set(params.roomCode, { cleanup, ws: null });
|
|
323
|
+
api.logger.info(`[chitin] Registered at ${params.roomCode}, WebSocket connected`);
|
|
324
|
+
return { ...result, wsConnected: true };
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
api.registerTool({
|
|
328
|
+
name: "chitin_poker_action",
|
|
329
|
+
description: "Send a poker action: fold, check, call, bet (with amount), or raise (with amount)",
|
|
330
|
+
parameters: {
|
|
331
|
+
type: "object",
|
|
332
|
+
properties: {
|
|
333
|
+
roomCode: { type: "string" },
|
|
334
|
+
action: { type: "string", description: "fold, check, call, bet, or raise" },
|
|
335
|
+
amount: { type: "number", description: "Required for bet and raise" }
|
|
336
|
+
},
|
|
337
|
+
required: ["roomCode", "action"]
|
|
338
|
+
},
|
|
339
|
+
execute: async (_toolCallId, params) => {
|
|
340
|
+
const ws = wsInstances.get(params.roomCode);
|
|
341
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
342
|
+
return { error: "Not connected to table. Call chitin_register first." };
|
|
343
|
+
}
|
|
344
|
+
const action = { type: params.action };
|
|
345
|
+
if (params.amount !== void 0) action.amount = params.amount;
|
|
346
|
+
ws.send(JSON.stringify({ type: "action", action }));
|
|
347
|
+
return { ok: true, sent: action };
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
api.registerTool({
|
|
351
|
+
name: "chitin_leave_table",
|
|
352
|
+
description: "Leave a poker table and disconnect",
|
|
353
|
+
parameters: {
|
|
354
|
+
type: "object",
|
|
355
|
+
properties: {
|
|
356
|
+
roomCode: { type: "string" },
|
|
357
|
+
token: { type: "string" }
|
|
358
|
+
},
|
|
359
|
+
required: ["roomCode", "token"]
|
|
360
|
+
},
|
|
361
|
+
execute: async (_toolCallId, params) => {
|
|
362
|
+
const conn = activeConnections.get(params.roomCode);
|
|
363
|
+
if (conn) {
|
|
364
|
+
conn.cleanup();
|
|
365
|
+
activeConnections.delete(params.roomCode);
|
|
366
|
+
}
|
|
367
|
+
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 };
|
|
372
|
+
}
|
|
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();
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
var index_default = plugin;
|
|
383
|
+
export {
|
|
384
|
+
index_default as default
|
|
385
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "chitin-casino",
|
|
3
|
+
"name": "Chitin Casino",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Play poker at Chitin Casino — wallet management and real-time game connection",
|
|
6
|
+
"author": "Chitin Casino",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"configSchema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"enabled": {
|
|
12
|
+
"type": "boolean",
|
|
13
|
+
"default": true
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chitincasino/openclaw-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenClaw plugin for Chitin Casino — wallet management and poker game connection",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/",
|
|
9
|
+
"openclaw.plugin.json"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"openclaw",
|
|
13
|
+
"openclaw-plugin",
|
|
14
|
+
"poker",
|
|
15
|
+
"chitin-casino",
|
|
16
|
+
"blockchain",
|
|
17
|
+
"base"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/chitincasino/numero"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"openclaw": {
|
|
25
|
+
"extensions": ["./src/index.ts"]
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
29
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"viem": "^2.0.0",
|
|
34
|
+
"ws": "^8.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"@types/ws": "^8.0.0",
|
|
39
|
+
"tsup": "^8.0.0",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|