create-message-kit 1.1.7-beta.9 → 1.1.8-beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. package/README.md +2 -2
  2. package/index.js +62 -50
  3. package/package.json +1 -1
  4. package/templates/agent/src/handler/ens.ts +19 -18
  5. package/templates/agent/src/index.ts +4 -17
  6. package/templates/agent/src/prompt.ts +16 -33
  7. package/templates/agent/src/skills.ts +7 -20
  8. package/templates/gm/.env.example +1 -1
  9. package/templates/gm/src/index.ts +1 -5
  10. package/templates/group/.env.example +2 -3
  11. package/templates/group/src/handler/game.ts +4 -5
  12. package/templates/group/src/handler/helpers.ts +10 -6
  13. package/templates/group/src/handler/payment.ts +29 -0
  14. package/templates/group/src/handler/tipping.ts +17 -35
  15. package/templates/group/src/index.ts +17 -26
  16. package/templates/group/src/prompt.ts +28 -0
  17. package/templates/group/src/skills.ts +22 -107
  18. package/templates/agent/package.json +0 -22
  19. package/templates/agent/src/lib/gpt.ts +0 -161
  20. package/templates/agent/src/lib/openai.ts +0 -174
  21. package/templates/agent/src/lib/resolver.ts +0 -151
  22. package/templates/gm/package.json +0 -21
  23. package/templates/group/package.json +0 -23
  24. package/templates/group/src/handler/agent.ts +0 -67
  25. package/templates/group/src/handler/group.ts +0 -24
  26. package/templates/group/src/handler/loyalty.ts +0 -46
  27. package/templates/group/src/handler/splitpayment.ts +0 -65
  28. package/templates/group/src/handler/transaction.ts +0 -50
  29. package/templates/group/src/lib/gpt.ts +0 -161
  30. package/templates/group/src/lib/openai.ts +0 -174
  31. package/templates/group/src/lib/resolver.ts +0 -151
  32. package/templates/group/src/lib/stack.ts +0 -18
  33. package/templates/group/src/lib/vision.ts +0 -42
package/README.md CHANGED
@@ -9,7 +9,7 @@ bun create message-kit
9
9
  ```
10
10
 
11
11
  ```bash
12
- npx create-message-kit@latest
12
+ npx create-message-kit
13
13
  ```
14
14
 
15
15
  ```bash
@@ -17,5 +17,5 @@ yarn create message-kit
17
17
  ```
18
18
 
19
19
  ```bash [npm]
20
- npm init message-kit@latest
20
+ npm init message-kit
21
21
  ```
package/index.js CHANGED
@@ -5,6 +5,7 @@ import { fileURLToPath } from "node:url";
5
5
  import { log, outro, text, select } from "@clack/prompts";
6
6
  import { default as fs } from "fs-extra";
7
7
  import { isCancel } from "@clack/prompts";
8
+ import { detect } from "detect-package-manager";
8
9
  import pc from "picocolors";
9
10
 
10
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -15,9 +16,14 @@ const packageJson = JSON.parse(
15
16
  );
16
17
  const version = packageJson.version;
17
18
  program
18
- .name("byob")
19
+ .name("message-kit")
19
20
  .description("CLI to initialize projects")
20
21
  .action(async () => {
22
+ // Add Yarn 4 check at the start of the action
23
+ const pkgManager = await detectPackageManager();
24
+
25
+ log.info(pc.cyan(`pkgManager detected: ${pkgManager}`));
26
+
21
27
  log.info(pc.cyan(`Welcome to MessageKit CLI v${version}!`));
22
28
  const coolLogo = `
23
29
  ███╗ ███╗███████╗███████╗███████╗ █████╗ ██████╗ ███████╗██╗ ██╗██╗████████╗
@@ -32,9 +38,6 @@ Powered by XMTP`;
32
38
 
33
39
  const { templateType, displayName, destDir } = await gatherProjectInfo();
34
40
 
35
- // Replace dot files
36
- //replaceDotfiles(destDir);
37
-
38
41
  // Create .gitignore
39
42
  createGitignore(destDir);
40
43
 
@@ -44,13 +47,11 @@ Powered by XMTP`;
44
47
  // Create tsconfig.json file
45
48
  createTsconfig(destDir);
46
49
 
47
- // Replace package.json properties
48
- updatePackageJson(destDir, displayName);
49
-
50
50
  // Wrap up
51
51
  log.success(`Project launched in ${pc.red(destDir)}!`);
52
52
 
53
- const pkgManager = detectPackageManager();
53
+ // Add package.json
54
+ addPackagejson(destDir, displayName, pkgManager);
54
55
 
55
56
  // Create README.md file
56
57
  createReadme(destDir, templateType, displayName, pkgManager);
@@ -63,6 +64,41 @@ Powered by XMTP`;
63
64
 
64
65
  program.parse(process.argv);
65
66
 
67
+ async function addPackagejson(destDir, name, pkgManager) {
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
+ engines: {
83
+ node: ">=20",
84
+ },
85
+ };
86
+
87
+ if (pkgManager.startsWith("yarn")) {
88
+ packageTemplate.packageManager = `${pkgManager}`;
89
+ // Add .yarnrc.yml to disable PnP mode
90
+ }
91
+
92
+ fs.writeFileSync(
93
+ resolve(destDir, ".yarnrc.yml"),
94
+ "nodeLinker: node-modules\n",
95
+ );
96
+
97
+ fs.writeJsonSync(resolve(destDir, "package.json"), packageTemplate, {
98
+ spaces: 2,
99
+ });
100
+ }
101
+
66
102
  async function gatherProjectInfo() {
67
103
  const templateOptions = [
68
104
  { value: "gm", label: "GM" },
@@ -108,24 +144,6 @@ async function gatherProjectInfo() {
108
144
  return { templateType, displayName, destDir, templateDir };
109
145
  }
110
146
 
111
- function updateDependenciesToLatest(pkgJson) {
112
- const updateToLatest = (deps) => {
113
- for (const key in deps) {
114
- if (deps[key].startsWith("workspace:")) {
115
- deps[key] = "latest";
116
- }
117
- }
118
- };
119
-
120
- if (pkgJson.dependencies) {
121
- updateToLatest(pkgJson.dependencies);
122
- }
123
-
124
- if (pkgJson.devDependencies) {
125
- updateToLatest(pkgJson.devDependencies);
126
- }
127
- }
128
-
129
147
  function createTsconfig(destDir) {
130
148
  const tsconfigContent = {
131
149
  include: ["src/**/*"],
@@ -151,22 +169,6 @@ function createTsconfig(destDir) {
151
169
  spaces: 2,
152
170
  });
153
171
  }
154
- function replaceDotfiles(destDir) {
155
- for (const file of fs.readdirSync(destDir)) {
156
- if (!file.startsWith("_")) continue;
157
- fs.renameSync(
158
- resolve(destDir, file),
159
- resolve(destDir, `.${file.slice(1)}`),
160
- );
161
- }
162
- }
163
-
164
- function updatePackageJson(destDir, name) {
165
- const pkgJson = fs.readJsonSync(resolve(destDir, "package.json"));
166
- pkgJson.name = name;
167
- updateDependenciesToLatest(pkgJson);
168
- fs.writeJsonSync(resolve(destDir, "package.json"), pkgJson, { spaces: 2 });
169
- }
170
172
 
171
173
  function logNextSteps(name) {
172
174
  log.message("Next steps:");
@@ -202,14 +204,24 @@ yarn-error.log*
202
204
  fs.writeFileSync(resolve(destDir, ".gitignore"), gitignoreContent.trim());
203
205
  }
204
206
 
205
- function detectPackageManager() {
206
- const userAgent = process.env.npm_config_user_agent;
207
- if (!userAgent) return "npm";
208
- if (userAgent.includes("bun")) return "bun";
209
- if (userAgent.includes("yarn")) return "yarn";
210
- if (userAgent.includes("pnpm")) return "pnpm";
211
- if (userAgent.includes("npm")) return "npm";
212
- return "npm";
207
+ async function detectPackageManager() {
208
+ try {
209
+ const pkgManager = await detect();
210
+ const userAgent = process.env.npm_config_user_agent;
211
+ let version = "";
212
+
213
+ if (userAgent && pkgManager === "yarn") {
214
+ const parts = userAgent.split(" ")[0]?.split("/");
215
+ if (parts && parts.length > 1) {
216
+ version = `@${parts[1]}`;
217
+ }
218
+ }
219
+
220
+ return pkgManager + version;
221
+ } catch (error) {
222
+ // Fallback to npm if detection fails
223
+ return "npm";
224
+ }
213
225
  }
214
226
 
215
227
  function kebabcase(str) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.1.7-beta.9",
3
+ "version": "1.1.8-beta.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -5,21 +5,23 @@ import { clearMemory } from "@xmtp/message-kit";
5
5
 
6
6
  export const frameUrl = "https://ens.steer.fun/";
7
7
  export const ensUrl = "https://app.ens.domains/";
8
- export const baseTxUrl = "https://base-tx-frame.vercel.app";
8
+ export const txpayUrl = "https://txpay.vercel.app";
9
9
 
10
10
  export async function handleEns(
11
11
  context: HandlerContext,
12
- ): Promise<SkillResponse> {
12
+ ): Promise<SkillResponse | undefined> {
13
13
  const {
14
14
  message: {
15
- content: { command, params, sender },
15
+ sender,
16
+ content: { skill, params },
16
17
  },
17
18
  } = context;
18
- if (command == "reset") {
19
+
20
+ if (skill == "reset") {
19
21
  clearMemory();
20
22
  return { code: 200, message: "Conversation reset." };
21
- } else if (command == "renew") {
22
- // Destructure and validate parameters for the ens command
23
+ } else if (skill == "renew") {
24
+ // Destructure and validate parameters for the ens
23
25
  const { domain } = params;
24
26
  // Check if the user holds the domain
25
27
  if (!domain) {
@@ -42,8 +44,8 @@ export async function handleEns(
42
44
  // Generate URL for the ens
43
45
  let url_ens = frameUrl + "frames/manage?name=" + domain;
44
46
  return { code: 200, message: `${url_ens}` };
45
- } else if (command == "register") {
46
- // Destructure and validate parameters for the ens command
47
+ } else if (skill == "register") {
48
+ // Destructure and validate parameters for the ens
47
49
  const { domain } = params;
48
50
 
49
51
  if (!domain) {
@@ -55,7 +57,7 @@ export async function handleEns(
55
57
  // Generate URL for the ens
56
58
  let url_ens = ensUrl + domain;
57
59
  return { code: 200, message: `${url_ens}` };
58
- } else if (command == "info") {
60
+ } else if (skill == "info") {
59
61
  const { domain } = params;
60
62
 
61
63
  const data = await getUserInfo(domain);
@@ -92,7 +94,7 @@ export async function handleEns(
92
94
  );
93
95
  }
94
96
  return { code: 200, message };
95
- } else if (command == "check") {
97
+ } else if (skill == "check") {
96
98
  const { domain } = params;
97
99
 
98
100
  if (!domain) {
@@ -117,7 +119,7 @@ export async function handleEns(
117
119
  message,
118
120
  };
119
121
  }
120
- } else if (command == "tip") {
122
+ } else if (skill == "tip") {
121
123
  const { address } = params;
122
124
  if (!address) {
123
125
  return {
@@ -126,15 +128,14 @@ export async function handleEns(
126
128
  };
127
129
  }
128
130
  const data = await getUserInfo(address);
129
- let txUrl = `${baseTxUrl}/transaction/?transaction_type=send&buttonName=Tip%20${data?.ensDomain ?? ""}&amount=1&token=USDC&receiver=${
130
- isAddress(address) ? address : data?.address
131
- }`;
132
- console.log(txUrl);
131
+
132
+ let sendUrl = `${txpayUrl}/?&amount=1&token=USDC&receiver=${address}`;
133
+
133
134
  return {
134
135
  code: 200,
135
- message: txUrl,
136
+ message: sendUrl,
136
137
  };
137
- } else if (command == "cool") {
138
+ } else if (skill == "cool") {
138
139
  const { domain } = params;
139
140
  //What about these cool alternatives?\
140
141
  return {
@@ -142,7 +143,7 @@ export async function handleEns(
142
143
  message: `${generateCoolAlternatives(domain)}`,
143
144
  };
144
145
  } else {
145
- return { code: 400, message: "Command not found." };
146
+ return { code: 400, message: "Skill not found." };
146
147
  }
147
148
  }
148
149
 
@@ -1,35 +1,22 @@
1
1
  import { run, HandlerContext } from "@xmtp/message-kit";
2
2
  import { textGeneration, processMultilineResponse } from "@xmtp/message-kit";
3
3
  import { agent_prompt } from "./prompt.js";
4
- import { getUserInfo } from "@xmtp/message-kit";
5
4
 
6
5
  run(async (context: HandlerContext) => {
7
- /*All the skills are handled through the skills file*/
8
- /* If its just text, it will be handled by the ensAgent*/
9
- /* If its a group message, it will be handled by the groupAgent*/
10
- if (!process?.env?.OPEN_AI_API_KEY) {
11
- console.warn("No OPEN_AI_API_KEY found in .env");
12
- return;
13
- }
14
-
15
6
  const {
16
7
  message: {
17
- content: { content, params },
8
+ content: { text, params },
18
9
  sender,
19
10
  },
20
11
  } = context;
21
12
 
22
13
  try {
23
- let userPrompt = params?.prompt ?? content;
24
- const userInfo = await getUserInfo(sender.address);
25
- if (!userInfo) {
26
- console.log("User info not found");
27
- return;
28
- }
14
+ let userPrompt = params?.prompt ?? text;
15
+
29
16
  const { reply } = await textGeneration(
30
17
  sender.address,
31
18
  userPrompt,
32
- await agent_prompt(userInfo),
19
+ await agent_prompt(sender.address),
33
20
  );
34
21
  await processMultilineResponse(sender.address, reply, context);
35
22
  } catch (error) {
@@ -1,57 +1,39 @@
1
1
  import { skills } from "./skills.js";
2
- import {
3
- getUserInfo,
4
- UserInfo,
5
- PROMPT_USER_CONTENT,
6
- PROMPT_RULES,
7
- PROMPT_SKILLS_AND_EXAMPLES,
8
- } from "@xmtp/message-kit";
9
-
10
- export async function agent_prompt(userInfo: UserInfo) {
11
- let { address, ensDomain, converseUsername, preferredName } = userInfo;
12
-
13
- //Update the name of the agent with predefined prompt
14
- let systemPrompt = PROMPT_RULES.replace("{NAME}", skills?.[0]?.tag ?? "@ens");
15
-
16
- //Add user context to the prompt
17
- systemPrompt += PROMPT_USER_CONTENT(userInfo);
18
-
19
- //Add skills and examples to the prompt
20
- systemPrompt += PROMPT_SKILLS_AND_EXAMPLES(skills, "@ens");
21
-
22
- systemPrompt += `
2
+ import { defaultPromptTemplate } from "@xmtp/message-kit";
23
3
 
4
+ export async function agent_prompt(senderAddress: string) {
5
+ let fineTuning = `
24
6
  ## Example responses:
25
7
 
26
8
  1. Check if the user does not have a ENS domain
27
- Hey ${preferredName}! it looks like you don't have a ENS domain yet! \n\Let me start by checking your Converse username with the .eth suffix\n/check ${converseUsername}.eth
9
+ Hey {PREFERRED_NAME}! it looks like you don't have a ENS domain yet! \n\Let me start by checking your Converse username with the .eth suffix\n/check {CONVERSE_USERNAME}.eth
28
10
 
29
11
  2. If the user has a ENS domain
30
- Hello ${preferredName} ! I'll help you get your ENS domain.\n Let's start by checking your ENS domain ${ensDomain}. Give me a moment.\n/check ${ensDomain}
12
+ Hello {PREFERRED_NAME} ! I'll help you get your ENS domain.\n Let's start by checking your ENS domain {ENS_DOMAIN}. Give me a moment.\n/check {ENS_DOMAIN}
31
13
 
32
14
  3. Check if the ENS domain is available
33
- Hello! I'll help you get your domain.\n Let's start by checking your ENS domain ${ensDomain}. Give me a moment.\n/check ${ensDomain}
15
+ Hello! I'll help you get your domain.\n Let's start by checking your ENS domain {ENS_DOMAIN}. Give me a moment.\n/check {ENS_DOMAIN}
34
16
 
35
17
  4. If the ENS domain is available,
36
- Looks like ${ensDomain} is available! Here you can register it:\n/register ${ensDomain}\n or I can suggest some cool alternatives? Le me know!
18
+ Looks like {ENS_DOMAIN} is available! Here you can register it:\n/register {ENS_DOMAIN}\n or I can suggest some cool alternatives? Le me know!
37
19
 
38
20
  5. If the ENS domain is already registered, let me suggest 5 cool alternatives
39
- Looks like ${ensDomain} is already registered!\n What about these cool alternatives?\n/cool ${ensDomain}
21
+ Looks like {ENS_DOMAIN} is already registered!\n What about these cool alternatives?\n/cool {ENS_DOMAIN}
40
22
 
41
23
  6. If the user wants to register a ENS domain, use the command "/register [domain]"
42
- Looks like ${ensDomain} is available! Let me help you register it\n/register ${ensDomain}
24
+ Looks like {ENS_DOMAIN} is available! Let me help you register it\n/register {ENS_DOMAIN}
43
25
 
44
- 7. If the user wants to directly to tip to the ENS domain owner, use directly the command "/tip [domain]", this will return a url but a button to send the tip
45
- Here is the url to send the tip:\n/tip ${ensDomain}
26
+ 7. If the user wants to directly to tip to the ENS domain owner, use directly the command "/tip [address]", this will return a url but a button to send the tip
27
+ Here is the url to send the tip:\n/tip 0x...
46
28
 
47
29
  8. If the user wants to get information about the ENS domain, use the command "/info [domain]"
48
- Hello! I'll help you get info about ${ensDomain}.\n Give me a moment.\n/info ${ensDomain}
30
+ Hello! I'll help you get info about {ENS_DOMAIN}.\n Give me a moment.\n/info {ENS_DOMAIN}
49
31
 
50
32
  9. If the user wants to renew their domain, use the command "/renew [domain]"
51
- Hello! I'll help you get your ENS domain.\n Let's start by checking your ENS domain ${ensDomain}. Give me a moment.\n/renew ${ensDomain}
33
+ Hello! I'll help you get your ENS domain.\n Let's start by checking your ENS domain {ENS_DOMAIN}. Give me a moment.\n/renew {ENS_DOMAIN}
52
34
 
53
35
  10. If the user wants cool suggestions about a domain, use the command "/cool [domain]"
54
- Here are some cool suggestions for your domain.\n/cool ${ensDomain}
36
+ Here are some cool suggestions for your domain.\n/cool {ENS_DOMAIN}
55
37
 
56
38
  ## Most common bugs
57
39
 
@@ -59,5 +41,6 @@ export async function agent_prompt(userInfo: UserInfo) {
59
41
  But you forgot to add the command at the end of the message.
60
42
  You should have said something like: "Looks like vitalik.eth is registered! What about these cool alternatives?\n/cool vitalik.eth
61
43
  `;
62
- return systemPrompt;
44
+
45
+ return defaultPromptTemplate(fineTuning, senderAddress, skills, "@ens");
63
46
  }
@@ -8,7 +8,7 @@ export const skills: SkillGroup[] = [
8
8
  description: "Register ENS domains.",
9
9
  skills: [
10
10
  {
11
- command: "/register [domain]",
11
+ skill: "/register [domain]",
12
12
  triggers: ["/register"],
13
13
  handler: handleEns,
14
14
  description:
@@ -21,20 +21,7 @@ export const skills: SkillGroup[] = [
21
21
  },
22
22
  },
23
23
  {
24
- command: "/exists",
25
- adminOnly: true,
26
- examples: ["/exists"],
27
- handler: handleEns,
28
- triggers: ["/exists"],
29
- description: "Check if an address is onboarded.",
30
- params: {
31
- address: {
32
- type: "address",
33
- },
34
- },
35
- },
36
- {
37
- command: "/info [domain]",
24
+ skill: "/info [domain]",
38
25
  triggers: ["/info"],
39
26
  handler: handleEns,
40
27
  description:
@@ -47,7 +34,7 @@ export const skills: SkillGroup[] = [
47
34
  },
48
35
  },
49
36
  {
50
- command: "/renew [domain]",
37
+ skill: "/renew [domain]",
51
38
  triggers: ["/renew"],
52
39
  handler: handleEns,
53
40
  description:
@@ -60,7 +47,7 @@ export const skills: SkillGroup[] = [
60
47
  },
61
48
  },
62
49
  {
63
- command: "/check [domain]",
50
+ skill: "/check [domain]",
64
51
  triggers: ["/check"],
65
52
  handler: handleEns,
66
53
  examples: ["/check vitalik.eth", "/check fabri.base.eth"],
@@ -72,7 +59,7 @@ export const skills: SkillGroup[] = [
72
59
  },
73
60
  },
74
61
  {
75
- command: "/cool [domain]",
62
+ skill: "/cool [domain]",
76
63
  triggers: ["/cool"],
77
64
  examples: ["/cool vitalik.eth"],
78
65
  handler: handleEns,
@@ -84,7 +71,7 @@ export const skills: SkillGroup[] = [
84
71
  },
85
72
  },
86
73
  {
87
- command: "/reset",
74
+ skill: "/reset",
88
75
  triggers: ["/reset"],
89
76
  examples: ["/reset"],
90
77
  handler: handleEns,
@@ -92,7 +79,7 @@ export const skills: SkillGroup[] = [
92
79
  params: {},
93
80
  },
94
81
  {
95
- command: "/tip [address]",
82
+ skill: "/tip [address]",
96
83
  description: "Show a URL for tipping a domain owner.",
97
84
  triggers: ["/tip"],
98
85
  handler: handleEns,
@@ -1 +1 @@
1
- KEY= # the private key of the bot wallet
1
+ KEY= # the private key of the agent wallet
@@ -1,9 +1,5 @@
1
1
  import { run, HandlerContext } from "@xmtp/message-kit";
2
2
 
3
3
  run(async (context: HandlerContext) => {
4
- // Get the message and the address from the sender
5
- const { content, sender } = context.message;
6
-
7
- // To reply, just call `reply` on the HandlerContext
8
- await context.send(`gm`);
4
+ context.send("gm");
9
5
  });
@@ -1,3 +1,2 @@
1
- KEY= # the private key of the bot wallet
2
- OPEN_AI_API_KEY= # openai api key
3
- STACK_API_KEY= # stack api key
1
+ KEY= # the private key of the agent wallet
2
+ OPEN_AI_API_KEY= # openai api key
@@ -1,14 +1,13 @@
1
1
  import { HandlerContext } from "@xmtp/message-kit";
2
2
 
3
- // Handler function to process game-related commands
3
+ // Handler function to process game-related
4
4
  export async function handler(context: HandlerContext) {
5
5
  const {
6
6
  message: {
7
- content: { command, params },
7
+ content: { skill, params, text },
8
8
  },
9
9
  } = context;
10
- if (!command) {
11
- const { content: text } = context?.message?.content;
10
+ if (!skill) {
12
11
  if (text === "🔎" || text === "🔍") {
13
12
  // Send the URL for the requested game
14
13
  context.reply("https://framedl.xyz/");
@@ -36,7 +35,7 @@ export async function handler(context: HandlerContext) {
36
35
  default:
37
36
  // Inform the user about unrecognized skills and provide available options
38
37
  context.send(
39
- "Command not recognized. Available games: wordle, slot, or help.",
38
+ "Skill not recognized. Available games: wordle, slot, or help.",
40
39
  );
41
40
  }
42
41
  }
@@ -3,22 +3,26 @@ import { HandlerContext } from "@xmtp/message-kit";
3
3
  export async function handler(context: HandlerContext) {
4
4
  const {
5
5
  skills,
6
- group,
7
6
  message: {
8
- content: { command },
7
+ content: { skill },
9
8
  },
9
+ group,
10
10
  } = context;
11
11
 
12
- if (command == "help") {
12
+ if (skill == "help") {
13
13
  const intro =
14
14
  "Available experiences:\n" +
15
15
  skills
16
16
  ?.flatMap((app) => app.skills)
17
- .map((skill) => `${skill.command} - ${skill.description}`)
17
+ .map((skill) => `${skill.skill} - ${skill.description}`)
18
18
  .join("\n") +
19
19
  "\nUse these skills to interact with specific apps.";
20
20
  context.send(intro);
21
- } else if (command == "id") {
22
- context.send(context.group?.id);
21
+ } else if (skill == "id") {
22
+ if (!group?.id) {
23
+ context.send("This skill only works in group chats.");
24
+ return;
25
+ }
26
+ context.send(group?.id);
23
27
  }
24
28
  }
@@ -0,0 +1,29 @@
1
+ import { getUserInfo, HandlerContext } from "@xmtp/message-kit";
2
+
3
+ export async function handler(context: HandlerContext) {
4
+ const {
5
+ message: {
6
+ content: { skill, params },
7
+ },
8
+ } = context;
9
+ const txpayUrl = "https://txpay.vercel.app";
10
+
11
+ if (skill === "pay") {
12
+ const { amount: amountSend, token: tokenSend, username } = params;
13
+ console.log("username", username);
14
+ let senderInfo = await getUserInfo(username);
15
+ if (!amountSend || !tokenSend || !senderInfo) {
16
+ context.reply(
17
+ "Missing required parameters. Please provide amount, token, and username.",
18
+ );
19
+ return {
20
+ code: 400,
21
+ message:
22
+ "Missing required parameters. Please provide amount, token, and username.",
23
+ };
24
+ }
25
+
26
+ let sendUrl = `${txpayUrl}/?&amount=${amountSend}&token=${tokenSend}&receiver=${senderInfo.address}`;
27
+ await context.send(`${sendUrl}`);
28
+ }
29
+ }
@@ -1,49 +1,31 @@
1
- import { HandlerContext, AbstractedMember } from "@xmtp/message-kit";
1
+ import {
2
+ HandlerContext,
3
+ AbstractedMember,
4
+ SkillResponse,
5
+ } from "@xmtp/message-kit";
2
6
  import { getUserInfo } from "@xmtp/message-kit";
3
7
 
4
8
  export async function handler(context: HandlerContext) {
5
9
  const {
6
- members,
7
- getMessageById,
8
- message: { content, sender, typeId },
10
+ message: {
11
+ content: {
12
+ skill,
13
+ params: { amount, username },
14
+ },
15
+ sender,
16
+ },
9
17
  } = context;
10
- const msg = await getMessageById(content.reference);
11
- const replyReceiver = members?.find(
12
- (member) => member.inboxId === msg?.senderInboxId,
13
- );
14
- let amount: number = 0,
15
- receivers: AbstractedMember[] = [];
16
- // Handle different types of messages
17
- if (typeId === "reply" && replyReceiver) {
18
- const { content: reply } = content;
19
-
20
- if (reply.includes("degen")) {
21
- receivers = [replyReceiver];
22
- const match = reply.match(/(\d+)/);
23
- if (match)
24
- amount = parseInt(match[0]); // Extract amount from reply
25
- else amount = 10;
26
- }
27
- } else if (typeId === "text") {
28
- const { content: text, params } = content;
29
- if (text.startsWith("/tip") && params) {
30
- // Process text skills starting with "/tip"
31
- const {
32
- params: { amount: extractedAmount, username },
33
- } = content;
34
- amount = extractedAmount || 10; // Default amount if not specified
18
+ let receivers: AbstractedMember[] = [];
35
19
 
36
- receivers = await Promise.all(
37
- username.map((username: string) => getUserInfo(username)),
38
- );
39
- }
20
+ if (skill === "tip") {
21
+ receivers = await Promise.all(
22
+ username.map((username: string) => getUserInfo(username)),
23
+ );
40
24
  }
41
25
  if (!sender || receivers.length === 0 || amount === 0) {
42
26
  context.reply("Sender or receiver or amount not found.");
43
- return;
44
27
  }
45
28
  const receiverAddresses = receivers.map((receiver) => receiver.address);
46
- // Process sending tokens to each receiver
47
29
 
48
30
  context.sendTo(
49
31
  `You received ${amount} tokens from ${sender.address}.`,