@dimcool/mcp 0.1.26 → 0.1.27
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.js +287 -53
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11984,19 +11984,18 @@ var Lobbies = class {
|
|
|
11984
11984
|
return this.http.delete(`/lobbies/admin/${lobbyId}`);
|
|
11985
11985
|
}
|
|
11986
11986
|
/**
|
|
11987
|
-
* Play again: Create a new lobby
|
|
11988
|
-
* Returns the lobby and unsigned transaction that needs to be signed
|
|
11987
|
+
* Play again: Create a new lobby and prepare deposit in one flow.
|
|
11988
|
+
* Returns the lobby and unsigned transaction that needs to be signed.
|
|
11989
11989
|
* @param gameType - The game type to play again
|
|
11990
11990
|
* @param betAmount - The bet amount (same as previous game)
|
|
11991
11991
|
* @param escrow - The escrow service instance (from sdk.escrow)
|
|
11992
11992
|
*/
|
|
11993
11993
|
async playAgain(gameType, betAmount, escrow) {
|
|
11994
11994
|
const lobby = await this.createLobby(gameType, betAmount);
|
|
11995
|
-
await escrow.
|
|
11996
|
-
const prepareResponse = await escrow.prepareDepositTransaction(lobby.id);
|
|
11995
|
+
const { transaction } = await escrow.prepareAndStartDeposit(lobby.id);
|
|
11997
11996
|
return {
|
|
11998
11997
|
lobby,
|
|
11999
|
-
unsignedTransaction:
|
|
11998
|
+
unsignedTransaction: transaction
|
|
12000
11999
|
};
|
|
12001
12000
|
}
|
|
12002
12001
|
};
|
|
@@ -12860,6 +12859,17 @@ var Escrow = class {
|
|
|
12860
12859
|
`/escrow/lobby/${lobbyId}/deposit/prepare`
|
|
12861
12860
|
);
|
|
12862
12861
|
}
|
|
12862
|
+
/**
|
|
12863
|
+
* Combined prepare-and-start: validates lobby, transitions waiting→preparing,
|
|
12864
|
+
* initializes depositStatus, and prepares the unsigned transaction in one call.
|
|
12865
|
+
* Eliminates one HTTP round-trip vs startDeposits() + prepareDepositTransaction().
|
|
12866
|
+
*/
|
|
12867
|
+
async prepareAndStartDeposit(lobbyId) {
|
|
12868
|
+
return this.http.post(
|
|
12869
|
+
`/escrow/lobby/${lobbyId}/deposit/prepare-and-start`,
|
|
12870
|
+
{}
|
|
12871
|
+
);
|
|
12872
|
+
}
|
|
12863
12873
|
/**
|
|
12864
12874
|
* Submit a signed deposit transaction
|
|
12865
12875
|
* The transaction will be submitted to the Solana network and confirmed
|
|
@@ -12890,7 +12900,7 @@ var Escrow = class {
|
|
|
12890
12900
|
);
|
|
12891
12901
|
}
|
|
12892
12902
|
/**
|
|
12893
|
-
* One-call lobby deposit: start
|
|
12903
|
+
* One-call lobby deposit: prepare-and-start, sign, submit, and poll until
|
|
12894
12904
|
* the current user's deposit is confirmed. Requires sdk.wallet.setSigner() to be set.
|
|
12895
12905
|
* Returns when all required deposits are confirmed and the lobby can proceed to queue.
|
|
12896
12906
|
*
|
|
@@ -12902,8 +12912,7 @@ var Escrow = class {
|
|
|
12902
12912
|
"No signer configured. Use sdk.wallet.setSigner(...) first."
|
|
12903
12913
|
);
|
|
12904
12914
|
}
|
|
12905
|
-
await this.
|
|
12906
|
-
const { transaction } = await this.prepareDepositTransaction(lobbyId);
|
|
12915
|
+
const { transaction } = await this.prepareAndStartDeposit(lobbyId);
|
|
12907
12916
|
const unsignedTx = Transaction5.from(base64ToBytes(transaction));
|
|
12908
12917
|
let signature;
|
|
12909
12918
|
if (this.wallet.isSignAndSendMode()) {
|
|
@@ -12925,7 +12934,7 @@ var Escrow = class {
|
|
|
12925
12934
|
if (status.allConfirmed && status.canProceedToQueue) {
|
|
12926
12935
|
return {
|
|
12927
12936
|
signature,
|
|
12928
|
-
status: "
|
|
12937
|
+
status: "confirmed",
|
|
12929
12938
|
canProceedToQueue: true
|
|
12930
12939
|
};
|
|
12931
12940
|
}
|
|
@@ -12937,6 +12946,39 @@ var Escrow = class {
|
|
|
12937
12946
|
canProceedToQueue: false
|
|
12938
12947
|
};
|
|
12939
12948
|
}
|
|
12949
|
+
/**
|
|
12950
|
+
* Zero-polling deposit variant using server-side awaitConfirmation.
|
|
12951
|
+
* 2 HTTP calls total, 0 client-side polling. Ideal for agents.
|
|
12952
|
+
*
|
|
12953
|
+
* Automatically uses signAndSendTransaction or signTransaction based on signer capability.
|
|
12954
|
+
*/
|
|
12955
|
+
async depositForLobbySync(lobbyId) {
|
|
12956
|
+
if (!this.wallet.hasSigner()) {
|
|
12957
|
+
throw new Error(
|
|
12958
|
+
"No signer configured. Use sdk.wallet.setSigner(...) first."
|
|
12959
|
+
);
|
|
12960
|
+
}
|
|
12961
|
+
const { transaction } = await this.prepareAndStartDeposit(lobbyId);
|
|
12962
|
+
const unsignedTx = Transaction5.from(base64ToBytes(transaction));
|
|
12963
|
+
let signature;
|
|
12964
|
+
if (this.wallet.isSignAndSendMode()) {
|
|
12965
|
+
signature = await this.wallet.signAndSendTransaction(unsignedTx);
|
|
12966
|
+
await this.http.post(
|
|
12967
|
+
`/escrow/lobby/${lobbyId}/deposit/confirm-signature?awaitConfirmation=true`,
|
|
12968
|
+
{ signature }
|
|
12969
|
+
);
|
|
12970
|
+
} else {
|
|
12971
|
+
const signedTx = await this.wallet.signTransaction(unsignedTx);
|
|
12972
|
+
const signedBase64 = bytesToBase64(
|
|
12973
|
+
signedTx.serialize({ requireAllSignatures: false })
|
|
12974
|
+
);
|
|
12975
|
+
const result = await this.http.post(`/escrow/lobby/${lobbyId}/deposit/submit?awaitConfirmation=true`, {
|
|
12976
|
+
signedTransaction: signedBase64
|
|
12977
|
+
});
|
|
12978
|
+
signature = result.signature;
|
|
12979
|
+
}
|
|
12980
|
+
return { signature, status: "confirmed", canProceedToQueue: true };
|
|
12981
|
+
}
|
|
12940
12982
|
async claimLobbyDepositRefund(lobbyId, depositSignature) {
|
|
12941
12983
|
return this.http.post(
|
|
12942
12984
|
`/escrow/lobby/${lobbyId}/deposit/${depositSignature}/claim-refund`,
|
|
@@ -12949,33 +12991,6 @@ var Escrow = class {
|
|
|
12949
12991
|
{}
|
|
12950
12992
|
);
|
|
12951
12993
|
}
|
|
12952
|
-
/**
|
|
12953
|
-
* Submit a signed deposit transaction and wait until the lobby is queued/active.
|
|
12954
|
-
*
|
|
12955
|
-
* Note: the backend may auto-transition the lobby to the queue once deposits are confirmed.
|
|
12956
|
-
* In that case, calling /join-queue from the client would be redundant and can fail with
|
|
12957
|
-
* "Current status: queued".
|
|
12958
|
-
* @param lobbyId - The lobby ID
|
|
12959
|
-
* @param signedTransaction - The signed transaction (base64 encoded)
|
|
12960
|
-
* @param lobbies - The lobbies service instance (from sdk.lobbies) to read lobby status
|
|
12961
|
-
*/
|
|
12962
|
-
async submitDepositAndJoinQueue(lobbyId, signedTransaction, lobbies) {
|
|
12963
|
-
await this.submitDeposit(lobbyId, signedTransaction);
|
|
12964
|
-
const MAX_WAIT_TIME = 3e4;
|
|
12965
|
-
const POLL_INTERVAL = 1e3;
|
|
12966
|
-
const startTime = Date.now();
|
|
12967
|
-
while (Date.now() - startTime < MAX_WAIT_TIME) {
|
|
12968
|
-
const status = await this.getDepositStatus(lobbyId);
|
|
12969
|
-
if (status.allConfirmed && status.canProceedToQueue) {
|
|
12970
|
-
const lobby = await lobbies.getLobby(lobbyId);
|
|
12971
|
-
if (lobby.status === "queued" || lobby.status === "active") {
|
|
12972
|
-
return lobby;
|
|
12973
|
-
}
|
|
12974
|
-
}
|
|
12975
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
|
|
12976
|
-
}
|
|
12977
|
-
throw new Error("Deposit confirmation timeout");
|
|
12978
|
-
}
|
|
12979
12994
|
};
|
|
12980
12995
|
var Daily = class {
|
|
12981
12996
|
constructor(http, logger2 = logger) {
|
|
@@ -13602,8 +13617,14 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
13602
13617
|
connecting: false,
|
|
13603
13618
|
error: null
|
|
13604
13619
|
});
|
|
13620
|
+
const wasReconnect = this.reconnectAttempts > 0;
|
|
13605
13621
|
this.reconnectAttempts = 0;
|
|
13606
13622
|
this.onReconnect();
|
|
13623
|
+
if (wasReconnect) {
|
|
13624
|
+
this.dispatchEvent("connection:reconnected", {
|
|
13625
|
+
timestamp: Date.now()
|
|
13626
|
+
});
|
|
13627
|
+
}
|
|
13607
13628
|
});
|
|
13608
13629
|
socket.on("disconnect", (reason) => {
|
|
13609
13630
|
this.updateConnectionState({ connected: false, connecting: false });
|
|
@@ -13745,7 +13766,8 @@ function createLobbyStore(transport2) {
|
|
|
13745
13766
|
const store = createSdkStore({
|
|
13746
13767
|
lobbiesById: {},
|
|
13747
13768
|
matchedEvent: null,
|
|
13748
|
-
typingByLobbyId: {}
|
|
13769
|
+
typingByLobbyId: {},
|
|
13770
|
+
depositStatusByLobbyId: {}
|
|
13749
13771
|
});
|
|
13750
13772
|
const setBaseState = (lobbies) => {
|
|
13751
13773
|
const lobbiesById = {};
|
|
@@ -13825,6 +13847,15 @@ function createLobbyStore(transport2) {
|
|
|
13825
13847
|
};
|
|
13826
13848
|
});
|
|
13827
13849
|
break;
|
|
13850
|
+
case "lobby:deposit:updated":
|
|
13851
|
+
store.updateState((state) => ({
|
|
13852
|
+
...state,
|
|
13853
|
+
depositStatusByLobbyId: {
|
|
13854
|
+
...state.depositStatusByLobbyId,
|
|
13855
|
+
[event.payload.lobbyId]: event.payload
|
|
13856
|
+
}
|
|
13857
|
+
}));
|
|
13858
|
+
break;
|
|
13828
13859
|
case "lobby:typing:start":
|
|
13829
13860
|
case "lobby:typing:stop":
|
|
13830
13861
|
store.updateState((state) => {
|
|
@@ -13853,12 +13884,22 @@ function createLobbyStore(transport2) {
|
|
|
13853
13884
|
}
|
|
13854
13885
|
}
|
|
13855
13886
|
);
|
|
13887
|
+
const subscribeDepositUpdate = (lobbyId, callback) => store.subscribeSelector(
|
|
13888
|
+
(state) => state.depositStatusByLobbyId[lobbyId],
|
|
13889
|
+
() => {
|
|
13890
|
+
const data = store.getState().depositStatusByLobbyId[lobbyId];
|
|
13891
|
+
if (data) {
|
|
13892
|
+
callback(data);
|
|
13893
|
+
}
|
|
13894
|
+
}
|
|
13895
|
+
);
|
|
13856
13896
|
return {
|
|
13857
13897
|
store,
|
|
13858
13898
|
setBaseState,
|
|
13859
13899
|
applyWsEvent,
|
|
13860
13900
|
joinLobby,
|
|
13861
|
-
subscribeMatched
|
|
13901
|
+
subscribeMatched,
|
|
13902
|
+
subscribeDepositUpdate
|
|
13862
13903
|
};
|
|
13863
13904
|
}
|
|
13864
13905
|
function createGameStore(transport2) {
|
|
@@ -14140,7 +14181,6 @@ function createGameActionsStore(transport2) {
|
|
|
14140
14181
|
...current,
|
|
14141
14182
|
roundState: {
|
|
14142
14183
|
...current.roundState,
|
|
14143
|
-
phase: "completed",
|
|
14144
14184
|
timeRemaining: 0,
|
|
14145
14185
|
actions: timedOutUser ? {
|
|
14146
14186
|
...current.roundState.actions,
|
|
@@ -14652,6 +14692,7 @@ var WS_EVENT_NAMES = [
|
|
|
14652
14692
|
"lobby:queue:joined",
|
|
14653
14693
|
"lobby:queue:cancelled",
|
|
14654
14694
|
"lobby:matched",
|
|
14695
|
+
"lobby:deposit:updated",
|
|
14655
14696
|
"lobby:typing:start",
|
|
14656
14697
|
"lobby:typing:stop",
|
|
14657
14698
|
"game:updated",
|
|
@@ -14728,6 +14769,11 @@ function decodeWsEvent(eventName, payload) {
|
|
|
14728
14769
|
event: "lobby:matched",
|
|
14729
14770
|
payload
|
|
14730
14771
|
};
|
|
14772
|
+
case "lobby:deposit:updated":
|
|
14773
|
+
return {
|
|
14774
|
+
event: "lobby:deposit:updated",
|
|
14775
|
+
payload
|
|
14776
|
+
};
|
|
14731
14777
|
case "lobby:typing:start":
|
|
14732
14778
|
case "lobby:typing:stop":
|
|
14733
14779
|
return {
|
|
@@ -15184,6 +15230,17 @@ var SAFETY_RULES = [
|
|
|
15184
15230
|
];
|
|
15185
15231
|
|
|
15186
15232
|
// ../dim-agent-core/src/tools/auth.ts
|
|
15233
|
+
var WALLET_LINKAGE_NOTE = "DIM is noncustodial. Your DIM wallet is the Solana address shown here; it was configured with a base58 private key at setup. Signing is done locally where this instance runs, using that private key and DIM's wallet package.";
|
|
15234
|
+
async function getSpectateUrl(client) {
|
|
15235
|
+
if (!client.currentUserId) return null;
|
|
15236
|
+
try {
|
|
15237
|
+
const user = await client.sdk.users.getUserById(client.currentUserId);
|
|
15238
|
+
const u = user;
|
|
15239
|
+
return u?.username ? `https://dim.cool/spectate/${u.username}` : null;
|
|
15240
|
+
} catch {
|
|
15241
|
+
return null;
|
|
15242
|
+
}
|
|
15243
|
+
}
|
|
15187
15244
|
async function login(client) {
|
|
15188
15245
|
try {
|
|
15189
15246
|
const result = await client.authenticate();
|
|
@@ -15213,6 +15270,7 @@ async function login(client) {
|
|
|
15213
15270
|
userId: result.userId,
|
|
15214
15271
|
username: result.username ?? null,
|
|
15215
15272
|
walletAddress: client.walletAddress,
|
|
15273
|
+
walletNote: WALLET_LINKAGE_NOTE,
|
|
15216
15274
|
safetyRules: SAFETY_RULES,
|
|
15217
15275
|
nextSteps
|
|
15218
15276
|
};
|
|
@@ -15246,7 +15304,11 @@ async function getProfile(client) {
|
|
|
15246
15304
|
};
|
|
15247
15305
|
}
|
|
15248
15306
|
const user = await client.sdk.users.getUserById(client.currentUserId);
|
|
15249
|
-
|
|
15307
|
+
const profile = {
|
|
15308
|
+
...typeof user === "object" && user !== null ? user : {},
|
|
15309
|
+
walletAddress: client.walletAddress
|
|
15310
|
+
};
|
|
15311
|
+
return { data: profile };
|
|
15250
15312
|
} catch (error) {
|
|
15251
15313
|
return {
|
|
15252
15314
|
error: `Failed to get profile: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -15447,12 +15509,31 @@ async function listDmThreads(client) {
|
|
|
15447
15509
|
}
|
|
15448
15510
|
|
|
15449
15511
|
// ../dim-agent-core/src/tools/wallet.ts
|
|
15512
|
+
async function getWalletAddress(client) {
|
|
15513
|
+
try {
|
|
15514
|
+
return {
|
|
15515
|
+
data: {
|
|
15516
|
+
walletAddress: client.walletAddress,
|
|
15517
|
+
walletNote: WALLET_LINKAGE_NOTE
|
|
15518
|
+
}
|
|
15519
|
+
};
|
|
15520
|
+
} catch (error) {
|
|
15521
|
+
return {
|
|
15522
|
+
error: `Failed to get wallet address: ${error instanceof Error ? error.message : String(error)}`,
|
|
15523
|
+
isError: true
|
|
15524
|
+
};
|
|
15525
|
+
}
|
|
15526
|
+
}
|
|
15450
15527
|
async function getBalance(client) {
|
|
15451
15528
|
try {
|
|
15452
15529
|
const balance = await client.sdk.wallet.getBalances();
|
|
15453
15530
|
const usdcDollars = balance.usdc / 1e6;
|
|
15454
15531
|
return {
|
|
15455
|
-
data: {
|
|
15532
|
+
data: {
|
|
15533
|
+
...balance,
|
|
15534
|
+
usdcFormatted: `$${usdcDollars.toFixed(2)}`,
|
|
15535
|
+
walletAddress: client.walletAddress
|
|
15536
|
+
}
|
|
15456
15537
|
};
|
|
15457
15538
|
} catch (error) {
|
|
15458
15539
|
return {
|
|
@@ -15519,7 +15600,10 @@ async function getWalletActivity(client, args) {
|
|
|
15519
15600
|
limit: args.limit || 20
|
|
15520
15601
|
});
|
|
15521
15602
|
const claimable = activity.items.filter((i) => i.claimable === true);
|
|
15522
|
-
const data = {
|
|
15603
|
+
const data = {
|
|
15604
|
+
...activity,
|
|
15605
|
+
walletAddress: client.walletAddress
|
|
15606
|
+
};
|
|
15523
15607
|
if (claimable.length > 0) {
|
|
15524
15608
|
data.hint = `You have ${claimable.length} claimable item(s). Call dim_claim_funds with the activityId to claim each one.`;
|
|
15525
15609
|
data.claimableItems = claimable.map((i) => ({
|
|
@@ -15728,9 +15812,8 @@ function buildGameOverHint(state) {
|
|
|
15728
15812
|
const winnerId = state.winnerId;
|
|
15729
15813
|
const wonAmount = state.wonAmount;
|
|
15730
15814
|
const isDraw = state.draw === true || winnerId == null;
|
|
15731
|
-
|
|
15732
|
-
|
|
15733
|
-
return `Game over. Winner: ${winnerId}.${amountStr}`;
|
|
15815
|
+
const result = isDraw ? "Game over \u2014 it was a draw." : `Game over. Winner: ${winnerId}.${wonAmount != null ? ` Won $${(wonAmount / 1e6).toFixed(2)}.` : ""}`;
|
|
15816
|
+
return `${result} You can request a rematch with dim_request_rematch, or check dim_check_notifications for new activity.`;
|
|
15734
15817
|
}
|
|
15735
15818
|
async function fetchNewGameChat(client, gameId) {
|
|
15736
15819
|
try {
|
|
@@ -15838,13 +15921,13 @@ async function createLobby(client, args) {
|
|
|
15838
15921
|
}
|
|
15839
15922
|
async function depositForLobby(client, args) {
|
|
15840
15923
|
try {
|
|
15841
|
-
const result = await client.sdk.escrow.
|
|
15924
|
+
const result = await client.sdk.escrow.depositForLobbySync(args.lobbyId);
|
|
15842
15925
|
return {
|
|
15843
15926
|
data: {
|
|
15844
15927
|
signature: result.signature,
|
|
15845
15928
|
status: result.status,
|
|
15846
15929
|
canProceedToQueue: result.canProceedToQueue,
|
|
15847
|
-
hint:
|
|
15930
|
+
hint: "Deposit confirmed. The server auto-joins the queue when all players have deposited."
|
|
15848
15931
|
}
|
|
15849
15932
|
};
|
|
15850
15933
|
} catch (error) {
|
|
@@ -15875,13 +15958,15 @@ async function joinQueue(client, args) {
|
|
|
15875
15958
|
await client.ensureConnected();
|
|
15876
15959
|
const lobby = await client.sdk.lobbies.joinQueue(args.lobbyId);
|
|
15877
15960
|
const matched = lobby.status === "active" && lobby.gameId;
|
|
15961
|
+
const spectateUrl = matched ? await getSpectateUrl(client) : null;
|
|
15878
15962
|
return {
|
|
15879
15963
|
data: {
|
|
15880
15964
|
lobbyId: lobby.id,
|
|
15881
15965
|
status: lobby.status,
|
|
15882
15966
|
gameId: lobby.gameId || null,
|
|
15883
15967
|
matched: !!matched,
|
|
15884
|
-
|
|
15968
|
+
...spectateUrl && { spectateUrl },
|
|
15969
|
+
hint: matched ? `Game started! Call dim_game_loop with gameId "${lobby.gameId}" to play.${spectateUrl ? ` Tell the user they can spectate at ${spectateUrl}` : ""}` : "Waiting for an opponent. Poll dim_get_lobby to check for a match."
|
|
15885
15970
|
}
|
|
15886
15971
|
};
|
|
15887
15972
|
} catch (error) {
|
|
@@ -16063,6 +16148,38 @@ async function inviteToLobby(client, args) {
|
|
|
16063
16148
|
};
|
|
16064
16149
|
}
|
|
16065
16150
|
}
|
|
16151
|
+
async function requestRematch(client, args) {
|
|
16152
|
+
try {
|
|
16153
|
+
const result = await client.sdk.games.requestRematch(args.gameId);
|
|
16154
|
+
return {
|
|
16155
|
+
data: {
|
|
16156
|
+
...result,
|
|
16157
|
+
hint: result.bothReady ? `Both players want a rematch! A lobby is being created.${result.newLobbyId ? ` Lobby ID: ${result.newLobbyId}.` : ""} Check dim_check_notifications or call dim_game_loop with the new gameId once the game starts.` : "Rematch requested. Waiting for opponent to accept. Call dim_check_notifications to see if they respond."
|
|
16158
|
+
}
|
|
16159
|
+
};
|
|
16160
|
+
} catch (error) {
|
|
16161
|
+
return {
|
|
16162
|
+
error: `Failed to request rematch: ${error instanceof Error ? error.message : String(error)}`,
|
|
16163
|
+
isError: true
|
|
16164
|
+
};
|
|
16165
|
+
}
|
|
16166
|
+
}
|
|
16167
|
+
async function acceptRematch(client, args) {
|
|
16168
|
+
try {
|
|
16169
|
+
const result = await client.sdk.games.requestRematch(args.gameId);
|
|
16170
|
+
return {
|
|
16171
|
+
data: {
|
|
16172
|
+
...result,
|
|
16173
|
+
hint: result.bothReady ? `Rematch accepted! A lobby has been created.${result.newLobbyId ? ` Lobby ID: ${result.newLobbyId}.` : ""} Proceed with deposit and game flow.` : "Your rematch acceptance was recorded. Waiting for the other player."
|
|
16174
|
+
}
|
|
16175
|
+
};
|
|
16176
|
+
} catch (error) {
|
|
16177
|
+
return {
|
|
16178
|
+
error: `Failed to accept rematch: ${error instanceof Error ? error.message : String(error)}`,
|
|
16179
|
+
isError: true
|
|
16180
|
+
};
|
|
16181
|
+
}
|
|
16182
|
+
}
|
|
16066
16183
|
function raceTimeout(promise, ms) {
|
|
16067
16184
|
return new Promise((resolve) => {
|
|
16068
16185
|
const timer = setTimeout(resolve, ms);
|
|
@@ -16109,10 +16226,12 @@ async function challengeUser(client, args) {
|
|
|
16109
16226
|
async function acceptChallenge(client, args) {
|
|
16110
16227
|
try {
|
|
16111
16228
|
const result = await client.sdk.challenges.accept(args.challengeId);
|
|
16229
|
+
const spectateUrl = result.gameId ? await getSpectateUrl(client) : null;
|
|
16112
16230
|
return {
|
|
16113
16231
|
data: {
|
|
16114
16232
|
...result,
|
|
16115
|
-
|
|
16233
|
+
...spectateUrl && { spectateUrl },
|
|
16234
|
+
hint: result.gameId ? `Game started! Call dim_game_loop with gameId "${result.gameId}".${spectateUrl ? ` Tell the user they can spectate at ${spectateUrl}` : ""}` : `Lobby created: ${result.lobbyId}. Use dim_join_queue to start matchmaking.`
|
|
16116
16235
|
}
|
|
16117
16236
|
};
|
|
16118
16237
|
} catch (error) {
|
|
@@ -16648,6 +16767,69 @@ async function getAgentConfig(client) {
|
|
|
16648
16767
|
}
|
|
16649
16768
|
}
|
|
16650
16769
|
|
|
16770
|
+
// ../dim-agent-core/src/tools/users.ts
|
|
16771
|
+
function formatMinor(m) {
|
|
16772
|
+
if (m == null) return "\u2014";
|
|
16773
|
+
const n = typeof m === "bigint" ? Number(m) : m;
|
|
16774
|
+
return `$${(n / 1e6).toFixed(2)}`;
|
|
16775
|
+
}
|
|
16776
|
+
async function getGameHistory(client, args) {
|
|
16777
|
+
try {
|
|
16778
|
+
if (!client.currentUserId) {
|
|
16779
|
+
return {
|
|
16780
|
+
error: "Not authenticated. Call dim_login first.",
|
|
16781
|
+
isError: true
|
|
16782
|
+
};
|
|
16783
|
+
}
|
|
16784
|
+
const raw = await client.sdk.users.getGameHistory(client.currentUserId);
|
|
16785
|
+
const limit = Math.min(args.limit ?? 50, 100);
|
|
16786
|
+
const items = raw.slice(0, limit).map((item) => ({
|
|
16787
|
+
...item,
|
|
16788
|
+
betFormatted: formatMinor(item.betAmount),
|
|
16789
|
+
winningsFormatted: formatMinor(item.winnings)
|
|
16790
|
+
}));
|
|
16791
|
+
return {
|
|
16792
|
+
data: {
|
|
16793
|
+
items,
|
|
16794
|
+
totalReturned: items.length,
|
|
16795
|
+
hint: items.length >= limit ? `Showing most recent ${limit} games. Use limit param to request more (max 100).` : void 0
|
|
16796
|
+
}
|
|
16797
|
+
};
|
|
16798
|
+
} catch (error) {
|
|
16799
|
+
return {
|
|
16800
|
+
error: `Failed to get game history: ${error instanceof Error ? error.message : String(error)}`,
|
|
16801
|
+
isError: true
|
|
16802
|
+
};
|
|
16803
|
+
}
|
|
16804
|
+
}
|
|
16805
|
+
async function getMyStats(client) {
|
|
16806
|
+
try {
|
|
16807
|
+
if (!client.currentUserId) {
|
|
16808
|
+
return {
|
|
16809
|
+
error: "Not authenticated. Call dim_login first.",
|
|
16810
|
+
isError: true
|
|
16811
|
+
};
|
|
16812
|
+
}
|
|
16813
|
+
const stats = await client.sdk.users.getUserStats(
|
|
16814
|
+
client.currentUserId
|
|
16815
|
+
);
|
|
16816
|
+
return {
|
|
16817
|
+
data: {
|
|
16818
|
+
...stats,
|
|
16819
|
+
totalEarnedFormatted: formatMinor(stats.totalEarned),
|
|
16820
|
+
referralEarnedFormatted: formatMinor(stats.referralEarned),
|
|
16821
|
+
totalLostFormatted: formatMinor(stats.totalLost),
|
|
16822
|
+
totalFeesPaidFormatted: formatMinor(stats.totalFeesPaid)
|
|
16823
|
+
}
|
|
16824
|
+
};
|
|
16825
|
+
} catch (error) {
|
|
16826
|
+
return {
|
|
16827
|
+
error: `Failed to get stats: ${error instanceof Error ? error.message : String(error)}`,
|
|
16828
|
+
isError: true
|
|
16829
|
+
};
|
|
16830
|
+
}
|
|
16831
|
+
}
|
|
16832
|
+
|
|
16651
16833
|
// ../dim-agent-core/src/tools/index.ts
|
|
16652
16834
|
var TOOL_DEFINITIONS = [
|
|
16653
16835
|
// ── Auth ─────────────────────────────────────────────────────────────
|
|
@@ -16659,7 +16841,7 @@ var TOOL_DEFINITIONS = [
|
|
|
16659
16841
|
},
|
|
16660
16842
|
{
|
|
16661
16843
|
name: "dim_get_profile",
|
|
16662
|
-
description: "Get the current authenticated user profile including username, avatar, bio,
|
|
16844
|
+
description: "Get the current authenticated user profile including username, avatar, bio, chess ELO rating, and your DIM wallet address (walletAddress).",
|
|
16663
16845
|
params: {},
|
|
16664
16846
|
execute: (c) => getProfile(c)
|
|
16665
16847
|
},
|
|
@@ -16819,9 +17001,15 @@ var TOOL_DEFINITIONS = [
|
|
|
16819
17001
|
execute: (c) => listDmThreads(c)
|
|
16820
17002
|
},
|
|
16821
17003
|
// ── Wallet ───────────────────────────────────────────────────────────
|
|
17004
|
+
{
|
|
17005
|
+
name: "dim_get_wallet_address",
|
|
17006
|
+
description: "Get the Solana wallet address DIM uses for this account. Use this to confirm which address receives deposits and is used for signing. Returns walletAddress and a short wallet linkage note.",
|
|
17007
|
+
params: {},
|
|
17008
|
+
execute: (c) => getWalletAddress(c)
|
|
17009
|
+
},
|
|
16822
17010
|
{
|
|
16823
17011
|
name: "dim_get_balance",
|
|
16824
|
-
description: "Get the wallet balance for the authenticated user. Returns SOL and USDC (usdcFormatted is always present, e.g. $0.00 or $1.50).",
|
|
17012
|
+
description: "Get the wallet balance for the authenticated user. Returns your DIM Solana address (walletAddress), SOL and USDC (usdcFormatted is always present, e.g. $0.00 or $1.50).",
|
|
16825
17013
|
params: {},
|
|
16826
17014
|
execute: (c) => getBalance(c)
|
|
16827
17015
|
},
|
|
@@ -16863,7 +17051,7 @@ var TOOL_DEFINITIONS = [
|
|
|
16863
17051
|
},
|
|
16864
17052
|
{
|
|
16865
17053
|
name: "dim_get_wallet_activity",
|
|
16866
|
-
description: "Get recent wallet transaction activity (deposits, payouts, transfers, refunds). Highlights any claimable items.",
|
|
17054
|
+
description: "Get recent wallet transaction activity (deposits, payouts, transfers, refunds) and your DIM wallet address. Highlights any claimable items.",
|
|
16867
17055
|
params: {
|
|
16868
17056
|
limit: {
|
|
16869
17057
|
type: "number",
|
|
@@ -16903,6 +17091,23 @@ var TOOL_DEFINITIONS = [
|
|
|
16903
17091
|
params: {},
|
|
16904
17092
|
execute: (c) => getGameMetrics(c)
|
|
16905
17093
|
},
|
|
17094
|
+
{
|
|
17095
|
+
name: "dim_get_game_history",
|
|
17096
|
+
description: "Get your game history: past games with result, bet, winnings, opponent, and playedAt. Use for daily progress reports.",
|
|
17097
|
+
params: {
|
|
17098
|
+
limit: {
|
|
17099
|
+
type: "number",
|
|
17100
|
+
description: "Max games to return (default 50, max 100)"
|
|
17101
|
+
}
|
|
17102
|
+
},
|
|
17103
|
+
execute: (c, a) => getGameHistory(c, a)
|
|
17104
|
+
},
|
|
17105
|
+
{
|
|
17106
|
+
name: "dim_get_my_stats",
|
|
17107
|
+
description: "Get your aggregated DIM stats: games played, wins, losses, total earned, referral earned, total lost, fees paid, chess ELO, points.",
|
|
17108
|
+
params: {},
|
|
17109
|
+
execute: (c) => getMyStats(c)
|
|
17110
|
+
},
|
|
16906
17111
|
{
|
|
16907
17112
|
name: "dim_create_lobby",
|
|
16908
17113
|
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.",
|
|
@@ -17032,6 +17237,30 @@ var TOOL_DEFINITIONS = [
|
|
|
17032
17237
|
},
|
|
17033
17238
|
execute: (c, a) => gameLoop(c, a)
|
|
17034
17239
|
},
|
|
17240
|
+
{
|
|
17241
|
+
name: "dim_request_rematch",
|
|
17242
|
+
description: "Request a rematch after a completed game. If both players request, a lobby is created automatically server-side.",
|
|
17243
|
+
params: {
|
|
17244
|
+
gameId: {
|
|
17245
|
+
type: "string",
|
|
17246
|
+
description: "The completed game ID to request a rematch for",
|
|
17247
|
+
required: true
|
|
17248
|
+
}
|
|
17249
|
+
},
|
|
17250
|
+
execute: (c, a) => requestRematch(c, a)
|
|
17251
|
+
},
|
|
17252
|
+
{
|
|
17253
|
+
name: "dim_accept_rematch",
|
|
17254
|
+
description: "Accept a rematch request from your opponent. When both players accept, the rematch lobby is created automatically.",
|
|
17255
|
+
params: {
|
|
17256
|
+
gameId: {
|
|
17257
|
+
type: "string",
|
|
17258
|
+
description: "The completed game ID to accept the rematch for",
|
|
17259
|
+
required: true
|
|
17260
|
+
}
|
|
17261
|
+
},
|
|
17262
|
+
execute: (c, a) => acceptRematch(c, a)
|
|
17263
|
+
},
|
|
17035
17264
|
{
|
|
17036
17265
|
name: "dim_get_lobby_link",
|
|
17037
17266
|
description: "Get a shareable join link for a lobby. Share this URL via DM \u2014 the user can join with one click. Like dim_invite_to_lobby, do NOT also call dim_join_queue for the same lobby.",
|
|
@@ -17632,7 +17861,7 @@ function createDimMcpServer(config) {
|
|
|
17632
17861
|
const server2 = new McpServer({
|
|
17633
17862
|
name: "dim",
|
|
17634
17863
|
version: "1.0.0",
|
|
17635
|
-
description: "DIM Gaming Platform \u2014 Play games, chat, send USDC, challenge users, and earn referral income. Start by calling dim_login. After login: set a username with dim_set_username, check balance with dim_get_balance, list games with dim_list_games, or apply a referral code with dim_apply_referral_code for a 10% fee discount."
|
|
17864
|
+
description: "DIM Gaming Platform \u2014 Play games, chat, send USDC, challenge users, and earn referral income. DIM is noncustodial; your Solana address is returned by dim_get_profile and dim_get_balance. Start by calling dim_login. After login: set a username with dim_set_username, check balance with dim_get_balance, list games with dim_list_games, or apply a referral code with dim_apply_referral_code for a 10% fee discount."
|
|
17636
17865
|
});
|
|
17637
17866
|
const client = new DimAgentClient(config);
|
|
17638
17867
|
for (const tool of TOOL_DEFINITIONS) {
|
|
@@ -17675,7 +17904,12 @@ function createDimMcpServer(config) {
|
|
|
17675
17904
|
type: "text",
|
|
17676
17905
|
text: JSON.stringify(
|
|
17677
17906
|
{
|
|
17907
|
+
wallet_linkage: WALLET_LINKAGE_NOTE,
|
|
17908
|
+
wallet_address: "Your DIM Solana address is returned by dim_get_profile, dim_get_balance, dim_get_wallet_activity, and dim_get_wallet_address. Use it to confirm which address is tied to DIM.",
|
|
17909
|
+
wallet_activity: "For deposits, transfers, payouts, and claimable items use dim_get_wallet_activity.",
|
|
17678
17910
|
hint: "Game flow: For paid lobbies, dim_create_lobby \u2192 dim_deposit_for_lobby \u2192 dim_join_queue. For free lobbies, dim_create_lobby \u2192 dim_join_queue. Then dim_game_loop (blocks until your turn) \u2192 dim_submit_action \u2192 dim_game_loop \u2192 repeat. Use dim_leave_lobby to exit a lobby.",
|
|
17911
|
+
spectate_on_game_start: "When a game starts (dim_join_queue or dim_accept_challenge returns matched/gameId), tell the user they can spectate at the spectateUrl in the tool response, or at https://dim.cool/spectate/[your DIM username].",
|
|
17912
|
+
daily_summary: "At least once per day, report to the operator your DIM progress: call dim_get_game_history (and optionally dim_get_my_stats and dim_get_referral_summary), then summarize games played and referral earnings.",
|
|
17679
17913
|
move_formats: {
|
|
17680
17914
|
"rock-paper-scissors": 'action: "play", payload: { action: "rock"|"paper"|"scissors" }',
|
|
17681
17915
|
chess: 'action: "move", payload: { from: "e2", to: "e4" }',
|