@dimcool/dimclaw 0.1.30 → 0.1.31

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 +273 -33
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -32884,6 +32884,9 @@ var Admin = class {
32884
32884
  this.http = http2;
32885
32885
  this.logger = logger2;
32886
32886
  }
32887
+ async getInternalBots() {
32888
+ return this.http.get("/admin/internal-bots");
32889
+ }
32887
32890
  async getUserById(id) {
32888
32891
  return this.http.get(`/admin/users/${id}`);
32889
32892
  }
@@ -35507,8 +35510,21 @@ function createGameActionsStore(transport) {
35507
35510
  });
35508
35511
  };
35509
35512
  const isNonRpsState = (state) => Boolean(state && !isRpsState(state));
35513
+ const pendingEvents = /* @__PURE__ */ new Map();
35514
+ function enqueue(gameId, event) {
35515
+ const q = pendingEvents.get(gameId) ?? [];
35516
+ q.push(event);
35517
+ pendingEvents.set(gameId, q);
35518
+ }
35519
+ function drainQueue(gameId) {
35520
+ const q = pendingEvents.get(gameId);
35521
+ if (!q?.length) return;
35522
+ pendingEvents.delete(gameId);
35523
+ for (const ev of q) applyWsEvent(ev);
35524
+ }
35510
35525
  const setBaseState = (gameId, state) => {
35511
35526
  updateState(gameId, state);
35527
+ drainQueue(gameId);
35512
35528
  };
35513
35529
  const clearState = (gameId) => {
35514
35530
  store.updateState((state) => {
@@ -35518,6 +35534,7 @@ function createGameActionsStore(transport) {
35518
35534
  const { [gameId]: _, ...rest } = state.statesByGameId;
35519
35535
  return { ...state, statesByGameId: rest };
35520
35536
  });
35537
+ pendingEvents.delete(gameId);
35521
35538
  };
35522
35539
  const applyWsEvent = (event) => {
35523
35540
  switch (event.event) {
@@ -35536,7 +35553,10 @@ function createGameActionsStore(transport) {
35536
35553
  }
35537
35554
  case "game:rps:starting": {
35538
35555
  const current = store.getState().statesByGameId[event.payload.gameId];
35539
- if (!current || !isRpsState(current)) return;
35556
+ if (!current || !isRpsState(current)) {
35557
+ enqueue(event.payload.gameId, event);
35558
+ return;
35559
+ }
35540
35560
  const betAmount = typeof event.payload.betAmount === "number" ? event.payload.betAmount : void 0;
35541
35561
  const startedAt = typeof event.payload.startedAt === "string" ? event.payload.startedAt : current.roundState.startedAt;
35542
35562
  const bufferEndsAt = typeof event.payload.bufferEndsAt === "string" ? event.payload.bufferEndsAt : current.roundState.selectionEndsAt;
@@ -35557,7 +35577,10 @@ function createGameActionsStore(transport) {
35557
35577
  }
35558
35578
  case "game:rps:round:started": {
35559
35579
  const current = store.getState().statesByGameId[event.payload.gameId];
35560
- if (!current || !isRpsState(current)) return;
35580
+ if (!current || !isRpsState(current)) {
35581
+ enqueue(event.payload.gameId, event);
35582
+ return;
35583
+ }
35561
35584
  const actions = {};
35562
35585
  const baseUsers = /* @__PURE__ */ new Set();
35563
35586
  Object.keys(current.roundState.actions).forEach(
@@ -35591,7 +35614,10 @@ function createGameActionsStore(transport) {
35591
35614
  }
35592
35615
  case "game:rps:action:received": {
35593
35616
  const current = store.getState().statesByGameId[event.payload.gameId];
35594
- if (!current || !isRpsState(current)) return;
35617
+ if (!current || !isRpsState(current)) {
35618
+ enqueue(event.payload.gameId, event);
35619
+ return;
35620
+ }
35595
35621
  const updated = {
35596
35622
  ...current,
35597
35623
  roundState: {
@@ -35610,7 +35636,10 @@ function createGameActionsStore(transport) {
35610
35636
  }
35611
35637
  case "game:rps:timer:cutoff": {
35612
35638
  const current = store.getState().statesByGameId[event.payload.gameId];
35613
- if (!current || !isRpsState(current)) return;
35639
+ if (!current || !isRpsState(current)) {
35640
+ enqueue(event.payload.gameId, event);
35641
+ return;
35642
+ }
35614
35643
  const updated = {
35615
35644
  ...current,
35616
35645
  roundState: {
@@ -35624,7 +35653,10 @@ function createGameActionsStore(transport) {
35624
35653
  }
35625
35654
  case "game:rps:round:reveal": {
35626
35655
  const current = store.getState().statesByGameId[event.payload.gameId];
35627
- if (!current || !isRpsState(current)) return;
35656
+ if (!current || !isRpsState(current)) {
35657
+ enqueue(event.payload.gameId, event);
35658
+ return;
35659
+ }
35628
35660
  const actions = {};
35629
35661
  const payloadActions = event.payload.actions;
35630
35662
  Object.keys(payloadActions || {}).forEach((userId) => {
@@ -35648,7 +35680,10 @@ function createGameActionsStore(transport) {
35648
35680
  }
35649
35681
  case "game:rps:round:completed": {
35650
35682
  const current = store.getState().statesByGameId[event.payload.gameId];
35651
- if (!current || !isRpsState(current)) return;
35683
+ if (!current || !isRpsState(current)) {
35684
+ enqueue(event.payload.gameId, event);
35685
+ return;
35686
+ }
35652
35687
  const roundHistory = [
35653
35688
  ...current.roundHistory || [],
35654
35689
  {
@@ -35673,7 +35708,10 @@ function createGameActionsStore(transport) {
35673
35708
  }
35674
35709
  case "game:rps:timeout": {
35675
35710
  const current = store.getState().statesByGameId[event.payload.gameId];
35676
- if (!current || !isRpsState(current)) return;
35711
+ if (!current || !isRpsState(current)) {
35712
+ enqueue(event.payload.gameId, event);
35713
+ return;
35714
+ }
35677
35715
  const timedOutUser = event.payload.playerId;
35678
35716
  const action = event.payload.action;
35679
35717
  const updated = {
@@ -35698,7 +35736,10 @@ function createGameActionsStore(transport) {
35698
35736
  const payload = event.payload;
35699
35737
  const { gameId } = payload;
35700
35738
  const current = store.getState().statesByGameId[gameId];
35701
- if (!current) return;
35739
+ if (!current) {
35740
+ enqueue(gameId, event);
35741
+ return;
35742
+ }
35702
35743
  const updated = isRpsCompletionPayload(payload) && isRpsState(current) ? {
35703
35744
  ...current,
35704
35745
  status: "completed",
@@ -35747,11 +35788,15 @@ function createGameActionsStore(transport) {
35747
35788
  const current = store.getState().statesByGameId[gameId];
35748
35789
  const updated = current ? { ...current, ...incoming } : incoming;
35749
35790
  updateState(gameId, updated);
35791
+ drainQueue(gameId);
35750
35792
  break;
35751
35793
  }
35752
35794
  case "game:rematch:requested": {
35753
35795
  const current = store.getState().statesByGameId[event.payload.gameId];
35754
- if (!current) return;
35796
+ if (!current) {
35797
+ enqueue(event.payload.gameId, event);
35798
+ return;
35799
+ }
35755
35800
  const requestedBy = event.payload.requestedBy;
35756
35801
  const userId = event.payload.userId;
35757
35802
  const requested = new Set(
@@ -35767,7 +35812,10 @@ function createGameActionsStore(transport) {
35767
35812
  }
35768
35813
  case "game:rematch:cancelled": {
35769
35814
  const current = store.getState().statesByGameId[event.payload.gameId];
35770
- if (!current) return;
35815
+ if (!current) {
35816
+ enqueue(event.payload.gameId, event);
35817
+ return;
35818
+ }
35771
35819
  const requestedBy = event.payload.requestedBy ?? [];
35772
35820
  const updated = {
35773
35821
  ...current,
@@ -35778,7 +35826,10 @@ function createGameActionsStore(transport) {
35778
35826
  }
35779
35827
  case "game:rematch:started": {
35780
35828
  const current = store.getState().statesByGameId[event.payload.gameId];
35781
- if (!current) return;
35829
+ if (!current) {
35830
+ enqueue(event.payload.gameId, event);
35831
+ return;
35832
+ }
35782
35833
  const updated = {
35783
35834
  ...current,
35784
35835
  rematchRequestedBy: event.payload.playerIds ?? []
@@ -35789,7 +35840,10 @@ function createGameActionsStore(transport) {
35789
35840
  case "game:pot:updated": {
35790
35841
  const { gameId, totalPotMinor } = event.payload;
35791
35842
  const current = store.getState().statesByGameId[gameId];
35792
- if (!current) return;
35843
+ if (!current) {
35844
+ enqueue(gameId, event);
35845
+ return;
35846
+ }
35793
35847
  const updated = {
35794
35848
  ...current,
35795
35849
  totalPotMinor
@@ -35802,12 +35856,123 @@ function createGameActionsStore(transport) {
35802
35856
  }
35803
35857
  };
35804
35858
  const joinGame = (gameId) => transport.joinRoom(`game:${gameId}`);
35859
+ const getCountdownDigit = (gameId, nowMs) => {
35860
+ const state = store.getState().statesByGameId[gameId];
35861
+ if (!state) return null;
35862
+ if (isRpsState(state)) {
35863
+ if (state.roundState.phase !== "starting") return null;
35864
+ const remaining = new Date(state.roundState.selectionEndsAt).getTime() - nowMs;
35865
+ if (remaining <= 0) return null;
35866
+ return Math.ceil(remaining / 1e3);
35867
+ }
35868
+ const bufferEndsAt = state.bufferEndsAt;
35869
+ if (bufferEndsAt) {
35870
+ const remaining = new Date(bufferEndsAt).getTime() - nowMs;
35871
+ if (remaining <= 0) return null;
35872
+ return Math.ceil(remaining / 1e3);
35873
+ }
35874
+ return null;
35875
+ };
35876
+ const getChessClockTimes = (gameId, nowMs) => {
35877
+ const state = store.getState().statesByGameId[gameId];
35878
+ if (!state || state.gameType !== "chess") return null;
35879
+ const s = state;
35880
+ let whiteMs = s.whiteTimeMs ?? 0;
35881
+ let blackMs = s.blackTimeMs ?? 0;
35882
+ if (s.status === "active" && s.currentPlayerId) {
35883
+ const startedAt = Date.parse(s.turnStartedAt);
35884
+ if (!Number.isNaN(startedAt)) {
35885
+ const elapsed = Math.max(0, nowMs - startedAt);
35886
+ if (s.currentPlayerId === s.whitePlayerId) {
35887
+ whiteMs = Math.max(0, whiteMs - elapsed);
35888
+ } else if (s.currentPlayerId === s.blackPlayerId) {
35889
+ blackMs = Math.max(0, blackMs - elapsed);
35890
+ }
35891
+ }
35892
+ }
35893
+ return { whiteTimeMs: whiteMs, blackTimeMs: blackMs };
35894
+ };
35895
+ const getChessCapturedPieces = (gameId) => {
35896
+ const state = store.getState().statesByGameId[gameId];
35897
+ if (!state || state.gameType !== "chess") return null;
35898
+ const fen = state.fen;
35899
+ if (!fen) return { capturedByWhite: [], capturedByBlack: [] };
35900
+ const placement = fen.split(" ")[0];
35901
+ const white = {};
35902
+ const black = {};
35903
+ for (const char of placement) {
35904
+ if (char === "/" || char >= "1" && char <= "8") continue;
35905
+ const lower = char.toLowerCase();
35906
+ if (char === lower) {
35907
+ black[lower] = (black[lower] ?? 0) + 1;
35908
+ } else {
35909
+ white[lower] = (white[lower] ?? 0) + 1;
35910
+ }
35911
+ }
35912
+ const INITIAL = {
35913
+ p: 8,
35914
+ r: 2,
35915
+ n: 2,
35916
+ b: 2,
35917
+ q: 1,
35918
+ k: 1
35919
+ };
35920
+ const capturedByWhite = [];
35921
+ const capturedByBlack = [];
35922
+ for (const [type2, initial] of Object.entries(INITIAL)) {
35923
+ const missingBlack = initial - (black[type2] ?? 0);
35924
+ for (let i = 0; i < missingBlack; i++) capturedByWhite.push(`b${type2}`);
35925
+ const missingWhite = initial - (white[type2] ?? 0);
35926
+ for (let i = 0; i < missingWhite; i++) capturedByBlack.push(`w${type2}`);
35927
+ }
35928
+ return { capturedByWhite, capturedByBlack };
35929
+ };
35930
+ const getTicTacToeClockTimes = (gameId, nowMs) => {
35931
+ const state = store.getState().statesByGameId[gameId];
35932
+ if (!state || state.gameType !== "tic-tac-toe") return null;
35933
+ const s = state;
35934
+ let xMs = s.xTimeMs ?? 0;
35935
+ let oMs = s.oTimeMs ?? 0;
35936
+ if (s.status === "active" && s.currentPlayerId) {
35937
+ const currentMark = s.playerMarks[s.currentPlayerId];
35938
+ const startedAt = Date.parse(s.turnStartedAt);
35939
+ if (!Number.isNaN(startedAt)) {
35940
+ const elapsed = Math.max(0, nowMs - startedAt);
35941
+ if (currentMark === "X") xMs = Math.max(0, xMs - elapsed);
35942
+ else if (currentMark === "O") oMs = Math.max(0, oMs - elapsed);
35943
+ }
35944
+ }
35945
+ return { xTimeMs: xMs, oTimeMs: oMs };
35946
+ };
35947
+ const getConnect4ClockTimes = (gameId, nowMs) => {
35948
+ const state = store.getState().statesByGameId[gameId];
35949
+ if (!state || state.gameType !== "connect-four") return null;
35950
+ const s = state;
35951
+ let redMs = s.redTimeMs ?? 0;
35952
+ let yellowMs = s.yellowTimeMs ?? 0;
35953
+ if (s.status === "active" && s.currentPlayerId) {
35954
+ const currentColor = s.playerColors[s.currentPlayerId];
35955
+ const startedAt = Date.parse(s.turnStartedAt);
35956
+ if (!Number.isNaN(startedAt)) {
35957
+ const elapsed = Math.max(0, nowMs - startedAt);
35958
+ if (currentColor === "RED") redMs = Math.max(0, redMs - elapsed);
35959
+ else if (currentColor === "YELLOW")
35960
+ yellowMs = Math.max(0, yellowMs - elapsed);
35961
+ }
35962
+ }
35963
+ return { redTimeMs: redMs, yellowTimeMs: yellowMs };
35964
+ };
35805
35965
  return {
35806
35966
  store,
35807
35967
  setBaseState,
35808
35968
  clearState,
35809
35969
  applyWsEvent,
35810
- joinGame
35970
+ joinGame,
35971
+ getCountdownDigit,
35972
+ getChessClockTimes,
35973
+ getChessCapturedPieces,
35974
+ getTicTacToeClockTimes,
35975
+ getConnect4ClockTimes
35811
35976
  };
35812
35977
  }
35813
35978
  function isRpsState(state) {
@@ -36465,12 +36630,14 @@ var WsRouter = class {
36465
36630
  }
36466
36631
  const decoded = decodeWsEvent(eventName, payload);
36467
36632
  if (!decoded) return;
36468
- this.deps.lobbyStore.applyWsEvent(decoded);
36469
- this.deps.gameStore.applyWsEvent(decoded);
36470
- this.deps.gameActionsStore.applyWsEvent(decoded);
36471
- this.deps.chatStore.applyWsEvent(decoded);
36472
- this.deps.dmThreadsStore.applyWsEvent(decoded);
36473
- this.deps.notificationsStore.applyWsEvent(decoded);
36633
+ const serverTs = payload !== null && typeof payload === "object" ? payload._serverTs : void 0;
36634
+ const event = serverTs !== void 0 ? { ...decoded, _serverTs: serverTs } : decoded;
36635
+ this.deps.lobbyStore.applyWsEvent(event);
36636
+ this.deps.gameStore.applyWsEvent(event);
36637
+ this.deps.gameActionsStore.applyWsEvent(event);
36638
+ this.deps.chatStore.applyWsEvent(event);
36639
+ this.deps.dmThreadsStore.applyWsEvent(event);
36640
+ this.deps.notificationsStore.applyWsEvent(event);
36474
36641
  });
36475
36642
  }
36476
36643
  stop() {
@@ -36482,12 +36649,14 @@ var WsRouter = class {
36482
36649
  this.transport.subscribeEvent(eventName, (payload) => {
36483
36650
  const decoded = decodeWsEvent(eventName, payload);
36484
36651
  if (!decoded) return;
36485
- this.deps.lobbyStore.applyWsEvent(decoded);
36486
- this.deps.gameStore.applyWsEvent(decoded);
36487
- this.deps.gameActionsStore.applyWsEvent(decoded);
36488
- this.deps.chatStore.applyWsEvent(decoded);
36489
- this.deps.dmThreadsStore.applyWsEvent(decoded);
36490
- this.deps.notificationsStore.applyWsEvent(decoded);
36652
+ const serverTs = payload !== null && typeof payload === "object" ? payload._serverTs : void 0;
36653
+ const event = serverTs !== void 0 ? { ...decoded, _serverTs: serverTs } : decoded;
36654
+ this.deps.lobbyStore.applyWsEvent(event);
36655
+ this.deps.gameStore.applyWsEvent(event);
36656
+ this.deps.gameActionsStore.applyWsEvent(event);
36657
+ this.deps.chatStore.applyWsEvent(event);
36658
+ this.deps.dmThreadsStore.applyWsEvent(event);
36659
+ this.deps.notificationsStore.applyWsEvent(event);
36491
36660
  });
36492
36661
  }
36493
36662
  }
@@ -36767,6 +36936,28 @@ var esm_default4 = esm_default3(ALPHABET2);
36767
36936
 
36768
36937
  // ../dim-agent-core/src/client.ts
36769
36938
  var import_tweetnacl = __toESM(require_nacl_fast(), 1);
36939
+ function decodeJwtSub(token) {
36940
+ try {
36941
+ const parts2 = token.split(".");
36942
+ if (parts2.length < 2) return null;
36943
+ const base64 = parts2[1].replace(/-/g, "+").replace(/_/g, "/");
36944
+ const json = Buffer.from(base64, "base64").toString("utf-8");
36945
+ const parsed = JSON.parse(json);
36946
+ return typeof parsed.sub === "string" ? parsed.sub : null;
36947
+ } catch {
36948
+ return null;
36949
+ }
36950
+ }
36951
+ function signatureToBytes(sig) {
36952
+ if (sig.includes("-") || sig.includes("_")) {
36953
+ const padded = sig.replace(/-/g, "+").replace(/_/g, "/") + "==".slice(sig.length % 4 === 0 ? 4 : sig.length % 4);
36954
+ return new Uint8Array(Buffer.from(padded, "base64"));
36955
+ }
36956
+ if (/[+/=]/.test(sig)) {
36957
+ return new Uint8Array(Buffer.from(sig, "base64"));
36958
+ }
36959
+ return esm_default4.decode(sig);
36960
+ }
36770
36961
  var DimAgentClient = class {
36771
36962
  sdk;
36772
36963
  agentConfig;
@@ -36793,10 +36984,19 @@ var DimAgentClient = class {
36793
36984
  } else {
36794
36985
  this.keypair = null;
36795
36986
  }
36987
+ const storage = new NodeStorage();
36988
+ if (config.accessToken) {
36989
+ storage.set(TOKEN_KEY, config.accessToken);
36990
+ const sub = decodeJwtSub(config.accessToken);
36991
+ if (sub) {
36992
+ this.authenticated = true;
36993
+ this.userId = sub;
36994
+ }
36995
+ }
36796
36996
  this.sdk = new SDK({
36797
36997
  appId: "dim-agents",
36798
36998
  baseUrl: config.apiUrl || "https://api.dim.cool",
36799
- storage: new NodeStorage(),
36999
+ storage,
36800
37000
  autoPay: {
36801
37001
  enabled: !this.externalSignerMode,
36802
37002
  maxAmountMinor: 25e3,
@@ -36900,10 +37100,10 @@ var DimAgentClient = class {
36900
37100
  /**
36901
37101
  * Complete authentication using an externally provided signature (external signer mode).
36902
37102
  * @param address - Solana wallet address (base58)
36903
- * @param signatureBase58 - Detached ed25519 signature in base58 (from sign_solana_message)
37103
+ * @param signature - Detached ed25519 signature in base58, base64, or base64url (from sign_solana_message)
36904
37104
  */
36905
- async completeAuth(address, signatureBase58) {
36906
- const signatureBytes = esm_default4.decode(signatureBase58);
37105
+ async completeAuth(address, signature) {
37106
+ const signatureBytes = signatureToBytes(signature);
36907
37107
  const signedMessage = Buffer.from(signatureBytes).toString("base64");
36908
37108
  const response = await this.sdk.auth.loginWithExternalSignature(
36909
37109
  address,
@@ -37057,7 +37257,7 @@ async function requestAuthMessage(client, args) {
37057
37257
  data: {
37058
37258
  message,
37059
37259
  address: args.address,
37060
- nextStep: 'Sign this message with sign_solana_message (networkId: "solana:mainnet"), then call dim_complete_login with the address and the base58 signature.'
37260
+ nextStep: 'Sign this message with sign_solana_message (networkId: "solana:mainnet"), then call dim_complete_login with the address and the signature. Accepted formats: base58, base64, or base64url (all formats returned by wallet MCPs are accepted).'
37061
37261
  }
37062
37262
  };
37063
37263
  } catch (error) {
@@ -39231,6 +39431,22 @@ async function getGameHistory(client, args) {
39231
39431
  };
39232
39432
  }
39233
39433
  }
39434
+ async function reportUser(client, args) {
39435
+ try {
39436
+ await client.sdk.reports.create(args.userId, args.reason);
39437
+ return {
39438
+ data: {
39439
+ success: true,
39440
+ hint: "Report submitted. The DIM moderation team will review it."
39441
+ }
39442
+ };
39443
+ } catch (error) {
39444
+ return {
39445
+ error: `Failed to report user: ${error instanceof Error ? error.message : String(error)}`,
39446
+ isError: true
39447
+ };
39448
+ }
39449
+ }
39234
39450
  async function getMyStats(client) {
39235
39451
  try {
39236
39452
  if (!client.currentUserId) {
@@ -39276,7 +39492,7 @@ var TOOL_DEFINITIONS = [
39276
39492
  },
39277
39493
  {
39278
39494
  name: "dim_complete_login",
39279
- description: "External wallet login step 2: provide the wallet address and base58 signature from sign_solana_message to complete authentication with DIM.",
39495
+ description: "External wallet login step 2: provide the wallet address and signature from sign_solana_message to complete authentication with DIM.",
39280
39496
  params: {
39281
39497
  address: {
39282
39498
  type: "string",
@@ -39285,7 +39501,7 @@ var TOOL_DEFINITIONS = [
39285
39501
  },
39286
39502
  signature: {
39287
39503
  type: "string",
39288
- description: "Base58-encoded signature returned by sign_solana_message",
39504
+ description: "Signature from sign_solana_message \u2014 base58, base64, or base64url accepted",
39289
39505
  required: true
39290
39506
  }
39291
39507
  },
@@ -39729,6 +39945,23 @@ var TOOL_DEFINITIONS = [
39729
39945
  params: {},
39730
39946
  execute: (c) => getMyStats(c)
39731
39947
  },
39948
+ {
39949
+ name: "dim_report_user",
39950
+ description: "Report a user for cheating, harassment, or other violations. Rate limited to 5 reports per hour.",
39951
+ params: {
39952
+ userId: {
39953
+ type: "string",
39954
+ description: "The ID of the user to report",
39955
+ required: true
39956
+ },
39957
+ reason: {
39958
+ type: "string",
39959
+ description: "Reason for the report (max 300 characters)",
39960
+ required: true
39961
+ }
39962
+ },
39963
+ execute: (c, a) => reportUser(c, a)
39964
+ },
39732
39965
  {
39733
39966
  name: "dim_create_lobby",
39734
39967
  description: "Create a new game lobby. Bet amount is in USDC dollars (e.g., 1.00 for $1.00). A 1% fee (min 1 cent) is charged per player.",
@@ -40293,11 +40526,18 @@ async function executeWithAuthRetry(client, tool, params) {
40293
40526
  if (tool.name === "dim_login") {
40294
40527
  return tool.execute(client, params);
40295
40528
  }
40529
+ if (client.externalSignerMode) {
40530
+ return tool.execute(client, params);
40531
+ }
40296
40532
  try {
40297
40533
  const result = await tool.execute(client, params);
40298
40534
  if (!result.error && !result.isError) return result;
40299
40535
  if (!isUnauthorizedResult(result)) return result;
40300
- await client.authenticate();
40536
+ try {
40537
+ await client.authenticate();
40538
+ } catch {
40539
+ return { error: UNAUTHORIZED_MESSAGE, isError: true };
40540
+ }
40301
40541
  const retryResult = await tool.execute(client, params);
40302
40542
  if (retryResult.isError || retryResult.error) {
40303
40543
  if (isUnauthorizedResult(retryResult)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimcool/dimclaw",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "OpenClaw plugin for DIM — play games, chat, send USDC, and earn on DIM using the SDK directly (no MCP subprocess).",
5
5
  "type": "module",
6
6
  "openclaw": {