@xalia/agent 0.5.0

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.
Files changed (66) hide show
  1. package/.prettierrc.json +11 -0
  2. package/README.md +56 -0
  3. package/dist/agent.js +238 -0
  4. package/dist/agentUtils.js +106 -0
  5. package/dist/chat.js +296 -0
  6. package/dist/dummyLLM.js +38 -0
  7. package/dist/files.js +115 -0
  8. package/dist/iplatform.js +2 -0
  9. package/dist/llm.js +2 -0
  10. package/dist/main.js +147 -0
  11. package/dist/mcpServerManager.js +278 -0
  12. package/dist/nodePlatform.js +61 -0
  13. package/dist/openAILLM.js +38 -0
  14. package/dist/openAILLMStreaming.js +431 -0
  15. package/dist/options.js +79 -0
  16. package/dist/prompt.js +83 -0
  17. package/dist/sudoMcpServerManager.js +183 -0
  18. package/dist/test/imageLoad.test.js +14 -0
  19. package/dist/test/mcpServerManager.test.js +71 -0
  20. package/dist/test/prompt.test.js +26 -0
  21. package/dist/test/sudoMcpServerManager.test.js +49 -0
  22. package/dist/tokenAuth.js +39 -0
  23. package/dist/tools.js +44 -0
  24. package/eslint.config.mjs +25 -0
  25. package/frog.png +0 -0
  26. package/package.json +42 -0
  27. package/scripts/git_message +31 -0
  28. package/scripts/git_wip +21 -0
  29. package/scripts/pr_message +18 -0
  30. package/scripts/pr_review +16 -0
  31. package/scripts/sudomcp_import +23 -0
  32. package/scripts/test_script +60 -0
  33. package/src/agent.ts +283 -0
  34. package/src/agentUtils.ts +198 -0
  35. package/src/chat.ts +346 -0
  36. package/src/dummyLLM.ts +50 -0
  37. package/src/files.ts +95 -0
  38. package/src/iplatform.ts +17 -0
  39. package/src/llm.ts +15 -0
  40. package/src/main.ts +187 -0
  41. package/src/mcpServerManager.ts +371 -0
  42. package/src/nodePlatform.ts +24 -0
  43. package/src/openAILLM.ts +51 -0
  44. package/src/openAILLMStreaming.ts +528 -0
  45. package/src/options.ts +103 -0
  46. package/src/prompt.ts +93 -0
  47. package/src/sudoMcpServerManager.ts +278 -0
  48. package/src/test/imageLoad.test.ts +14 -0
  49. package/src/test/mcpServerManager.test.ts +98 -0
  50. package/src/test/prompt.test.src +0 -0
  51. package/src/test/prompt.test.ts +26 -0
  52. package/src/test/sudoMcpServerManager.test.ts +65 -0
  53. package/src/tokenAuth.ts +50 -0
  54. package/src/tools.ts +57 -0
  55. package/test_data/background_test_profile.json +6 -0
  56. package/test_data/background_test_script.json +11 -0
  57. package/test_data/dummyllm_script_simplecalc.json +28 -0
  58. package/test_data/git_message_profile.json +4 -0
  59. package/test_data/git_wip_system.txt +5 -0
  60. package/test_data/pr_message_profile.json +4 -0
  61. package/test_data/pr_review_profile.json +4 -0
  62. package/test_data/prompt_simplecalc.txt +1 -0
  63. package/test_data/simplecalc_profile.json +4 -0
  64. package/test_data/sudomcp_import_profile.json +4 -0
  65. package/test_data/test_script_profile.json +8 -0
  66. package/tsconfig.json +13 -0
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SudoMcpServerManager = exports.LOCAL_SERVER_URL = void 0;
4
+ const sdk_1 = require("@xalia/xmcp/sdk");
5
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
6
+ const logger = (0, sdk_1.getLogger)();
7
+ exports.LOCAL_SERVER_URL = "http://localhost:5001";
8
+ /**
9
+ * ServerBrief with sanitized name, and original name in another field.
10
+ */
11
+ class SanitizedServerBrief extends sdk_1.McpServerBrief {
12
+ constructor() {
13
+ super("dummy", "dummy", "dummy", false, {}, "dummy", "dummy");
14
+ this.originalName = "dummy";
15
+ }
16
+ static fromServerBrief(brief) {
17
+ const b = brief;
18
+ const origName = brief.name;
19
+ b.originalName = origName; // eslint-disable-line
20
+ brief.name = sanitizeName(origName);
21
+ return b;
22
+ }
23
+ }
24
+ /**
25
+ * Manages access to the catalogue of servers hosted by sudomcp. Supports
26
+ * adding these servers to McpServerManager.
27
+ */
28
+ class SudoMcpServerManager {
29
+ constructor(mcpServerManager, apiClient, serverBriefs, serverBriefsMap, toolCache, openUrl,
30
+ // Redirect to this page after successful authorization
31
+ authorized_url) {
32
+ this.mcpServerManager = mcpServerManager;
33
+ this.apiClient = apiClient;
34
+ this.serverBriefs = serverBriefs;
35
+ this.serverBriefsMap = serverBriefsMap;
36
+ this.toolCache = toolCache;
37
+ this.openUrl = openUrl;
38
+ this.authorized_url = authorized_url;
39
+ }
40
+ /**
41
+ * Initialize an ApiClient to interface with SudoMCP backend and
42
+ * fetch the current list of ServerBriefs.
43
+ */
44
+ static async initialize(mcpServerManager, openUrl, sudoMcpUrl, sudoMcpApiKey, authorized_url) {
45
+ // TODO: Keep it on here and pass to `McpServerManager.addMcpServer`
46
+ const apiClient = new sdk_1.ApiClient(sudoMcpUrl ?? sdk_1.DEFAULT_SERVER_URL, sudoMcpApiKey ?? "dummy_key");
47
+ // Fetch server list
48
+ const servers = await apiClient.listServers();
49
+ const [mcpServers, mcpServersMap] = buildServersList(servers);
50
+ return new SudoMcpServerManager(mcpServerManager, apiClient, mcpServers, mcpServersMap, {}, openUrl, authorized_url);
51
+ }
52
+ /// TODO: Bit awkward that we have to restore via this class, but it's the
53
+ /// only class which knows how to restore (restart) the mcp servers.
54
+ async restoreMcpSettings(mcpSettings) {
55
+ await this.restoreConfiguration(mcpSettings);
56
+ }
57
+ /**
58
+ * Load the configuration from sudomcp, and enable the specified tools.
59
+ */
60
+ async restoreConfiguration(mcpConfig) {
61
+ logger.debug("Restoring Mcp config");
62
+ // Concurrently establish all server connections
63
+ const addServer = async (serverName) => {
64
+ logger.debug(`restoring ${serverName} ...`);
65
+ return this.addMcpServer(serverName);
66
+ };
67
+ await Promise.all(Object.entries(mcpConfig).map((e) => addServer(e[0])));
68
+ // Enable tools
69
+ const enableTools = ([serverName, enabled]) => {
70
+ // Migrate the old style: { [tool: string]: true } to the new list format
71
+ if (!(enabled instanceof Array)) {
72
+ enabled = Object.keys(enabled);
73
+ }
74
+ if (enabled.length === 0) {
75
+ logger.debug(` restoring "${serverName}": (all tools)`);
76
+ this.mcpServerManager.enableAllTools(serverName);
77
+ return;
78
+ }
79
+ logger.debug(` restoring "${serverName}": ${JSON.stringify(enabled)}`);
80
+ for (const toolName of enabled) {
81
+ this.mcpServerManager.enableTool(serverName, toolName);
82
+ }
83
+ };
84
+ Object.entries(mcpConfig).map((e) => enableTools(e));
85
+ }
86
+ /**
87
+ * Query backend for server list, clear tool cache.
88
+ */
89
+ async refresh() {
90
+ const servers = await this.apiClient.listServers();
91
+ const [mcpServers, mcpServersMap] = buildServersList(servers);
92
+ this.serverBriefs = mcpServers;
93
+ this.serverBriefsMap = mcpServersMap;
94
+ this.toolCache = {};
95
+ }
96
+ getServerBriefs() {
97
+ return this.serverBriefs;
98
+ }
99
+ getMcpServerManager() {
100
+ return this.mcpServerManager;
101
+ }
102
+ /**
103
+ * Return tool list for a given MCP server. Queries the backend
104
+ * if necessary and caches the result.
105
+ */
106
+ async getServerTools(serverName) {
107
+ // Check cache
108
+ let tools = this.toolCache[serverName];
109
+ if (tools) {
110
+ return tools;
111
+ }
112
+ // Query backend (using the original name)
113
+ const originalName = this.serverBriefsMap[serverName].originalName;
114
+ tools = await this.apiClient.listTools(originalName);
115
+ this.toolCache[serverName] = tools;
116
+ return tools;
117
+ }
118
+ /**
119
+ * Add a server to the `McpServerManager`, using `ApiClient`
120
+ * to produce the transport. Validates the server's config
121
+ * schema, if applicable.
122
+ */
123
+ async addMcpServer(serverName) {
124
+ const tools = await this.getServerTools(serverName);
125
+ const originalName = this.serverBriefsMap[serverName].originalName;
126
+ const mcpserver = await this.apiClient.getDetails(originalName, "run");
127
+ const client = new index_js_1.Client({
128
+ name: "@xalia/agent",
129
+ version: "1.0.0",
130
+ });
131
+ await connectServer(client, this.apiClient, mcpserver, this.openUrl, this.authorized_url);
132
+ await this.mcpServerManager.addMcpServerWithClient(client, serverName, tools);
133
+ }
134
+ getOriginalName(serverName) {
135
+ return this.serverBriefsMap[serverName].name;
136
+ }
137
+ getApiClient() {
138
+ return this.apiClient;
139
+ }
140
+ }
141
+ exports.SudoMcpServerManager = SudoMcpServerManager;
142
+ /**
143
+ * Connect a client to a hosted MCP server session,
144
+ * prompting for authentication if needed.
145
+ */
146
+ async function connectServer(client, apiClient, mcpServer, openUrl, authorized_url, noRetry = false) {
147
+ const transport = apiClient.mcpSession(mcpServer);
148
+ await client.connect(transport).catch(async (e) => {
149
+ if (e instanceof sdk_1.AuthenticationRequired && !noRetry) {
150
+ logger.info("authentication required: " + e.msg);
151
+ const { url, authenticatedP } = await apiClient.authenticate(mcpServer.name, authorized_url);
152
+ logger.info(`authenticate at url: ${url}`);
153
+ openUrl(url, authenticatedP, mcpServer.title);
154
+ const authResult = await authenticatedP;
155
+ logger.info(`authResult: ${authResult}`);
156
+ if (!authResult) {
157
+ throw "authentication failed";
158
+ }
159
+ return connectServer(client, apiClient, mcpServer, openUrl, authorized_url, true);
160
+ }
161
+ else {
162
+ throw e;
163
+ }
164
+ });
165
+ }
166
+ /**
167
+ * Given a list of`ServerBrief` objects, create the corresponding list and map
168
+ * of `SantiizedServerBrief` objects (namely, objects with sanitized names,
169
+ * holding the original name in a new field).
170
+ */
171
+ function buildServersList(serverList) {
172
+ const servers = [];
173
+ const serversMap = {};
174
+ for (const s of serverList) {
175
+ const ss = SanitizedServerBrief.fromServerBrief(s);
176
+ servers.push(ss);
177
+ serversMap[ss.name] = ss;
178
+ }
179
+ return [servers, serversMap];
180
+ }
181
+ function sanitizeName(name) {
182
+ return name.replace("/", "_");
183
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chai_1 = require("chai");
4
+ const files_1 = require("../files");
5
+ const assert_1 = require("assert");
6
+ describe("Image loading", () => {
7
+ it("convert to data url", async function () {
8
+ const imageB64 = (0, files_1.loadImageB64OrUndefined)("frog.png");
9
+ // console.log(`imageB64: ${imageB64}`);
10
+ (0, chai_1.expect)(imageB64).to.be.a("string");
11
+ (0, assert_1.strict)(typeof imageB64 === "string");
12
+ (0, chai_1.expect)(imageB64.startsWith("data:image/png;base64")).eql(true);
13
+ });
14
+ });
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chai_1 = require("chai");
4
+ const mcpServerManager_1 = require("../mcpServerManager");
5
+ // Handle automatically closing at the end of tests.
6
+ let managers = {};
7
+ let idx = 0;
8
+ function getMcpServerManager() {
9
+ const tm = new mcpServerManager_1.McpServerManager();
10
+ const name = "mgr" + ++idx;
11
+ managers[name] = tm;
12
+ return tm;
13
+ }
14
+ async function shutdownAll() {
15
+ for (const [k, v] of Object.entries(managers)) {
16
+ console.log(`shutting down ${k}`);
17
+ await v.shutdown();
18
+ }
19
+ managers = {};
20
+ }
21
+ describe("McpServerManager", async () => {
22
+ it("should initialize with correct descriptions", async () => {
23
+ const tm = getMcpServerManager();
24
+ await tm.addMcpServer("simplecalc", "http://localhost:5001/mcpservers/sudomcp/simplecalc/session", "dummy_key");
25
+ const server = tm.getMcpServer("simplecalc");
26
+ const availableTools = server.getTools();
27
+ (0, chai_1.expect)(availableTools.length).greaterThan(0);
28
+ // Initially, no tools are enabled.
29
+ (0, chai_1.expect)(tm.getOpenAITools().length).equal(0);
30
+ // Enable a tool and check we get a description for it.
31
+ const toolName = availableTools[0].name;
32
+ {
33
+ tm.enableTool("simplecalc", toolName);
34
+ const tools = tm.getOpenAITools();
35
+ (0, chai_1.expect)(tools.length).greaterThan(0);
36
+ console.log(`tools: ${JSON.stringify(tools, undefined, 2)}`);
37
+ }
38
+ // Invoke
39
+ {
40
+ const qualifiedName = tm.getOpenAITools()[0].function.name;
41
+ const r = await tm.invoke(qualifiedName, { a: 1000, b: 10 });
42
+ console.log(`response: ${r}`);
43
+ }
44
+ // Disable and check we don't get the spec anymore
45
+ {
46
+ tm.disableTool("simplecalc", toolName);
47
+ const tools = tm.getOpenAITools();
48
+ (0, chai_1.expect)(tools.length).equal(0);
49
+ }
50
+ }).timeout(10000);
51
+ it("qualified names", async () => {
52
+ const serverName = "server";
53
+ const toolName = "tool";
54
+ const qualifiedName = (0, mcpServerManager_1.computeQualifiedName)(serverName, toolName);
55
+ const [_serverName, _toolName] = (0, mcpServerManager_1.splitQualifiedName)(qualifiedName);
56
+ (0, chai_1.expect)(_serverName).eql(serverName);
57
+ (0, chai_1.expect)(_toolName).eql(toolName);
58
+ });
59
+ it("add / remove servers", async () => {
60
+ const tm = getMcpServerManager();
61
+ await tm.addMcpServer("simplecalc", "http://localhost:5001/mcpservers/sudomcp/simplecalc/session", "dummy_key");
62
+ tm.enableAllTools("simplecalc");
63
+ (0, chai_1.expect)(tm.getOpenAITools().length).greaterThan(0);
64
+ // Remove server and check there is no server, and no openai entries.
65
+ await tm.removeMcpServer("simplecalc");
66
+ (0, chai_1.expect)(tm.getOpenAITools().length).equal(0);
67
+ (0, chai_1.expect)(() => {
68
+ tm.getMcpServer("simplecalc");
69
+ }).throws();
70
+ });
71
+ }).afterAll(shutdownAll);
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chai_1 = require("chai");
4
+ const prompt_1 = require("../prompt");
5
+ describe("Prompt", () => {
6
+ it("should recognise commands", async function () {
7
+ const expectedResults = {
8
+ "some text ": { msg: "some text", cmds: undefined },
9
+ ":i image.png some text": { msg: "some text", cmds: ["i", "image.png"] },
10
+ ":i image.png": { msg: undefined, cmds: ["i", "image.png"] },
11
+ ":l": { msg: undefined, cmds: ["l"] },
12
+ ":e serverName toolName": {
13
+ msg: undefined,
14
+ cmds: ["e", "serverName", "toolName"],
15
+ },
16
+ ":ea serverName": {
17
+ msg: undefined,
18
+ cmds: ["ea", "serverName"],
19
+ },
20
+ };
21
+ for (const [prompt, expected] of Object.entries(expectedResults)) {
22
+ const res = (0, prompt_1.parsePrompt)(prompt);
23
+ (0, chai_1.expect)(res).eql(expected);
24
+ }
25
+ });
26
+ });
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.prettyPrintTool = prettyPrintTool;
7
+ const chai_1 = require("chai");
8
+ const mcpServerManager_1 = require("../mcpServerManager");
9
+ const sudoMcpServerManager_1 = require("../sudoMcpServerManager");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ let managers = undefined;
12
+ async function getServerManagers() {
13
+ if (!managers) {
14
+ const tm = new mcpServerManager_1.McpServerManager();
15
+ const sm = await sudoMcpServerManager_1.SudoMcpServerManager.initialize(tm, (_url) => {
16
+ throw "unexpected call to openUrl";
17
+ }, sudoMcpServerManager_1.LOCAL_SERVER_URL, "dummy_key");
18
+ managers = [tm, sm];
19
+ }
20
+ return managers;
21
+ }
22
+ async function shutdownAll() {
23
+ if (managers) {
24
+ await managers[0].shutdown();
25
+ }
26
+ managers = undefined;
27
+ }
28
+ describe("SudoMcpServerManager", async () => {
29
+ it("should fetch servers from deployed backend", async () => {
30
+ const [, sm] = await getServerManagers();
31
+ const serverBriefs = sm.getServerBriefs();
32
+ (0, chai_1.expect)(serverBriefs.length).greaterThan(0);
33
+ }).timeout(10000);
34
+ it("should fetch tools for a server", async () => {
35
+ const [, sm] = await getServerManagers();
36
+ const tools = await sm.getServerTools("sudomcp_simplecalc");
37
+ (0, chai_1.expect)(tools.length).greaterThan(0);
38
+ }).timeout(10000);
39
+ it("should add a new MCP server", async () => {
40
+ const [, sm] = await getServerManagers();
41
+ await sm.addMcpServer("sudomcp_simplecalc");
42
+ const serverBriefs = sm.getServerBriefs();
43
+ (0, chai_1.expect)(serverBriefs.some((brief) => brief.name === "sudomcp_simplecalc")).eql(true);
44
+ }).timeout(20000);
45
+ }).afterAll(shutdownAll);
46
+ function prettyPrintTool(tool) {
47
+ console.log(`- ${chalk_1.default.green(tool.name)}:`);
48
+ console.log(` ${chalk_1.default.italic(tool.description)}\n`);
49
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TokenAuth = void 0;
4
+ class TokenAuth {
5
+ constructor(token) {
6
+ this.token = token;
7
+ }
8
+ get redirectUrl() {
9
+ throw "unimpl";
10
+ }
11
+ get clientMetadata() {
12
+ throw "unimpl";
13
+ }
14
+ clientInformation() {
15
+ return undefined;
16
+ }
17
+ saveClientInformation(_clientInformation) {
18
+ throw "unimpl";
19
+ }
20
+ tokens() {
21
+ return {
22
+ access_token: this.token,
23
+ token_type: "bearer",
24
+ };
25
+ }
26
+ saveTokens(_tokens) {
27
+ throw "unimpl";
28
+ }
29
+ redirectToAuthorization(_authorizationUrl) {
30
+ throw "unimpl";
31
+ }
32
+ saveCodeVerifier(_codeVerifier) {
33
+ throw "unimpl";
34
+ }
35
+ codeVerifier() {
36
+ throw "unimpl";
37
+ }
38
+ }
39
+ exports.TokenAuth = TokenAuth;
package/dist/tools.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolCallbacks = exports.temperatureTool = void 0;
4
+ exports.displayToolCall = displayToolCall;
5
+ exports.temperatureTool = {
6
+ type: "function",
7
+ function: {
8
+ name: "getCurrentTemperature",
9
+ description: "Get the current temperature for a specific location",
10
+ parameters: {
11
+ type: "object",
12
+ properties: {
13
+ location: {
14
+ type: "string",
15
+ description: "The city and state, e.g., San Francisco, CA",
16
+ },
17
+ unit: {
18
+ type: "string",
19
+ enum: ["Celsius", "Fahrenheit"],
20
+ description: "The temperature unit to use. Infer this from the user's location.",
21
+ },
22
+ },
23
+ required: ["location", "unit"],
24
+ },
25
+ },
26
+ };
27
+ function isTemperatureArgs(args) {
28
+ return (typeof args === "object" &&
29
+ args !== null &&
30
+ ("location" in args || "unit" in args));
31
+ }
32
+ // Handle non-MCP tools
33
+ exports.toolCallbacks = {
34
+ getCurrentTemperature: (args) => {
35
+ if (!isTemperatureArgs(args) || !args.location) {
36
+ return `Location required`;
37
+ }
38
+ return `The temperature in ${args.location} is 22 degrees ${args.unit}`;
39
+ },
40
+ };
41
+ function displayToolCall(toolCall) {
42
+ console.log(`AGENT: Tool Call: ${toolCall.function.name}`);
43
+ console.log(` Args: ${toolCall.function.arguments}`);
44
+ }
@@ -0,0 +1,25 @@
1
+ import eslint from '@eslint/js';
2
+ import tseslint from 'typescript-eslint';
3
+
4
+ export default tseslint.config(
5
+ eslint.configs.recommended,
6
+ tseslint.configs.recommended,
7
+ {
8
+ "rules": {
9
+ "@typescript-eslint/no-unused-vars": [
10
+ "error",
11
+ {
12
+ "args": "all",
13
+ "argsIgnorePattern": "^_",
14
+ "caughtErrors": "all",
15
+ "caughtErrorsIgnorePattern": "^_",
16
+ "destructuredArrayIgnorePattern": "^_",
17
+ "varsIgnorePattern": "^_",
18
+ "ignoreRestSiblings": true
19
+ }
20
+ ],
21
+ "max-len": ["error", { code: 80 }],
22
+ "linebreak-style": ["error", "unix"]
23
+ }
24
+ }
25
+ );
package/frog.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@xalia/agent",
3
+ "version": "0.5.0",
4
+ "keywords": [],
5
+ "author": "",
6
+ "license": "ISC",
7
+ "description": "",
8
+ "engines": {
9
+ "node": ">=20.0.0"
10
+ },
11
+ "bin": {
12
+ "agent": "dist/main.js"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc && node -e \"require('fs').chmodSync('dist/main.js', '755')\"",
16
+ "lint": "eslint src && yarn prettier --check src/**/*.ts",
17
+ "format": "yarn prettier --write src/**/*.ts",
18
+ "test": "yarn --emoji false build && mocha dist/test/**.js --reporter-option maxDiffSize=0"
19
+ },
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "=1.11.1",
22
+ "@types/readline-sync": "^1.4.8",
23
+ "chalk": "^4.1.2",
24
+ "cmd-ts": "^0.13.0",
25
+ "dotenv": "^16.5.0",
26
+ "openai": "=4.98.0",
27
+ "readline-sync": "^1.4.10",
28
+ "yocto-spinner": "^0.2.2"
29
+ },
30
+ "devDependencies": {
31
+ "@eslint/js": "^9.24.0",
32
+ "@types/chai": "^4.0.0",
33
+ "@types/mocha": "^10.0.10",
34
+ "@types/node": "^22.13.9",
35
+ "chai": "^4.0.0",
36
+ "eslint": "^9.24.0",
37
+ "mocha": "^11.1.0",
38
+ "prettier": "3.5.3",
39
+ "typescript": "^5.8.3",
40
+ "typescript-eslint": "^8.29.1"
41
+ }
42
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env bash
2
+
3
+ this_dir=`dirname ${BASH_SOURCE[0]}`
4
+ this_dir=`realpath ${this_dir}`
5
+ client=${this_dir}/../dist/main.js
6
+
7
+ prompt=/tmp/git_message_prompt.txt
8
+ msg=/tmp/git_message.txt
9
+
10
+ while [[ "$#" -gt 0 ]]; do
11
+ case "$1" in
12
+ -n) dry_run=1 ;;
13
+ *) echo "Unknown parameter: $1" ; exit 1 ;;
14
+ esac
15
+ shift
16
+ done
17
+
18
+ # Create prompt
19
+ echo "Create the commit message for the following diff:" > ${prompt}
20
+ git diff --no-ext-diff --cached -U6 >> ${prompt}
21
+
22
+ ${client} -1 \
23
+ --agent-profile ${this_dir}/../test_data/git_message_profile.json \
24
+ --prompt ${prompt} > ${msg}
25
+
26
+ # Use as commit message
27
+ if [ -z ${dry_run} ] ; then
28
+ git commit -e -F ${msg}
29
+ else
30
+ cat ${msg}
31
+ fi
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+
3
+ this_dir=`dirname ${BASH_SOURCE[0]}`
4
+ this_dir=`realpath ${this_dir}`
5
+ client=${this_dir}/../dist/main.js
6
+
7
+ prompt=/tmp/git_wip_prompt.txt
8
+
9
+ # Create prompt
10
+ echo "Below are my WIP diffs:" > ${prompt}
11
+ git diff HEAD --no-ext-diff -U6 >> ${prompt}
12
+ num_lines=`cat ${prompt} | wc -l`
13
+ if [ "1" == ${num_lines} ] ; then
14
+ echo Using last commit
15
+ git show -U6 >> ${prompt}
16
+ fi
17
+
18
+ ${client} -y -1 -q \
19
+ --sysprompt ${this_dir}/../test_data/git_wip_system.txt \
20
+ --prompt ${prompt} | pbcopy
21
+ pbpaste
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+
3
+ this_dir=`dirname ${BASH_SOURCE[0]}`
4
+ this_dir=`realpath ${this_dir}`
5
+ client=${this_dir}/../dist/main.js
6
+
7
+ prompt=/tmp/pr_message_prompt.txt
8
+ msg=/tmp/pr_message.txt
9
+
10
+
11
+ # Create prompt
12
+ echo "Create the PR message for the following commits:" > ${prompt}
13
+ git log origin/master..HEAD >> ${prompt}
14
+
15
+ ${client} -1 \
16
+ --agent-profile ${this_dir}/../test_data/pr_message_profile.json \
17
+ --prompt ${prompt} | tee ${msg}
18
+ cat ${msg} | pbcopy
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+
3
+ this_dir=`dirname ${BASH_SOURCE[0]}`
4
+ this_dir=`realpath ${this_dir}`
5
+ client=${this_dir}/../dist/main.js
6
+
7
+ prompt=/tmp/pr_review_prompt.txt
8
+
9
+
10
+ # Create prompt
11
+ echo "Review the following PR diff:" > ${prompt}
12
+ git log -p -U10 origin/master..HEAD >> ${prompt}
13
+
14
+ ${client} -1 \
15
+ --agent-profile ${this_dir}/../test_data/pr_review_profile.json \
16
+ --prompt ${prompt}
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # set -x
4
+ # set -e
5
+
6
+ this_dir=`dirname ${BASH_SOURCE[0]}`
7
+ this_dir=`realpath ${this_dir}`
8
+ client=${this_dir}/../dist/main.js
9
+
10
+ if [ -z "$1" ] ; then
11
+ echo "Usage: $0 <url>"
12
+ exit 1
13
+ fi
14
+
15
+ prompt=/tmp/sudomcp_import_prompt.txt
16
+
17
+ # Create prompt
18
+ echo "Create the sudomcp yaml spec for the MCP at url: $1" \
19
+ > ${prompt}
20
+
21
+ ${client} -1 \
22
+ --agent-profile ${this_dir}/../test_data/sudomcp_import_profile.json \
23
+ --prompt ${prompt}
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env bash
2
+
3
+ . env/bin/activate
4
+ make dev-setup
5
+
6
+ # Build client
7
+
8
+ pushd ../client
9
+ yarn
10
+ yarn build
11
+ client=`realpath dist/src/tool/main.js`
12
+ popd
13
+
14
+ # Build agent
15
+ yarn
16
+ yarn build
17
+ agent=`realpath dist/main.js`
18
+
19
+ set -x
20
+ set -e
21
+
22
+ # Start server
23
+
24
+ pushd ../mcppro
25
+
26
+ function stop_server() {
27
+ if [ -e sudomcp.pid ] ; then
28
+ kill `cat sudomcp.pid` || echo -n
29
+ fi
30
+ }
31
+
32
+ if [ -z ${NO_START} ] ; then
33
+ stop_server
34
+ make start-dev > server.log 2>&1 &
35
+ sleep 5
36
+ fi
37
+
38
+ [ -n "${URL}" ] || URL=http://localhost:5001
39
+
40
+ # enable agent logging
41
+ export LOG_LEVEL=DEBUG
42
+ LOG_FILE="agent.log"
43
+ rm -f $LOG_FILE && touch $LOG_FILE
44
+ export LOG_FILE=`realpath $LOG_FILE`
45
+
46
+ # list mcp servers
47
+ ${client} config -f --dev --server-url ${URL}
48
+ ${client} server list
49
+
50
+ if [ -z ${NO_START} ] ; then
51
+ stop_server
52
+ # cat server.log
53
+ fi
54
+
55
+ set +e
56
+ set +x
57
+
58
+ echo "=============================="
59
+ echo "== MCP Agent TEST PASSED =="
60
+ echo "=============================="