mastra-starter 1.0.5 → 1.0.7

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/.env.example ADDED
@@ -0,0 +1,2 @@
1
+ OPENAI_API_KEY=
2
+ COMPOSIO_API_KEY=
package/index.mjs CHANGED
@@ -6,7 +6,12 @@ import fs from 'fs';
6
6
  import { Command } from 'commander';
7
7
  import dotenv from 'dotenv';
8
8
 
9
- import { runCharacter, installPackages } from './util.mjs';
9
+ import {
10
+ runCharacter,
11
+ getPluginType,
12
+ installNpmPackages,
13
+ buildNpmPackages,
14
+ } from "./util.mjs";
10
15
 
11
16
  const main = async () => {
12
17
  dotenv.config();
@@ -42,7 +47,8 @@ const main = async () => {
42
47
  .argument('<packages...>', 'packages to install')
43
48
  .action(async (packages) => {
44
49
  try {
45
- await installPackages(packages);
50
+ await installNpmPackages(packages);
51
+ await buildNpmPackages(packages);
46
52
  } catch (error) {
47
53
  console.error(`Error in install command: ${error.message}`);
48
54
  }
@@ -64,7 +70,11 @@ const main = async () => {
64
70
  const characterJson = JSON.parse(characterJsonString);
65
71
 
66
72
  if (characterJson.plugins && Array.isArray(characterJson.plugins)) {
67
- characterJson.plugins.forEach(plugin => pluginsToInstall.add(plugin));
73
+ characterJson.plugins.forEach(plugin => {
74
+ if (getPluginType(plugin) === 'npm') {
75
+ pluginsToInstall.add(plugin);
76
+ }
77
+ });
68
78
  }
69
79
  }
70
80
 
@@ -73,13 +83,63 @@ const main = async () => {
73
83
  return;
74
84
  }
75
85
 
76
- await installPackages([...pluginsToInstall]);
86
+ await installNpmPackages([...pluginsToInstall]);
87
+ await buildNpmPackages([...pluginsToInstall]);
77
88
  } catch (error) {
78
89
  console.error(`Error in installall command: ${error.message}`);
79
90
  }
80
91
  process.exit(1);
81
92
  });
82
93
 
94
+ program
95
+ .command('build')
96
+ .alias('b')
97
+ .description('Build packages without installing them')
98
+ .argument('<packages...>', 'packages to build')
99
+ .action(async (packages) => {
100
+ try {
101
+ await buildNpmPackages(packages);
102
+ } catch (error) {
103
+ console.error(`Error in build command: ${error.message}`);
104
+ }
105
+ process.exit(1);
106
+ });
107
+
108
+ program
109
+ .command('buildall')
110
+ .alias('ba')
111
+ .description('Build all plugins from character.json files')
112
+ .argument('<files...>', 'character.json file paths')
113
+ .action(async (files) => {
114
+ try {
115
+ const pluginsToBuild = new Set();
116
+
117
+ for (const file of files) {
118
+ const characterJsonPath = path.resolve(process.cwd(), file);
119
+ const characterJsonString = await fs.promises.readFile(characterJsonPath, 'utf8');
120
+ const characterJson = JSON.parse(characterJsonString);
121
+
122
+ if (characterJson.plugins && Array.isArray(characterJson.plugins)) {
123
+ characterJson.plugins.forEach(plugin => {
124
+ if (getPluginType(plugin) === 'npm') {
125
+ pluginsToBuild.add(plugin);
126
+ }
127
+ });
128
+ }
129
+ }
130
+
131
+ if (pluginsToBuild.size === 0) {
132
+ console.log('No plugins found to build');
133
+ return;
134
+ }
135
+
136
+ await buildNpmPackages([...pluginsToBuild]);
137
+ } catch (error) {
138
+ console.error(`Error in buildall command: ${error.message}`);
139
+ }
140
+ process.exit(1);
141
+ });
142
+
83
143
  program.parse(process.argv);
84
144
  };
85
145
  (async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mastra-starter",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "main": "index.mjs",
5
5
  "bin": {
6
6
  "mastra-starter": "./index.mjs"
@@ -15,13 +15,14 @@
15
15
  "type": "module",
16
16
  "dependencies": {
17
17
  "@ai-sdk/openai": "^1.2.2",
18
+ "@mastra/composio": "^0.1.9",
18
19
  "@mastra/core": "^0.5.0",
19
20
  "@mastra/mcp": "^0.3.0",
20
21
  "commander": "^13.1.0",
21
22
  "dedent": "^1.5.3",
22
23
  "dotenv": "^16.4.7",
23
24
  "mastra": "^0.3.0",
24
- "pnpm-package-lookup": "^0.0.1",
25
+ "pnpm-package-lookup": "^0.0.2",
25
26
  "yaml": "^2.7.0",
26
27
  "zod": "^3.24.2"
27
28
  },
@@ -1,22 +1,31 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { openai } from '@ai-sdk/openai';
4
- import { Agent } from '@mastra/core/agent';
4
+ import { Agent, ToolsInput } from '@mastra/core/agent';
5
5
  import dedent from 'dedent';
6
6
  import { MCPConfiguration } from "@mastra/mcp";
7
+ import { ComposioIntegration } from '@mastra/composio';
8
+ import { sortPlugins } from '../../../util.mjs';
7
9
  import { PnpmPackageLookup } from 'pnpm-package-lookup';
8
10
 
11
+ // character
9
12
  const packageLookup = new PnpmPackageLookup({
10
13
  pnpmLockYamlPath: path.join('..', '..', 'pnpm-lock.yaml'),
11
14
  });
12
-
13
15
  const characterJsonPath = process.env._CHARACTER_JSON_PATH as string;
14
16
  const characterJsonString = await fs.promises.readFile(characterJsonPath, 'utf8');
15
17
  const characterJson = JSON.parse(characterJsonString);
18
+
19
+ // sort plugins
16
20
  const { plugins = [] } = characterJson;
21
+ const {
22
+ npm: npmPlugins,
23
+ composio: composioPlugins,
24
+ } = sortPlugins(plugins);
17
25
 
26
+ // resolve npm plugins
18
27
  const servers: Record<string, any> = {};
19
- for (const plugin of plugins) {
28
+ for (const plugin of npmPlugins) {
20
29
  // find the package name matching this specifier
21
30
  const packageName = await packageLookup.getPackageNameBySpecifier(plugin);
22
31
  if (!packageName) {
@@ -30,15 +39,41 @@ for (const plugin of plugins) {
30
39
  env: process.env as any,
31
40
  };
32
41
  }
42
+
43
+ // mcp tools
33
44
  const mcp = new MCPConfiguration({
34
45
  servers,
35
46
  });
47
+ const mcpTools = await mcp.getTools();
48
+
49
+ // composio tools
50
+ const composio = new ComposioIntegration({
51
+ config: {
52
+ API_KEY: process.env.COMPOSIO_API_KEY!,
53
+ entityId: 'default',
54
+ // connectedAccountId: '899144e5-a466-428b-8a00-7c931fb57f9f',
55
+ connectedAccountId: '4d79004e-320a-4dc9-be1a-1037a6fe9866',
56
+ },
57
+ });
58
+ // const actionsEnums = [
59
+ // 'GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER',
60
+ // 'GITHUB_ACTIVITY_LIST_STARGAZERS_FOR_REPO',
61
+ // 'GITHUB_GET_OCTOCAT',
62
+ // ];
63
+ const actionsEnums = composioPlugins.map((plugin) => plugin.replace('composio:', ''));
64
+ const composioToolset = await composio.getTools({
65
+ actions: actionsEnums,
66
+ }) as ToolsInput;
36
67
 
68
+ // agent
37
69
  export const characterAgent = new Agent({
38
70
  name: "Character",
39
71
  instructions: dedent`\
40
72
  You are the following character:
41
73
  ` + '\n' + JSON.stringify(characterJson, null, 2),
42
74
  model: openai("gpt-4o"),
43
- tools: { ...(await mcp.getTools()) },
75
+ tools: { // ToolsInput = string -> ToolAction
76
+ ...mcpTools,
77
+ ...composioToolset,
78
+ },
44
79
  });
@@ -10,7 +10,10 @@
10
10
  }
11
11
  },
12
12
  "plugins": [
13
- "github:v-3/discordmcp"
13
+ "github:v-3/discordmcp",
14
+ "composio:GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER",
15
+ "composio:GITHUB_ACTIVITY_LIST_STARGAZERS_FOR_REPO",
16
+ "composio:GITHUB_GET_OCTOCAT"
14
17
  ],
15
18
  "bio": [
16
19
  "secured the Southern Border COMPLETELY (until they DESTROYED it)",
package/util.mjs CHANGED
@@ -1,4 +1,6 @@
1
+ import path from 'path';
1
2
  import child_process from "child_process";
3
+ import { PnpmPackageLookup } from 'pnpm-package-lookup';
2
4
 
3
5
  export const runCharacter = async (characterJsonPath, {
4
6
  env = {},
@@ -27,7 +29,32 @@ export const runCharacter = async (characterJsonPath, {
27
29
  });
28
30
  });
29
31
  };
30
- export const installPackages = async (packageSpecifiers) => {
32
+
33
+ export const getPluginType = (plugin) => {
34
+ if (plugin.startsWith('composio:')) {
35
+ return 'composio';
36
+ } else {
37
+ return 'npm';
38
+ }
39
+ };
40
+ export const sortPlugins = (plugins) => {
41
+ const npm = [];
42
+ const composio = [];
43
+ for (const plugin of plugins) {
44
+ const pluginType = getPluginType(plugin);
45
+ if (pluginType === 'npm') {
46
+ npm.push(plugin);
47
+ } else if (pluginType === 'composio') {
48
+ composio.push(plugin);
49
+ }
50
+ }
51
+ return {
52
+ npm,
53
+ composio,
54
+ };
55
+ };
56
+
57
+ export const installNpmPackages = (packageSpecifiers) => {
31
58
  console.log(`Installing packages: ${packageSpecifiers.join(", ")}`);
32
59
 
33
60
  return new Promise((resolve, reject) => {
@@ -51,3 +78,58 @@ export const installPackages = async (packageSpecifiers) => {
51
78
  });
52
79
  });
53
80
  };
81
+ export const buildNpmPackages = async (packageSpecifiers) => {
82
+ console.log(`Building packages: ${packageSpecifiers.join(", ")}`);
83
+
84
+ // get the packagePaths from the packageSpecifiers
85
+ const packageLookup = new PnpmPackageLookup({
86
+ pnpmLockYamlPath: path.resolve(process.cwd(), 'pnpm-lock.yaml'),
87
+ });
88
+ const packagePaths = await Promise.all(packageSpecifiers.map(async (packageSpecifier) => {
89
+ return await packageLookup.getPackageNameBySpecifier(packageSpecifier);
90
+ }));
91
+
92
+ const results = [];
93
+ let allSuccessful = true;
94
+
95
+ for (const packagePath of packagePaths) {
96
+ console.log(`Building package: ${packagePath}`);
97
+
98
+ try {
99
+ const p = path.resolve(process.cwd(), 'node_modules', packagePath);
100
+ const cp = child_process.spawn("pnpm", ["build"], {
101
+ stdio: "inherit",
102
+ cwd: p,
103
+ env: { ...process.env },
104
+ });
105
+
106
+ const result = await new Promise((resolveSpawn, rejectSpawn) => {
107
+ cp.on("error", (error) => {
108
+ console.error(`Error executing pnpm build for ${packagePath}: ${error.message}`);
109
+ resolveSpawn({ success: false, package: packagePath, error: error.message });
110
+ });
111
+
112
+ cp.on("close", (code) => {
113
+ if (code !== 0) {
114
+ console.error(`pnpm build for ${packagePath} exited with code ${code}`);
115
+ resolveSpawn({ success: false, package: packagePath, error: `exited with code ${code}` });
116
+ } else {
117
+ console.log(`Build completed successfully for ${packagePath}`);
118
+ resolveSpawn({ success: true, package: packagePath });
119
+ }
120
+ });
121
+ });
122
+
123
+ results.push(result);
124
+ if (!result.success) {
125
+ allSuccessful = false;
126
+ }
127
+ } catch (error) {
128
+ console.log('error', error);
129
+ results.push({ success: false, package: packagePath, error: error.message });
130
+ allSuccessful = false;
131
+ }
132
+ }
133
+
134
+ return { success: allSuccessful, results };
135
+ };