@midscene/shared 1.0.1-beta-20251208075922.0 → 1.0.1-beta-20251208112226.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 (67) hide show
  1. package/dist/es/node/fs.mjs +1 -1
  2. package/dist/lib/baseDB.js +2 -2
  3. package/dist/lib/build/copy-static.js +2 -2
  4. package/dist/lib/build/rspack-config.js +2 -2
  5. package/dist/lib/common.js +2 -2
  6. package/dist/lib/constants/example-code.js +2 -2
  7. package/dist/lib/constants/index.js +2 -2
  8. package/dist/lib/env/basic.js +2 -2
  9. package/dist/lib/env/constants.js +2 -2
  10. package/dist/lib/env/global-config-manager.js +2 -2
  11. package/dist/lib/env/helper.js +2 -2
  12. package/dist/lib/env/index.js +6 -6
  13. package/dist/lib/env/init-debug.js +2 -2
  14. package/dist/lib/env/model-config-manager.js +2 -2
  15. package/dist/lib/env/parse-model-config.js +2 -2
  16. package/dist/lib/env/types.js +2 -2
  17. package/dist/lib/env/utils.js +2 -2
  18. package/dist/lib/extractor/constants.js +2 -2
  19. package/dist/lib/extractor/debug.js +1 -1
  20. package/dist/lib/extractor/dom-util.js +2 -2
  21. package/dist/lib/extractor/index.js +2 -2
  22. package/dist/lib/extractor/locator.js +2 -2
  23. package/dist/lib/extractor/tree.js +2 -2
  24. package/dist/lib/extractor/util.js +2 -2
  25. package/dist/lib/extractor/web-extractor.js +2 -2
  26. package/dist/lib/img/box-select.js +2 -2
  27. package/dist/lib/img/draw-box.js +2 -2
  28. package/dist/lib/img/get-jimp.js +2 -2
  29. package/dist/lib/img/get-photon.js +2 -2
  30. package/dist/lib/img/get-sharp.js +2 -2
  31. package/dist/lib/img/index.js +2 -2
  32. package/dist/lib/img/info.js +2 -2
  33. package/dist/lib/img/transform.js +2 -2
  34. package/dist/lib/index.js +2 -2
  35. package/dist/lib/logger.js +2 -2
  36. package/dist/lib/node/fs.js +3 -3
  37. package/dist/lib/node/index.js +2 -2
  38. package/dist/lib/polyfills/async-hooks.js +2 -2
  39. package/dist/lib/polyfills/index.js +2 -2
  40. package/dist/lib/types/index.js +2 -2
  41. package/dist/lib/us-keyboard-layout.js +2 -2
  42. package/dist/lib/utils.js +2 -2
  43. package/package.json +3 -17
  44. package/dist/es/mcp/base-server.mjs +0 -250
  45. package/dist/es/mcp/base-tools.mjs +0 -84
  46. package/dist/es/mcp/index.mjs +0 -5
  47. package/dist/es/mcp/inject-report-html-plugin.mjs +0 -53
  48. package/dist/es/mcp/tool-generator.mjs +0 -215
  49. package/dist/es/mcp/types.mjs +0 -3
  50. package/dist/lib/mcp/base-server.js +0 -290
  51. package/dist/lib/mcp/base-tools.js +0 -118
  52. package/dist/lib/mcp/index.js +0 -86
  53. package/dist/lib/mcp/inject-report-html-plugin.js +0 -98
  54. package/dist/lib/mcp/tool-generator.js +0 -252
  55. package/dist/lib/mcp/types.js +0 -40
  56. package/dist/types/mcp/base-server.d.ts +0 -77
  57. package/dist/types/mcp/base-tools.d.ts +0 -55
  58. package/dist/types/mcp/index.d.ts +0 -5
  59. package/dist/types/mcp/inject-report-html-plugin.d.ts +0 -18
  60. package/dist/types/mcp/tool-generator.d.ts +0 -11
  61. package/dist/types/mcp/types.d.ts +0 -100
  62. package/src/mcp/base-server.ts +0 -432
  63. package/src/mcp/base-tools.ts +0 -196
  64. package/src/mcp/index.ts +0 -5
  65. package/src/mcp/inject-report-html-plugin.ts +0 -119
  66. package/src/mcp/tool-generator.ts +0 -311
  67. package/src/mcp/types.ts +0 -108
@@ -1,119 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
-
4
- const MAGIC_STRING = 'REPLACE_ME_WITH_REPORT_HTML';
5
- const REPLACED_MARK = '/*REPORT_HTML_REPLACED*/';
6
- const REG_EXP_FOR_REPLACE = /\/\*REPORT_HTML_REPLACED\*\/.*/;
7
-
8
- interface RslibPluginApi {
9
- onAfterBuild: (callback: () => void) => void;
10
- }
11
-
12
- /**
13
- * Rslib plugin to inject report HTML from @midscene/core dist into MCP bundle.
14
- * This runs after build and reads the already-injected HTML from core.
15
- *
16
- * Prerequisites:
17
- * - @midscene/report must be in devDependencies to ensure correct build order
18
- * - @midscene/core dist must exist with injected HTML
19
- *
20
- * @param packageDir - The directory of the MCP package (use __dirname)
21
- */
22
- export function injectReportHtmlFromCore(packageDir: string) {
23
- return {
24
- name: 'inject-report-html-from-core',
25
- setup(api: RslibPluginApi) {
26
- api.onAfterBuild(() => {
27
- const coreUtilsPath = path.resolve(
28
- packageDir,
29
- '..',
30
- 'core',
31
- 'dist',
32
- 'lib',
33
- 'utils.js',
34
- );
35
-
36
- if (!fs.existsSync(coreUtilsPath)) {
37
- console.warn(
38
- '[inject-report-html] @midscene/core dist not found, skipping',
39
- );
40
- return;
41
- }
42
-
43
- const coreContent = fs.readFileSync(coreUtilsPath, 'utf-8');
44
- if (!coreContent.includes(REPLACED_MARK)) {
45
- console.warn(
46
- '[inject-report-html] HTML not found in core dist. Ensure report builds first.',
47
- );
48
- return;
49
- }
50
-
51
- // Extract the JSON string after the marker
52
- // JSON strings can contain escaped quotes, so we need to properly parse it
53
- const markerIndex = coreContent.indexOf(REPLACED_MARK);
54
- const jsonStart = markerIndex + REPLACED_MARK.length;
55
-
56
- // Find the end of the JSON string by tracking quote escaping
57
- let jsonEnd = jsonStart;
58
- if (coreContent[jsonStart] === '"') {
59
- jsonEnd = jsonStart + 1;
60
- while (jsonEnd < coreContent.length) {
61
- if (coreContent[jsonEnd] === '\\') {
62
- jsonEnd += 2; // Skip escaped character
63
- } else if (coreContent[jsonEnd] === '"') {
64
- jsonEnd += 1; // Include closing quote
65
- break;
66
- } else {
67
- jsonEnd += 1;
68
- }
69
- }
70
- }
71
-
72
- const jsonString = coreContent.slice(jsonStart, jsonEnd);
73
- if (!jsonString || jsonString.length < 10) {
74
- console.warn('[inject-report-html] Failed to extract HTML from core');
75
- return;
76
- }
77
-
78
- const finalContent = `${REPLACED_MARK}${jsonString}`;
79
- const distDir = path.join(packageDir, 'dist');
80
-
81
- if (!fs.existsSync(distDir)) return;
82
-
83
- const jsFiles = fs
84
- .readdirSync(distDir)
85
- .filter((f) => f.endsWith('.js'));
86
- let injectedCount = 0;
87
-
88
- for (const file of jsFiles) {
89
- const filePath = path.join(distDir, file);
90
- const content = fs.readFileSync(filePath, 'utf-8');
91
-
92
- if (content.includes(REPLACED_MARK)) {
93
- if (REG_EXP_FOR_REPLACE.test(content)) {
94
- fs.writeFileSync(
95
- filePath,
96
- content.replace(REG_EXP_FOR_REPLACE, () => finalContent),
97
- );
98
- console.log(`[inject-report-html] Updated: ${file}`);
99
- injectedCount++;
100
- }
101
- } else if (content.includes(`'${MAGIC_STRING}'`)) {
102
- fs.writeFileSync(
103
- filePath,
104
- content.replace(`'${MAGIC_STRING}'`, () => finalContent),
105
- );
106
- console.log(`[inject-report-html] Injected: ${file}`);
107
- injectedCount++;
108
- }
109
- }
110
-
111
- if (injectedCount > 0) {
112
- console.log(
113
- `[inject-report-html] Completed: ${injectedCount} file(s)`,
114
- );
115
- }
116
- });
117
- },
118
- };
119
- }
@@ -1,311 +0,0 @@
1
- import { parseBase64 } from '@midscene/shared/img';
2
- import { z } from 'zod';
3
- import type {
4
- ActionSpaceItem,
5
- BaseAgent,
6
- ToolDefinition,
7
- ToolResult,
8
- } from './types';
9
-
10
- /**
11
- * Extract error message from unknown error type
12
- */
13
- function getErrorMessage(error: unknown): string {
14
- return error instanceof Error ? error.message : String(error);
15
- }
16
-
17
- /**
18
- * Type guard: check if a Zod type is ZodOptional
19
- */
20
- function isZodOptional(
21
- value: z.ZodTypeAny,
22
- ): value is z.ZodOptional<z.ZodTypeAny> {
23
- return '_def' in value && value._def?.typeName === 'ZodOptional';
24
- }
25
-
26
- /**
27
- * Type guard: check if a Zod type is ZodObject
28
- */
29
- function isZodObject(value: z.ZodTypeAny): value is z.ZodObject<z.ZodRawShape> {
30
- return (
31
- '_def' in value && value._def?.typeName === 'ZodObject' && 'shape' in value
32
- );
33
- }
34
-
35
- /**
36
- * Unwrap ZodOptional to get inner type
37
- */
38
- function unwrapOptional(value: z.ZodTypeAny): {
39
- innerValue: z.ZodTypeAny;
40
- isOptional: boolean;
41
- } {
42
- if (isZodOptional(value)) {
43
- return { innerValue: value._def.innerType, isOptional: true };
44
- }
45
- return { innerValue: value, isOptional: false };
46
- }
47
-
48
- /**
49
- * Check if a Zod object schema contains a 'prompt' field (locate field pattern)
50
- */
51
- function isLocateField(value: z.ZodTypeAny): boolean {
52
- if (!isZodObject(value)) {
53
- return false;
54
- }
55
- return 'prompt' in value.shape;
56
- }
57
-
58
- /**
59
- * Transform a locate field schema to make its 'prompt' field optional
60
- */
61
- function makePromptOptional(
62
- value: z.ZodObject<z.ZodRawShape>,
63
- wrapInOptional: boolean,
64
- ): z.ZodTypeAny {
65
- const newShape = { ...value.shape };
66
- newShape.prompt = value.shape.prompt.optional();
67
-
68
- let newSchema: z.ZodTypeAny = z.object(newShape).passthrough();
69
- if (wrapInOptional) {
70
- newSchema = newSchema.optional();
71
- }
72
- return newSchema;
73
- }
74
-
75
- /**
76
- * Transform schema field to make locate.prompt optional if applicable
77
- */
78
- function transformSchemaField(
79
- key: string,
80
- value: z.ZodTypeAny,
81
- ): [string, z.ZodTypeAny] {
82
- const { innerValue, isOptional } = unwrapOptional(value);
83
-
84
- if (isZodObject(innerValue) && isLocateField(innerValue)) {
85
- return [key, makePromptOptional(innerValue, isOptional)];
86
- }
87
- return [key, value];
88
- }
89
-
90
- /**
91
- * Extract and transform schema from action's paramSchema
92
- */
93
- function extractActionSchema(
94
- paramSchema: z.ZodTypeAny | undefined,
95
- ): Record<string, z.ZodTypeAny> {
96
- if (!paramSchema) {
97
- return {};
98
- }
99
-
100
- const schema = paramSchema as z.ZodTypeAny;
101
- if (!isZodObject(schema)) {
102
- return schema as unknown as Record<string, z.ZodTypeAny>;
103
- }
104
-
105
- return Object.fromEntries(
106
- Object.entries(schema.shape).map(([key, value]) =>
107
- transformSchemaField(key, value as z.ZodTypeAny),
108
- ),
109
- );
110
- }
111
-
112
- /**
113
- * Serialize args to human-readable description for AI action
114
- */
115
- function serializeArgsToDescription(args: Record<string, unknown>): string {
116
- try {
117
- return Object.entries(args)
118
- .map(([key, value]) => {
119
- if (typeof value === 'object' && value !== null) {
120
- try {
121
- return `${key}: ${JSON.stringify(value)}`;
122
- } catch {
123
- // Circular reference or non-serializable object
124
- return `${key}: [object]`;
125
- }
126
- }
127
- return `${key}: "${value}"`;
128
- })
129
- .join(', ');
130
- } catch (error: unknown) {
131
- const errorMessage = getErrorMessage(error);
132
- console.error('Error serializing args:', errorMessage);
133
- return `[args serialization failed: ${errorMessage}]`;
134
- }
135
- }
136
-
137
- /**
138
- * Build action instruction string from action name and args
139
- */
140
- function buildActionInstruction(
141
- actionName: string,
142
- args: Record<string, unknown>,
143
- ): string {
144
- const argsDescription = serializeArgsToDescription(args);
145
- return argsDescription
146
- ? `Use the action "${actionName}" with ${argsDescription}`
147
- : `Use the action "${actionName}"`;
148
- }
149
-
150
- /**
151
- * Capture screenshot and return as tool result
152
- */
153
- async function captureScreenshotResult(
154
- agent: BaseAgent,
155
- actionName: string,
156
- ): Promise<ToolResult> {
157
- try {
158
- const screenshot = await agent.page?.screenshotBase64();
159
- if (!screenshot) {
160
- return {
161
- content: [{ type: 'text', text: `Action "${actionName}" completed.` }],
162
- };
163
- }
164
-
165
- const { mimeType, body } = parseBase64(screenshot);
166
- return {
167
- content: [
168
- { type: 'text', text: `Action "${actionName}" completed.` },
169
- { type: 'image', data: body, mimeType },
170
- ],
171
- };
172
- } catch (error: unknown) {
173
- const errorMessage = getErrorMessage(error);
174
- console.error('Error capturing screenshot:', errorMessage);
175
- return {
176
- content: [
177
- {
178
- type: 'text',
179
- text: `Action "${actionName}" completed (screenshot unavailable: ${errorMessage})`,
180
- },
181
- ],
182
- };
183
- }
184
- }
185
-
186
- /**
187
- * Create error result for tool handler
188
- */
189
- function createErrorResult(message: string): ToolResult {
190
- return {
191
- content: [{ type: 'text', text: message }],
192
- isError: true,
193
- };
194
- }
195
-
196
- /**
197
- * Converts DeviceAction from actionSpace into MCP ToolDefinition
198
- * This is the core logic that removes need for hardcoded tool definitions
199
- */
200
- export function generateToolsFromActionSpace(
201
- actionSpace: ActionSpaceItem[],
202
- getAgent: () => Promise<BaseAgent>,
203
- ): ToolDefinition[] {
204
- return actionSpace.map((action) => {
205
- const schema = extractActionSchema(action.paramSchema as z.ZodTypeAny);
206
-
207
- return {
208
- name: action.name,
209
- description: action.description || `Execute ${action.name} action`,
210
- schema,
211
- handler: async (args: Record<string, unknown>) => {
212
- try {
213
- const agent = await getAgent();
214
-
215
- if (agent.aiAction) {
216
- const instruction = buildActionInstruction(action.name, args);
217
- try {
218
- await agent.aiAction(instruction);
219
- } catch (error: unknown) {
220
- const errorMessage = getErrorMessage(error);
221
- console.error(
222
- `Error executing action "${action.name}":`,
223
- errorMessage,
224
- );
225
- return createErrorResult(
226
- `Failed to execute action "${action.name}": ${errorMessage}`,
227
- );
228
- }
229
- }
230
-
231
- return await captureScreenshotResult(agent, action.name);
232
- } catch (error: unknown) {
233
- const errorMessage = getErrorMessage(error);
234
- console.error(`Error in handler for "${action.name}":`, errorMessage);
235
- return createErrorResult(
236
- `Failed to get agent or execute action "${action.name}": ${errorMessage}`,
237
- );
238
- }
239
- },
240
- autoDestroy: true,
241
- };
242
- });
243
- }
244
-
245
- /**
246
- * Generate common tools (screenshot, waitFor)
247
- * SIMPLIFIED: Only keep essential helper tools, removed assert
248
- */
249
- export function generateCommonTools(
250
- getAgent: () => Promise<BaseAgent>,
251
- ): ToolDefinition[] {
252
- return [
253
- {
254
- name: 'take_screenshot',
255
- description: 'Capture screenshot of current page/screen',
256
- schema: {},
257
- handler: async (): Promise<ToolResult> => {
258
- try {
259
- const agent = await getAgent();
260
- const screenshot = await agent.page?.screenshotBase64();
261
- if (!screenshot) {
262
- return createErrorResult('Screenshot not available');
263
- }
264
- const { mimeType, body } = parseBase64(screenshot);
265
- return {
266
- content: [{ type: 'image', data: body, mimeType }],
267
- };
268
- } catch (error: unknown) {
269
- const errorMessage = getErrorMessage(error);
270
- console.error('Error taking screenshot:', errorMessage);
271
- return createErrorResult(
272
- `Failed to capture screenshot: ${errorMessage}`,
273
- );
274
- }
275
- },
276
- autoDestroy: true,
277
- },
278
- {
279
- name: 'wait_for',
280
- description: 'Wait until condition becomes true',
281
- schema: {
282
- assertion: z.string().describe('Condition to wait for'),
283
- timeoutMs: z.number().optional().default(15000),
284
- checkIntervalMs: z.number().optional().default(3000),
285
- },
286
- handler: async (args): Promise<ToolResult> => {
287
- try {
288
- const agent = await getAgent();
289
- const { assertion, timeoutMs, checkIntervalMs } = args as {
290
- assertion: string;
291
- timeoutMs?: number;
292
- checkIntervalMs?: number;
293
- };
294
-
295
- if (agent.aiWaitFor) {
296
- await agent.aiWaitFor(assertion, { timeoutMs, checkIntervalMs });
297
- }
298
-
299
- return {
300
- content: [{ type: 'text', text: `Condition met: "${assertion}"` }],
301
- };
302
- } catch (error: unknown) {
303
- const errorMessage = getErrorMessage(error);
304
- console.error('Error in wait_for:', errorMessage);
305
- return createErrorResult(`Wait condition failed: ${errorMessage}`);
306
- }
307
- },
308
- autoDestroy: true,
309
- },
310
- ];
311
- }
package/src/mcp/types.ts DELETED
@@ -1,108 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { z } from 'zod';
3
-
4
- // Avoid circular dependency: don't import from @midscene/core
5
- // Instead, use generic types that will be provided by implementation
6
-
7
- /**
8
- * Default timeout constants for app loading verification
9
- */
10
- export const defaultAppLoadingTimeoutMs = 10000;
11
- export const defaultAppLoadingCheckIntervalMs = 2000;
12
-
13
- /**
14
- * Content item types for tool results (MCP compatible)
15
- */
16
- export type ToolResultContent =
17
- | { type: 'text'; text: string }
18
- | { type: 'image'; data: string; mimeType: string }
19
- | { type: 'audio'; data: string; mimeType: string }
20
- | {
21
- type: 'resource';
22
- resource:
23
- | { text: string; uri: string; mimeType?: string }
24
- | { uri: string; blob: string; mimeType?: string };
25
- };
26
-
27
- /**
28
- * Result type for tool execution (MCP compatible)
29
- */
30
- export interface ToolResult {
31
- [x: string]: unknown;
32
- content: ToolResultContent[];
33
- isError?: boolean;
34
- _meta?: Record<string, unknown>;
35
- }
36
-
37
- /**
38
- * Tool handler function type
39
- * Takes parsed arguments and returns a tool result
40
- */
41
- export type ToolHandler<T = Record<string, unknown>> = (
42
- args: T,
43
- ) => Promise<ToolResult>;
44
-
45
- /**
46
- * Tool schema type using Zod
47
- */
48
- export type ToolSchema = Record<string, z.ZodTypeAny>;
49
-
50
- /**
51
- * Tool definition for MCP server
52
- */
53
- export interface ToolDefinition<T = Record<string, unknown>> {
54
- name: string;
55
- description: string;
56
- schema: ToolSchema;
57
- handler: ToolHandler<T>;
58
- autoDestroy?: boolean;
59
- }
60
-
61
- /**
62
- * Action space item definition
63
- * Note: Intentionally no index signature to maintain compatibility with DeviceAction
64
- */
65
- export interface ActionSpaceItem {
66
- name: string;
67
- description?: string;
68
- args?: Record<string, unknown>;
69
- paramSchema?: z.ZodTypeAny;
70
- }
71
-
72
- /**
73
- * Base agent interface
74
- * Represents a platform-specific agent (Android, iOS, Web)
75
- * Note: Return types use `unknown` for compatibility with platform-specific implementations
76
- */
77
- export interface BaseAgent {
78
- getActionSpace(): Promise<ActionSpaceItem[]>;
79
- destroy?(): Promise<void>;
80
- page?: {
81
- screenshotBase64(): Promise<string>;
82
- };
83
- aiAction?: (
84
- description: string,
85
- params?: Record<string, unknown>,
86
- ) => Promise<unknown>;
87
- aiWaitFor?: (
88
- assertion: string,
89
- options: Record<string, unknown>,
90
- ) => Promise<unknown>;
91
- }
92
-
93
- /**
94
- * Base device interface for temporary device instances
95
- */
96
- export interface BaseDevice {
97
- actionSpace(): ActionSpaceItem[];
98
- destroy?(): Promise<void>;
99
- }
100
-
101
- /**
102
- * Interface for platform-specific MCP tools manager
103
- */
104
- export interface IMidsceneTools {
105
- attachToServer(server: McpServer): void;
106
- initTools(): Promise<void>;
107
- closeBrowser?(): Promise<void>;
108
- }