wopee-mcp 1.3.0 → 1.4.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.
package/README.md CHANGED
@@ -210,6 +210,26 @@ Fetches the test cases JSON file for a suite.
210
210
  Fetch test cases for suite abc-123-def-456
211
211
  ```
212
212
 
213
+ ### Update Tools
214
+
215
+ These tools are used to update or set certain files(artifacts) for a specific suite. `suiteUuid`, `fileType` and `fileContent` is required.
216
+
217
+ #### `wopee_update_file`
218
+
219
+ Updates/replaces existing file(artifact) for a specific suite
220
+
221
+ - **Parameters:**
222
+ - `suiteUuid` - The UUID of the suite
223
+ - `fileType` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES" | "TEST_CASES"`
224
+ - `fileContent` - Markdown content for `app context` and `general user stories`, structured JSON for `user stories` and `test cases`
225
+ - **Returns:** Boolean based of success status of the tool call
226
+
227
+ **Example Usage:**
228
+
229
+ ```
230
+ Update app context file for the most recent suite with this content: <YourMarkdown>
231
+ ```
232
+
213
233
  ### Agent Testing
214
234
 
215
235
  #### `wopee_dispatch_agent`
@@ -1,3 +1,4 @@
1
+ import { wopeeUpdateFile } from "./wopee_update_file/index.js";
1
2
  import { wopeeDispatchAgent } from "./wopee_dispatch_agent/index.js";
2
3
  import { wopeeFetchTestCases } from "./wopee_fetch_test_cases/index.js";
3
4
  import { wopeeFetchAppContext } from "./wopee_fetch_app_context/index.js";
@@ -21,4 +22,5 @@ export const TOOLS = [
21
22
  wopeeFetchGeneralUserStories,
22
23
  wopeeFetchUserStories,
23
24
  wopeeFetchTestCases,
25
+ wopeeUpdateFile,
24
26
  ];
@@ -30,3 +30,14 @@ export const createGenerateAIDataInput = (input) => {
30
30
  sourceSuiteUuid: null,
31
31
  };
32
32
  };
33
+ export const createUpdateFileInput = (input) => {
34
+ const { WOPEE_PROJECT_UUID } = getConfig();
35
+ if (!WOPEE_PROJECT_UUID)
36
+ throw new Error("WOPEE_PROJECT_UUID is not set");
37
+ return {
38
+ bucket: input.bucket,
39
+ projectUuid: WOPEE_PROJECT_UUID,
40
+ suiteUuid: input.suiteUuid,
41
+ [input.type === "markdown" ? "code" : "json"]: input.fileContent,
42
+ };
43
+ };
@@ -104,3 +104,8 @@ export const GenerateUserStories = `
104
104
  generateUserStories(input: $input)
105
105
  }
106
106
  `;
107
+ export const UpdateFile = `
108
+ mutation UpdateFile($input: UpdateFileInput!) {
109
+ updateFile(input: $input)
110
+ }
111
+ `;
@@ -1,8 +1,8 @@
1
1
  import { z } from "zod";
2
- import { FetchFileInputSchema, GenerateAIDataInputSchema, } from "./schemas.js";
3
- import { FetchFile, GenerateTestCases, GenerateAppContext, GenerateUserStories, GenerateGeneralUserStories, } from "./gql-queries.js";
4
- import { createFetchFileInput, createGenerateAIDataInput, } from "./factories.js";
5
- import { Bucket, GenerationType } from "./types.js";
2
+ import { FetchFileInputSchema, UpdateFileInputSchema, GenerateAIDataInputSchema, } from "./schemas.js";
3
+ import { FetchFile, UpdateFile, GenerateTestCases, GenerateAppContext, GenerateUserStories, GenerateGeneralUserStories, } from "./gql-queries.js";
4
+ import { createFetchFileInput, createUpdateFileInput, createGenerateAIDataInput, } from "./factories.js";
5
+ import { Bucket, FileType } from "./types.js";
6
6
  import { requestClient } from "../../utils/requestClient.js";
7
7
  export function parseError(error) {
8
8
  console.error(error instanceof z.ZodError ? error.issues : error);
@@ -21,40 +21,46 @@ export function parseError(error) {
21
21
  ],
22
22
  };
23
23
  }
24
- function parseGenerationType(type) {
24
+ function parseFileType(type) {
25
25
  switch (type) {
26
- case GenerationType.APP_CONTEXT:
26
+ case FileType.APP_CONTEXT:
27
27
  return {
28
28
  query: GenerateAppContext,
29
29
  dataKey: "generateAppContext",
30
30
  bucket: Bucket.APP_CONTEXT,
31
+ type: "markdown",
31
32
  description: "application's context markdown file for selected suite",
32
33
  };
33
- case GenerationType.GENERAL_USER_STORIES:
34
+ case FileType.GENERAL_USER_STORIES:
34
35
  return {
35
36
  query: GenerateGeneralUserStories,
36
37
  dataKey: "generateGeneralUserStories",
37
38
  bucket: Bucket.GENERAL_USER_STORIES,
39
+ type: "markdown",
38
40
  description: "general user stories markdown file for selected suite",
39
41
  };
40
- case GenerationType.USER_STORIES:
42
+ case FileType.USER_STORIES:
41
43
  return {
42
44
  query: GenerateUserStories,
43
45
  dataKey: "generateUserStories",
44
46
  bucket: Bucket.USER_STORIES,
47
+ type: "json",
45
48
  description: "user stories JSON file for selected suite",
46
49
  };
47
- case GenerationType.TEST_CASES:
50
+ case FileType.TEST_CASES:
48
51
  return {
49
52
  query: GenerateTestCases,
50
53
  dataKey: "generateTestCases",
51
54
  bucket: Bucket.USER_STORIES,
55
+ type: "json",
52
56
  description: "test cases for selected suite",
53
57
  };
54
58
  default:
55
59
  return {
56
60
  query: null,
57
61
  dataKey: null,
62
+ bucket: null,
63
+ type: null,
58
64
  description: null,
59
65
  };
60
66
  }
@@ -87,7 +93,7 @@ export async function fetchFile(input) {
87
93
  }
88
94
  }
89
95
  export async function generateAIDataFile(type, input) {
90
- const { query, dataKey, bucket, description } = parseGenerationType(type);
96
+ const { query, dataKey, bucket, description } = parseFileType(type);
91
97
  if (!query || !dataKey || !description || !bucket)
92
98
  return {
93
99
  content: [
@@ -121,3 +127,47 @@ export async function generateAIDataFile(type, input) {
121
127
  return parseError(error);
122
128
  }
123
129
  }
130
+ export async function updateFile(input) {
131
+ try {
132
+ const { bucket, type } = parseFileType(input.fileType);
133
+ if (!bucket || !type)
134
+ return {
135
+ content: [
136
+ {
137
+ type: "text",
138
+ text: "Failed to parse file type",
139
+ },
140
+ ],
141
+ };
142
+ const updateFileInput = createUpdateFileInput({
143
+ type,
144
+ bucket,
145
+ suiteUuid: input.suiteUuid,
146
+ fileContent: input.fileContent,
147
+ });
148
+ const parsedInput = UpdateFileInputSchema.parse(updateFileInput);
149
+ const updateFileResult = await requestClient(UpdateFile, {
150
+ input: parsedInput,
151
+ });
152
+ if (!updateFileResult || !updateFileResult.updateFile)
153
+ return {
154
+ content: [
155
+ {
156
+ type: "text",
157
+ text: "Failed to update file",
158
+ },
159
+ ],
160
+ };
161
+ return {
162
+ content: [
163
+ {
164
+ type: "text",
165
+ text: "File updated successfully",
166
+ },
167
+ ],
168
+ };
169
+ }
170
+ catch (error) {
171
+ return parseError(error);
172
+ }
173
+ }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Bucket } from "./types.js";
2
+ import { Bucket, FileType } from "./types.js";
3
3
  var CookiesPreference;
4
4
  (function (CookiesPreference) {
5
5
  CookiesPreference["ACCEPT_ALL"] = "ACCEPT_ALL";
@@ -15,7 +15,9 @@ export const SuiteAnalysisConfigSchema = z.object({
15
15
  additionalVariables: z.string().nullable().default(null),
16
16
  });
17
17
  export const GenerateAIDataHandlerInputSchema = z.object({
18
- suiteUuid: z.string().min(1, "Suite UUID is required"),
18
+ suiteUuid: z
19
+ .string({ description: "UUID of the suite to generate AI data for" })
20
+ .min(1, "Suite UUID is required"),
19
21
  });
20
22
  export const GenerateAIDataInputSchema = z.object({
21
23
  projectUuid: z.string().min(1, "Project UUID is required"),
@@ -27,7 +29,9 @@ export const GenerateAIDataInputSchema = z.object({
27
29
  continueGeneration: z.boolean().nullish().default(false),
28
30
  });
29
31
  export const FetchFileHandlerInputSchema = z.object({
30
- suiteUuid: z.string().min(1, "Suite UUID is required"),
32
+ suiteUuid: z
33
+ .string({ description: "UUID of the suite to fetch the file from" })
34
+ .min(1, "Suite UUID is required"),
31
35
  });
32
36
  export const FetchFileFactoryInputSchema = z.object({
33
37
  suiteUuid: z.string().min(1, "Suite UUID is required"),
@@ -38,3 +42,27 @@ export const FetchFileInputSchema = z.object({
38
42
  suiteUuid: z.string().min(1, "Suite UUID is required"),
39
43
  bucket: z.nativeEnum(Bucket),
40
44
  });
45
+ export const UpdateFileHandlerInputSchema = z.object({
46
+ fileType: z.nativeEnum(FileType, {
47
+ description: "Chosen file/artifact to update",
48
+ }),
49
+ fileContent: z.string({
50
+ description: "Content of the file/artifact to update",
51
+ }),
52
+ suiteUuid: z
53
+ .string({ description: "UUID of the suite to update the file for" })
54
+ .min(1, "Suite UUID is required"),
55
+ });
56
+ export const UpdateFileFactoryInputSchema = z.object({
57
+ bucket: z.nativeEnum(Bucket),
58
+ suiteUuid: z.string().min(1, "Suite UUID is required"),
59
+ fileContent: z.string(),
60
+ type: z.enum(["markdown", "json"]),
61
+ });
62
+ export const UpdateFileInputSchema = z.object({
63
+ projectUuid: z.string().min(1, "Project UUID is required"),
64
+ suiteUuid: z.string().min(1, "Suite UUID is required"),
65
+ bucket: z.nativeEnum(Bucket),
66
+ json: z.string().nullish(),
67
+ code: z.string().nullish(),
68
+ });
@@ -11,6 +11,7 @@ export var ToolName;
11
11
  ToolName["WOPEE_GENERATE_GENERAL_USER_STORIES"] = "wopee_generate_general_user_stories";
12
12
  ToolName["WOPEE_GENERATE_USER_STORIES"] = "wopee_generate_user_stories";
13
13
  ToolName["WOPEE_GENERATE_TEST_CASES"] = "wopee_generate_test_cases";
14
+ ToolName["WOPEE_UPDATE_FILE"] = "wopee_update_file";
14
15
  })(ToolName || (ToolName = {}));
15
16
  export const Bucket = {
16
17
  APP_CONTEXT: "project-suite-app-context",
@@ -21,13 +22,13 @@ export const Bucket = {
21
22
  PLAYWRIGHT_CODE: "project-suite-playwright-code",
22
23
  UPLOADED_PAGE_DATA: "project-uploaded-page-data",
23
24
  };
24
- export var GenerationType;
25
- (function (GenerationType) {
26
- GenerationType["APP_CONTEXT"] = "APP_CONTEXT";
27
- GenerationType["GENERAL_USER_STORIES"] = "GENERAL_USER_STORIES";
28
- GenerationType["USER_STORIES"] = "USER_STORIES";
29
- GenerationType["TEST_CASES"] = "TEST_CASES";
30
- })(GenerationType || (GenerationType = {}));
25
+ export var FileType;
26
+ (function (FileType) {
27
+ FileType["APP_CONTEXT"] = "APP_CONTEXT";
28
+ FileType["GENERAL_USER_STORIES"] = "GENERAL_USER_STORIES";
29
+ FileType["USER_STORIES"] = "USER_STORIES";
30
+ FileType["TEST_CASES"] = "TEST_CASES";
31
+ })(FileType || (FileType = {}));
31
32
  export var SuiteType;
32
33
  (function (SuiteType) {
33
34
  SuiteType["BOT"] = "BOT";
@@ -1,12 +1,28 @@
1
1
  import { z } from "zod";
2
2
  const SelectedTestCasesSchema = z.object({
3
- testCaseId: z.string().min(1, "Test case ID is required"),
4
- userStoryId: z.string().min(1, "User story ID is required"),
3
+ testCaseId: z
4
+ .string({
5
+ description: "ID of the test case belonging to the user story to dispatch the agent for (ex. TC001)",
6
+ })
7
+ .min(1, "Test case ID is required"),
8
+ userStoryId: z
9
+ .string({
10
+ description: "ID of the user story that the test case belongs to (ex. US001)",
11
+ })
12
+ .min(1, "User story ID is required"),
5
13
  });
6
14
  export const WopeeDispatchAgentInputSchema = z.object({
7
- suiteUuid: z.string().min(1, "Suite UUID is required"),
8
- analysisIdentifier: z.string().min(1, "Analysis identifier is required"),
9
- testCases: z.array(SelectedTestCasesSchema),
15
+ suiteUuid: z
16
+ .string({ description: "UUID of the suite to dispatch the agent for" })
17
+ .min(1, "Suite UUID is required"),
18
+ analysisIdentifier: z
19
+ .string({
20
+ description: "Analysis identifier of the suite to dispatch the agent for",
21
+ })
22
+ .min(1, "Analysis identifier is required"),
23
+ testCases: z.array(SelectedTestCasesSchema, {
24
+ description: "Chosen test cases to dispatch the agent for",
25
+ }),
10
26
  });
11
27
  export const DispatchAgentInputSchema = z.object({
12
28
  projectUuid: z.string().min(1, "Project UUID is required"),
@@ -1,7 +1,7 @@
1
+ import { getConfig } from "../../utils/getConfig.js";
1
2
  import { requestClient } from "../../utils/requestClient.js";
2
3
  import { ToolName } from "../shared/types.js";
3
4
  import { FetchAnalysisSuites } from "../shared/gql-queries.js";
4
- import { getConfig } from "../../utils/getConfig.js";
5
5
  export const wopeeFetchAnalysisSuites = {
6
6
  name: ToolName.WOPEE_FETCH_ANALYSIS_SUITES,
7
7
  config: {
@@ -1,6 +1,6 @@
1
+ import { FetchFileHandlerInputSchema, } from "../shared/schemas.js";
1
2
  import { fetchFile } from "../shared/handlers.js";
2
3
  import { Bucket, ToolName } from "../shared/types.js";
3
- import { FetchFileHandlerInputSchema, } from "../shared/schemas.js";
4
4
  export const wopeeFetchAppContext = {
5
5
  name: ToolName.WOPEE_FETCH_APP_CONTEXT,
6
6
  config: {
@@ -1,6 +1,6 @@
1
1
  import { GenerateAIDataHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { FileType, ToolName } from "../shared/types.js";
2
3
  import { generateAIDataFile } from "../shared/handlers.js";
3
- import { GenerationType, ToolName } from "../shared/types.js";
4
4
  export const wopeeGenerateAppContext = {
5
5
  name: ToolName.WOPEE_GENERATE_APP_CONTEXT,
6
6
  config: {
@@ -8,5 +8,5 @@ export const wopeeGenerateAppContext = {
8
8
  description: "Generate application's context markdown file for selected suite",
9
9
  inputSchema: GenerateAIDataHandlerInputSchema.shape,
10
10
  },
11
- handler: async (input) => await generateAIDataFile(GenerationType.APP_CONTEXT, input),
11
+ handler: async (input) => await generateAIDataFile(FileType.APP_CONTEXT, input),
12
12
  };
@@ -1,6 +1,6 @@
1
1
  import { GenerateAIDataHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { FileType, ToolName } from "../shared/types.js";
2
3
  import { generateAIDataFile } from "../shared/handlers.js";
3
- import { GenerationType, ToolName } from "../shared/types.js";
4
4
  export const wopeeGenerateGeneralUserStories = {
5
5
  name: ToolName.WOPEE_GENERATE_GENERAL_USER_STORIES,
6
6
  config: {
@@ -8,5 +8,5 @@ export const wopeeGenerateGeneralUserStories = {
8
8
  description: "Generate general user stories markdown file for selected suite",
9
9
  inputSchema: GenerateAIDataHandlerInputSchema.shape,
10
10
  },
11
- handler: async (input) => await generateAIDataFile(GenerationType.GENERAL_USER_STORIES, input),
11
+ handler: async (input) => await generateAIDataFile(FileType.GENERAL_USER_STORIES, input),
12
12
  };
@@ -1,6 +1,6 @@
1
1
  import { GenerateAIDataHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { FileType, ToolName } from "../shared/types.js";
2
3
  import { generateAIDataFile } from "../shared/handlers.js";
3
- import { GenerationType, ToolName } from "../shared/types.js";
4
4
  export const wopeeGenerateTestCases = {
5
5
  name: ToolName.WOPEE_GENERATE_TEST_CASES,
6
6
  config: {
@@ -8,5 +8,5 @@ export const wopeeGenerateTestCases = {
8
8
  description: "Generate test cases for selected suite",
9
9
  inputSchema: GenerateAIDataHandlerInputSchema.shape,
10
10
  },
11
- handler: async (input) => await generateAIDataFile(GenerationType.TEST_CASES, input),
11
+ handler: async (input) => await generateAIDataFile(FileType.TEST_CASES, input),
12
12
  };
@@ -1,6 +1,6 @@
1
1
  import { GenerateAIDataHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { FileType, ToolName } from "../shared/types.js";
2
3
  import { generateAIDataFile } from "../shared/handlers.js";
3
- import { GenerationType, ToolName } from "../shared/types.js";
4
4
  export const wopeeGenerateUserStories = {
5
5
  name: ToolName.WOPEE_GENERATE_USER_STORIES,
6
6
  config: {
@@ -8,5 +8,5 @@ export const wopeeGenerateUserStories = {
8
8
  description: "Generate user stories JSON file for selected suite",
9
9
  inputSchema: GenerateAIDataHandlerInputSchema.shape,
10
10
  },
11
- handler: async (input) => await generateAIDataFile(GenerationType.USER_STORIES, input),
11
+ handler: async (input) => await generateAIDataFile(FileType.USER_STORIES, input),
12
12
  };
@@ -0,0 +1,12 @@
1
+ import { UpdateFileHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { ToolName } from "../shared/types.js";
3
+ import { updateFile } from "../shared/handlers.js";
4
+ export const wopeeUpdateFile = {
5
+ name: ToolName.WOPEE_UPDATE_FILE,
6
+ config: {
7
+ title: "Update file",
8
+ description: "Update file(artifact) in the project",
9
+ inputSchema: UpdateFileHandlerInputSchema.shape,
10
+ },
11
+ handler: async (input) => await updateFile(input),
12
+ };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "bin": {
5
5
  "wopee-mcp": "./build/index.js"
6
6
  },
7
- "version": "1.3.0",
7
+ "version": "1.4.0",
8
8
  "description": "Wopee.io MCP server",
9
9
  "main": "./build/index.js",
10
10
  "scripts": {