chitin-openclaw-plugin 0.2.2 → 0.3.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.
Files changed (2) hide show
  1. package/dist/index.js +87 -22
  2. package/package.json +6 -1
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)",
@@ -100,12 +106,18 @@ function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress,
100
106
  }
101
107
  function promptAgent(text, logger2) {
102
108
  logger2.info(`[chitin] Prompting agent: ${text.slice(0, 100)}...`);
103
- execFile("openclaw", ["agent", "--local", "--message", text], (err, _stdout, stderr) => {
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) => {
104
114
  if (err) {
105
115
  logger2.error(`[chitin] Agent prompt failed: ${err.message}`);
116
+ if (stderr) logger2.error(`[chitin] Agent stderr: ${stderr.slice(0, 500)}`);
106
117
  return;
107
118
  }
108
- if (stderr) logger2.warn(`[chitin] Agent stderr: ${stderr.slice(0, 200)}`);
119
+ if (stdout) logger2.info(`[chitin] Agent response: ${stdout.slice(0, 300)}`);
120
+ if (stderr) logger2.warn(`[chitin] Agent stderr: ${stderr.slice(0, 300)}`);
109
121
  logger2.info(`[chitin] Agent prompted ok`);
110
122
  });
111
123
  }
@@ -115,6 +127,7 @@ function connectToTable(gameServerUrl, roomCode, playerId, name, walletAddress,
115
127
  ws?.close();
116
128
  };
117
129
  }
130
+ var otelInitialized = false;
118
131
  var plugin = {
119
132
  id: "chitin-openclaw-plugin",
120
133
  name: "Chitin Casino",
@@ -126,6 +139,58 @@ var plugin = {
126
139
  },
127
140
  register(api) {
128
141
  api.logger.info("[chitin] Chitin Casino plugin loaded");
142
+ let tracer = trace.getTracer("chitin-plugin");
143
+ if (!otelInitialized) try {
144
+ otelInitialized = true;
145
+ const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
146
+ const headers = process.env.OTEL_EXPORTER_OTLP_HEADERS;
147
+ if (endpoint) {
148
+ const headerObj = {};
149
+ if (headers) {
150
+ for (const pair of headers.split(",")) {
151
+ const [k, ...v] = pair.split("=");
152
+ if (k) headerObj[k.trim()] = v.join("=").trim();
153
+ }
154
+ }
155
+ const provider = new NodeTracerProvider({
156
+ resource: new Resource({ [ATTR_SERVICE_NAME]: "chitin-plugin" }),
157
+ spanProcessors: [
158
+ new BatchSpanProcessor(new OTLPTraceExporter({
159
+ url: `${endpoint}/v1/traces`,
160
+ headers: headerObj
161
+ }))
162
+ ]
163
+ });
164
+ provider.register();
165
+ tracer = trace.getTracer("chitin-plugin");
166
+ api.logger.info(`[chitin] OTel initialized \u2014 endpoint=${endpoint}`);
167
+ const span = tracer.startSpan("plugin.loaded");
168
+ span.setAttributes({ "plugin.name": "chitin-openclaw-plugin" });
169
+ span.setStatus({ code: SpanStatusCode.OK });
170
+ span.end();
171
+ api.logger.info("[chitin] OTel test span emitted: plugin.loaded");
172
+ } else {
173
+ api.logger.info("[chitin] OTel skipped \u2014 no OTEL_EXPORTER_OTLP_ENDPOINT");
174
+ }
175
+ } catch (err) {
176
+ api.logger.warn(`[chitin] OTel init failed (non-fatal): ${err.message}`);
177
+ }
178
+ function withSpan(spanName, attrs, fn) {
179
+ const span = tracer.startSpan(spanName, { attributes: attrs });
180
+ return fn().then(
181
+ (result) => {
182
+ span.setStatus({ code: SpanStatusCode.OK });
183
+ span.end();
184
+ return result;
185
+ },
186
+ (err) => {
187
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
188
+ span.recordException(err);
189
+ span.end();
190
+ throw err;
191
+ }
192
+ );
193
+ }
129
194
  const gameServerUrl = process.env.GAME_SERVER_URL || "http://localhost:3665";
130
195
  const adminServerUrl = process.env.ADMIN_SERVER_URL || "http://localhost:3667";
131
196
  const activeConnections = /* @__PURE__ */ new Map();
@@ -134,11 +199,11 @@ var plugin = {
134
199
  name: "chitin_wallet_address",
135
200
  description: "Get your Chitin Casino wallet address",
136
201
  parameters: {},
137
- execute: async () => {
202
+ execute: async () => withSpan("plugin.tool.wallet_address", {}, async () => {
138
203
  const { account } = getWalletClients();
139
204
  api.logger.info(`[chitin] wallet_address: ${account.address}`);
140
205
  return { address: account.address };
141
- }
206
+ })
142
207
  });
143
208
  api.registerTool({
144
209
  name: "chitin_wallet_balance",
@@ -149,7 +214,7 @@ var plugin = {
149
214
  tokenAddress: { type: "string", description: "Token address (auto-fetched if omitted)" }
150
215
  }
151
216
  },
152
- execute: async (_toolCallId, params) => {
217
+ execute: async (_toolCallId, params) => withSpan("plugin.tool.wallet_balance", {}, async () => {
153
218
  const { account, publicClient } = getWalletClients();
154
219
  api.logger.info(`[chitin] wallet_balance: checking ${account.address}`);
155
220
  const ethBalance = await publicClient.getBalance({ address: account.address });
@@ -180,13 +245,13 @@ var plugin = {
180
245
  ethBalance: formatEther(ethBalance),
181
246
  tokenBalance: formatEther(tokenBalance)
182
247
  };
183
- }
248
+ })
184
249
  });
185
250
  api.registerTool({
186
251
  name: "chitin_faucet_claim",
187
252
  description: "Claim NUMERO tokens from the faucet. Free \u2014 no gas needed.",
188
253
  parameters: {},
189
- execute: async () => {
254
+ execute: async () => withSpan("plugin.tool.faucet_claim", {}, async () => {
190
255
  const { account } = getWalletClients();
191
256
  api.logger.info(`[chitin] faucet_claim: wallet=${account.address} server=${adminServerUrl}`);
192
257
  const res = await fetch(`${adminServerUrl}/faucet/claim`, {
@@ -198,7 +263,7 @@ var plugin = {
198
263
  api.logger.info(`[chitin] faucet_claim: status=${res.status} response=${JSON.stringify(data)}`);
199
264
  if (!res.ok) throw new Error(data.error || "Faucet claim failed");
200
265
  return data;
201
- }
266
+ })
202
267
  });
203
268
  api.registerTool({
204
269
  name: "chitin_deposit",
@@ -212,7 +277,7 @@ var plugin = {
212
277
  },
213
278
  required: ["amount", "tableId", "gameId"]
214
279
  },
215
- execute: async (_toolCallId, params) => {
280
+ execute: async (_toolCallId, params) => withSpan("plugin.tool.deposit", { "deposit.amount": params.amount, "deposit.table_id": params.tableId }, async () => {
216
281
  api.logger.info(`[chitin] deposit: amount=${params.amount} tableId=${params.tableId} gameId=${params.gameId}`);
217
282
  const { publicClient, walletClient } = getWalletClients();
218
283
  api.logger.info(`[chitin] deposit: fetching contracts from ${gameServerUrl}/contracts`);
@@ -235,31 +300,31 @@ var plugin = {
235
300
  const receipt = await publicClient.waitForTransactionReceipt({ hash });
236
301
  api.logger.info(`[chitin] deposit: confirmed block=${receipt.blockNumber} status=${receipt.status}`);
237
302
  return { txHash: hash, blockNumber: Number(receipt.blockNumber) };
238
- }
303
+ })
239
304
  });
240
305
  api.registerTool({
241
306
  name: "chitin_discover",
242
307
  description: "Discover Chitin Casino \u2014 games, contracts, faucet info",
243
308
  parameters: {},
244
- execute: async () => {
309
+ execute: async () => withSpan("plugin.tool.discover", {}, async () => {
245
310
  api.logger.info(`[chitin] discover: ${gameServerUrl}/discover`);
246
311
  const res = await fetch(`${gameServerUrl}/discover`);
247
312
  const data = await res.json();
248
313
  api.logger.info(`[chitin] discover: status=${res.status}`);
249
314
  return data;
250
- }
315
+ })
251
316
  });
252
317
  api.registerTool({
253
318
  name: "chitin_lobby",
254
319
  description: "List poker tables with open seats",
255
320
  parameters: {},
256
- execute: async () => {
321
+ execute: async () => withSpan("plugin.tool.lobby", {}, async () => {
257
322
  api.logger.info(`[chitin] lobby: ${gameServerUrl}/parties/pokerlobby/main/tables`);
258
323
  const res = await fetch(`${gameServerUrl}/parties/pokerlobby/main/tables`);
259
324
  const data = await res.json();
260
325
  api.logger.info(`[chitin] lobby: status=${res.status} tables=${Array.isArray(data) ? data.length : "?"}`);
261
326
  return data;
262
- }
327
+ })
263
328
  });
264
329
  api.registerTool({
265
330
  name: "chitin_create_table",
@@ -273,7 +338,7 @@ var plugin = {
273
338
  maxBuyIn: { type: "number" }
274
339
  }
275
340
  },
276
- execute: async (_toolCallId, params) => {
341
+ execute: async (_toolCallId, params) => withSpan("plugin.tool.create_table", {}, async () => {
277
342
  const settings = {
278
343
  smallBlind: params.smallBlind || 1,
279
344
  bigBlind: params.bigBlind || 2,
@@ -289,7 +354,7 @@ var plugin = {
289
354
  const data = await res.json();
290
355
  api.logger.info(`[chitin] create_table: status=${res.status} response=${JSON.stringify(data)}`);
291
356
  return data;
292
- }
357
+ })
293
358
  });
294
359
  api.registerTool({
295
360
  name: "chitin_register",
@@ -303,7 +368,7 @@ var plugin = {
303
368
  },
304
369
  required: ["roomCode"]
305
370
  },
306
- execute: async (_toolCallId, params) => {
371
+ execute: async (_toolCallId, params) => withSpan("plugin.tool.register", { "register.room": params.roomCode }, async () => {
307
372
  const { account } = getWalletClients();
308
373
  const botName = params.name || "ClawBot";
309
374
  api.logger.info(`[chitin] register: room=${params.roomCode} name=${botName} buyIn=${params.buyIn || 200} wallet=${account.address}`);
@@ -330,7 +395,7 @@ var plugin = {
330
395
  );
331
396
  activeConnections.set(params.roomCode, { cleanup });
332
397
  return { ...result, wsConnected: true };
333
- }
398
+ })
334
399
  });
335
400
  api.registerTool({
336
401
  name: "chitin_poker_action",
@@ -344,7 +409,7 @@ var plugin = {
344
409
  },
345
410
  required: ["roomCode", "action"]
346
411
  },
347
- execute: async (_toolCallId, params) => {
412
+ execute: async (_toolCallId, params) => withSpan("plugin.tool.poker_action", { "action.room": params.roomCode, "action.type": params.action, "action.amount": params.amount ?? 0 }, async () => {
348
413
  api.logger.info(`[chitin] poker_action: room=${params.roomCode} action=${params.action} amount=${params.amount ?? "n/a"}`);
349
414
  const ws = wsInstances.get(params.roomCode);
350
415
  if (!ws || ws.readyState !== WebSocket.OPEN) {
@@ -356,7 +421,7 @@ var plugin = {
356
421
  ws.send(JSON.stringify({ type: "action", action }));
357
422
  api.logger.info(`[chitin] poker_action: sent ${JSON.stringify(action)}`);
358
423
  return { ok: true, sent: action };
359
- }
424
+ })
360
425
  });
361
426
  api.registerTool({
362
427
  name: "chitin_leave_table",
@@ -369,7 +434,7 @@ var plugin = {
369
434
  },
370
435
  required: ["roomCode", "token"]
371
436
  },
372
- execute: async (_toolCallId, params) => {
437
+ execute: async (_toolCallId, params) => withSpan("plugin.tool.leave_table", { "leave.room": params.roomCode }, async () => {
373
438
  api.logger.info(`[chitin] leave_table: room=${params.roomCode}`);
374
439
  const ws = wsInstances.get(params.roomCode);
375
440
  if (ws?.readyState === WebSocket.OPEN) {
@@ -391,7 +456,7 @@ var plugin = {
391
456
  return await res.json();
392
457
  }
393
458
  return { ok: true };
394
- }
459
+ })
395
460
  });
396
461
  }
397
462
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chitin-openclaw-plugin",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
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
  },