create-message-kit 1.2.7 → 1.2.8

Sign up to get free protection for your applications and to get access to all the features.
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.7";
10
+ const defVersion = "1.2.8";
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
 
13
13
  // Read package.json to get the version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -12,7 +12,6 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "clean": "rm -rf .turbo && rm -rf node_modules",
15
- "copy": "node copyTemplates.js",
16
15
  "format": "yarn format:base -w .",
17
16
  "format:base": "prettier --ignore-path ../../.gitignore",
18
17
  "format:check": "yarn format:base -c ."
@@ -38,4 +37,4 @@
38
37
  "access": "public",
39
38
  "registry": "https://registry.npmjs.org/"
40
39
  }
41
- }
40
+ }
@@ -13,7 +13,6 @@ import { register } from "./skills/register.js";
13
13
  import { renew } from "./skills/renew.js";
14
14
  import { pay } from "./skills/pay.js";
15
15
  import { reset } from "./skills/reset.js";
16
- import { game } from "./skills/game.js";
17
16
  import fs from "fs";
18
17
 
19
18
  // [!region skills]
@@ -29,7 +28,6 @@ export const agent: Agent = {
29
28
  ...renew,
30
29
  ...reset,
31
30
  ...pay,
32
- ...game,
33
31
  ],
34
32
  };
35
33
  // [!endregion skills]
@@ -11,6 +11,7 @@
11
11
  "@xmtp/message-kit": "workspace:*",
12
12
  "alchemy-sdk": "^3.0.0",
13
13
  "express": "^4.19.2",
14
+ "node-fetch": "^3.3.2",
14
15
  "resend": "^4.0.1"
15
16
  },
16
17
  "devDependencies": {
@@ -4,26 +4,38 @@ import {
4
4
  replaceVariables,
5
5
  XMTPContext,
6
6
  Agent,
7
+ xmtpClient,
8
+ V3Client,
7
9
  } from "@xmtp/message-kit";
8
- import { systemPrompt } from "./prompt.js";
9
10
  import fs from "fs";
10
- //Local imports
11
+ import { systemPrompt } from "./prompt.js";
11
12
  import { token } from "./skills/token.js";
12
13
  import { todo } from "./skills/todo.js";
13
- import { gated } from "./skills/gated.js";
14
+ import { gated, startGatedGroupServer } from "./skills/gated.js";
14
15
  import { broadcast } from "./skills/broadcast.js";
16
+ import { wordle } from "./skills/wordle.js";
15
17
 
16
18
  export const agent: Agent = {
17
19
  name: "Experimental Agent",
18
- tag: "@exp",
20
+ tag: "@bot",
19
21
  description: "An experimental agent with a lot of skills.",
20
22
  skills: [
21
23
  ...token,
22
24
  ...(process?.env?.RESEND_API_KEY ? todo : []),
23
25
  ...(process?.env?.ALCHEMY_SDK ? gated : []),
24
26
  ...broadcast,
27
+ ...wordle,
25
28
  ],
26
29
  };
30
+
31
+ // [!region gated]
32
+ const { client } = await xmtpClient({
33
+ hideInitLogMessage: true,
34
+ });
35
+
36
+ startGatedGroupServer(client);
37
+ // [!endregion gated]
38
+
27
39
  run(
28
40
  async (context: XMTPContext) => {
29
41
  const {
@@ -17,10 +17,10 @@ export async function checkNft(
17
17
  (nft: any) =>
18
18
  nft.contract.name.toLowerCase() === collectionSlug.toLowerCase(),
19
19
  );
20
- console.log(
21
- `NFTs owned on ${Network.BASE_MAINNET}:`,
22
- nfts.ownedNfts.length,
23
- );
20
+ // console.log(
21
+ // `NFTs owned on ${Network.BASE_MAINNET}:`,
22
+ // nfts.ownedNfts.length,
23
+ // );
24
24
  console.log("is the nft owned: ", ownsNft);
25
25
  return ownsNft as boolean;
26
26
  } catch (error) {
@@ -0,0 +1,26 @@
1
+ import fetch from "node-fetch";
2
+
3
+ export async function sendLog(title: string, description: string) {
4
+ const response = await fetch("https://api.minilog.dev/v1/logs/testlog", {
5
+ method: "POST",
6
+ headers: {
7
+ "Content-Type": "application/json",
8
+ Authorization: "Bearer pthsm38sccpux5acriqish7isz5inet7q73ef7br",
9
+ },
10
+ body: JSON.stringify({
11
+ application: "myapp-1",
12
+ severity: "DEBUG",
13
+ data: title,
14
+ metadata: {
15
+ title,
16
+ description,
17
+ },
18
+ }),
19
+ });
20
+ console.log(response);
21
+ if (!response.ok) {
22
+ console.error("Failed to send log:", response.statusText);
23
+ } else {
24
+ console.log("Log sent successfully");
25
+ }
26
+ }
@@ -20,7 +20,7 @@ export async function createGroup(
20
20
  member.accountAddresses.includes(senderAddress.toLowerCase()),
21
21
  );
22
22
  if (senderMember) {
23
- const senderInboxId = senderMember.inboxId;
23
+ senderInboxId = senderMember.inboxId;
24
24
  console.log("Sender's inboxId:", senderInboxId);
25
25
  } else {
26
26
  console.log("Sender not found in members list");
@@ -91,26 +91,24 @@ export async function removeFromGroup(
91
91
  export async function addToGroup(
92
92
  groupId: string,
93
93
  client: V3Client,
94
- v2client: V2Client,
95
- senderAddress: string,
94
+ address: string,
96
95
  ): Promise<{ code: number; message: string }> {
97
96
  try {
98
- let lowerAddress = senderAddress.toLowerCase();
99
- const { v2, v3 } = await isOnXMTP(client, v2client, lowerAddress);
97
+ let lowerAddress = address.toLowerCase();
98
+ const { v2, v3 } = await isOnXMTP(client, null, lowerAddress);
100
99
  if (!v3)
101
100
  return {
102
101
  code: 400,
103
102
  message: "You don't seem to have a v3 identity ",
104
103
  };
105
- const conversation =
106
- await client.conversations.getConversationById(groupId);
107
- console.warn("Adding to group", conversation?.id);
108
- await conversation?.sync();
104
+ const group = await client.conversations.getConversationById(groupId);
105
+ console.warn("Adding to group", group?.id);
106
+ await group?.sync();
109
107
  //DON'T TOUCH THIS LINE
110
- await conversation?.addMembers([lowerAddress]);
108
+ await group?.addMembers([lowerAddress]);
111
109
  console.warn("Added member to group");
112
- await conversation?.sync();
113
- const members = await conversation?.members();
110
+ await group?.sync();
111
+ const members = await group?.members();
114
112
  console.warn("Number of members", members?.length);
115
113
 
116
114
  if (members) {
@@ -18,12 +18,13 @@ export const broadcast: Skill[] = [
18
18
  async function handler(context: XMTPContext) {
19
19
  const {
20
20
  message: {
21
- content: { params },
21
+ content: {
22
+ params: { message },
23
+ },
22
24
  },
23
25
  } = context;
24
26
 
25
27
  const fakeSubscribers = ["0x93E2fc3e99dFb1238eB9e0eF2580EFC5809C7204"];
26
- const { message } = params;
27
28
  await context.send("This is how your message will look like:");
28
29
  await context.send(message);
29
30
  const emailResponse = await context.awaitResponse(
@@ -2,7 +2,7 @@ import { XMTPContext, Skill, V3Client } from "@xmtp/message-kit";
2
2
  import { createGroup } from "../lib/xmtp.js";
3
3
  import express from "express";
4
4
  import { checkNft } from "../lib/alchemy.js";
5
-
5
+ import { addToGroup } from "../lib/xmtp.js";
6
6
  export const gated: Skill[] = [
7
7
  {
8
8
  skill: "/create",
@@ -12,14 +12,6 @@ export const gated: Skill[] = [
12
12
  params: {},
13
13
  description: "Create a new group.",
14
14
  },
15
- {
16
- skill: "/id",
17
- examples: ["/id"],
18
- handler: handler,
19
- adminOnly: true,
20
- params: {},
21
- description: "Get group id.",
22
- },
23
15
  ];
24
16
 
25
17
  async function handler(context: XMTPContext) {
@@ -29,23 +21,18 @@ async function handler(context: XMTPContext) {
29
21
  content: { skill },
30
22
  },
31
23
  client,
32
- group,
33
24
  } = context;
34
25
 
35
- if (skill == "id") {
36
- console.log(group?.id);
37
- } else if (skill === "create") {
38
- console.log(client, sender.address, client.accountAddress);
26
+ if (skill === "create") {
39
27
  const group = await createGroup(
40
28
  client,
41
29
  sender.address,
42
30
  client.accountAddress,
43
31
  );
44
32
 
45
- // await context.send(
46
- // `Group created!\n- ID: ${group.id}\n- Group Frame URL: https://converse.xyz/group/${group.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
47
- // );
48
- //startServer(client);
33
+ await context.send(
34
+ `Group created!\n- ID: ${group?.id}\n- Group Frame URL: https://converse.xyz/group/${group?.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
35
+ );
49
36
  return;
50
37
  } else {
51
38
  await context.send(
@@ -54,22 +41,24 @@ async function handler(context: XMTPContext) {
54
41
  }
55
42
  }
56
43
 
57
- export function startServer(client: V3Client) {
44
+ export function startGatedGroupServer(client: V3Client) {
58
45
  async function addWalletToGroup(
59
46
  walletAddress: string,
60
47
  groupId: string,
61
48
  ): Promise<string> {
62
- const conversation =
63
- await client.conversations.getConversationById(groupId);
64
- const verified = await checkNft(walletAddress, "XMTPeople");
49
+ const verified = true; //await checkNft(walletAddress, "XMTPeople");
65
50
  if (!verified) {
66
51
  console.log("User cant be added to the group");
67
52
  return "not verified";
68
53
  } else {
69
54
  try {
70
- await conversation?.addMembers([walletAddress]);
71
- console.log(`Added wallet address: ${walletAddress} to the group`);
72
- return "success";
55
+ const added = await addToGroup(groupId, client, walletAddress);
56
+ if (added.code === 200) {
57
+ console.log(`Added wallet address: ${walletAddress} to the group`);
58
+ return "success";
59
+ } else {
60
+ return added.message;
61
+ }
73
62
  } catch (error: any) {
74
63
  console.log(error.message);
75
64
  return "error";
@@ -54,9 +54,9 @@ export async function handler(context: XMTPContext) {
54
54
  try {
55
55
  let { reply } = await context.textGeneration(
56
56
  email,
57
- "Make this summary concise and to the point to be sent in an html email. Just return the content inside the body tag.\n msg: " +
57
+ "Make this summary concise and to the point to be sent in an email.\n msg: " +
58
58
  previousMsg,
59
- "You are an expert at summarizing to-dos.",
59
+ "You are an expert at summarizing to-dos. Return in format html and just the content inside the body tag. Dont return `html` or `body` tags",
60
60
  );
61
61
  if (typeof reply === "string") {
62
62
  let content = {
@@ -0,0 +1,97 @@
1
+ import { XMTPContext } from "@xmtp/message-kit";
2
+ import type { Skill } from "@xmtp/message-kit";
3
+
4
+ export const wordle: Skill[] = [
5
+ {
6
+ skill: "/wordle",
7
+ handler: handler,
8
+ examples: ["/wordle"],
9
+ description: "Play wordle.",
10
+ params: {},
11
+ },
12
+ {
13
+ skill: "/arena [word count] [audience size]",
14
+ examples: ["/arena 3 15"],
15
+ handler: handler,
16
+ description: "Play arena.",
17
+ params: {
18
+ wordCount: {
19
+ default: 3,
20
+ type: "number",
21
+ },
22
+ audienceSize: {
23
+ default: 15,
24
+ type: "number",
25
+ },
26
+ },
27
+ },
28
+ ];
29
+
30
+ async function handler(context: XMTPContext) {
31
+ const {
32
+ message: {
33
+ content: { skill },
34
+ },
35
+ } = context;
36
+
37
+ if (skill === "arena") {
38
+ await handleArenaMessage(context);
39
+ } else if (skill === "wordle") {
40
+ await context.send("https://framedl.xyz");
41
+ } else if (skill === "help") {
42
+ await context.send(
43
+ "For using this bot you can use the following commands:\n\n" +
44
+ "/wordle, @wordle, 🔍, 🔎 - To start the game\n" +
45
+ "/arena <word count> <audience size> - To start the arena game\n" +
46
+ "/help - To see commands",
47
+ );
48
+ }
49
+ }
50
+ async function handleArenaMessage(context: XMTPContext) {
51
+ const {
52
+ message: {
53
+ content: { text },
54
+ },
55
+ members,
56
+ } = context;
57
+
58
+ const apiKey = process.env.FRAMEDL_API_KEY;
59
+ if (!apiKey) {
60
+ console.log("FRAMEDL_API_KEY is not set");
61
+ await context.send("https://www.framedl.xyz/games/arena/create");
62
+ return;
63
+ }
64
+ const participantCount = members && members.length ? members.length - 1 : 0;
65
+ const args = text?.split(" ") ?? [];
66
+ const wordCountArg = args[1] ? parseInt(args[1], 10) : 3;
67
+ const audienceSizeArg = args[2] ? parseInt(args[2], 10) : participantCount;
68
+ if (isNaN(wordCountArg) || isNaN(audienceSizeArg)) {
69
+ await context.send(
70
+ "usage: /arena <word count> <audience size>\n\n" +
71
+ "word count: number of words in the arena (default: 3, min: 1, max: 9)\n" +
72
+ "audience size: number of audience members (default: number of participants excluding wordle bot, min: 1, max: 15)",
73
+ );
74
+ return;
75
+ }
76
+
77
+ const audienceSize = Math.max(1, Math.min(15, audienceSizeArg));
78
+ const wordCount = Math.max(1, Math.min(9, wordCountArg));
79
+
80
+ try {
81
+ const response = await fetch("https://www.framedl.xyz/api/arenas", {
82
+ method: "POST",
83
+ body: JSON.stringify({ wordCount, audienceSize }),
84
+ headers: {
85
+ "Content-Type": "application/json",
86
+ "x-framedl-api-key": apiKey,
87
+ },
88
+ });
89
+
90
+ const data = (await response.json()) as { arenaUrl: string };
91
+
92
+ await context.send(data.arenaUrl);
93
+ } catch (error) {
94
+ console.error(error);
95
+ await context.send("https://www.framedl.xyz/games/arena/create");
96
+ }
97
+ }
@@ -1,58 +0,0 @@
1
- import { XMTPContext } from "@xmtp/message-kit";
2
- import type { Skill } from "@xmtp/message-kit";
3
-
4
- export const game: Skill[] = [
5
- {
6
- skill: "/game [game]",
7
- handler: handler,
8
- description: "Play a game.",
9
- examples: ["/game wordle", "/game slot", "/game help"],
10
- params: {
11
- game: {
12
- default: "",
13
- type: "string",
14
- values: ["wordle", "slot", "help"],
15
- },
16
- },
17
- },
18
- ];
19
-
20
- export async function handler(context: XMTPContext) {
21
- const {
22
- message: {
23
- content: { skill, params, text },
24
- },
25
- } = context;
26
- if (!skill) {
27
- if (text === "🔎" || text === "🔍") {
28
- // Send the URL for the requested game
29
- context.reply("https://framedl.xyz/");
30
- }
31
- return;
32
- }
33
- // URLs for each game type
34
- const gameUrls: { [key: string]: string } = {
35
- wordle: "https://framedl.xyz",
36
- slot: "https://slot-machine-frame.vercel.app",
37
- };
38
- let returnText = "";
39
- switch (params.game) {
40
- case "wordle":
41
- case "slot":
42
- // Retrieve the URL for the requested game using a simplified variable assignment
43
- const gameUrl = gameUrls[params.game];
44
- // Send the URL for the requested game
45
- returnText = gameUrl;
46
- break;
47
-
48
- case "help":
49
- returnText = "Available games: \n/game wordle\n/game slot";
50
- break;
51
- default:
52
- // Inform the user about unrecognized skills and provide available options
53
- returnText =
54
- "Skill not recognized. Available games: wordle, slot, or help.";
55
- break;
56
- }
57
- return { code: 200, message: returnText };
58
- }