@aiscene/shared 8.0.1 → 8.0.3

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 (92) hide show
  1. package/dist/es/cli/cli-args.mjs +95 -0
  2. package/dist/es/cli/cli-error.mjs +24 -0
  3. package/dist/es/cli/cli-runner.mjs +10 -40
  4. package/dist/es/cli/index.mjs +4 -2
  5. package/dist/es/constants/example-code.mjs +2 -2
  6. package/dist/es/constants/index.mjs +6 -1
  7. package/dist/es/env/model-config-manager.mjs +3 -0
  8. package/dist/es/env/parse-model-config.mjs +6 -1
  9. package/dist/es/env/types.mjs +2 -1
  10. package/dist/es/env/utils.mjs +1 -9
  11. package/dist/es/extractor/index.mjs +2 -2
  12. package/dist/es/img/index.mjs +2 -2
  13. package/dist/es/img/info.mjs +7 -1
  14. package/dist/es/key-alias-utils.mjs +19 -0
  15. package/dist/es/mcp/base-server.mjs +10 -9
  16. package/dist/es/mcp/base-tools.mjs +72 -4
  17. package/dist/es/mcp/cli-report-session.mjs +78 -0
  18. package/dist/es/mcp/error-formatter.mjs +19 -0
  19. package/dist/es/mcp/index.mjs +2 -0
  20. package/dist/es/mcp/init-arg-utils.mjs +38 -0
  21. package/dist/es/mcp/inject-report-html-plugin.mjs +1 -1
  22. package/dist/es/mcp/tool-generator.mjs +65 -17
  23. package/dist/es/node/fs.mjs +1 -1
  24. package/dist/lib/cli/cli-args.js +138 -0
  25. package/dist/lib/cli/cli-error.js +61 -0
  26. package/dist/lib/cli/cli-runner.js +19 -46
  27. package/dist/lib/cli/index.js +8 -3
  28. package/dist/lib/constants/example-code.js +2 -2
  29. package/dist/lib/constants/index.js +23 -3
  30. package/dist/lib/env/model-config-manager.js +3 -0
  31. package/dist/lib/env/parse-model-config.js +6 -1
  32. package/dist/lib/env/types.js +4 -0
  33. package/dist/lib/env/utils.js +0 -11
  34. package/dist/lib/extractor/index.js +3 -0
  35. package/dist/lib/img/index.js +3 -0
  36. package/dist/lib/img/info.js +10 -1
  37. package/dist/lib/key-alias-utils.js +62 -0
  38. package/dist/lib/mcp/base-server.js +11 -10
  39. package/dist/lib/mcp/base-tools.js +74 -6
  40. package/dist/lib/mcp/cli-report-session.js +121 -0
  41. package/dist/lib/mcp/error-formatter.js +53 -0
  42. package/dist/lib/mcp/index.js +24 -10
  43. package/dist/lib/mcp/init-arg-utils.js +78 -0
  44. package/dist/lib/mcp/inject-report-html-plugin.js +1 -1
  45. package/dist/lib/mcp/tool-generator.js +74 -26
  46. package/dist/lib/node/fs.js +1 -1
  47. package/dist/types/cli/cli-args.d.ts +8 -0
  48. package/dist/types/cli/cli-error.d.ts +5 -0
  49. package/dist/types/cli/cli-runner.d.ts +4 -7
  50. package/dist/types/cli/index.d.ts +3 -1
  51. package/dist/types/constants/example-code.d.ts +1 -1
  52. package/dist/types/constants/index.d.ts +5 -0
  53. package/dist/types/env/types.d.ts +10 -2
  54. package/dist/types/env/utils.d.ts +0 -31
  55. package/dist/types/extractor/index.d.ts +1 -1
  56. package/dist/types/img/index.d.ts +1 -1
  57. package/dist/types/img/info.d.ts +5 -0
  58. package/dist/types/key-alias-utils.d.ts +9 -0
  59. package/dist/types/mcp/base-tools.d.ts +74 -5
  60. package/dist/types/mcp/cli-report-session.d.ts +12 -0
  61. package/dist/types/mcp/error-formatter.d.ts +12 -0
  62. package/dist/types/mcp/index.d.ts +2 -0
  63. package/dist/types/mcp/init-arg-utils.d.ts +13 -0
  64. package/dist/types/mcp/inject-report-html-plugin.d.ts +2 -2
  65. package/dist/types/mcp/launcher-helper.d.ts +3 -3
  66. package/dist/types/mcp/tool-generator.d.ts +3 -3
  67. package/dist/types/mcp/types.d.ts +9 -0
  68. package/package.json +1 -1
  69. package/src/cli/cli-args.ts +173 -0
  70. package/src/cli/cli-error.ts +24 -0
  71. package/src/cli/cli-runner.ts +37 -56
  72. package/src/cli/index.ts +3 -7
  73. package/src/constants/example-code.ts +2 -2
  74. package/src/constants/index.ts +10 -0
  75. package/src/env/model-config-manager.ts +3 -0
  76. package/src/env/parse-model-config.ts +19 -1
  77. package/src/env/types.ts +11 -2
  78. package/src/env/utils.ts +0 -50
  79. package/src/extractor/index.ts +1 -1
  80. package/src/img/index.ts +2 -0
  81. package/src/img/info.ts +27 -0
  82. package/src/key-alias-utils.ts +23 -0
  83. package/src/mcp/base-server.ts +10 -12
  84. package/src/mcp/base-tools.ts +218 -11
  85. package/src/mcp/cli-report-session.ts +130 -0
  86. package/src/mcp/error-formatter.ts +52 -0
  87. package/src/mcp/index.ts +2 -0
  88. package/src/mcp/init-arg-utils.ts +105 -0
  89. package/src/mcp/inject-report-html-plugin.ts +3 -3
  90. package/src/mcp/launcher-helper.ts +3 -3
  91. package/src/mcp/tool-generator.ts +98 -20
  92. package/src/mcp/types.ts +16 -1
@@ -1,4 +1,4 @@
1
- import { parseBase64 } from '../img';
1
+ import { parseBase64 } from '@aiscene/shared/img';
2
2
  import { z } from 'zod';
3
3
  import {
4
4
  getZodDescription,
@@ -6,20 +6,16 @@ import {
6
6
  isMidsceneLocatorField,
7
7
  unwrapZodField,
8
8
  } from '../zod-schema-utils';
9
+ import { getErrorMessage } from './error-formatter';
9
10
  import type {
10
11
  ActionSpaceItem,
11
12
  BaseAgent,
13
+ ToolCliMetadata,
12
14
  ToolDefinition,
13
15
  ToolResult,
16
+ ToolSchema,
14
17
  } from './types';
15
18
 
16
- /**
17
- * Extract error message from unknown error type
18
- */
19
- function getErrorMessage(error: unknown): string {
20
- return error instanceof Error ? error.message : String(error);
21
- }
22
-
23
19
  /**
24
20
  * Generate MCP tool description from ActionSpaceItem
25
21
  * Format: "actionName action, description. Parameters: param1 (type) - desc; param2 (type) - desc"
@@ -157,10 +153,19 @@ function transformSchemaField(
157
153
  }
158
154
 
159
155
  /**
160
- * Extract and transform schema from action's paramSchema
156
+ * Extract and transform schema from action's paramSchema.
157
+ *
158
+ * CLI and MCP both expose parameters as named fields, so the only schema
159
+ * shapes we can surface are ZodObject (any number of fields) or undefined
160
+ * (the action takes no parameters). A primitive schema like `z.string()`
161
+ * silently degraded to leaking the ZodString instance's prototype methods
162
+ * as CLI flags — see https://github.com/web-infra-dev/midscene/issues/2313.
163
+ * Reject such schemas up front so the next author gets a loud error
164
+ * instead of a silent misconfiguration at runtime.
161
165
  */
162
166
  function extractActionSchema(
163
167
  paramSchema: z.ZodTypeAny | undefined,
168
+ actionName: string,
164
169
  ): Record<string, z.ZodTypeAny> {
165
170
  if (!paramSchema) {
166
171
  return {};
@@ -168,7 +173,12 @@ function extractActionSchema(
168
173
 
169
174
  const shape = getZodObjectShape(paramSchema);
170
175
  if (!shape) {
171
- return paramSchema as unknown as Record<string, z.ZodTypeAny>;
176
+ const typeName =
177
+ (paramSchema as unknown as { _def?: { typeName?: string } })?._def
178
+ ?.typeName ?? 'unknown';
179
+ throw new Error(
180
+ `Action "${actionName}" declared a non-object paramSchema (${typeName}). CLI and MCP tool schemas must be a ZodObject (e.g. z.object({ uri: z.string() })) or undefined. Wrap primitive fields in an object schema.`,
181
+ );
172
182
  }
173
183
 
174
184
  return Object.fromEntries(
@@ -453,25 +463,49 @@ async function captureFailureResult(
453
463
  }
454
464
  }
455
465
 
466
+ function mergeToolCliMetadata(
467
+ base?: ToolCliMetadata,
468
+ extra?: ToolCliMetadata,
469
+ ): ToolCliMetadata | undefined {
470
+ const options = {
471
+ ...(base?.options ?? {}),
472
+ ...(extra?.options ?? {}),
473
+ };
474
+
475
+ return Object.keys(options).length > 0 ? { options } : undefined;
476
+ }
477
+
456
478
  /**
457
479
  * Converts DeviceAction from actionSpace into MCP ToolDefinition
458
480
  * This is the core logic that removes need for hardcoded tool definitions
459
481
  */
460
482
  export function generateToolsFromActionSpace(
461
483
  actionSpace: ActionSpaceItem[],
462
- getAgent: () => Promise<BaseAgent>,
484
+ getAgent: (args?: Record<string, unknown>) => Promise<BaseAgent>,
485
+ sanitizeArgs: (args: Record<string, unknown>) => Record<string, unknown> = (
486
+ args,
487
+ ) => args,
488
+ initArgSchema: ToolSchema = {},
489
+ initArgCliMetadata?: ToolCliMetadata,
463
490
  ): ToolDefinition[] {
464
491
  return actionSpace.map((action) => {
465
- const schema = extractActionSchema(action.paramSchema as z.ZodTypeAny);
492
+ const schema = {
493
+ ...extractActionSchema(action.paramSchema as z.ZodTypeAny, action.name),
494
+ ...initArgSchema,
495
+ };
466
496
 
467
497
  return {
468
498
  name: action.name,
469
499
  description: describeActionForMCP(action),
470
500
  schema,
501
+ cli: initArgCliMetadata,
471
502
  handler: async (args: Record<string, unknown>) => {
472
503
  try {
473
- const agent = await getAgent();
474
- const normalizedArgs = normalizeActionArgs(args, action.paramSchema);
504
+ const agent = await getAgent(args);
505
+ const normalizedArgs = normalizeActionArgs(
506
+ sanitizeArgs(args),
507
+ action.paramSchema,
508
+ );
475
509
  let actionResult: unknown;
476
510
 
477
511
  try {
@@ -513,16 +547,23 @@ export function generateToolsFromActionSpace(
513
547
  * Generate common tools (screenshot, act)
514
548
  */
515
549
  export function generateCommonTools(
516
- getAgent: () => Promise<BaseAgent>,
550
+ getAgent: (args?: Record<string, unknown>) => Promise<BaseAgent>,
551
+ initArgSchema: ToolSchema = {},
552
+ initArgCliMetadata?: ToolCliMetadata,
517
553
  ): ToolDefinition[] {
518
554
  return [
519
555
  {
520
556
  name: 'take_screenshot',
521
557
  description: 'Capture screenshot of current page/screen',
522
- schema: {},
523
- handler: async (): Promise<ToolResult> => {
558
+ schema: {
559
+ ...initArgSchema,
560
+ },
561
+ cli: initArgCliMetadata,
562
+ handler: async (
563
+ args: Record<string, unknown> = {},
564
+ ): Promise<ToolResult> => {
524
565
  try {
525
- const agent = await getAgent();
566
+ const agent = await getAgent(args);
526
567
  const screenshot = await agent.page?.screenshotBase64();
527
568
  if (!screenshot) {
528
569
  return createErrorResult('Screenshot not available');
@@ -550,11 +591,15 @@ export function generateCommonTools(
550
591
  .describe(
551
592
  'Natural language description of the action to perform, e.g. "press Command+Space, type Safari, press Enter"',
552
593
  ),
594
+ ...initArgSchema,
553
595
  },
554
- handler: async (args: Record<string, unknown>): Promise<ToolResult> => {
596
+ cli: mergeToolCliMetadata(undefined, initArgCliMetadata),
597
+ handler: async (
598
+ args: Record<string, unknown> = {},
599
+ ): Promise<ToolResult> => {
555
600
  const prompt = args.prompt as string;
556
601
  try {
557
- const agent = await getAgent();
602
+ const agent = await getAgent(args);
558
603
  if (!agent.aiAction) {
559
604
  return createErrorResult('act is not supported by this agent');
560
605
  }
@@ -576,5 +621,38 @@ export function generateCommonTools(
576
621
  }
577
622
  },
578
623
  },
624
+ {
625
+ name: 'assert',
626
+ description:
627
+ 'Assert a natural language statement against the current page/screen.',
628
+ schema: {
629
+ prompt: z
630
+ .string()
631
+ .describe(
632
+ 'Natural language assertion to verify, e.g. "there is a login button visible"',
633
+ ),
634
+ ...initArgSchema,
635
+ },
636
+ cli: mergeToolCliMetadata(undefined, initArgCliMetadata),
637
+ handler: async (
638
+ args: Record<string, unknown> = {},
639
+ ): Promise<ToolResult> => {
640
+ const prompt = args.prompt as string;
641
+ try {
642
+ const agent = await getAgent(args);
643
+ if (!agent.aiAssert) {
644
+ return createErrorResult('assert is not supported by this agent');
645
+ }
646
+ await agent.aiAssert(prompt);
647
+ return {
648
+ content: [{ type: 'text', text: 'Assertion passed.' }],
649
+ };
650
+ } catch (error: unknown) {
651
+ const errorMessage = getErrorMessage(error);
652
+ console.error('Error executing assert:', errorMessage);
653
+ return createErrorResult(`Failed to execute assert: ${errorMessage}`);
654
+ }
655
+ },
656
+ },
579
657
  ];
580
658
  }
package/src/mcp/types.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { z } from 'zod';
3
3
 
4
- // Avoid circular dependency: don't import from @midscene/core
4
+ // Avoid circular dependency: don't import from @aiscene/core
5
5
  // Instead, use generic types that will be provided by implementation
6
6
 
7
7
  /**
@@ -47,6 +47,15 @@ export type ToolHandler<T = Record<string, unknown>> = (
47
47
  */
48
48
  export type ToolSchema = Record<string, z.ZodTypeAny>;
49
49
 
50
+ export interface ToolCliOption {
51
+ preferredName?: string;
52
+ aliases?: string[];
53
+ }
54
+
55
+ export interface ToolCliMetadata {
56
+ options?: Record<string, ToolCliOption>;
57
+ }
58
+
50
59
  /**
51
60
  * Tool definition for MCP server
52
61
  */
@@ -55,6 +64,7 @@ export interface ToolDefinition<T = Record<string, unknown>> {
55
64
  description: string;
56
65
  schema: ToolSchema;
57
66
  handler: ToolHandler<T>;
67
+ cli?: ToolCliMetadata;
58
68
  }
59
69
 
60
70
  /**
@@ -96,6 +106,11 @@ export interface BaseAgent {
96
106
  assertion: string,
97
107
  options: Record<string, unknown>,
98
108
  ) => Promise<unknown>;
109
+ aiAssert?: (
110
+ assertion: string,
111
+ msg?: string,
112
+ options?: Record<string, unknown>,
113
+ ) => Promise<unknown>;
99
114
  }
100
115
 
101
116
  /**