create-message-kit 1.2.20 → 1.2.22
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/index.js +6 -1
- package/package.json +2 -2
- package/templates/toss/src/plugins/helpers.ts +1 -4
- package/templates/toss/src/skills/toss.ts +52 -103
- package/templates.json +58 -0
- package/templates/thegeneralstore/.cursorrules +0 -290
- package/templates/thegeneralstore/.env.example +0 -9
- package/templates/thegeneralstore/.yarnrc.yml +0 -9
- package/templates/thegeneralstore/package.json +0 -24
- package/templates/thegeneralstore/src/data/db.json +0 -812
- package/templates/thegeneralstore/src/index.ts +0 -37
- package/templates/thegeneralstore/src/plugins/learnweb3.ts +0 -96
- package/templates/thegeneralstore/src/plugins/lowdb.ts +0 -11
- package/templates/thegeneralstore/src/plugins/notion.ts +0 -89
- package/templates/thegeneralstore/src/plugins/redis.ts +0 -15
- package/templates/thegeneralstore/src/prompt.md +0 -51
- package/templates/thegeneralstore/src/prompt.ts +0 -3
- package/templates/thegeneralstore/src/skills/faucet.ts +0 -114
- package/templates/thegeneralstore/src/skills/notion.ts +0 -17
- package/templates/thegeneralstore/src/skills/poap.ts +0 -48
- package/templates/thegeneralstore/src/skills.ts +0 -37
    
        package/index.js
    CHANGED
    
    | @@ -7,7 +7,7 @@ import { default as fs } from "fs-extra"; | |
| 7 7 | 
             
            import { isCancel } from "@clack/prompts";
         | 
| 8 8 | 
             
            import { detect } from "detect-package-manager";
         | 
| 9 9 | 
             
            import pc from "picocolors";
         | 
| 10 | 
            -
            const defVersion = "1.2. | 
| 10 | 
            +
            const defVersion = "1.2.22";
         | 
| 11 11 | 
             
            const __dirname = dirname(fileURLToPath(import.meta.url));
         | 
| 12 12 |  | 
| 13 13 | 
             
            // Read package.json to get the version
         | 
| @@ -140,6 +140,11 @@ async function gatherProjectInfo() { | |
| 140 140 | 
             
              const name = kebabcase(displayName);
         | 
| 141 141 | 
             
              const destDir = resolve(process.cwd(), name);
         | 
| 142 142 |  | 
| 143 | 
            +
              // Remove existing directory if it exists
         | 
| 144 | 
            +
              if (fs.existsSync(destDir)) {
         | 
| 145 | 
            +
                fs.removeSync(destDir);
         | 
| 146 | 
            +
              }
         | 
| 147 | 
            +
             | 
| 143 148 | 
             
              // Copy template files
         | 
| 144 149 | 
             
              fs.copySync(templateDir, destDir);
         | 
| 145 150 |  | 
    
        package/package.json
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "create-message-kit",
         | 
| 3 | 
            -
              "version": "1.2. | 
| 3 | 
            +
              "version": "1.2.22",
         | 
| 4 4 | 
             
              "license": "MIT",
         | 
| 5 5 | 
             
              "type": "module",
         | 
| 6 6 | 
             
              "main": "index.js",
         | 
| 7 7 | 
             
              "module": "index.js",
         | 
| 8 8 | 
             
              "bin": "index.js",
         | 
| 9 9 | 
             
              "files": [
         | 
| 10 | 
            -
                " | 
| 10 | 
            +
                "templates.json",
         | 
| 11 11 | 
             
                "templates/**/*"
         | 
| 12 12 | 
             
              ],
         | 
| 13 13 | 
             
              "scripts": {
         | 
| @@ -5,7 +5,6 @@ interface Participant { | |
| 5 5 | 
             
              response: string;
         | 
| 6 6 | 
             
              name: string;
         | 
| 7 7 | 
             
              address: string;
         | 
| 8 | 
            -
              agent_address: string;
         | 
| 9 8 | 
             
            }
         | 
| 10 9 | 
             
            export interface TossData {
         | 
| 11 10 | 
             
              group_id: string;
         | 
| @@ -18,7 +17,6 @@ export interface TossData { | |
| 18 17 | 
             
              end_time: string;
         | 
| 19 18 | 
             
              description: string;
         | 
| 20 19 | 
             
              participants: Participant[];
         | 
| 21 | 
            -
              toss_wallet_address: string;
         | 
| 22 20 | 
             
            }
         | 
| 23 21 | 
             
            export async function checkTossCorrect(
         | 
| 24 22 | 
             
              context: XMTPContext,
         | 
| @@ -64,8 +62,7 @@ export async function checkTossCorrect( | |
| 64 62 | 
             
                return undefined;
         | 
| 65 63 | 
             
              }
         | 
| 66 64 |  | 
| 67 | 
            -
               | 
| 68 | 
            -
              return { ...tossData, toss_id, pool };
         | 
| 65 | 
            +
              return { ...tossData, toss_id };
         | 
| 69 66 | 
             
            }
         | 
| 70 67 |  | 
| 71 68 | 
             
            export function extractTossId(message: string): string | null {
         | 
| @@ -139,9 +139,13 @@ export async function handleTossCreation(context: XMTPContext) { | |
| 139 139 | 
             
              if (params.description && params.options && !isNaN(Number(params.amount))) {
         | 
| 140 140 | 
             
                const keys = await tossDBClient.keys("*");
         | 
| 141 141 | 
             
                let tossId = keys.length + 1;
         | 
| 142 | 
            -
                const  | 
| 143 | 
            -
                  tossId. | 
| 142 | 
            +
                const isCreated = await walletService.createWallet(
         | 
| 143 | 
            +
                  tossId + ":" + sender.address,
         | 
| 144 144 | 
             
                );
         | 
| 145 | 
            +
                if (!isCreated) {
         | 
| 146 | 
            +
                  await context.reply("Failed to create toss wallet");
         | 
| 147 | 
            +
                  return;
         | 
| 148 | 
            +
                }
         | 
| 145 149 |  | 
| 146 150 | 
             
                let tossData: TossData = {
         | 
| 147 151 | 
             
                  toss_id: tossId.toString(),
         | 
| @@ -158,20 +162,13 @@ export async function handleTossCreation(context: XMTPContext) { | |
| 158 162 | 
             
                    ? new Date(params.endTime).toLocaleString()
         | 
| 159 163 | 
             
                    : new Date(Date.now() + 24 * 60 * 60 * 1000).toLocaleString(),
         | 
| 160 164 | 
             
                  participants: [],
         | 
| 161 | 
            -
                  toss_wallet_address: createdTossWallet?.address,
         | 
| 162 165 | 
             
                };
         | 
| 163 | 
            -
                await tossDBClient.set(
         | 
| 164 | 
            -
                  "toss:" + tossId.toString(),
         | 
| 165 | 
            -
                  JSON.stringify(tossData),
         | 
| 166 | 
            -
                );
         | 
| 167 | 
            -
                console.log(tossData);
         | 
| 166 | 
            +
                await tossDBClient.set("toss:" + tossId, JSON.stringify(tossData));
         | 
| 168 167 | 
             
                if (tossId !== undefined) {
         | 
| 169 | 
            -
                   | 
| 170 | 
            -
                  console.log(msg);
         | 
| 171 | 
            -
                  await context.send(msg);
         | 
| 168 | 
            +
                  await context.send(generateTossMessage(tossData));
         | 
| 172 169 | 
             
                } else {
         | 
| 173 170 | 
             
                  await context.reply(
         | 
| 174 | 
            -
                    `An error occurred while creating the toss. ${ | 
| 171 | 
            +
                    `An error occurred while creating the toss. ${tossId}`,
         | 
| 175 172 | 
             
                  );
         | 
| 176 173 | 
             
                }
         | 
| 177 174 | 
             
              }
         | 
| @@ -183,7 +180,7 @@ export async function handleJoinToss(context: XMTPContext) { | |
| 183 180 | 
             
                return;
         | 
| 184 181 | 
             
              }
         | 
| 185 182 |  | 
| 186 | 
            -
              const { toss_id, participants, amount } = tossData;
         | 
| 183 | 
            +
              const { toss_id, participants, amount, admin_address } = tossData;
         | 
| 187 184 |  | 
| 188 185 | 
             
              const {
         | 
| 189 186 | 
             
                message: {
         | 
| @@ -192,7 +189,6 @@ export async function handleJoinToss(context: XMTPContext) { | |
| 192 189 | 
             
                    params: { response },
         | 
| 193 190 | 
             
                  },
         | 
| 194 191 | 
             
                },
         | 
| 195 | 
            -
                group,
         | 
| 196 192 | 
             
                walletService,
         | 
| 197 193 | 
             
              } = context;
         | 
| 198 194 |  | 
| @@ -201,35 +197,16 @@ export async function handleJoinToss(context: XMTPContext) { | |
| 201 197 | 
             
                await context.reply("You have already joined this toss.");
         | 
| 202 198 | 
             
                return;
         | 
| 203 199 | 
             
              }
         | 
| 204 | 
            -
             | 
| 205 | 
            -
               | 
| 206 | 
            -
              if (!tossWallet) {
         | 
| 207 | 
            -
                await context.reply("Toss wallet not found");
         | 
| 208 | 
            -
                return;
         | 
| 209 | 
            -
              }
         | 
| 200 | 
            +
              //Create wallet for sender
         | 
| 201 | 
            +
              await walletService.createWallet(sender.address);
         | 
| 210 202 | 
             
              const balance = await walletService.checkBalance(sender.address);
         | 
| 211 | 
            -
             | 
| 212 | 
            -
              if (balance < amount) {
         | 
| 213 | 
            -
                await context.send("You need to fund your account. Check your DMs:");
         | 
| 214 | 
            -
                await walletService.requestFunds(context, amount);
         | 
| 215 | 
            -
                return;
         | 
| 216 | 
            -
              }
         | 
| 203 | 
            +
              if (balance < amount) return walletService.requestFunds(amount);
         | 
| 217 204 |  | 
| 218 205 | 
             
              try {
         | 
| 219 | 
            -
                 | 
| 220 | 
            -
                 | 
| 221 | 
            -
                  await context.reply("Sender wallet not found");
         | 
| 222 | 
            -
                  return;
         | 
| 223 | 
            -
                }
         | 
| 224 | 
            -
                const transfer = await walletService.transfer(
         | 
| 225 | 
            -
                  senderWallet,
         | 
| 226 | 
            -
                  tossWallet,
         | 
| 227 | 
            -
                  amount,
         | 
| 228 | 
            -
                );
         | 
| 229 | 
            -
                console.log("Transfer:", transfer.getTransactionHash());
         | 
| 206 | 
            +
                let tempWalletID = toss_id + ":" + admin_address;
         | 
| 207 | 
            +
                await walletService.transfer(sender.address, tempWalletID, amount);
         | 
| 230 208 | 
             
                const participant = {
         | 
| 231 209 | 
             
                  address: sender.address,
         | 
| 232 | 
            -
                  agent_address: senderWallet.address,
         | 
| 233 210 | 
             
                  response: response,
         | 
| 234 211 | 
             
                  name:
         | 
| 235 212 | 
             
                    (await context.getUserInfo(sender.address))?.preferredName ??
         | 
| @@ -274,49 +251,30 @@ export async function handleEndToss(context: XMTPContext) { | |
| 274 251 | 
             
                await context.reply("No participants for this toss.");
         | 
| 275 252 | 
             
                return;
         | 
| 276 253 | 
             
              } else if (admin_address.toLowerCase() !== sender.address.toLowerCase()) {
         | 
| 277 | 
            -
                await context.reply("Only the admin can  | 
| 278 | 
            -
                return;
         | 
| 279 | 
            -
              } else if (
         | 
| 280 | 
            -
                !options
         | 
| 281 | 
            -
                  .split(",")
         | 
| 282 | 
            -
                  .map((o) => o.toLowerCase())
         | 
| 283 | 
            -
                  .includes(option.toLowerCase())
         | 
| 284 | 
            -
              ) {
         | 
| 285 | 
            -
                await context.reply("Invalid option selected.");
         | 
| 254 | 
            +
                await context.reply("Only the admin can cancel the toss.");
         | 
| 286 255 | 
             
                return;
         | 
| 287 256 | 
             
              }
         | 
| 288 | 
            -
              const { winners, losers } = await extractWinners(participants ?? [], option);
         | 
| 289 257 |  | 
| 290 | 
            -
               | 
| 291 | 
            -
             | 
| 258 | 
            +
              let tempWalletID = toss_id + ":" + admin_address;
         | 
| 259 | 
            +
              const balance = await walletService.checkBalance(tempWalletID);
         | 
| 260 | 
            +
              const fundsNeeded = tossData.amount * participants?.length;
         | 
| 261 | 
            +
              if (balance < fundsNeeded) {
         | 
| 262 | 
            +
                await context.reply(
         | 
| 263 | 
            +
                  `Toss wallet does not have enough funds ${fundsNeeded}, has ${balance}`,
         | 
| 264 | 
            +
                );
         | 
| 292 265 | 
             
                return;
         | 
| 293 266 | 
             
              }
         | 
| 294 267 |  | 
| 268 | 
            +
              //Winners
         | 
| 269 | 
            +
             | 
| 270 | 
            +
              const { winners, losers } = await extractWinners(participants, option);
         | 
| 271 | 
            +
             | 
| 295 272 | 
             
              const prize =
         | 
| 296 273 | 
             
                (tossData.amount * (participants?.length ?? 0)) / (winners.length ?? 1);
         | 
| 297 274 |  | 
| 298 275 | 
             
              try {
         | 
| 299 276 | 
             
                for (const winner of winners) {
         | 
| 300 | 
            -
                   | 
| 301 | 
            -
             | 
| 302 | 
            -
                  if (!tossWallet) {
         | 
| 303 | 
            -
                    await context.reply("Toss wallet not found");
         | 
| 304 | 
            -
                    return;
         | 
| 305 | 
            -
                  }
         | 
| 306 | 
            -
                  const winnerWallet = await walletService.getUserWallet(
         | 
| 307 | 
            -
                    winner.address,
         | 
| 308 | 
            -
                    winner.address,
         | 
| 309 | 
            -
                  );
         | 
| 310 | 
            -
                  if (!winnerWallet) {
         | 
| 311 | 
            -
                    await context.reply("Winner wallet not found");
         | 
| 312 | 
            -
                    return;
         | 
| 313 | 
            -
                  }
         | 
| 314 | 
            -
                  const transfer = await walletService.transfer(
         | 
| 315 | 
            -
                    tossWallet,
         | 
| 316 | 
            -
                    winnerWallet,
         | 
| 317 | 
            -
                    prize,
         | 
| 318 | 
            -
                  );
         | 
| 319 | 
            -
                  console.log("Transfer:", transfer.getTransactionHash());
         | 
| 277 | 
            +
                  await walletService.transfer(tempWalletID, winner.address, prize);
         | 
| 320 278 | 
             
                  await tossDBClient.set(
         | 
| 321 279 | 
             
                    `toss:${toss_id}`,
         | 
| 322 280 | 
             
                    JSON.stringify({ ...tossData, status: "closed" }),
         | 
| @@ -357,31 +315,26 @@ export async function handleCancelToss(context: XMTPContext) { | |
| 357 315 | 
             
                return;
         | 
| 358 316 | 
             
              }
         | 
| 359 317 |  | 
| 360 | 
            -
               | 
| 318 | 
            +
              let tempWalletID = toss_id + ":" + admin_address;
         | 
| 319 | 
            +
              const balance = await walletService.checkBalance(tempWalletID);
         | 
| 320 | 
            +
              const fundsNeeded = tossData.amount * participants?.length;
         | 
| 321 | 
            +
              if (balance < fundsNeeded) {
         | 
| 322 | 
            +
                await context.reply(
         | 
| 323 | 
            +
                  `Toss wallet does not have enough funds ${fundsNeeded}, has ${balance}`,
         | 
| 324 | 
            +
                );
         | 
| 325 | 
            +
                return;
         | 
| 326 | 
            +
              }
         | 
| 327 | 
            +
              for (const participant of participants) {
         | 
| 361 328 | 
             
                try {
         | 
| 362 | 
            -
                   | 
| 363 | 
            -
             | 
| 364 | 
            -
                   | 
| 365 | 
            -
                     | 
| 366 | 
            -
                     | 
| 367 | 
            -
                  }
         | 
| 368 | 
            -
             | 
| 369 | 
            -
                  const participantWallet = await walletService.getUserWallet(
         | 
| 370 | 
            -
                    participant.address,
         | 
| 329 | 
            +
                  await walletService.transfer(tempWalletID, participant.address, amount);
         | 
| 330 | 
            +
                } catch (error) {
         | 
| 331 | 
            +
                  console.error(
         | 
| 332 | 
            +
                    `Failed to send prize to ${participant.address} agent wallet:`,
         | 
| 333 | 
            +
                    error,
         | 
| 371 334 | 
             
                  );
         | 
| 372 | 
            -
                   | 
| 373 | 
            -
                     | 
| 374 | 
            -
                    return;
         | 
| 375 | 
            -
                  }
         | 
| 376 | 
            -
                  const transfer = await walletService.transfer(
         | 
| 377 | 
            -
                    tossWallet,
         | 
| 378 | 
            -
                    participantWallet,
         | 
| 379 | 
            -
                    amount,
         | 
| 335 | 
            +
                  await context.reply(
         | 
| 336 | 
            +
                    `Failed to send prize to ${participant.address} agent wallet`,
         | 
| 380 337 | 
             
                  );
         | 
| 381 | 
            -
                  console.log("Transfer:", transfer.getTransactionHash());
         | 
| 382 | 
            -
                } catch (error) {
         | 
| 383 | 
            -
                  console.error(`Failed to send prize to ${participant.address}:`, error);
         | 
| 384 | 
            -
                  await context.reply(`Failed to send prize to ${participant.address}`);
         | 
| 385 338 | 
             
                }
         | 
| 386 339 | 
             
              }
         | 
| 387 340 |  | 
| @@ -424,20 +377,17 @@ export async function handleDM(context: XMTPContext) { | |
| 424 377 | 
             
              if (skill === "help") {
         | 
| 425 378 | 
             
                await context.send(DM_HELP_MESSAGE);
         | 
| 426 379 | 
             
              } else if (skill === "create") {
         | 
| 427 | 
            -
                const walletExist = await walletService. | 
| 380 | 
            +
                const walletExist = await walletService.getWallet(sender.address);
         | 
| 428 381 | 
             
                if (walletExist) {
         | 
| 429 382 | 
             
                  await context.reply("You already have an agent wallet.");
         | 
| 430 383 | 
             
                  return;
         | 
| 431 384 | 
             
                }
         | 
| 432 | 
            -
                 | 
| 433 | 
            -
                await context.reply(
         | 
| 434 | 
            -
                  `Your agent wallet address is ${userWallet.address}\nBalance: $${await walletService.checkBalance(sender.address)}`,
         | 
| 435 | 
            -
                );
         | 
| 385 | 
            +
                await walletService.createWallet(sender.address);
         | 
| 436 386 | 
             
              } else if (skill === "balance") {
         | 
| 437 | 
            -
                const userWallet = await walletService. | 
| 387 | 
            +
                const userWallet = await walletService.getWallet(sender.address);
         | 
| 438 388 |  | 
| 439 389 | 
             
                context.sendTo(
         | 
| 440 | 
            -
                  `Your agent wallet address is ${ | 
| 390 | 
            +
                  `Your agent wallet for address is ${sender.address}\nBalance: $${await walletService.checkBalance(sender.address)}`,
         | 
| 441 391 | 
             
                  [sender.address],
         | 
| 442 392 | 
             
                );
         | 
| 443 393 | 
             
              } else if (skill === "fund") {
         | 
| @@ -447,8 +397,7 @@ export async function handleDM(context: XMTPContext) { | |
| 447 397 | 
             
                  return;
         | 
| 448 398 | 
             
                } else if (amount) {
         | 
| 449 399 | 
             
                  if (amount + balance <= 10) {
         | 
| 450 | 
            -
                     | 
| 451 | 
            -
                    return;
         | 
| 400 | 
            +
                    return walletService.requestFunds(Number(amount));
         | 
| 452 401 | 
             
                  } else {
         | 
| 453 402 | 
             
                    await context.send("Wrong amount. Max 10 USDC.");
         | 
| 454 403 | 
             
                    return;
         | 
| @@ -464,7 +413,7 @@ export async function handleDM(context: XMTPContext) { | |
| 464 413 | 
             
                  `Please specify the amount of USDC to prefund (1 to ${10 - balance}):`,
         | 
| 465 414 | 
             
                  options,
         | 
| 466 415 | 
             
                );
         | 
| 467 | 
            -
                 | 
| 416 | 
            +
                return walletService.requestFunds(Number(response));
         | 
| 468 417 | 
             
              } else if (skill === "withdraw") {
         | 
| 469 418 | 
             
                const balance = await walletService.checkBalance(sender.address);
         | 
| 470 419 | 
             
                if (balance === 0) {
         | 
| @@ -478,6 +427,6 @@ export async function handleDM(context: XMTPContext) { | |
| 478 427 | 
             
                  `Please specify the amount of USDC to withdraw (1 to ${balance}):`,
         | 
| 479 428 | 
             
                  options,
         | 
| 480 429 | 
             
                );
         | 
| 481 | 
            -
                await walletService.withdrawFunds( | 
| 430 | 
            +
                await walletService.withdrawFunds(Number(response));
         | 
| 482 431 | 
             
              }
         | 
| 483 432 | 
             
            }
         | 
    
        package/templates.json
    ADDED
    
    | @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            [
         | 
| 2 | 
            +
              {
         | 
| 3 | 
            +
                "href": "/templates/ens",
         | 
| 4 | 
            +
                "title": "ENS Agent",
         | 
| 5 | 
            +
                "description": "A template for working with ENS domains.",
         | 
| 6 | 
            +
                "icon": "🔗",
         | 
| 7 | 
            +
                "author": "humanagent"
         | 
| 8 | 
            +
              },
         | 
| 9 | 
            +
              {
         | 
| 10 | 
            +
                "href": "/templates/simple",
         | 
| 11 | 
            +
                "title": "Simple Template",
         | 
| 12 | 
            +
                "description": "A simple template without skills.",
         | 
| 13 | 
            +
                "icon": "🤖",
         | 
| 14 | 
            +
                "author": "humanagent"
         | 
| 15 | 
            +
              },
         | 
| 16 | 
            +
              {
         | 
| 17 | 
            +
                "href": "/templates/coinbase-agent",
         | 
| 18 | 
            +
                "title": "Coinbase Agent",
         | 
| 19 | 
            +
                "description": "A template for a Coinbase features.",
         | 
| 20 | 
            +
                "icon": "💰",
         | 
| 21 | 
            +
                "author": "humanagent"
         | 
| 22 | 
            +
              },
         | 
| 23 | 
            +
              {
         | 
| 24 | 
            +
                "href": "/templates/thegeneralstore",
         | 
| 25 | 
            +
                "title": "The General Store",
         | 
| 26 | 
            +
                "description": "All the goodies needed in a hackathon.",
         | 
| 27 | 
            +
                "icon": "🏪",
         | 
| 28 | 
            +
                "author": "humanagent"
         | 
| 29 | 
            +
              },
         | 
| 30 | 
            +
              {
         | 
| 31 | 
            +
                "href": "/templates/faucet",
         | 
| 32 | 
            +
                "title": "Faucet Agent",
         | 
| 33 | 
            +
                "description": "A template for requesting testnet funds.",
         | 
| 34 | 
            +
                "icon": "💧",
         | 
| 35 | 
            +
                "author": "humanagent"
         | 
| 36 | 
            +
              },
         | 
| 37 | 
            +
              {
         | 
| 38 | 
            +
                "href": "/templates/gated-group",
         | 
| 39 | 
            +
                "title": "Gated Group",
         | 
| 40 | 
            +
                "description": "A template for a gated group.",
         | 
| 41 | 
            +
                "icon": "🔒",
         | 
| 42 | 
            +
                "author": "humanagent"
         | 
| 43 | 
            +
              },
         | 
| 44 | 
            +
              {
         | 
| 45 | 
            +
                "href": "/templates/gm",
         | 
| 46 | 
            +
                "title": "GM Bot",
         | 
| 47 | 
            +
                "description": "A template for a GM bot.",
         | 
| 48 | 
            +
                "icon": "👑",
         | 
| 49 | 
            +
                "author": "humanagent"
         | 
| 50 | 
            +
              },
         | 
| 51 | 
            +
              {
         | 
| 52 | 
            +
                "href": "/templates/toss",
         | 
| 53 | 
            +
                "title": "Toss",
         | 
| 54 | 
            +
                "description": "A friendly game for groups.",
         | 
| 55 | 
            +
                "icon": "🪙",
         | 
| 56 | 
            +
                "author": "humanagent"
         | 
| 57 | 
            +
              }
         | 
| 58 | 
            +
            ]
         | 
| @@ -1,290 +0,0 @@ | |
| 1 | 
            -
            # MessageKit Skill Template
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            ## Examples
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            ### Check if a Domain is Available
         | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
            import { ensUrl } from "../index.js";
         | 
| 9 | 
            -
            import { XMTPContext } from "@xmtp/message-kit";
         | 
| 10 | 
            -
            import type { Skill } from "@xmtp/message-kit";
         | 
| 11 | 
            -
             | 
| 12 | 
            -
            // Define Skill
         | 
| 13 | 
            -
            export const checkDomain: Skill[] = [
         | 
| 14 | 
            -
              {
         | 
| 15 | 
            -
                skill: "check",
         | 
| 16 | 
            -
                handler: handler,
         | 
| 17 | 
            -
                examples: ["/check vitalik.eth", "/check fabri.base.eth"],
         | 
| 18 | 
            -
                description: "Check if a domain is available.",
         | 
| 19 | 
            -
                params: {
         | 
| 20 | 
            -
                  domain: {
         | 
| 21 | 
            -
                    type: "string",
         | 
| 22 | 
            -
                  },
         | 
| 23 | 
            -
                },
         | 
| 24 | 
            -
              },
         | 
| 25 | 
            -
            ];
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            // Handler Implementation
         | 
| 28 | 
            -
            export async function handler(context: XMTPContext) {
         | 
| 29 | 
            -
              const {
         | 
| 30 | 
            -
                message: {
         | 
| 31 | 
            -
                  content: {
         | 
| 32 | 
            -
                    params: { domain },
         | 
| 33 | 
            -
                  },
         | 
| 34 | 
            -
                },
         | 
| 35 | 
            -
              } = context;
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              const data = await context.getUserInfo(domain);
         | 
| 38 | 
            -
             | 
| 39 | 
            -
              if (!data?.address) {
         | 
| 40 | 
            -
                let message = `Looks like ${domain} is available! Here you can register it: ${ensUrl}${domain} or would you like to see some cool alternatives?`;
         | 
| 41 | 
            -
                return {
         | 
| 42 | 
            -
                  code: 200,
         | 
| 43 | 
            -
                  message,
         | 
| 44 | 
            -
                };
         | 
| 45 | 
            -
              } else {
         | 
| 46 | 
            -
                let message = `Looks like ${domain} is already registered!`;
         | 
| 47 | 
            -
                await context.executeSkill("/cool " + domain);
         | 
| 48 | 
            -
                return {
         | 
| 49 | 
            -
                  code: 404,
         | 
| 50 | 
            -
                  message,
         | 
| 51 | 
            -
                };
         | 
| 52 | 
            -
              }
         | 
| 53 | 
            -
            }
         | 
| 54 | 
            -
             | 
| 55 | 
            -
            ### Generate a payment request
         | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
            import { XMTPContext } from "@xmtp/message-kit";
         | 
| 59 | 
            -
            import type { Skill } from "@xmtp/message-kit";
         | 
| 60 | 
            -
             | 
| 61 | 
            -
            // Define Skill
         | 
| 62 | 
            -
            export const paymentRequest: Skill[] = [
         | 
| 63 | 
            -
              {
         | 
| 64 | 
            -
                skill: "pay",
         | 
| 65 | 
            -
                examples: [
         | 
| 66 | 
            -
                  "/pay 10 vitalik.eth",
         | 
| 67 | 
            -
                  "/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03",
         | 
| 68 | 
            -
                ],
         | 
| 69 | 
            -
                description:
         | 
| 70 | 
            -
                  "Send a specified amount of a cryptocurrency to a destination address. \nWhen tipping, you can assume it's 1 USDC.",
         | 
| 71 | 
            -
                handler: handler,
         | 
| 72 | 
            -
                params: {
         | 
| 73 | 
            -
                  amount: {
         | 
| 74 | 
            -
                    default: 10,
         | 
| 75 | 
            -
                    type: "number",
         | 
| 76 | 
            -
                  },
         | 
| 77 | 
            -
                  token: {
         | 
| 78 | 
            -
                    default: "usdc",
         | 
| 79 | 
            -
                    type: "string",
         | 
| 80 | 
            -
                    values: ["eth", "dai", "usdc", "degen"], // Accepted tokens
         | 
| 81 | 
            -
                  },
         | 
| 82 | 
            -
                  username: {
         | 
| 83 | 
            -
                    default: "",
         | 
| 84 | 
            -
                    type: "username",
         | 
| 85 | 
            -
                  },
         | 
| 86 | 
            -
                  address: {
         | 
| 87 | 
            -
                    default: "",
         | 
| 88 | 
            -
                    type: "address",
         | 
| 89 | 
            -
                  },
         | 
| 90 | 
            -
                },
         | 
| 91 | 
            -
              },
         | 
| 92 | 
            -
            ];
         | 
| 93 | 
            -
             | 
| 94 | 
            -
            // Handler Implementation
         | 
| 95 | 
            -
            export async function handler(context: XMTPContext) {
         | 
| 96 | 
            -
              const {
         | 
| 97 | 
            -
                message: {
         | 
| 98 | 
            -
                  content: {
         | 
| 99 | 
            -
                    params: { amount, token, username, address },
         | 
| 100 | 
            -
                  },
         | 
| 101 | 
            -
                },
         | 
| 102 | 
            -
              } = context;
         | 
| 103 | 
            -
              let receiverAddress = address;
         | 
| 104 | 
            -
              if (username) {
         | 
| 105 | 
            -
                receiverAddress = (await context.getUserInfo(username))?.address;
         | 
| 106 | 
            -
              }
         | 
| 107 | 
            -
              if (address) {
         | 
| 108 | 
            -
                // Prioritize address over username
         | 
| 109 | 
            -
                receiverAddress = address;
         | 
| 110 | 
            -
              }
         | 
| 111 | 
            -
             | 
| 112 | 
            -
              await context.requestPayment(amount, token, receiverAddress);
         | 
| 113 | 
            -
            }
         | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
            ## Types
         | 
| 117 | 
            -
             | 
| 118 | 
            -
            import { XMTPContext } from "../plugins/xmtp.js";
         | 
| 119 | 
            -
            import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
         | 
| 120 | 
            -
            import { ContentTypeId } from "@xmtp/content-type-primitives";
         | 
| 121 | 
            -
             | 
| 122 | 
            -
            export type MessageAbstracted = {
         | 
| 123 | 
            -
              id: string;
         | 
| 124 | 
            -
              sent: Date;
         | 
| 125 | 
            -
              content: {
         | 
| 126 | 
            -
                text?: string | undefined;
         | 
| 127 | 
            -
                reply?: string | undefined;
         | 
| 128 | 
            -
                previousMsg?: string | undefined;
         | 
| 129 | 
            -
                react?: string | undefined;
         | 
| 130 | 
            -
                content?: any | undefined;
         | 
| 131 | 
            -
                params?: any | undefined;
         | 
| 132 | 
            -
                reference?: string | undefined;
         | 
| 133 | 
            -
                skill?: string | undefined;
         | 
| 134 | 
            -
              };
         | 
| 135 | 
            -
              version: "v2" | "v3";
         | 
| 136 | 
            -
              sender: AbstractedMember;
         | 
| 137 | 
            -
              typeId: string;
         | 
| 138 | 
            -
            };
         | 
| 139 | 
            -
            export type GroupAbstracted = {
         | 
| 140 | 
            -
              id: string;
         | 
| 141 | 
            -
              sync: () => Promise<void>;
         | 
| 142 | 
            -
              addMembers: (addresses: string[]) => Promise<void>;
         | 
| 143 | 
            -
              addMembersByInboxId: (inboxIds: string[]) => Promise<void>;
         | 
| 144 | 
            -
              send: (content: string, contentType?: ContentTypeId) => Promise<string>;
         | 
| 145 | 
            -
              isAdmin: (inboxId: string) => boolean;
         | 
| 146 | 
            -
              isSuperAdmin: (inboxId: string) => boolean;
         | 
| 147 | 
            -
              admins: string[];
         | 
| 148 | 
            -
              superAdmins: string[];
         | 
| 149 | 
            -
              createdAt: Date;
         | 
| 150 | 
            -
              members: GroupMember[];
         | 
| 151 | 
            -
            };
         | 
| 152 | 
            -
            export type SkillResponse = {
         | 
| 153 | 
            -
              code: number;
         | 
| 154 | 
            -
              message: string;
         | 
| 155 | 
            -
              data?: any;
         | 
| 156 | 
            -
            };
         | 
| 157 | 
            -
             | 
| 158 | 
            -
            export type SkillHandler = (
         | 
| 159 | 
            -
              context: XMTPContext,
         | 
| 160 | 
            -
            ) => Promise<SkillResponse | void>;
         | 
| 161 | 
            -
             | 
| 162 | 
            -
            export type Handler = (context: XMTPContext) => Promise<void>;
         | 
| 163 | 
            -
             | 
| 164 | 
            -
            export type RunConfig = {
         | 
| 165 | 
            -
              // client options from XMTP client
         | 
| 166 | 
            -
              client?: ClientOptions;
         | 
| 167 | 
            -
              // private key to be used for the client, if not, default from env
         | 
| 168 | 
            -
              privateKey?: string;
         | 
| 169 | 
            -
              // if true, the init log message with messagekit logo and stuff will be hidden
         | 
| 170 | 
            -
              experimental?: boolean;
         | 
| 171 | 
            -
              // hide the init log message with messagekit logo and stuff
         | 
| 172 | 
            -
              hideInitLogMessage?: boolean;
         | 
| 173 | 
            -
              // if true, attachments will be enabled
         | 
| 174 | 
            -
              attachments?: boolean;
         | 
| 175 | 
            -
              // if true, member changes will be enabled, like adding members to the group
         | 
| 176 | 
            -
              memberChange?: boolean;
         | 
| 177 | 
            -
              // skills to be used
         | 
| 178 | 
            -
              agent?: Agent;
         | 
| 179 | 
            -
              // model to be used
         | 
| 180 | 
            -
              gptModel?: string;
         | 
| 181 | 
            -
            };
         | 
| 182 | 
            -
            export interface SkillParamConfig {
         | 
| 183 | 
            -
              default?: string | number | boolean;
         | 
| 184 | 
            -
              type:
         | 
| 185 | 
            -
                | "number"
         | 
| 186 | 
            -
                | "string"
         | 
| 187 | 
            -
                | "username"
         | 
| 188 | 
            -
                | "quoted"
         | 
| 189 | 
            -
                | "address"
         | 
| 190 | 
            -
                | "prompt"
         | 
| 191 | 
            -
                | "url";
         | 
| 192 | 
            -
              plural?: boolean;
         | 
| 193 | 
            -
              values?: string[]; // Accepted values for the parameter
         | 
| 194 | 
            -
            }
         | 
| 195 | 
            -
             | 
| 196 | 
            -
            export interface Frame {
         | 
| 197 | 
            -
              title: string;
         | 
| 198 | 
            -
              buttons: { content: string; action: string; target: string }[];
         | 
| 199 | 
            -
              image: string;
         | 
| 200 | 
            -
            }
         | 
| 201 | 
            -
            export interface Agent {
         | 
| 202 | 
            -
              name: string;
         | 
| 203 | 
            -
              description: string;
         | 
| 204 | 
            -
              tag: string;
         | 
| 205 | 
            -
              skills: Skill[];
         | 
| 206 | 
            -
            }
         | 
| 207 | 
            -
            export interface Skill {
         | 
| 208 | 
            -
              skill: string;
         | 
| 209 | 
            -
              handler?: SkillHandler | undefined;
         | 
| 210 | 
            -
              adminOnly?: boolean;
         | 
| 211 | 
            -
              description: string;
         | 
| 212 | 
            -
              examples: string[];
         | 
| 213 | 
            -
              params: Record<string, SkillParamConfig>;
         | 
| 214 | 
            -
            }
         | 
| 215 | 
            -
             | 
| 216 | 
            -
            export interface AbstractedMember {
         | 
| 217 | 
            -
              inboxId: string;
         | 
| 218 | 
            -
              address: string;
         | 
| 219 | 
            -
              accountAddresses: string[];
         | 
| 220 | 
            -
              installationIds?: string[];
         | 
| 221 | 
            -
            }
         | 
| 222 | 
            -
             | 
| 223 | 
            -
            export type MetadataValue = string | number | boolean;
         | 
| 224 | 
            -
            export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
         | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
            ## Example final prompt
         | 
| 228 | 
            -
             | 
| 229 | 
            -
            Your are a helpful and playful ens agent called @bot that lives inside a messaging app called Converse.
         | 
| 230 | 
            -
             | 
| 231 | 
            -
             | 
| 232 | 
            -
            # Rules
         | 
| 233 | 
            -
            - You can respond with multiple messages if needed. Each message should be separated by a newline character.
         | 
| 234 | 
            -
            - You can trigger skills by only sending the command in a newline message.
         | 
| 235 | 
            -
            - Each command starts with a slash (/).
         | 
| 236 | 
            -
            - Never announce actions without using a command separated by a newline character.
         | 
| 237 | 
            -
            - Never use markdown in your responses.
         | 
| 238 | 
            -
            - Do not make guesses or assumptions
         | 
| 239 | 
            -
            - Only answer if the verified information is in the prompt.
         | 
| 240 | 
            -
            - Check that you are not missing a command
         | 
| 241 | 
            -
            - Focus only on helping users with operations detailed below.
         | 
| 242 | 
            -
            - Date: Fri, 06 Dec 2024 16:03:22 GMT
         | 
| 243 | 
            -
            - When mentioning any action related to available skills, you MUST trigger the corresponding command in a new line
         | 
| 244 | 
            -
            - If you suggest an action that has a command, you must trigger that command
         | 
| 245 | 
            -
             | 
| 246 | 
            -
             | 
| 247 | 
            -
            ## User context
         | 
| 248 | 
            -
            - Start by fetch their domain from or Converse username
         | 
| 249 | 
            -
            - Call the user by their name or domain, in case they have one
         | 
| 250 | 
            -
            - Ask for a name (if they don't have one) so you can suggest domains.
         | 
| 251 | 
            -
            - Message sent date: 2024-12-06T16:03:36.582Z
         | 
| 252 | 
            -
            - Users address is: 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09
         | 
| 253 | 
            -
            - Users name is: ArizonaOregon
         | 
| 254 | 
            -
            - Converse username is: ArizonaOregon
         | 
| 255 | 
            -
             | 
| 256 | 
            -
            ## Commands
         | 
| 257 | 
            -
            /check [domain] - Check if a domain is available.
         | 
| 258 | 
            -
            /cool [domain] - Get cool alternatives for a .eth domain.
         | 
| 259 | 
            -
            /info [domain] - Get detailed information about an ENS domain including owner, expiry date, and resolver.
         | 
| 260 | 
            -
            /register [domain] - Register a new ENS domain. Returns a URL to complete the registration process.
         | 
| 261 | 
            -
            /renew [domain] - Extend the registration period of your ENS domain. Returns a URL to complete the renewal.
         | 
| 262 | 
            -
            /reset  - Reset the conversation clearing memory and usernames cache.
         | 
| 263 | 
            -
            /pay [amount] [token] [username] [address] - Send a specified amount of a cryptocurrency to a destination address. 
         | 
| 264 | 
            -
            When tipping, you can asume its 1 usdc.
         | 
| 265 | 
            -
             | 
| 266 | 
            -
            ## Examples
         | 
| 267 | 
            -
            /check vitalik.eth
         | 
| 268 | 
            -
            /check fabri.base.eth
         | 
| 269 | 
            -
            /cool vitalik.eth
         | 
| 270 | 
            -
            /info nick.eth
         | 
| 271 | 
            -
            /register vitalik.eth
         | 
| 272 | 
            -
            /renew fabri.base.eth
         | 
| 273 | 
            -
            /reset
         | 
| 274 | 
            -
            /pay 10 vitalik.eth
         | 
| 275 | 
            -
            /pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03
         | 
| 276 | 
            -
             | 
| 277 | 
            -
            ## Scenarios
         | 
| 278 | 
            -
            1. Missing commands in responses
         | 
| 279 | 
            -
               **Issue**: Sometimes responses are sent without the required command.
         | 
| 280 | 
            -
               **Example**:
         | 
| 281 | 
            -
               Incorrect:
         | 
| 282 | 
            -
               > "Looks like vitalik.eth is registered! What about these cool alternatives?"
         | 
| 283 | 
            -
               Correct:
         | 
| 284 | 
            -
               > "Looks like vitalik.eth is registered! What about these cool alternatives?
         | 
| 285 | 
            -
               > /cool vitalik.eth"
         | 
| 286 | 
            -
             | 
| 287 | 
            -
               Incorrect:
         | 
| 288 | 
            -
               > Here is a summary of your TODOs. I will now send it via email.
         | 
| 289 | 
            -
               Correct:
         | 
| 290 | 
            -
               > /todo
         | 
| @@ -1,9 +0,0 @@ | |
| 1 | 
            -
            KEY= # the private key of the agent wallet
         | 
| 2 | 
            -
            TEST_ENCRYPTION_KEY= # a different private key for encryption
         | 
| 3 | 
            -
            NOTION_API_KEY= # your Notion API key
         | 
| 4 | 
            -
            NOTION_PAGE_ID= # the ID of the Notion page
         | 
| 5 | 
            -
            NOTION_POAP_DB= # the ID of the Notion database
         | 
| 6 | 
            -
            OPEN_AI_API_KEY= # your OpenAI API key
         | 
| 7 | 
            -
            REDIS_CONNECTION_STRING= # your Redis connection string
         | 
| 8 | 
            -
            LEARN_WEB3_API_KEY= # your Learn Web3 API key
         | 
| 9 | 
            -
            FRAME_BASE_URL= # the URL of the Frame API
         |