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 +10 -34
- package/package.json +1 -1
- package/templates/agent/.yarnrc.yml +4 -0
- package/templates/agent/package.json +21 -0
- package/templates/agent/src/index.ts +9 -4
- package/templates/agent/src/prompt.ts +1 -1
- package/templates/gated/.env.example +3 -0
- package/templates/gated/.yarnrc.yml +4 -0
- package/templates/gated/package.json +24 -0
- package/templates/gated/src/index.ts +64 -0
- package/templates/gated/src/lib/gated.ts +51 -0
- package/templates/gated/src/lib/nft.ts +37 -0
- package/templates/gated/src/skills.ts +24 -0
- package/templates/gpt/.yarnrc.yml +4 -0
- package/templates/gpt/package.json +21 -0
- package/templates/gpt/src/index.ts +8 -9
- package/templates/group/.yarnrc.yml +4 -0
- package/templates/group/package.json +21 -0
- package/templates/group/src/handlers/helpers.ts +2 -2
- package/templates/group/src/handlers/tipping.ts +1 -2
- package/templates/group/src/index.ts +9 -4
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
|
-
|
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
|
67
|
+
async function updatePackagejson(destDir, templateType) {
|
68
68
|
// Create package.json based on the template
|
69
|
-
|
70
|
-
|
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
|
-
|
96
|
-
|
97
|
-
|
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
@@ -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 {
|
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
|
-
|
42
|
+
skills,
|
38
43
|
} = context;
|
39
44
|
|
40
45
|
let prompt = await replaceVariables(
|
41
46
|
systemPrompt,
|
42
47
|
sender.address,
|
43
|
-
|
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.
|
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,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,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 {
|
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,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
|
-
|
28
|
+
skills,
|
29
29
|
} = context;
|
30
30
|
|
31
31
|
if (skill == "help") {
|
32
32
|
const intro =
|
33
33
|
"Available experiences:\n" +
|
34
|
-
|
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 {
|
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 {
|
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
|
-
|
26
|
+
skills,
|
22
27
|
} = context;
|
23
28
|
|
24
29
|
let prompt = await replaceVariables(
|
25
30
|
systemPrompt,
|
26
31
|
sender.address,
|
27
|
-
|
32
|
+
skills,
|
28
33
|
"@bot",
|
29
34
|
);
|
30
35
|
await agentReply(context, prompt);
|