create-message-kit 1.1.9-beta.2 → 1.1.9-beta.4

Sign up to get free protection for your applications and to get access to all the features.
package/index.js CHANGED
@@ -51,7 +51,7 @@ Powered by XMTP`;
51
51
  log.success(`Project launched in ${pc.red(destDir)}!`);
52
52
 
53
53
  // Add package.json
54
- addPackagejson(destDir, displayName, pkgManager);
54
+ updatePackagejson(destDir, templateType);
55
55
 
56
56
  // Create README.md file
57
57
  createReadme(destDir, templateType, displayName, pkgManager);
@@ -64,39 +64,14 @@ Powered by XMTP`;
64
64
 
65
65
  program.parse(process.argv);
66
66
 
67
- async function addPackagejson(destDir, name, pkgManager) {
67
+ async function updatePackagejson(destDir, templateType) {
68
68
  // Create package.json based on the template
69
- let packageTemplate = {
70
- name: name,
71
- private: true,
72
- type: "module",
73
- scripts: {
74
- build: "tsc",
75
- dev: "tsc -w & sleep 1 && node --watch dist/index.js",
76
- start: "node dist/index.js",
77
- postinstall: "tsc",
78
- },
79
- dependencies: {
80
- "@xmtp/message-kit": "latest",
81
- },
82
- devDependencies: {
83
- "@types/node": "latest",
84
- typescript: "latest",
85
- },
86
- engines: {
87
- node: ">=20",
88
- },
89
- };
90
-
91
- if (pkgManager.includes("yarn")) {
92
- packageTemplate.packageManager = `yarn@4.5.1`;
93
- }
69
+ const templateDir = resolve(__dirname, `./templates/${templateType}`);
70
+ const packageTemplate = fs.readJsonSync(`${templateDir}/package.json`);
94
71
 
95
- // Add .yarnrc.yml just in caseto disable PnP mode
96
- fs.writeFileSync(
97
- resolve(destDir, ".yarnrc.yml"),
98
- "nodeLinker: node-modules\n",
99
- );
72
+ packageTemplate.dependencies["@xmtp/message-kit"] = "latest";
73
+ //Add for yarn in general
74
+ packageTemplate.packageManager = `yarn@4.5.1`;
100
75
 
101
76
  fs.writeJsonSync(resolve(destDir, "package.json"), packageTemplate, {
102
77
  spaces: 2,
@@ -106,8 +81,9 @@ async function addPackagejson(destDir, name, pkgManager) {
106
81
  async function gatherProjectInfo() {
107
82
  const templateOptions = [
108
83
  { value: "gpt", label: "Simple Gpt" },
109
- { value: "agent", label: "Agent" },
110
- { value: "group", label: "Group" },
84
+ { value: "agent", label: "ENS Agent" },
85
+ { value: "group", label: "Group bot" },
86
+ { value: "gated", label: "Gated Group" },
111
87
  ];
112
88
 
113
89
  const templateType = await select({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.1.9-beta.2",
3
+ "version": "1.1.9-beta.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -0,0 +1,4 @@
1
+ compressionLevel: mixed
2
+ enableGlobalCache: false
3
+ enableTelemetry: false
4
+ nodeLinker: node-modules
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "agent",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc",
7
+ "dev": "tsc -w & sleep 1 && node --watch dist/index.js",
8
+ "postinstall": "tsc",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@xmtp/message-kit": "workspace:*"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^20.14.2",
16
+ "typescript": "^5.4.5"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ }
21
+ }
@@ -1,4 +1,9 @@
1
- import { run, agentReply, replaceVariables } from "@xmtp/message-kit";
1
+ import {
2
+ run,
3
+ agentReply,
4
+ replaceVariables,
5
+ XMTPContext,
6
+ } from "@xmtp/message-kit";
2
7
  import { systemPrompt } from "./prompt.js";
3
8
  import { registerSkill as checkSkill } from "./handlers/check.js";
4
9
  import { registerSkill as coolSkill } from "./handlers/cool.js";
@@ -31,16 +36,16 @@ export const skills = [
31
36
  ];
32
37
 
33
38
  run(
34
- async (context) => {
39
+ async (context: XMTPContext) => {
35
40
  const {
36
41
  message: { sender },
37
- runConfig,
42
+ skills,
38
43
  } = context;
39
44
 
40
45
  let prompt = await replaceVariables(
41
46
  systemPrompt,
42
47
  sender.address,
43
- runConfig?.skills,
48
+ skills,
44
49
  "@ens",
45
50
  );
46
51
  fs.writeFileSync("example_prompt.md", prompt);
@@ -48,5 +48,5 @@ Your are helpful and playful agent called {agent_name} that lives inside a web3
48
48
  /cool [domain]
49
49
 
50
50
  ## Most common bugs
51
- 1. Sometimes you will say something like: "Looks like vitalik.eth is registered! What about these cool alternatives?" But you forgot to add the command at the end of the message.
51
+ 1. Some times you will say something like: "Looks like vitalik.eth is registered! What about these cool alternatives?" But you forgot to add the command at the end of the message.
52
52
  `;
@@ -0,0 +1,3 @@
1
+ KEY= # the private key of the bot wallet
2
+ PORT= # the port of the server
3
+ ALCHEMY_API_KEY= # the alchemy api key
@@ -0,0 +1,4 @@
1
+ compressionLevel: mixed
2
+ enableGlobalCache: false
3
+ enableTelemetry: false
4
+ nodeLinker: node-modules
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "gated",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc",
7
+ "dev": "tsc -w & sleep 1 && node --watch dist/index.js",
8
+ "postinstall": "tsc",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@xmtp/message-kit": "workspace:*",
13
+ "alchemy-sdk": "^3.4.3",
14
+ "express": "^4.19.2"
15
+ },
16
+ "devDependencies": {
17
+ "@types/express": "^4",
18
+ "@types/node": "^20.14.2",
19
+ "typescript": "^5.4.5"
20
+ },
21
+ "engines": {
22
+ "node": ">=20"
23
+ }
24
+ }
@@ -0,0 +1,64 @@
1
+ import { run, xmtpClient, XMTPContext } from "@xmtp/message-kit";
2
+ import { Client } from "@xmtp/node-sdk";
3
+ import { startServer } from "./lib/gated.js";
4
+ import { verifiedRequest } from "./lib/nft.js";
5
+ const { client } = await xmtpClient({ hideInitLogMessage: true });
6
+ startServer(client, verifiedRequest);
7
+
8
+ run(async (context: XMTPContext) => {
9
+ const {
10
+ message: {
11
+ sender,
12
+ content: { skill },
13
+ },
14
+ client,
15
+ group,
16
+ } = context;
17
+
18
+ if (skill == "id") {
19
+ console.log(group?.id);
20
+ } else if (skill === "create") {
21
+ await context.send("Creating group...");
22
+ const group = await createGroup(
23
+ client,
24
+ sender.address,
25
+ client.accountAddress,
26
+ );
27
+
28
+ await context.send(
29
+ `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.`,
30
+ );
31
+ return;
32
+ } else {
33
+ await context.send(
34
+ "👋 Welcome to the Gated Bot Group!\nTo get started, type /create to set up a new group. 🚀\nThis example will check if the user has a particular nft and add them to the group if they do.\nOnce your group is created, you'll receive a unique Group ID and URL.\nShare the URL with friends to invite them to join your group!",
35
+ );
36
+ }
37
+ });
38
+
39
+ async function createGroup(
40
+ client: Client,
41
+ senderAddress: string,
42
+ clientAddress: string,
43
+ ) {
44
+ let senderInboxId = "";
45
+ const group = await client?.conversations.newConversation([
46
+ senderAddress,
47
+ clientAddress,
48
+ ]);
49
+ const members = await group.members();
50
+ const senderMember = members.find((member) =>
51
+ member.accountAddresses.includes(senderAddress.toLowerCase()),
52
+ );
53
+ if (senderMember) {
54
+ const senderInboxId = senderMember.inboxId;
55
+ console.log("Sender's inboxId:", senderInboxId);
56
+ } else {
57
+ console.log("Sender not found in members list");
58
+ }
59
+ await group.addSuperAdmin(senderInboxId);
60
+ console.log("Sender is superAdmin", await group.isSuperAdmin(senderInboxId));
61
+ await group.send(`Welcome to the new group!`);
62
+ await group.send(`You are now the admin of this group as well as the bot`);
63
+ return group;
64
+ }
@@ -0,0 +1,51 @@
1
+ // Import necessary modules
2
+ import express from "express";
3
+ import { Client } from "@xmtp/node-sdk";
4
+
5
+ export function startServer(
6
+ client: Client,
7
+ verifiedRequest: (walletAddress: string, groupId: string) => Promise<boolean>,
8
+ ) {
9
+ async function addWalletToGroup(
10
+ walletAddress: string,
11
+ groupId: string,
12
+ ): Promise<string> {
13
+ const conversation =
14
+ await client.conversations.getConversationById(groupId);
15
+ const verified = await verifiedRequest(walletAddress, groupId);
16
+ if (!verified) {
17
+ console.log("User cant be added to the group");
18
+ return "not verified";
19
+ } else {
20
+ try {
21
+ await conversation?.addMembers([walletAddress]);
22
+ console.log(`Added wallet address: ${walletAddress} to the group`);
23
+ return "success";
24
+ } catch (error: any) {
25
+ console.log(error.message);
26
+ return "error";
27
+ }
28
+ }
29
+ }
30
+
31
+ // Endpoint to add wallet address to a group from an external source
32
+ const app = express();
33
+ app.use(express.json());
34
+ app.post("/add-wallet", async (req, res) => {
35
+ try {
36
+ const { walletAddress, groupId } = req.body;
37
+ const result = await addWalletToGroup(walletAddress, groupId);
38
+ res.status(200).send(result);
39
+ } catch (error: any) {
40
+ res.status(400).send(error.message);
41
+ }
42
+ });
43
+ // Start the server
44
+ const PORT = process.env.PORT || 3000;
45
+ const url = process.env.URL || `http://localhost:${PORT}`;
46
+ app.listen(PORT, () => {
47
+ console.warn(
48
+ `Use this endpoint to add a wallet to a group indicated by the groupId\n${url}/add-wallet <body: {walletAddress, groupId}>`,
49
+ );
50
+ });
51
+ }
@@ -0,0 +1,37 @@
1
+ import { Alchemy, Network } from "alchemy-sdk";
2
+
3
+ const settings = {
4
+ apiKey: process.env.ALCHEMY_API_KEY, // Replace with your Alchemy API key
5
+ network: Network.BASE_MAINNET, // Use the appropriate network
6
+ };
7
+
8
+ export async function verifiedRequest(
9
+ walletAddress: string,
10
+ groupId: string
11
+ ): Promise<boolean> {
12
+ console.log("new-request", {
13
+ groupId,
14
+ walletAddress,
15
+ });
16
+
17
+ const alchemy = new Alchemy(settings);
18
+ try {
19
+ const nfts = await alchemy.nft.getNftsForOwner(walletAddress);
20
+ const collectionSlug = "XMTPeople"; // The slug for the collection
21
+
22
+ const ownsNft = nfts.ownedNfts.some(
23
+ (nft: any) =>
24
+ nft.contract.name.toLowerCase() === collectionSlug.toLowerCase()
25
+ );
26
+ console.log(
27
+ `NFTs owned on ${Network.BASE_MAINNET}:`,
28
+ nfts.ownedNfts.length
29
+ );
30
+ console.log("is the nft owned: ", ownsNft);
31
+ return ownsNft as boolean;
32
+ } catch (error) {
33
+ console.error("Error fetching NFTs from Alchemy:", error);
34
+ }
35
+
36
+ return false;
37
+ }
@@ -0,0 +1,24 @@
1
+ import type { SkillGroup } from "@xmtp/message-kit";
2
+
3
+ export const skills: SkillGroup[] = [
4
+ {
5
+ name: "Group Id",
6
+ description: "Create and get group id.",
7
+ skills: [
8
+ {
9
+ skill: "/create",
10
+ examples: ["/create"],
11
+ adminOnly: true,
12
+ params: {},
13
+ description: "Create a new group.",
14
+ },
15
+ {
16
+ skill: "/id",
17
+ examples: ["/id"],
18
+ adminOnly: true,
19
+ params: {},
20
+ description: "Get group id.",
21
+ },
22
+ ],
23
+ },
24
+ ];
@@ -0,0 +1,4 @@
1
+ compressionLevel: mixed
2
+ enableGlobalCache: false
3
+ enableTelemetry: false
4
+ nodeLinker: node-modules
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "gpt",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc",
7
+ "dev": "tsc -w & sleep 1 && node --watch dist/index.js",
8
+ "postinstall": "tsc",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@xmtp/message-kit": "workspace:*"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^20.14.2",
16
+ "typescript": "^5.4.5"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ }
21
+ }
@@ -1,18 +1,17 @@
1
- import { run, agentReply, replaceVariables } from "@xmtp/message-kit";
1
+ import {
2
+ run,
3
+ agentReply,
4
+ replaceVariables,
5
+ XMTPContext,
6
+ } from "@xmtp/message-kit";
2
7
 
3
8
  import { systemPrompt } from "./prompt.js";
4
9
 
5
- run(async (context) => {
10
+ run(async (context: XMTPContext) => {
6
11
  const {
7
12
  message: { sender },
8
- runConfig,
9
13
  } = context;
10
14
 
11
- let prompt = await replaceVariables(
12
- systemPrompt,
13
- sender.address,
14
- runConfig?.skills,
15
- "@bot",
16
- );
15
+ let prompt = await replaceVariables(systemPrompt, sender.address, [], "@bot");
17
16
  await agentReply(context, prompt);
18
17
  });
@@ -0,0 +1,4 @@
1
+ compressionLevel: mixed
2
+ enableGlobalCache: false
3
+ enableTelemetry: false
4
+ nodeLinker: node-modules
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "group",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc",
7
+ "dev": "tsc -w & sleep 1 && node --watch dist/index.js",
8
+ "postinstall": "tsc",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@xmtp/message-kit": "workspace:*"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^20.14.2",
16
+ "typescript": "^5.4.5"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ }
21
+ }
@@ -25,13 +25,13 @@ export async function handleHelp(context: XMTPContext) {
25
25
  content: { skill },
26
26
  },
27
27
  group,
28
- runConfig,
28
+ skills,
29
29
  } = context;
30
30
 
31
31
  if (skill == "help") {
32
32
  const intro =
33
33
  "Available experiences:\n" +
34
- runConfig?.skills
34
+ skills
35
35
  ?.flatMap((app) => app.skills)
36
36
  .map((skill) => `${skill.skill} - ${skill.description}`)
37
37
  .join("\n") +
@@ -1,5 +1,4 @@
1
- import { XMTPContext, AbstractedMember } from "@xmtp/message-kit";
2
- import { getUserInfo } from "@xmtp/message-kit";
1
+ import { getUserInfo, AbstractedMember, XMTPContext } from "@xmtp/message-kit";
3
2
  import type { skillAction } from "@xmtp/message-kit";
4
3
 
5
4
  export const registerSkill: skillAction[] = [
@@ -1,4 +1,9 @@
1
- import { run, agentReply, replaceVariables } from "@xmtp/message-kit";
1
+ import {
2
+ run,
3
+ agentReply,
4
+ XMTPContext,
5
+ replaceVariables,
6
+ } from "@xmtp/message-kit";
2
7
  import { registerSkill as tippingSkill } from "./handlers/tipping.js";
3
8
  import { registerSkill as paymentSkill } from "./handlers/payment.js";
4
9
  import { registerSkill as gameSkill } from "./handlers/game.js";
@@ -15,16 +20,16 @@ export const skills = [
15
20
  ];
16
21
 
17
22
  run(
18
- async (context) => {
23
+ async (context: XMTPContext) => {
19
24
  const {
20
25
  message: { sender },
21
- runConfig,
26
+ skills,
22
27
  } = context;
23
28
 
24
29
  let prompt = await replaceVariables(
25
30
  systemPrompt,
26
31
  sender.address,
27
- runConfig?.skills,
32
+ skills,
28
33
  "@bot",
29
34
  );
30
35
  await agentReply(context, prompt);