@midscene/shared 1.7.5-beta-20260421030751.0 → 1.7.5
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/dist/es/cli/cli-args.mjs +95 -0
- package/dist/es/cli/cli-error.mjs +24 -0
- package/dist/es/cli/cli-runner.mjs +10 -40
- package/dist/es/cli/index.mjs +4 -2
- package/dist/es/constants/index.mjs +3 -2
- package/dist/es/key-alias-utils.mjs +19 -0
- package/dist/es/mcp/base-tools.mjs +45 -2
- package/dist/es/mcp/index.mjs +1 -0
- package/dist/es/mcp/init-arg-utils.mjs +38 -0
- package/dist/es/mcp/tool-generator.mjs +29 -11
- package/dist/lib/cli/cli-args.js +138 -0
- package/dist/lib/cli/cli-error.js +61 -0
- package/dist/lib/cli/cli-runner.js +19 -46
- package/dist/lib/cli/index.js +8 -3
- package/dist/lib/constants/index.js +5 -1
- package/dist/lib/key-alias-utils.js +62 -0
- package/dist/lib/mcp/base-tools.js +45 -2
- package/dist/lib/mcp/index.js +19 -12
- package/dist/lib/mcp/init-arg-utils.js +78 -0
- package/dist/lib/mcp/tool-generator.js +29 -11
- package/dist/types/cli/cli-args.d.ts +8 -0
- package/dist/types/cli/cli-error.d.ts +5 -0
- package/dist/types/cli/cli-runner.d.ts +4 -7
- package/dist/types/cli/index.d.ts +3 -1
- package/dist/types/constants/index.d.ts +1 -0
- package/dist/types/key-alias-utils.d.ts +9 -0
- package/dist/types/mcp/base-tools.d.ts +65 -5
- package/dist/types/mcp/index.d.ts +1 -0
- package/dist/types/mcp/init-arg-utils.d.ts +13 -0
- package/dist/types/mcp/tool-generator.d.ts +3 -3
- package/dist/types/mcp/types.d.ts +8 -0
- package/package.json +1 -1
- package/src/cli/cli-args.ts +173 -0
- package/src/cli/cli-error.ts +24 -0
- package/src/cli/cli-runner.ts +37 -56
- package/src/cli/index.ts +3 -7
- package/src/constants/index.ts +2 -0
- package/src/key-alias-utils.ts +23 -0
- package/src/mcp/base-tools.ts +164 -9
- package/src/mcp/index.ts +1 -0
- package/src/mcp/init-arg-utils.ts +105 -0
- package/src/mcp/tool-generator.ts +47 -10
- package/src/mcp/types.ts +10 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getKeyAliases } from "../key-alias-utils.mjs";
|
|
3
|
+
function parseValue(raw) {
|
|
4
|
+
if (raw.startsWith('{') || raw.startsWith('[')) try {
|
|
5
|
+
return JSON.parse(raw);
|
|
6
|
+
} catch {}
|
|
7
|
+
if (/^-?\d+(\.\d+)?$/.test(raw)) return Number(raw);
|
|
8
|
+
return raw;
|
|
9
|
+
}
|
|
10
|
+
function walkCliArgs(args, setArgValue) {
|
|
11
|
+
for(let i = 0; i < args.length; i++){
|
|
12
|
+
const arg = args[i];
|
|
13
|
+
if (!arg.startsWith('--')) continue;
|
|
14
|
+
const body = arg.slice(2);
|
|
15
|
+
const eqIdx = body.indexOf('=');
|
|
16
|
+
if (eqIdx >= 0) setArgValue(body.slice(0, eqIdx), parseValue(body.slice(eqIdx + 1)));
|
|
17
|
+
else if (args[i + 1] && !args[i + 1].startsWith('--')) {
|
|
18
|
+
i++;
|
|
19
|
+
setArgValue(body, parseValue(args[i]));
|
|
20
|
+
} else setArgValue(body, true);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function parseCliArgs(args) {
|
|
24
|
+
const result = {};
|
|
25
|
+
walkCliArgs(args, (key, value)=>{
|
|
26
|
+
result[key] = value;
|
|
27
|
+
});
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function formatCliOptionName(name) {
|
|
31
|
+
return `--${name}`;
|
|
32
|
+
}
|
|
33
|
+
function getCliOptionDisplay(key, cliOption) {
|
|
34
|
+
const label = formatCliOptionName(cliOption?.preferredName ?? key);
|
|
35
|
+
const aliases = [
|
|
36
|
+
...new Set(cliOption?.aliases ?? [])
|
|
37
|
+
].map((alias)=>formatCliOptionName(alias)).filter((alias)=>alias !== label);
|
|
38
|
+
return {
|
|
39
|
+
label,
|
|
40
|
+
aliases
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function getAcceptedCliOptionNames(key, cliOption) {
|
|
44
|
+
return [
|
|
45
|
+
...new Set(cliOption ? [
|
|
46
|
+
cliOption.preferredName ?? key,
|
|
47
|
+
...cliOption.aliases ?? []
|
|
48
|
+
] : [
|
|
49
|
+
key,
|
|
50
|
+
...getKeyAliases(key)
|
|
51
|
+
])
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
function toOptionalCliSchemaField(field) {
|
|
55
|
+
if ('object' == typeof field && null !== field && 'function' == typeof field.optional) return field.optional();
|
|
56
|
+
const description = 'object' == typeof field && null !== field && "description" in field && 'string' == typeof field.description ? field.description : void 0;
|
|
57
|
+
return description ? z.any().describe(description) : z.any();
|
|
58
|
+
}
|
|
59
|
+
function buildCliArgSchema(def) {
|
|
60
|
+
return Object.fromEntries(Object.entries(def.schema).flatMap(([key, zodType])=>getAcceptedCliOptionNames(key, def.cli?.options?.[key]).map((cliKey)=>[
|
|
61
|
+
cliKey,
|
|
62
|
+
toOptionalCliSchemaField(zodType)
|
|
63
|
+
])));
|
|
64
|
+
}
|
|
65
|
+
function buildDisallowedCliSpellings(def) {
|
|
66
|
+
const disallowedSpellings = new Set();
|
|
67
|
+
for (const [key] of Object.entries(def.schema)){
|
|
68
|
+
const cliOption = def.cli?.options?.[key];
|
|
69
|
+
const acceptedNames = new Set(getAcceptedCliOptionNames(key, cliOption));
|
|
70
|
+
const knownSpellings = new Set([
|
|
71
|
+
key,
|
|
72
|
+
...getKeyAliases(key),
|
|
73
|
+
...cliOption?.preferredName ? getKeyAliases(cliOption.preferredName) : [],
|
|
74
|
+
...cliOption?.aliases ?? []
|
|
75
|
+
]);
|
|
76
|
+
for (const spelling of knownSpellings)if (!acceptedNames.has(spelling)) disallowedSpellings.add(spelling);
|
|
77
|
+
}
|
|
78
|
+
return disallowedSpellings;
|
|
79
|
+
}
|
|
80
|
+
function formatCliValidationError(scriptName, commandName, def, rawArgs) {
|
|
81
|
+
if (0 === Object.keys(def.schema).length) return;
|
|
82
|
+
const cliSchema = z.object(buildCliArgSchema(def)).strict();
|
|
83
|
+
const parsed = cliSchema.safeParse(rawArgs);
|
|
84
|
+
if (parsed.success) return;
|
|
85
|
+
const disallowedSpellings = buildDisallowedCliSpellings(def);
|
|
86
|
+
const unknownKeys = parsed.error.issues.flatMap((issue)=>'unrecognized_keys' === issue.code ? issue.keys : []);
|
|
87
|
+
if (unknownKeys.length > 0) return unknownKeys.map((key)=>{
|
|
88
|
+
if (disallowedSpellings.has(key)) return `Unsupported option "--${key}" for ${scriptName} ${commandName}.`;
|
|
89
|
+
return `Unknown option "--${key}" for ${scriptName} ${commandName}.`;
|
|
90
|
+
}).join('\n');
|
|
91
|
+
const [issue] = parsed.error.issues;
|
|
92
|
+
const optionName = 'string' == typeof issue?.path[0] ? `--${issue.path[0]}` : 'CLI arguments';
|
|
93
|
+
return `Invalid value for "${optionName}" in ${scriptName} ${commandName}: ${issue?.message ?? parsed.error.message}`;
|
|
94
|
+
}
|
|
95
|
+
export { formatCliValidationError, getCliOptionDisplay, parseCliArgs, parseValue };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
3
|
+
value: value,
|
|
4
|
+
enumerable: true,
|
|
5
|
+
configurable: true,
|
|
6
|
+
writable: true
|
|
7
|
+
});
|
|
8
|
+
else obj[key] = value;
|
|
9
|
+
return obj;
|
|
10
|
+
}
|
|
11
|
+
class CLIError extends Error {
|
|
12
|
+
constructor(message, exitCode = 1){
|
|
13
|
+
super(message), _define_property(this, "exitCode", void 0), this.exitCode = exitCode;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function reportCLIError(error, log = console.error) {
|
|
17
|
+
if (error instanceof CLIError) {
|
|
18
|
+
log(error.message);
|
|
19
|
+
return error.exitCode;
|
|
20
|
+
}
|
|
21
|
+
log(error);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
export { CLIError, reportCLIError };
|
|
@@ -3,44 +3,9 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import dotenv from "dotenv";
|
|
5
5
|
import { getDebug } from "../logger.mjs";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
value: value,
|
|
9
|
-
enumerable: true,
|
|
10
|
-
configurable: true,
|
|
11
|
-
writable: true
|
|
12
|
-
});
|
|
13
|
-
else obj[key] = value;
|
|
14
|
-
return obj;
|
|
15
|
-
}
|
|
6
|
+
import { formatCliValidationError, getCliOptionDisplay, parseCliArgs, parseValue } from "./cli-args.mjs";
|
|
7
|
+
import { CLIError, reportCLIError } from "./cli-error.mjs";
|
|
16
8
|
const debug = getDebug('cli-runner');
|
|
17
|
-
class CLIError extends Error {
|
|
18
|
-
constructor(message, exitCode = 1){
|
|
19
|
-
super(message), _define_property(this, "exitCode", void 0), this.exitCode = exitCode;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function parseValue(raw) {
|
|
23
|
-
if (raw.startsWith('{') || raw.startsWith('[')) try {
|
|
24
|
-
return JSON.parse(raw);
|
|
25
|
-
} catch {}
|
|
26
|
-
if (/^-?\d+(\.\d+)?$/.test(raw)) return Number(raw);
|
|
27
|
-
return raw;
|
|
28
|
-
}
|
|
29
|
-
function parseCliArgs(args) {
|
|
30
|
-
const result = {};
|
|
31
|
-
for(let i = 0; i < args.length; i++){
|
|
32
|
-
const arg = args[i];
|
|
33
|
-
if (!arg.startsWith('--')) continue;
|
|
34
|
-
const body = arg.slice(2);
|
|
35
|
-
const eqIdx = body.indexOf('=');
|
|
36
|
-
if (eqIdx >= 0) result[body.slice(0, eqIdx)] = parseValue(body.slice(eqIdx + 1));
|
|
37
|
-
else if (args[i + 1] && !args[i + 1].startsWith('--')) {
|
|
38
|
-
i++;
|
|
39
|
-
result[body] = parseValue(args[i]);
|
|
40
|
-
} else result[body] = true;
|
|
41
|
-
}
|
|
42
|
-
return result;
|
|
43
|
-
}
|
|
44
9
|
function outputContentItem(item, isError) {
|
|
45
10
|
switch(item.type){
|
|
46
11
|
case 'text':
|
|
@@ -72,10 +37,13 @@ function printCommandHelp(scriptName, cmd) {
|
|
|
72
37
|
console.log(def.description);
|
|
73
38
|
const schemaEntries = Object.entries(def.schema);
|
|
74
39
|
if (schemaEntries.length > 0) {
|
|
40
|
+
const optionWidth = Math.max(22, ...schemaEntries.map(([key])=>getCliOptionDisplay(key, def.cli?.options?.[key]).label.length));
|
|
75
41
|
console.log('\nOptions:');
|
|
76
42
|
for (const [key, zodType] of schemaEntries){
|
|
43
|
+
const { label, aliases } = getCliOptionDisplay(key, def.cli?.options?.[key]);
|
|
77
44
|
const desc = zodType.description ?? '';
|
|
78
|
-
|
|
45
|
+
const aliasText = aliases.length > 0 ? ` (aliases: ${aliases.join(', ')})` : '';
|
|
46
|
+
console.log(` ${label.padEnd(optionWidth)} ${desc}${aliasText}`);
|
|
79
47
|
}
|
|
80
48
|
}
|
|
81
49
|
}
|
|
@@ -137,16 +105,18 @@ async function runToolsCLI(tools, scriptName, options) {
|
|
|
137
105
|
throw new CLIError(`Unknown command: ${commandName}`);
|
|
138
106
|
}
|
|
139
107
|
const parsedArgs = parseCliArgs(restArgs);
|
|
140
|
-
debug('command: %s, args: %s', match.name, JSON.stringify(parsedArgs));
|
|
141
108
|
if (true === parsedArgs.help) {
|
|
142
109
|
debug('showing command help for: %s', match.name);
|
|
143
110
|
printCommandHelp(scriptName, match);
|
|
144
111
|
return;
|
|
145
112
|
}
|
|
113
|
+
const cliValidationError = formatCliValidationError(scriptName, match.name, match.def, parsedArgs);
|
|
114
|
+
if (cliValidationError) throw new CLIError(cliValidationError);
|
|
115
|
+
debug('command: %s, args: %s', match.name, JSON.stringify(parsedArgs));
|
|
146
116
|
const result = await match.def.handler(parsedArgs);
|
|
147
117
|
debug('command %s completed, isError: %s', match.name, result.isError ?? false);
|
|
148
118
|
outputResult(result);
|
|
149
119
|
await tools.destroy();
|
|
150
120
|
if (result.isError) throw new CLIError('Command failed', 1);
|
|
151
121
|
}
|
|
152
|
-
export { CLIError, parseCliArgs, parseValue, removePrefix, runToolsCLI };
|
|
122
|
+
export { CLIError, parseCliArgs, parseValue, removePrefix, reportCLIError, runToolsCLI };
|
package/dist/es/cli/index.mjs
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import { CLIError,
|
|
2
|
-
|
|
1
|
+
import { CLIError, reportCLIError } from "./cli-error.mjs";
|
|
2
|
+
import { parseCliArgs, parseValue } from "./cli-args.mjs";
|
|
3
|
+
import { removePrefix, runToolsCLI } from "./cli-runner.mjs";
|
|
4
|
+
export { CLIError, parseCliArgs, parseValue, removePrefix, reportCLIError, runToolsCLI };
|
|
@@ -15,13 +15,14 @@ var constants_NodeType = /*#__PURE__*/ function(NodeType) {
|
|
|
15
15
|
}({});
|
|
16
16
|
const PLAYGROUND_SERVER_PORT = 5800;
|
|
17
17
|
const SCRCPY_SERVER_PORT = 5700;
|
|
18
|
+
const SCRCPY_ADB_CONNECT_TIMEOUT_MS = 10000;
|
|
18
19
|
const SCRCPY_PUSH_TIMEOUT_MS = 10000;
|
|
19
20
|
const SCRCPY_START_TIMEOUT_MS = 15000;
|
|
20
21
|
const SCRCPY_VIDEO_STREAM_TIMEOUT_MS = 15000;
|
|
21
|
-
const SCRCPY_PREVIEW_METADATA_TIMEOUT_MS = SCRCPY_PUSH_TIMEOUT_MS + SCRCPY_START_TIMEOUT_MS + SCRCPY_VIDEO_STREAM_TIMEOUT_MS + 5000;
|
|
22
|
+
const SCRCPY_PREVIEW_METADATA_TIMEOUT_MS = SCRCPY_ADB_CONNECT_TIMEOUT_MS + SCRCPY_PUSH_TIMEOUT_MS + SCRCPY_START_TIMEOUT_MS + SCRCPY_VIDEO_STREAM_TIMEOUT_MS + 5000;
|
|
22
23
|
const WEBDRIVER_ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf';
|
|
23
24
|
const DEFAULT_WDA_PORT = 8100;
|
|
24
25
|
const DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT = 5000;
|
|
25
26
|
const DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT = 2000;
|
|
26
27
|
const DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY = 2;
|
|
27
|
-
export { CONTAINER_MINI_HEIGHT, CONTAINER_MINI_WIDTH, DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT, DEFAULT_WDA_PORT, constants_NodeType as NodeType, PLAYGROUND_SERVER_PORT, PLAYWRIGHT_EXAMPLE_CODE, SCRCPY_PREVIEW_METADATA_TIMEOUT_MS, SCRCPY_PUSH_TIMEOUT_MS, SCRCPY_SERVER_PORT, SCRCPY_START_TIMEOUT_MS, SCRCPY_VIDEO_STREAM_TIMEOUT_MS, TEXT_MAX_SIZE, TEXT_SIZE_THRESHOLD, WEBDRIVER_ELEMENT_ID_KEY, YAML_EXAMPLE_CODE };
|
|
28
|
+
export { CONTAINER_MINI_HEIGHT, CONTAINER_MINI_WIDTH, DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT, DEFAULT_WDA_PORT, constants_NodeType as NodeType, PLAYGROUND_SERVER_PORT, PLAYWRIGHT_EXAMPLE_CODE, SCRCPY_ADB_CONNECT_TIMEOUT_MS, SCRCPY_PREVIEW_METADATA_TIMEOUT_MS, SCRCPY_PUSH_TIMEOUT_MS, SCRCPY_SERVER_PORT, SCRCPY_START_TIMEOUT_MS, SCRCPY_VIDEO_STREAM_TIMEOUT_MS, TEXT_MAX_SIZE, TEXT_SIZE_THRESHOLD, WEBDRIVER_ELEMENT_ID_KEY, YAML_EXAMPLE_CODE };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function kebabToCamel(str) {
|
|
2
|
+
return str.replace(/-([a-z])/g, (_, letter)=>letter.toUpperCase());
|
|
3
|
+
}
|
|
4
|
+
function camelToKebab(str) {
|
|
5
|
+
return str.replace(/[A-Z]/g, (letter)=>`-${letter.toLowerCase()}`).replace(/^-/, '');
|
|
6
|
+
}
|
|
7
|
+
function getKeyAliases(key) {
|
|
8
|
+
return [
|
|
9
|
+
...new Set([
|
|
10
|
+
key,
|
|
11
|
+
kebabToCamel(key),
|
|
12
|
+
camelToKebab(key)
|
|
13
|
+
])
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return 'object' == typeof value && null !== value && !Array.isArray(value);
|
|
18
|
+
}
|
|
19
|
+
export { camelToKebab, getKeyAliases, isRecord, kebabToCamel };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { parseBase64 } from "@midscene/shared/img";
|
|
2
2
|
import { getDebug } from "@midscene/shared/logger";
|
|
3
|
+
import { camelToKebab, getKeyAliases } from "../key-alias-utils.mjs";
|
|
4
|
+
import { createNamespacedInitArgSchema, extractNamespacedArgs, sanitizeNamespacedArgs } from "./init-arg-utils.mjs";
|
|
3
5
|
import { generateCommonTools, generateToolsFromActionSpace } from "./tool-generator.mjs";
|
|
4
6
|
function _define_property(obj, key, value) {
|
|
5
7
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
@@ -13,6 +15,47 @@ function _define_property(obj, key, value) {
|
|
|
13
15
|
}
|
|
14
16
|
const debug = getDebug('mcp:base-tools');
|
|
15
17
|
class BaseMidsceneTools {
|
|
18
|
+
getInitArgKeys() {
|
|
19
|
+
return this.initArgSpec ? Object.keys(this.initArgSpec.shape) : [];
|
|
20
|
+
}
|
|
21
|
+
extractAgentInitParam(args) {
|
|
22
|
+
if (!this.initArgSpec) return;
|
|
23
|
+
const extracted = extractNamespacedArgs(args, this.initArgSpec.namespace, this.getInitArgKeys());
|
|
24
|
+
if (this.initArgSpec.adapt) return this.initArgSpec.adapt(extracted);
|
|
25
|
+
return extracted;
|
|
26
|
+
}
|
|
27
|
+
sanitizeToolArgs(args) {
|
|
28
|
+
if (!this.initArgSpec) return args;
|
|
29
|
+
return sanitizeNamespacedArgs(args, this.initArgSpec.namespace, this.getInitArgKeys());
|
|
30
|
+
}
|
|
31
|
+
getAgentInitArgSchema() {
|
|
32
|
+
if (!this.initArgSpec) return {};
|
|
33
|
+
return createNamespacedInitArgSchema(this.initArgSpec.namespace, this.initArgSpec.shape);
|
|
34
|
+
}
|
|
35
|
+
getAgentInitArgCliMetadata() {
|
|
36
|
+
if (!this.initArgSpec?.cli) return;
|
|
37
|
+
const options = Object.fromEntries(this.getInitArgKeys().map((key)=>{
|
|
38
|
+
const canonicalKey = `${this.initArgSpec.namespace}.${key}`;
|
|
39
|
+
const preferredName = this.initArgSpec.cli?.preferredNames?.[key] ?? (this.initArgSpec.cli?.preferBareKeys ? camelToKebab(key) : canonicalKey);
|
|
40
|
+
const acceptedNames = new Set([
|
|
41
|
+
preferredName,
|
|
42
|
+
...this.initArgSpec.cli?.preferBareKeys ? getKeyAliases(key) : getKeyAliases(canonicalKey)
|
|
43
|
+
]);
|
|
44
|
+
acceptedNames.delete(preferredName);
|
|
45
|
+
return [
|
|
46
|
+
canonicalKey,
|
|
47
|
+
{
|
|
48
|
+
preferredName,
|
|
49
|
+
aliases: [
|
|
50
|
+
...acceptedNames
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
}));
|
|
55
|
+
return {
|
|
56
|
+
options
|
|
57
|
+
};
|
|
58
|
+
}
|
|
16
59
|
preparePlatformTools() {
|
|
17
60
|
return [];
|
|
18
61
|
}
|
|
@@ -30,8 +73,8 @@ class BaseMidsceneTools {
|
|
|
30
73
|
await tempDevice.destroy?.();
|
|
31
74
|
debug('Action space from temporary device:', actionSpace.map((a)=>a.name).join(', '));
|
|
32
75
|
}
|
|
33
|
-
const actionTools = generateToolsFromActionSpace(actionSpace, ()=>this.ensureAgent());
|
|
34
|
-
const commonTools = generateCommonTools(()=>this.ensureAgent());
|
|
76
|
+
const actionTools = generateToolsFromActionSpace(actionSpace, (args = {})=>this.ensureAgent(this.extractAgentInitParam(args)), (args = {})=>this.sanitizeToolArgs(args), this.getAgentInitArgSchema(), this.getAgentInitArgCliMetadata());
|
|
77
|
+
const commonTools = generateCommonTools((args = {})=>this.ensureAgent(this.extractAgentInitParam(args)), this.getAgentInitArgSchema(), this.getAgentInitArgCliMetadata());
|
|
35
78
|
this.toolDefinitions.push(...actionTools, ...commonTools);
|
|
36
79
|
debug('Total tools prepared:', this.toolDefinitions.length);
|
|
37
80
|
}
|
package/dist/es/mcp/index.mjs
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getKeyAliases, isRecord } from "../key-alias-utils.mjs";
|
|
2
|
+
function readAliasedValue(args, key) {
|
|
3
|
+
for (const alias of getKeyAliases(key))if (alias in args) return args[alias];
|
|
4
|
+
}
|
|
5
|
+
function readNamespacedArg(args, namespace, key) {
|
|
6
|
+
const namespacedArgs = readAliasedValue(args, namespace);
|
|
7
|
+
if (isRecord(namespacedArgs)) {
|
|
8
|
+
const nestedValue = readAliasedValue(namespacedArgs, key);
|
|
9
|
+
if (void 0 !== nestedValue) return nestedValue;
|
|
10
|
+
}
|
|
11
|
+
const dottedValue = readAliasedValue(args, `${namespace}.${key}`);
|
|
12
|
+
if (void 0 !== dottedValue) return dottedValue;
|
|
13
|
+
const directValue = readAliasedValue(args, key);
|
|
14
|
+
if (void 0 !== directValue) return directValue;
|
|
15
|
+
}
|
|
16
|
+
function extractNamespacedArgs(args, namespace, keys) {
|
|
17
|
+
const extracted = {};
|
|
18
|
+
for (const key of keys){
|
|
19
|
+
const value = readNamespacedArg(args, namespace, key);
|
|
20
|
+
if (void 0 !== value) extracted[key] = value;
|
|
21
|
+
}
|
|
22
|
+
return Object.keys(extracted).length > 0 ? extracted : void 0;
|
|
23
|
+
}
|
|
24
|
+
function sanitizeNamespacedArgs(args, namespace, keys) {
|
|
25
|
+
const excludedKeys = new Set(getKeyAliases(namespace));
|
|
26
|
+
for (const key of keys){
|
|
27
|
+
for (const alias of getKeyAliases(key))excludedKeys.add(alias);
|
|
28
|
+
for (const alias of getKeyAliases(`${namespace}.${key}`))excludedKeys.add(alias);
|
|
29
|
+
}
|
|
30
|
+
return Object.fromEntries(Object.entries(args).filter(([key])=>!excludedKeys.has(key)));
|
|
31
|
+
}
|
|
32
|
+
function createNamespacedInitArgSchema(namespace, shape) {
|
|
33
|
+
return Object.fromEntries(Object.entries(shape).map(([key, value])=>[
|
|
34
|
+
`${namespace}.${key}`,
|
|
35
|
+
value
|
|
36
|
+
]));
|
|
37
|
+
}
|
|
38
|
+
export { createNamespacedInitArgSchema, extractNamespacedArgs, sanitizeNamespacedArgs };
|
|
@@ -277,17 +277,30 @@ async function captureFailureResult(agent, actionName, errorMessage) {
|
|
|
277
277
|
};
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
|
-
function
|
|
280
|
+
function mergeToolCliMetadata(base, extra) {
|
|
281
|
+
const options = {
|
|
282
|
+
...base?.options ?? {},
|
|
283
|
+
...extra?.options ?? {}
|
|
284
|
+
};
|
|
285
|
+
return Object.keys(options).length > 0 ? {
|
|
286
|
+
options
|
|
287
|
+
} : void 0;
|
|
288
|
+
}
|
|
289
|
+
function generateToolsFromActionSpace(actionSpace, getAgent, sanitizeArgs = (args)=>args, initArgSchema = {}, initArgCliMetadata) {
|
|
281
290
|
return actionSpace.map((action)=>{
|
|
282
|
-
const schema =
|
|
291
|
+
const schema = {
|
|
292
|
+
...extractActionSchema(action.paramSchema),
|
|
293
|
+
...initArgSchema
|
|
294
|
+
};
|
|
283
295
|
return {
|
|
284
296
|
name: action.name,
|
|
285
297
|
description: describeActionForMCP(action),
|
|
286
298
|
schema,
|
|
299
|
+
cli: initArgCliMetadata,
|
|
287
300
|
handler: async (args)=>{
|
|
288
301
|
try {
|
|
289
|
-
const agent = await getAgent();
|
|
290
|
-
const normalizedArgs = normalizeActionArgs(args, action.paramSchema);
|
|
302
|
+
const agent = await getAgent(args);
|
|
303
|
+
const normalizedArgs = normalizeActionArgs(sanitizeArgs(args), action.paramSchema);
|
|
291
304
|
let actionResult;
|
|
292
305
|
try {
|
|
293
306
|
actionResult = await executeAction(agent, action.name, normalizedArgs);
|
|
@@ -306,15 +319,18 @@ function generateToolsFromActionSpace(actionSpace, getAgent) {
|
|
|
306
319
|
};
|
|
307
320
|
});
|
|
308
321
|
}
|
|
309
|
-
function generateCommonTools(getAgent) {
|
|
322
|
+
function generateCommonTools(getAgent, initArgSchema = {}, initArgCliMetadata) {
|
|
310
323
|
return [
|
|
311
324
|
{
|
|
312
325
|
name: 'take_screenshot',
|
|
313
326
|
description: 'Capture screenshot of current page/screen',
|
|
314
|
-
schema: {
|
|
315
|
-
|
|
327
|
+
schema: {
|
|
328
|
+
...initArgSchema
|
|
329
|
+
},
|
|
330
|
+
cli: initArgCliMetadata,
|
|
331
|
+
handler: async (args = {})=>{
|
|
316
332
|
try {
|
|
317
|
-
const agent = await getAgent();
|
|
333
|
+
const agent = await getAgent(args);
|
|
318
334
|
const screenshot = await agent.page?.screenshotBase64();
|
|
319
335
|
if (!screenshot) return createErrorResult('Screenshot not available');
|
|
320
336
|
const { mimeType, body } = parseBase64(screenshot);
|
|
@@ -338,12 +354,14 @@ function generateCommonTools(getAgent) {
|
|
|
338
354
|
name: 'act',
|
|
339
355
|
description: 'Execute a natural language action. The AI will plan and perform multi-step operations in a single invocation, useful for transient UI interactions (e.g., Spotlight, dropdown menus) that disappear between separate commands.',
|
|
340
356
|
schema: {
|
|
341
|
-
prompt: z.string().describe('Natural language description of the action to perform, e.g. "press Command+Space, type Safari, press Enter"')
|
|
357
|
+
prompt: z.string().describe('Natural language description of the action to perform, e.g. "press Command+Space, type Safari, press Enter"'),
|
|
358
|
+
...initArgSchema
|
|
342
359
|
},
|
|
343
|
-
|
|
360
|
+
cli: mergeToolCliMetadata(void 0, initArgCliMetadata),
|
|
361
|
+
handler: async (args = {})=>{
|
|
344
362
|
const prompt = args.prompt;
|
|
345
363
|
try {
|
|
346
|
-
const agent = await getAgent();
|
|
364
|
+
const agent = await getAgent(args);
|
|
347
365
|
if (!agent.aiAction) return createErrorResult('act is not supported by this agent');
|
|
348
366
|
const result = await agent.aiAction(prompt, {
|
|
349
367
|
deepThink: false
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
parseCliArgs: ()=>parseCliArgs,
|
|
28
|
+
parseValue: ()=>parseValue,
|
|
29
|
+
formatCliValidationError: ()=>formatCliValidationError,
|
|
30
|
+
getCliOptionDisplay: ()=>getCliOptionDisplay
|
|
31
|
+
});
|
|
32
|
+
const external_zod_namespaceObject = require("zod");
|
|
33
|
+
const external_key_alias_utils_js_namespaceObject = require("../key-alias-utils.js");
|
|
34
|
+
function parseValue(raw) {
|
|
35
|
+
if (raw.startsWith('{') || raw.startsWith('[')) try {
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
} catch {}
|
|
38
|
+
if (/^-?\d+(\.\d+)?$/.test(raw)) return Number(raw);
|
|
39
|
+
return raw;
|
|
40
|
+
}
|
|
41
|
+
function walkCliArgs(args, setArgValue) {
|
|
42
|
+
for(let i = 0; i < args.length; i++){
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
if (!arg.startsWith('--')) continue;
|
|
45
|
+
const body = arg.slice(2);
|
|
46
|
+
const eqIdx = body.indexOf('=');
|
|
47
|
+
if (eqIdx >= 0) setArgValue(body.slice(0, eqIdx), parseValue(body.slice(eqIdx + 1)));
|
|
48
|
+
else if (args[i + 1] && !args[i + 1].startsWith('--')) {
|
|
49
|
+
i++;
|
|
50
|
+
setArgValue(body, parseValue(args[i]));
|
|
51
|
+
} else setArgValue(body, true);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function parseCliArgs(args) {
|
|
55
|
+
const result = {};
|
|
56
|
+
walkCliArgs(args, (key, value)=>{
|
|
57
|
+
result[key] = value;
|
|
58
|
+
});
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
function formatCliOptionName(name) {
|
|
62
|
+
return `--${name}`;
|
|
63
|
+
}
|
|
64
|
+
function getCliOptionDisplay(key, cliOption) {
|
|
65
|
+
const label = formatCliOptionName(cliOption?.preferredName ?? key);
|
|
66
|
+
const aliases = [
|
|
67
|
+
...new Set(cliOption?.aliases ?? [])
|
|
68
|
+
].map((alias)=>formatCliOptionName(alias)).filter((alias)=>alias !== label);
|
|
69
|
+
return {
|
|
70
|
+
label,
|
|
71
|
+
aliases
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function getAcceptedCliOptionNames(key, cliOption) {
|
|
75
|
+
return [
|
|
76
|
+
...new Set(cliOption ? [
|
|
77
|
+
cliOption.preferredName ?? key,
|
|
78
|
+
...cliOption.aliases ?? []
|
|
79
|
+
] : [
|
|
80
|
+
key,
|
|
81
|
+
...(0, external_key_alias_utils_js_namespaceObject.getKeyAliases)(key)
|
|
82
|
+
])
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
function toOptionalCliSchemaField(field) {
|
|
86
|
+
if ('object' == typeof field && null !== field && 'function' == typeof field.optional) return field.optional();
|
|
87
|
+
const description = 'object' == typeof field && null !== field && "description" in field && 'string' == typeof field.description ? field.description : void 0;
|
|
88
|
+
return description ? external_zod_namespaceObject.z.any().describe(description) : external_zod_namespaceObject.z.any();
|
|
89
|
+
}
|
|
90
|
+
function buildCliArgSchema(def) {
|
|
91
|
+
return Object.fromEntries(Object.entries(def.schema).flatMap(([key, zodType])=>getAcceptedCliOptionNames(key, def.cli?.options?.[key]).map((cliKey)=>[
|
|
92
|
+
cliKey,
|
|
93
|
+
toOptionalCliSchemaField(zodType)
|
|
94
|
+
])));
|
|
95
|
+
}
|
|
96
|
+
function buildDisallowedCliSpellings(def) {
|
|
97
|
+
const disallowedSpellings = new Set();
|
|
98
|
+
for (const [key] of Object.entries(def.schema)){
|
|
99
|
+
const cliOption = def.cli?.options?.[key];
|
|
100
|
+
const acceptedNames = new Set(getAcceptedCliOptionNames(key, cliOption));
|
|
101
|
+
const knownSpellings = new Set([
|
|
102
|
+
key,
|
|
103
|
+
...(0, external_key_alias_utils_js_namespaceObject.getKeyAliases)(key),
|
|
104
|
+
...cliOption?.preferredName ? (0, external_key_alias_utils_js_namespaceObject.getKeyAliases)(cliOption.preferredName) : [],
|
|
105
|
+
...cliOption?.aliases ?? []
|
|
106
|
+
]);
|
|
107
|
+
for (const spelling of knownSpellings)if (!acceptedNames.has(spelling)) disallowedSpellings.add(spelling);
|
|
108
|
+
}
|
|
109
|
+
return disallowedSpellings;
|
|
110
|
+
}
|
|
111
|
+
function formatCliValidationError(scriptName, commandName, def, rawArgs) {
|
|
112
|
+
if (0 === Object.keys(def.schema).length) return;
|
|
113
|
+
const cliSchema = external_zod_namespaceObject.z.object(buildCliArgSchema(def)).strict();
|
|
114
|
+
const parsed = cliSchema.safeParse(rawArgs);
|
|
115
|
+
if (parsed.success) return;
|
|
116
|
+
const disallowedSpellings = buildDisallowedCliSpellings(def);
|
|
117
|
+
const unknownKeys = parsed.error.issues.flatMap((issue)=>'unrecognized_keys' === issue.code ? issue.keys : []);
|
|
118
|
+
if (unknownKeys.length > 0) return unknownKeys.map((key)=>{
|
|
119
|
+
if (disallowedSpellings.has(key)) return `Unsupported option "--${key}" for ${scriptName} ${commandName}.`;
|
|
120
|
+
return `Unknown option "--${key}" for ${scriptName} ${commandName}.`;
|
|
121
|
+
}).join('\n');
|
|
122
|
+
const [issue] = parsed.error.issues;
|
|
123
|
+
const optionName = 'string' == typeof issue?.path[0] ? `--${issue.path[0]}` : 'CLI arguments';
|
|
124
|
+
return `Invalid value for "${optionName}" in ${scriptName} ${commandName}: ${issue?.message ?? parsed.error.message}`;
|
|
125
|
+
}
|
|
126
|
+
exports.formatCliValidationError = __webpack_exports__.formatCliValidationError;
|
|
127
|
+
exports.getCliOptionDisplay = __webpack_exports__.getCliOptionDisplay;
|
|
128
|
+
exports.parseCliArgs = __webpack_exports__.parseCliArgs;
|
|
129
|
+
exports.parseValue = __webpack_exports__.parseValue;
|
|
130
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
131
|
+
"formatCliValidationError",
|
|
132
|
+
"getCliOptionDisplay",
|
|
133
|
+
"parseCliArgs",
|
|
134
|
+
"parseValue"
|
|
135
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
136
|
+
Object.defineProperty(exports, '__esModule', {
|
|
137
|
+
value: true
|
|
138
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
CLIError: ()=>CLIError,
|
|
28
|
+
reportCLIError: ()=>reportCLIError
|
|
29
|
+
});
|
|
30
|
+
function _define_property(obj, key, value) {
|
|
31
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
32
|
+
value: value,
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true
|
|
36
|
+
});
|
|
37
|
+
else obj[key] = value;
|
|
38
|
+
return obj;
|
|
39
|
+
}
|
|
40
|
+
class CLIError extends Error {
|
|
41
|
+
constructor(message, exitCode = 1){
|
|
42
|
+
super(message), _define_property(this, "exitCode", void 0), this.exitCode = exitCode;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function reportCLIError(error, log = console.error) {
|
|
46
|
+
if (error instanceof CLIError) {
|
|
47
|
+
log(error.message);
|
|
48
|
+
return error.exitCode;
|
|
49
|
+
}
|
|
50
|
+
log(error);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
exports.CLIError = __webpack_exports__.CLIError;
|
|
54
|
+
exports.reportCLIError = __webpack_exports__.reportCLIError;
|
|
55
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
56
|
+
"CLIError",
|
|
57
|
+
"reportCLIError"
|
|
58
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
59
|
+
Object.defineProperty(exports, '__esModule', {
|
|
60
|
+
value: true
|
|
61
|
+
});
|