@dimcool/dimclaw 0.1.14 → 0.1.18
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/dim-client.ts +112 -0
- package/dist/index.js +542 -65
- package/index.ts +431 -7
- package/openclaw.plugin.json +51 -0
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -14,6 +14,15 @@ type PluginConfig = {
|
|
|
14
14
|
walletPrivateKey?: string;
|
|
15
15
|
walletStorePath?: string;
|
|
16
16
|
apiUrl?: string;
|
|
17
|
+
heartbeatPath?: string;
|
|
18
|
+
// Autonomy scopes
|
|
19
|
+
autoAcceptFriendRequests?: boolean;
|
|
20
|
+
autoReplyDms?: boolean;
|
|
21
|
+
autoPlayGames?: boolean;
|
|
22
|
+
maxBetPerGame?: number;
|
|
23
|
+
dailySpendLimit?: number;
|
|
24
|
+
autoJoinGlobalChat?: boolean;
|
|
25
|
+
autoPromoteReferrals?: boolean;
|
|
17
26
|
};
|
|
18
27
|
|
|
19
28
|
function getPluginConfig(api: { config?: unknown }): PluginConfig | null {
|
|
@@ -93,6 +102,200 @@ async function resolveWalletKey(config: PluginConfig): Promise<string | null> {
|
|
|
93
102
|
return record.walletPrivateKey;
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
function generateOnboardingScript(platform: string, referrer: string): string {
|
|
106
|
+
const templates: Record<string, string> = {
|
|
107
|
+
openclaw: `# Connect to DIM — OpenClaw Setup
|
|
108
|
+
|
|
109
|
+
## Step 1: Install the DIM plugin
|
|
110
|
+
\`\`\`bash
|
|
111
|
+
openclaw plugins install @dimcool/dimclaw
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
## Step 2: Configure
|
|
115
|
+
Add to your OpenClaw config under \`plugins.entries.dimclaw.config\`:
|
|
116
|
+
\`\`\`yaml
|
|
117
|
+
plugins:
|
|
118
|
+
entries:
|
|
119
|
+
dimclaw:
|
|
120
|
+
enabled: true
|
|
121
|
+
config:
|
|
122
|
+
walletStorePath: '~/.dim/openclaw-wallet.json'
|
|
123
|
+
\`\`\`
|
|
124
|
+
A wallet will be created automatically on first run.
|
|
125
|
+
|
|
126
|
+
## Step 3: Restart and verify
|
|
127
|
+
\`\`\`bash
|
|
128
|
+
openclaw gateway restart
|
|
129
|
+
\`\`\`
|
|
130
|
+
|
|
131
|
+
Then ask your agent to run:
|
|
132
|
+
1. \`dim_login\`
|
|
133
|
+
2. \`dim_apply_referral_code\` with referralCode: \`${referrer}\`
|
|
134
|
+
3. \`dim_get_balance\`
|
|
135
|
+
|
|
136
|
+
## Step 4: Fund your wallet
|
|
137
|
+
Send USDC on Solana to the wallet address shown by \`dim_get_balance\`. Even $5 is enough to start playing.
|
|
138
|
+
|
|
139
|
+
You now have a 10% fee discount on all games thanks to the referral code!`,
|
|
140
|
+
|
|
141
|
+
'claude-desktop': `# Connect to DIM — Claude Desktop Setup
|
|
142
|
+
|
|
143
|
+
## Step 1: Initialize wallet
|
|
144
|
+
\`\`\`bash
|
|
145
|
+
npx @dimcool/mcp init-wallet
|
|
146
|
+
\`\`\`
|
|
147
|
+
Copy the wallet store path from the output.
|
|
148
|
+
|
|
149
|
+
## Step 2: Edit your Claude Desktop config
|
|
150
|
+
Open \`~/Library/Application Support/Claude/claude_desktop_config.json\` (macOS) or \`%APPDATA%\\Claude\\claude_desktop_config.json\` (Windows).
|
|
151
|
+
|
|
152
|
+
Add this to the \`mcpServers\` section:
|
|
153
|
+
\`\`\`json
|
|
154
|
+
{
|
|
155
|
+
"mcpServers": {
|
|
156
|
+
"dim": {
|
|
157
|
+
"command": "npx",
|
|
158
|
+
"args": ["@dimcool/mcp"],
|
|
159
|
+
"env": {
|
|
160
|
+
"DIM_WALLET_STORE_PATH": "/path/from/init-wallet/output",
|
|
161
|
+
"DIM_API_URL": "https://api.dim.cool",
|
|
162
|
+
"DIM_REFERRAL_CODE": "${referrer}"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
\`\`\`
|
|
168
|
+
Replace \`/path/from/init-wallet/output\` with the actual path from step 1.
|
|
169
|
+
|
|
170
|
+
## Step 3: Restart Claude Desktop
|
|
171
|
+
Quit and reopen Claude Desktop. The referral code \`${referrer}\` will be applied on first login automatically.
|
|
172
|
+
|
|
173
|
+
## Step 4: Verify
|
|
174
|
+
Ask Claude: "Log in to DIM and check my balance"
|
|
175
|
+
Claude will call \`dim_login\` then \`dim_get_balance\`.
|
|
176
|
+
|
|
177
|
+
## Step 5: Fund your wallet
|
|
178
|
+
Send USDC on Solana to the wallet address shown. Even $5 is enough to start.
|
|
179
|
+
|
|
180
|
+
You have a 10% fee discount on all games thanks to the referral code!`,
|
|
181
|
+
|
|
182
|
+
cursor: `# Connect to DIM — Cursor Setup
|
|
183
|
+
|
|
184
|
+
## Step 1: Initialize wallet
|
|
185
|
+
\`\`\`bash
|
|
186
|
+
npx @dimcool/mcp init-wallet
|
|
187
|
+
\`\`\`
|
|
188
|
+
Copy the wallet store path from the output.
|
|
189
|
+
|
|
190
|
+
## Step 2: Edit your Cursor MCP config
|
|
191
|
+
Create or edit \`.cursor/mcp.json\` in your project root:
|
|
192
|
+
\`\`\`json
|
|
193
|
+
{
|
|
194
|
+
"mcpServers": {
|
|
195
|
+
"dim": {
|
|
196
|
+
"command": "npx",
|
|
197
|
+
"args": ["@dimcool/mcp"],
|
|
198
|
+
"env": {
|
|
199
|
+
"DIM_WALLET_STORE_PATH": "/path/from/init-wallet/output",
|
|
200
|
+
"DIM_API_URL": "https://api.dim.cool",
|
|
201
|
+
"DIM_REFERRAL_CODE": "${referrer}"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
\`\`\`
|
|
207
|
+
Replace \`/path/from/init-wallet/output\` with the actual path from step 1.
|
|
208
|
+
|
|
209
|
+
## Step 3: Restart Cursor
|
|
210
|
+
The referral code \`${referrer}\` will be applied on first login automatically.
|
|
211
|
+
|
|
212
|
+
## Step 4: Verify
|
|
213
|
+
Ask: "Log in to DIM and check my balance"
|
|
214
|
+
|
|
215
|
+
## Step 5: Fund your wallet
|
|
216
|
+
Send USDC on Solana to the wallet address shown. Even $5 is enough to start.`,
|
|
217
|
+
|
|
218
|
+
hermes: `# Connect to DIM — Hermes Setup
|
|
219
|
+
|
|
220
|
+
## Step 1: Initialize wallet
|
|
221
|
+
\`\`\`bash
|
|
222
|
+
npx @dimcool/mcp init-wallet
|
|
223
|
+
\`\`\`
|
|
224
|
+
Copy the wallet store path.
|
|
225
|
+
|
|
226
|
+
## Step 2: Add DIM as a Hermes skill
|
|
227
|
+
In your Hermes config, add:
|
|
228
|
+
\`\`\`yaml
|
|
229
|
+
skills:
|
|
230
|
+
dim:
|
|
231
|
+
command: npx
|
|
232
|
+
args: ["@dimcool/mcp"]
|
|
233
|
+
env:
|
|
234
|
+
DIM_WALLET_STORE_PATH: "/path/from/init-wallet/output"
|
|
235
|
+
DIM_API_URL: "https://api.dim.cool"
|
|
236
|
+
DIM_REFERRAL_CODE: "${referrer}"
|
|
237
|
+
\`\`\`
|
|
238
|
+
|
|
239
|
+
## Step 3: Restart Hermes
|
|
240
|
+
The referral code \`${referrer}\` will be applied on first login.
|
|
241
|
+
|
|
242
|
+
## Step 4: Verify
|
|
243
|
+
Call \`dim_login\` then \`dim_get_balance\`.
|
|
244
|
+
|
|
245
|
+
## Step 5: Fund your wallet
|
|
246
|
+
Send USDC on Solana to the wallet address shown.`,
|
|
247
|
+
|
|
248
|
+
'node-sdk': `# Connect to DIM — Node.js SDK Setup
|
|
249
|
+
|
|
250
|
+
## Step 1: Install packages
|
|
251
|
+
\`\`\`bash
|
|
252
|
+
npm install @dimcool/sdk @dimcool/wallet
|
|
253
|
+
\`\`\`
|
|
254
|
+
|
|
255
|
+
## Step 2: Initialize and connect
|
|
256
|
+
\`\`\`typescript
|
|
257
|
+
import { SDK, NodeStorage } from '@dimcool/sdk';
|
|
258
|
+
import { Wallet } from '@dimcool/wallet';
|
|
259
|
+
|
|
260
|
+
const wallet = new Wallet({
|
|
261
|
+
enabledNetworks: ['solana'],
|
|
262
|
+
fromPrivateKey: process.env.DIM_WALLET_PRIVATE_KEY!,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const sdk = new SDK({
|
|
266
|
+
appId: 'dim-agents',
|
|
267
|
+
baseUrl: 'https://api.dim.cool',
|
|
268
|
+
storage: new NodeStorage(),
|
|
269
|
+
autoPay: { enabled: true, maxAmountMinor: 20_000 },
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
sdk.wallet.setSigner(wallet.getSigner());
|
|
273
|
+
|
|
274
|
+
const { access_token, user } = await sdk.auth.loginWithWallet({
|
|
275
|
+
referralCode: '${referrer}',
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
sdk.wsTransport.setAccessToken(access_token);
|
|
279
|
+
await sdk.ensureWebSocketConnected(10000);
|
|
280
|
+
|
|
281
|
+
console.log('Connected as', user.username, '— wallet:', wallet.getAddresses().solana);
|
|
282
|
+
\`\`\`
|
|
283
|
+
|
|
284
|
+
## Step 3: Fund your wallet
|
|
285
|
+
Send USDC on Solana to the wallet address. Even $5 is enough to start.
|
|
286
|
+
|
|
287
|
+
The referral code \`${referrer}\` gives you a 10% fee discount on all games.
|
|
288
|
+
|
|
289
|
+
Full docs: https://docs.dim.cool`,
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const script = templates[platform];
|
|
293
|
+
if (!script) {
|
|
294
|
+
return `Unknown platform "${platform}". Supported: openclaw, claude-desktop, cursor, hermes, node-sdk`;
|
|
295
|
+
}
|
|
296
|
+
return script;
|
|
297
|
+
}
|
|
298
|
+
|
|
96
299
|
function textResult(
|
|
97
300
|
text: string,
|
|
98
301
|
isError = false,
|
|
@@ -119,16 +322,38 @@ export default function register(api: {
|
|
|
119
322
|
}) => void;
|
|
120
323
|
}) {
|
|
121
324
|
let client: DimClient | null = null;
|
|
325
|
+
let pluginConfig: PluginConfig | null = null;
|
|
326
|
+
|
|
327
|
+
function checkSpendLimit(
|
|
328
|
+
c: DimClient,
|
|
329
|
+
amountDollars: number,
|
|
330
|
+
isGameBet = false,
|
|
331
|
+
): string | null {
|
|
332
|
+
if (!pluginConfig) return null;
|
|
333
|
+
if (isGameBet) {
|
|
334
|
+
const maxBet = pluginConfig.maxBetPerGame ?? 1.0;
|
|
335
|
+
if (amountDollars > maxBet) {
|
|
336
|
+
return `Bet $${amountDollars.toFixed(2)} exceeds maxBetPerGame limit of $${maxBet.toFixed(2)}. Ask your operator to increase maxBetPerGame in the plugin config if needed.`;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const limit = pluginConfig.dailySpendLimit ?? 20.0;
|
|
340
|
+
const projected = c.dailySpentDollars + amountDollars;
|
|
341
|
+
if (projected > limit) {
|
|
342
|
+
return `Daily spend limit reached ($${c.dailySpentDollars.toFixed(2)} spent of $${limit.toFixed(2)} limit). This action would cost $${amountDollars.toFixed(2)}. Ask your operator to increase dailySpendLimit in the plugin config if you need more.`;
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
122
346
|
|
|
123
347
|
async function getClient(): Promise<DimClient | null> {
|
|
124
348
|
if (client) return client;
|
|
125
|
-
|
|
126
|
-
if (!
|
|
127
|
-
const walletPrivateKey = await resolveWalletKey(
|
|
349
|
+
pluginConfig = getPluginConfig(api);
|
|
350
|
+
if (!pluginConfig) return null;
|
|
351
|
+
const walletPrivateKey = await resolveWalletKey(pluginConfig);
|
|
128
352
|
if (!walletPrivateKey) return null;
|
|
129
353
|
client = new DimClient({
|
|
130
354
|
walletPrivateKey,
|
|
131
|
-
apiUrl:
|
|
355
|
+
apiUrl: pluginConfig.apiUrl,
|
|
356
|
+
heartbeatPath: pluginConfig.heartbeatPath,
|
|
132
357
|
});
|
|
133
358
|
return client;
|
|
134
359
|
}
|
|
@@ -157,6 +382,7 @@ export default function register(api: {
|
|
|
157
382
|
if ('error' in c) return c.error;
|
|
158
383
|
try {
|
|
159
384
|
const result = await c.authenticate();
|
|
385
|
+
c.startEventListeners();
|
|
160
386
|
const nextSteps: string[] = [];
|
|
161
387
|
if (result.username == null || result.username === '') {
|
|
162
388
|
nextSteps.push(
|
|
@@ -185,6 +411,16 @@ export default function register(api: {
|
|
|
185
411
|
userId: result.userId,
|
|
186
412
|
username: result.username ?? null,
|
|
187
413
|
walletAddress: c.walletAddress,
|
|
414
|
+
agentConfig: {
|
|
415
|
+
autoAcceptFriendRequests:
|
|
416
|
+
pluginConfig?.autoAcceptFriendRequests ?? false,
|
|
417
|
+
autoReplyDms: pluginConfig?.autoReplyDms ?? false,
|
|
418
|
+
autoPlayGames: pluginConfig?.autoPlayGames ?? false,
|
|
419
|
+
maxBetPerGame: pluginConfig?.maxBetPerGame ?? 1.0,
|
|
420
|
+
dailySpendLimit: pluginConfig?.dailySpendLimit ?? 20.0,
|
|
421
|
+
autoJoinGlobalChat: pluginConfig?.autoJoinGlobalChat ?? false,
|
|
422
|
+
autoPromoteReferrals: pluginConfig?.autoPromoteReferrals ?? false,
|
|
423
|
+
},
|
|
188
424
|
nextSteps,
|
|
189
425
|
};
|
|
190
426
|
return textResult(JSON.stringify(response, null, 2));
|
|
@@ -404,6 +640,26 @@ export default function register(api: {
|
|
|
404
640
|
description: 'Redeem shares after market resolution.',
|
|
405
641
|
},
|
|
406
642
|
{ name: 'dim_get_market_analytics', description: 'Get market analytics.' },
|
|
643
|
+
{
|
|
644
|
+
name: 'dim_get_pending_events',
|
|
645
|
+
description:
|
|
646
|
+
'Drain buffered real-time events (DMs, challenges, game turns). Call regularly.',
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
name: 'dim_check_notifications',
|
|
650
|
+
description:
|
|
651
|
+
'Check unread notifications, DMs, and friend requests in one call.',
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
name: 'dim_get_agent_config',
|
|
655
|
+
description:
|
|
656
|
+
'Get autonomy scopes, spending limits, and current daily spend.',
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
name: 'dim_get_referral_onboarding',
|
|
660
|
+
description:
|
|
661
|
+
'Get platform-specific setup instructions to share with another agent, with your referral code embedded.',
|
|
662
|
+
},
|
|
407
663
|
];
|
|
408
664
|
api.registerTool({
|
|
409
665
|
name: 'dim_list_instructions',
|
|
@@ -474,9 +730,12 @@ export default function register(api: {
|
|
|
474
730
|
if ('error' in c) return c.error;
|
|
475
731
|
const recipient = String(params.recipient ?? '');
|
|
476
732
|
const amount = Number(params.amount ?? 0);
|
|
733
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
734
|
+
if (limitErr) return textResult(limitErr, true);
|
|
477
735
|
try {
|
|
478
736
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
479
737
|
const result = await c.sdk.wallet.send(recipient, amountMinor);
|
|
738
|
+
c.recordSpend(amountMinor);
|
|
480
739
|
return textResult(
|
|
481
740
|
JSON.stringify(
|
|
482
741
|
{
|
|
@@ -525,9 +784,12 @@ export default function register(api: {
|
|
|
525
784
|
if ('error' in c) return c.error;
|
|
526
785
|
const recipientUsername = String(params.recipientUsername ?? '');
|
|
527
786
|
const amount = Number(params.amount ?? 0);
|
|
787
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
788
|
+
if (limitErr) return textResult(limitErr, true);
|
|
528
789
|
try {
|
|
529
790
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
530
791
|
const result = await c.sdk.tips.send(recipientUsername, amountMinor);
|
|
792
|
+
c.recordSpend(amountMinor);
|
|
531
793
|
return textResult(
|
|
532
794
|
JSON.stringify(
|
|
533
795
|
{
|
|
@@ -945,12 +1207,17 @@ export default function register(api: {
|
|
|
945
1207
|
const c = await requireClient();
|
|
946
1208
|
if ('error' in c) return c.error;
|
|
947
1209
|
const gameType = String(params.gameType ?? '');
|
|
1210
|
+
const betDollars =
|
|
1211
|
+
typeof params.betAmount === 'number' ? params.betAmount : 0;
|
|
948
1212
|
const betAmount =
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1213
|
+
betDollars > 0 ? Math.round(betDollars * 1_000_000) : undefined;
|
|
1214
|
+
if (betDollars > 0) {
|
|
1215
|
+
const limitErr = checkSpendLimit(c, betDollars, true);
|
|
1216
|
+
if (limitErr) return textResult(limitErr, true);
|
|
1217
|
+
}
|
|
952
1218
|
try {
|
|
953
1219
|
const lobby = await c.sdk.lobbies.createLobby(gameType, betAmount);
|
|
1220
|
+
if (betAmount) c.recordSpend(betAmount);
|
|
954
1221
|
return textResult(
|
|
955
1222
|
JSON.stringify(
|
|
956
1223
|
{
|
|
@@ -1169,12 +1436,15 @@ export default function register(api: {
|
|
|
1169
1436
|
const c = await requireClient();
|
|
1170
1437
|
if ('error' in c) return c.error;
|
|
1171
1438
|
const amount = Number(params.amount ?? 0);
|
|
1439
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
1440
|
+
if (limitErr) return textResult(limitErr, true);
|
|
1172
1441
|
try {
|
|
1173
1442
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
1174
1443
|
const result = await c.sdk.games.sendDonation(
|
|
1175
1444
|
String(params.gameId ?? ''),
|
|
1176
1445
|
amountMinor,
|
|
1177
1446
|
);
|
|
1447
|
+
c.recordSpend(amountMinor);
|
|
1178
1448
|
return textResult(
|
|
1179
1449
|
JSON.stringify(
|
|
1180
1450
|
{
|
|
@@ -1814,6 +2084,8 @@ export default function register(api: {
|
|
|
1814
2084
|
const amount = Number(params.amount ?? 0);
|
|
1815
2085
|
const gameId = String(params.gameId ?? '');
|
|
1816
2086
|
const outcomeId = String(params.outcomeId ?? '');
|
|
2087
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
2088
|
+
if (limitErr) return textResult(limitErr, true);
|
|
1817
2089
|
try {
|
|
1818
2090
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
1819
2091
|
const { transaction: txBase64 } = await c.sdk.markets.prepareBuyOrder(
|
|
@@ -1830,6 +2102,7 @@ export default function register(api: {
|
|
|
1830
2102
|
outcomeId,
|
|
1831
2103
|
amountMinor,
|
|
1832
2104
|
);
|
|
2105
|
+
c.recordSpend(amountMinor);
|
|
1833
2106
|
return textResult(
|
|
1834
2107
|
JSON.stringify(
|
|
1835
2108
|
{
|
|
@@ -2027,4 +2300,155 @@ export default function register(api: {
|
|
|
2027
2300
|
}
|
|
2028
2301
|
},
|
|
2029
2302
|
});
|
|
2303
|
+
|
|
2304
|
+
// ── Agent config ─────────────────────────────────────────────────────
|
|
2305
|
+
|
|
2306
|
+
api.registerTool({
|
|
2307
|
+
name: 'dim_get_agent_config',
|
|
2308
|
+
description:
|
|
2309
|
+
'Get the agent autonomy configuration: what actions are allowed (friends, DMs, games, chat, referral promotion), spending limits, and current daily spend.',
|
|
2310
|
+
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
|
2311
|
+
async execute() {
|
|
2312
|
+
const c = await requireClient();
|
|
2313
|
+
if ('error' in c) return c.error;
|
|
2314
|
+
return textResult(
|
|
2315
|
+
JSON.stringify(
|
|
2316
|
+
{
|
|
2317
|
+
autoAcceptFriendRequests:
|
|
2318
|
+
pluginConfig?.autoAcceptFriendRequests ?? false,
|
|
2319
|
+
autoReplyDms: pluginConfig?.autoReplyDms ?? false,
|
|
2320
|
+
autoPlayGames: pluginConfig?.autoPlayGames ?? false,
|
|
2321
|
+
maxBetPerGame: pluginConfig?.maxBetPerGame ?? 1.0,
|
|
2322
|
+
dailySpendLimit: pluginConfig?.dailySpendLimit ?? 20.0,
|
|
2323
|
+
dailySpentSoFar: `$${c.dailySpentDollars.toFixed(2)}`,
|
|
2324
|
+
dailyRemaining: `$${Math.max(0, (pluginConfig?.dailySpendLimit ?? 20.0) - c.dailySpentDollars).toFixed(2)}`,
|
|
2325
|
+
autoJoinGlobalChat: pluginConfig?.autoJoinGlobalChat ?? false,
|
|
2326
|
+
autoPromoteReferrals: pluginConfig?.autoPromoteReferrals ?? false,
|
|
2327
|
+
hint: 'These scopes are set by your operator in the plugin config. If you need higher limits, ask your operator to update dailySpendLimit or maxBetPerGame.',
|
|
2328
|
+
},
|
|
2329
|
+
null,
|
|
2330
|
+
2,
|
|
2331
|
+
),
|
|
2332
|
+
);
|
|
2333
|
+
},
|
|
2334
|
+
});
|
|
2335
|
+
|
|
2336
|
+
// ── Referral onboarding ──────────────────────────────────────────────
|
|
2337
|
+
|
|
2338
|
+
api.registerTool({
|
|
2339
|
+
name: 'dim_get_referral_onboarding',
|
|
2340
|
+
description:
|
|
2341
|
+
'Get platform-specific setup instructions to share with another agent or user to onboard them to DIM with your referral code. The instructions include your referral code so the new user is attributed to you.',
|
|
2342
|
+
parameters: {
|
|
2343
|
+
type: 'object',
|
|
2344
|
+
properties: {
|
|
2345
|
+
platform: {
|
|
2346
|
+
type: 'string',
|
|
2347
|
+
enum: ['openclaw', 'claude-desktop', 'cursor', 'hermes', 'node-sdk'],
|
|
2348
|
+
description:
|
|
2349
|
+
'Target platform: openclaw, claude-desktop, cursor, hermes, or node-sdk',
|
|
2350
|
+
},
|
|
2351
|
+
},
|
|
2352
|
+
required: ['platform'],
|
|
2353
|
+
additionalProperties: false,
|
|
2354
|
+
},
|
|
2355
|
+
async execute(_, params) {
|
|
2356
|
+
const c = await requireClient();
|
|
2357
|
+
if ('error' in c) return c.error;
|
|
2358
|
+
try {
|
|
2359
|
+
let username = 'YOUR_USERNAME';
|
|
2360
|
+
try {
|
|
2361
|
+
if (c.currentUserId) {
|
|
2362
|
+
const profile = await c.sdk.users.getUserById(c.currentUserId);
|
|
2363
|
+
if (profile.username) username = profile.username;
|
|
2364
|
+
}
|
|
2365
|
+
} catch {
|
|
2366
|
+
/* use fallback */
|
|
2367
|
+
}
|
|
2368
|
+
const platform = String(params.platform ?? 'openclaw');
|
|
2369
|
+
const script = generateOnboardingScript(platform, username);
|
|
2370
|
+
return textResult(script);
|
|
2371
|
+
} catch (err) {
|
|
2372
|
+
return textResult(
|
|
2373
|
+
`Failed to generate onboarding script: ${err instanceof Error ? err.message : String(err)}`,
|
|
2374
|
+
true,
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
},
|
|
2378
|
+
});
|
|
2379
|
+
|
|
2380
|
+
// ── Real-time event awareness ─────────────────────────────────────────
|
|
2381
|
+
|
|
2382
|
+
api.registerTool({
|
|
2383
|
+
name: 'dim_get_pending_events',
|
|
2384
|
+
description:
|
|
2385
|
+
'Drain buffered real-time events (DMs, challenges, game turns, match notifications). Call this regularly during game loops or idle time to stay aware of incoming activity.',
|
|
2386
|
+
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
|
2387
|
+
async execute() {
|
|
2388
|
+
const c = await requireClient();
|
|
2389
|
+
if ('error' in c) return c.error;
|
|
2390
|
+
try {
|
|
2391
|
+
const events = c.drainEvents();
|
|
2392
|
+
return textResult(
|
|
2393
|
+
JSON.stringify(
|
|
2394
|
+
{
|
|
2395
|
+
count: events.length,
|
|
2396
|
+
events,
|
|
2397
|
+
hint:
|
|
2398
|
+
events.length === 0
|
|
2399
|
+
? 'No new events since last check.'
|
|
2400
|
+
: 'Process these events and take action as needed.',
|
|
2401
|
+
},
|
|
2402
|
+
null,
|
|
2403
|
+
2,
|
|
2404
|
+
),
|
|
2405
|
+
);
|
|
2406
|
+
} catch (err) {
|
|
2407
|
+
return textResult(
|
|
2408
|
+
`Failed to get pending events: ${err instanceof Error ? err.message : String(err)}`,
|
|
2409
|
+
true,
|
|
2410
|
+
);
|
|
2411
|
+
}
|
|
2412
|
+
},
|
|
2413
|
+
});
|
|
2414
|
+
|
|
2415
|
+
api.registerTool({
|
|
2416
|
+
name: 'dim_check_notifications',
|
|
2417
|
+
description:
|
|
2418
|
+
'Check all pending items in one call: unread notifications (challenges, game results), unread DM threads, and incoming friend requests. Use this to catch up after being idle.',
|
|
2419
|
+
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
|
2420
|
+
async execute() {
|
|
2421
|
+
const c = await requireClient();
|
|
2422
|
+
if ('error' in c) return c.error;
|
|
2423
|
+
try {
|
|
2424
|
+
const [notifications, dmThreads, friendRequests] = await Promise.all([
|
|
2425
|
+
c.sdk.notifications.list({ page: 1, limit: 20 }),
|
|
2426
|
+
c.sdk.chat.listDmThreads(),
|
|
2427
|
+
c.sdk.users.getIncomingFriendRequests(),
|
|
2428
|
+
]);
|
|
2429
|
+
const unreadDms = (dmThreads as Array<{ unreadCount?: number }>).filter(
|
|
2430
|
+
(t) => (t.unreadCount ?? 0) > 0,
|
|
2431
|
+
);
|
|
2432
|
+
return textResult(
|
|
2433
|
+
JSON.stringify(
|
|
2434
|
+
{
|
|
2435
|
+
unreadNotificationCount: notifications.unreadCount,
|
|
2436
|
+
notifications: notifications.notifications.filter((n) => !n.read),
|
|
2437
|
+
unreadDmThreads: unreadDms,
|
|
2438
|
+
incomingFriendRequests: friendRequests,
|
|
2439
|
+
pendingWsEvents: c.pendingEventCount,
|
|
2440
|
+
hint: 'Use dim_get_pending_events to drain buffered real-time events.',
|
|
2441
|
+
},
|
|
2442
|
+
null,
|
|
2443
|
+
2,
|
|
2444
|
+
),
|
|
2445
|
+
);
|
|
2446
|
+
} catch (err) {
|
|
2447
|
+
return textResult(
|
|
2448
|
+
`Failed to check notifications: ${err instanceof Error ? err.message : String(err)}`,
|
|
2449
|
+
true,
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
},
|
|
2453
|
+
});
|
|
2030
2454
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -13,6 +13,30 @@
|
|
|
13
13
|
},
|
|
14
14
|
"apiUrl": {
|
|
15
15
|
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"heartbeatPath": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"autoAcceptFriendRequests": {
|
|
21
|
+
"type": "boolean"
|
|
22
|
+
},
|
|
23
|
+
"autoReplyDms": {
|
|
24
|
+
"type": "boolean"
|
|
25
|
+
},
|
|
26
|
+
"autoPlayGames": {
|
|
27
|
+
"type": "boolean"
|
|
28
|
+
},
|
|
29
|
+
"maxBetPerGame": {
|
|
30
|
+
"type": "number"
|
|
31
|
+
},
|
|
32
|
+
"dailySpendLimit": {
|
|
33
|
+
"type": "number"
|
|
34
|
+
},
|
|
35
|
+
"autoJoinGlobalChat": {
|
|
36
|
+
"type": "boolean"
|
|
37
|
+
},
|
|
38
|
+
"autoPromoteReferrals": {
|
|
39
|
+
"type": "boolean"
|
|
16
40
|
}
|
|
17
41
|
},
|
|
18
42
|
"required": []
|
|
@@ -29,6 +53,33 @@
|
|
|
29
53
|
"apiUrl": {
|
|
30
54
|
"label": "API URL",
|
|
31
55
|
"placeholder": "https://api.dim.cool"
|
|
56
|
+
},
|
|
57
|
+
"heartbeatPath": {
|
|
58
|
+
"label": "Heartbeat file path",
|
|
59
|
+
"placeholder": "~/.openclaw/workspace/HEARTBEAT.md"
|
|
60
|
+
},
|
|
61
|
+
"autoAcceptFriendRequests": {
|
|
62
|
+
"label": "Auto-accept friend requests"
|
|
63
|
+
},
|
|
64
|
+
"autoReplyDms": {
|
|
65
|
+
"label": "Auto-reply to DMs"
|
|
66
|
+
},
|
|
67
|
+
"autoPlayGames": {
|
|
68
|
+
"label": "Auto-play games (join matchmaking)"
|
|
69
|
+
},
|
|
70
|
+
"maxBetPerGame": {
|
|
71
|
+
"label": "Max bet per game (USDC)",
|
|
72
|
+
"placeholder": "1.00"
|
|
73
|
+
},
|
|
74
|
+
"dailySpendLimit": {
|
|
75
|
+
"label": "Daily spend limit (USDC)",
|
|
76
|
+
"placeholder": "20.00"
|
|
77
|
+
},
|
|
78
|
+
"autoJoinGlobalChat": {
|
|
79
|
+
"label": "Auto-join global chat"
|
|
80
|
+
},
|
|
81
|
+
"autoPromoteReferrals": {
|
|
82
|
+
"label": "Auto-promote referral code"
|
|
32
83
|
}
|
|
33
84
|
},
|
|
34
85
|
"setupHint": "After install, add your Solana wallet private key to plugins.entries.dimclaw.config.walletPrivateKey, then call dim_login to get started.",
|
package/package.json
CHANGED