@midscene/shared 1.12.6 → 1.12.7-beta-20260911063016.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/dist/es/cli/cli-args.mjs +40 -7
- package/dist/es/cli/cli-runner.mjs +1 -1
- package/dist/es/env/parse-model-config.mjs +1 -1
- package/dist/es/zod-schema-utils.mjs +55 -1
- package/dist/lib/cli/cli-args.js +40 -7
- package/dist/lib/cli/cli-runner.js +1 -1
- package/dist/lib/env/parse-model-config.js +1 -1
- package/dist/lib/zod-schema-utils.js +57 -0
- package/dist/types/cli/cli-args.d.ts +1 -1
- package/dist/types/zod-schema-utils.d.ts +7 -0
- package/package.json +1 -1
- package/src/cli/cli-args.ts +86 -18
- package/src/cli/cli-runner.ts +1 -1
- package/src/zod-schema-utils.ts +70 -0
package/dist/es/cli/cli-args.mjs
CHANGED
|
@@ -1,28 +1,61 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getKeyAliases } from "../key-alias-utils.mjs";
|
|
3
|
+
import { getZodValueKinds } from "../zod-schema-utils.mjs";
|
|
3
4
|
import { CLIError } from "./cli-error.mjs";
|
|
5
|
+
const cliNumberPattern = /^-?\d+(\.\d+)?$/;
|
|
4
6
|
function parseValue(raw) {
|
|
5
7
|
if (raw.startsWith('{') || raw.startsWith('[')) try {
|
|
6
8
|
return JSON.parse(raw);
|
|
7
9
|
} catch {}
|
|
8
|
-
if (
|
|
10
|
+
if (cliNumberPattern.test(raw)) return Number(raw);
|
|
9
11
|
return raw;
|
|
10
12
|
}
|
|
11
|
-
function walkCliArgs(args, setArgValue) {
|
|
13
|
+
function walkCliArgs(args, setArgValue, fieldByCliName) {
|
|
12
14
|
for(let i = 0; i < args.length; i++){
|
|
13
15
|
const arg = args[i];
|
|
14
16
|
if (!arg.startsWith('--')) continue;
|
|
15
17
|
const body = arg.slice(2);
|
|
16
18
|
const eqIdx = body.indexOf('=');
|
|
17
|
-
if (eqIdx >= 0)
|
|
18
|
-
|
|
19
|
+
if (eqIdx >= 0) {
|
|
20
|
+
const key = body.slice(0, eqIdx);
|
|
21
|
+
setArgValue(key, parseCliValue(body.slice(eqIdx + 1), fieldByCliName?.get(key)));
|
|
22
|
+
} else if (args[i + 1] && !args[i + 1].startsWith('--')) {
|
|
19
23
|
i++;
|
|
20
|
-
setArgValue(body,
|
|
24
|
+
setArgValue(body, parseCliValue(args[i], fieldByCliName?.get(body)));
|
|
21
25
|
} else setArgValue(body, true);
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
|
-
function
|
|
28
|
+
function buildCliFieldIndex(def) {
|
|
29
|
+
const fieldByCliName = new Map();
|
|
30
|
+
for (const [schemaKey, field] of Object.entries(def.schema))for (const cliName of getAcceptedCliOptionNames(schemaKey, def.cli?.options?.[schemaKey]))fieldByCliName.set(cliName, field);
|
|
31
|
+
return fieldByCliName;
|
|
32
|
+
}
|
|
33
|
+
function parseJsonValue(raw) {
|
|
34
|
+
if (!raw.startsWith('{') && !raw.startsWith('[')) return raw;
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
} catch {
|
|
38
|
+
return raw;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function parseCliValue(raw, field) {
|
|
42
|
+
if (!field) return parseValue(raw);
|
|
43
|
+
const kinds = getZodValueKinds(field);
|
|
44
|
+
if (kinds.has('object') || kinds.has('array')) {
|
|
45
|
+
const parsedJson = parseJsonValue(raw);
|
|
46
|
+
if (parsedJson !== raw) return parsedJson;
|
|
47
|
+
}
|
|
48
|
+
if (kinds.has('string')) return raw;
|
|
49
|
+
if (kinds.has('number') && cliNumberPattern.test(raw)) return Number(raw);
|
|
50
|
+
if (kinds.has('boolean')) {
|
|
51
|
+
if ('true' === raw) return true;
|
|
52
|
+
if ('false' === raw) return false;
|
|
53
|
+
}
|
|
54
|
+
return kinds.has('unknown') ? parseValue(raw) : raw;
|
|
55
|
+
}
|
|
56
|
+
function parseCliArgs(args, def) {
|
|
25
57
|
const result = {};
|
|
58
|
+
const fieldByCliName = def ? buildCliFieldIndex(def) : void 0;
|
|
26
59
|
walkCliArgs(args, (key, value)=>{
|
|
27
60
|
const existing = result[key];
|
|
28
61
|
if (void 0 === existing) {
|
|
@@ -38,7 +71,7 @@ function parseCliArgs(args) {
|
|
|
38
71
|
existing,
|
|
39
72
|
value
|
|
40
73
|
];
|
|
41
|
-
});
|
|
74
|
+
}, fieldByCliName);
|
|
42
75
|
return result;
|
|
43
76
|
}
|
|
44
77
|
function formatCliOptionName(name) {
|
|
@@ -155,7 +155,7 @@ async function runToolsCLI(tools, scriptName, options) {
|
|
|
155
155
|
}
|
|
156
156
|
const parsedArgs = {
|
|
157
157
|
...positionalArgs,
|
|
158
|
-
...parseCliArgs(restArgs.slice(optionStartIndex))
|
|
158
|
+
...parseCliArgs(restArgs.slice(optionStartIndex), match.def)
|
|
159
159
|
};
|
|
160
160
|
if (true === parsedArgs.help) {
|
|
161
161
|
debug('showing command help for: %s', match.name);
|
|
@@ -5,7 +5,7 @@ import { assert } from "../utils.mjs";
|
|
|
5
5
|
import { maskConfig, parseJson } from "./helper.mjs";
|
|
6
6
|
import { initDebugConfig } from "./init-debug.mjs";
|
|
7
7
|
const MODEL_CONFIG_DOC_URL = 'https://midscenejs.com/model-common-config.html';
|
|
8
|
-
const getCurrentVersion = ()=>"1.12.
|
|
8
|
+
const getCurrentVersion = ()=>"1.12.7-beta-20260911063016.0";
|
|
9
9
|
const getInvalidModelFamilyMessage = (modelFamily)=>`Invalid MIDSCENE_MODEL_FAMILY value: ${modelFamily}. Current version v${getCurrentVersion()} accepts the following model families: ${MODEL_FAMILY_VALUES.join(', ')}. You can also visit ${MODEL_CONFIG_DOC_URL} for the latest configuration information.`;
|
|
10
10
|
const KEYS_MAP = {
|
|
11
11
|
insight: INSIGHT_MODEL_CONFIG_KEYS,
|
|
@@ -8,6 +8,60 @@ function unwrapZodField(field) {
|
|
|
8
8
|
}
|
|
9
9
|
return f;
|
|
10
10
|
}
|
|
11
|
+
function getLiteralValueKind(value) {
|
|
12
|
+
if ('string' == typeof value) return 'string';
|
|
13
|
+
if ('number' == typeof value) return 'number';
|
|
14
|
+
if ('boolean' == typeof value) return 'boolean';
|
|
15
|
+
return 'unknown';
|
|
16
|
+
}
|
|
17
|
+
function getNativeEnumValueKinds(values) {
|
|
18
|
+
const enumValues = Object.entries(values ?? {}).filter(([key])=>Number.isNaN(Number(key))).map(([, value])=>value);
|
|
19
|
+
return new Set(enumValues.map(getLiteralValueKind));
|
|
20
|
+
}
|
|
21
|
+
function getZodValueKinds(field) {
|
|
22
|
+
const actualField = unwrapZodField(field);
|
|
23
|
+
const definition = actualField._def;
|
|
24
|
+
switch(definition?.typeName){
|
|
25
|
+
case 'ZodString':
|
|
26
|
+
case 'ZodEnum':
|
|
27
|
+
return new Set([
|
|
28
|
+
'string'
|
|
29
|
+
]);
|
|
30
|
+
case 'ZodNumber':
|
|
31
|
+
return new Set([
|
|
32
|
+
'number'
|
|
33
|
+
]);
|
|
34
|
+
case 'ZodBoolean':
|
|
35
|
+
return new Set([
|
|
36
|
+
'boolean'
|
|
37
|
+
]);
|
|
38
|
+
case 'ZodArray':
|
|
39
|
+
case 'ZodTuple':
|
|
40
|
+
return new Set([
|
|
41
|
+
'array'
|
|
42
|
+
]);
|
|
43
|
+
case 'ZodObject':
|
|
44
|
+
case 'ZodRecord':
|
|
45
|
+
case 'ZodDiscriminatedUnion':
|
|
46
|
+
return new Set([
|
|
47
|
+
'object'
|
|
48
|
+
]);
|
|
49
|
+
case 'ZodLiteral':
|
|
50
|
+
return new Set([
|
|
51
|
+
getLiteralValueKind(definition.value)
|
|
52
|
+
]);
|
|
53
|
+
case 'ZodNativeEnum':
|
|
54
|
+
return getNativeEnumValueKinds(definition.values);
|
|
55
|
+
case 'ZodUnion':
|
|
56
|
+
return new Set((definition.options ?? []).flatMap((option)=>[
|
|
57
|
+
...getZodValueKinds(option)
|
|
58
|
+
]));
|
|
59
|
+
default:
|
|
60
|
+
return new Set([
|
|
61
|
+
'unknown'
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
11
65
|
function isMidsceneLocatorField(field) {
|
|
12
66
|
const actualField = unwrapZodField(field);
|
|
13
67
|
if (actualField._def?.typeName === 'ZodObject') {
|
|
@@ -47,4 +101,4 @@ function getZodDescription(field) {
|
|
|
47
101
|
if (isMidsceneLocatorField(actualField)) return 'Location information for the target element';
|
|
48
102
|
return null;
|
|
49
103
|
}
|
|
50
|
-
export { getZodDescription, getZodTypeName, isMidsceneLocatorField, unwrapZodField };
|
|
104
|
+
export { getZodDescription, getZodTypeName, getZodValueKinds, isMidsceneLocatorField, unwrapZodField };
|
package/dist/lib/cli/cli-args.js
CHANGED
|
@@ -32,29 +32,62 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
32
32
|
});
|
|
33
33
|
const external_zod_namespaceObject = require("zod");
|
|
34
34
|
const external_key_alias_utils_js_namespaceObject = require("../key-alias-utils.js");
|
|
35
|
+
const external_zod_schema_utils_js_namespaceObject = require("../zod-schema-utils.js");
|
|
35
36
|
const external_cli_error_js_namespaceObject = require("./cli-error.js");
|
|
37
|
+
const cliNumberPattern = /^-?\d+(\.\d+)?$/;
|
|
36
38
|
function parseValue(raw) {
|
|
37
39
|
if (raw.startsWith('{') || raw.startsWith('[')) try {
|
|
38
40
|
return JSON.parse(raw);
|
|
39
41
|
} catch {}
|
|
40
|
-
if (
|
|
42
|
+
if (cliNumberPattern.test(raw)) return Number(raw);
|
|
41
43
|
return raw;
|
|
42
44
|
}
|
|
43
|
-
function walkCliArgs(args, setArgValue) {
|
|
45
|
+
function walkCliArgs(args, setArgValue, fieldByCliName) {
|
|
44
46
|
for(let i = 0; i < args.length; i++){
|
|
45
47
|
const arg = args[i];
|
|
46
48
|
if (!arg.startsWith('--')) continue;
|
|
47
49
|
const body = arg.slice(2);
|
|
48
50
|
const eqIdx = body.indexOf('=');
|
|
49
|
-
if (eqIdx >= 0)
|
|
50
|
-
|
|
51
|
+
if (eqIdx >= 0) {
|
|
52
|
+
const key = body.slice(0, eqIdx);
|
|
53
|
+
setArgValue(key, parseCliValue(body.slice(eqIdx + 1), fieldByCliName?.get(key)));
|
|
54
|
+
} else if (args[i + 1] && !args[i + 1].startsWith('--')) {
|
|
51
55
|
i++;
|
|
52
|
-
setArgValue(body,
|
|
56
|
+
setArgValue(body, parseCliValue(args[i], fieldByCliName?.get(body)));
|
|
53
57
|
} else setArgValue(body, true);
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
|
-
function
|
|
60
|
+
function buildCliFieldIndex(def) {
|
|
61
|
+
const fieldByCliName = new Map();
|
|
62
|
+
for (const [schemaKey, field] of Object.entries(def.schema))for (const cliName of getAcceptedCliOptionNames(schemaKey, def.cli?.options?.[schemaKey]))fieldByCliName.set(cliName, field);
|
|
63
|
+
return fieldByCliName;
|
|
64
|
+
}
|
|
65
|
+
function parseJsonValue(raw) {
|
|
66
|
+
if (!raw.startsWith('{') && !raw.startsWith('[')) return raw;
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(raw);
|
|
69
|
+
} catch {
|
|
70
|
+
return raw;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function parseCliValue(raw, field) {
|
|
74
|
+
if (!field) return parseValue(raw);
|
|
75
|
+
const kinds = (0, external_zod_schema_utils_js_namespaceObject.getZodValueKinds)(field);
|
|
76
|
+
if (kinds.has('object') || kinds.has('array')) {
|
|
77
|
+
const parsedJson = parseJsonValue(raw);
|
|
78
|
+
if (parsedJson !== raw) return parsedJson;
|
|
79
|
+
}
|
|
80
|
+
if (kinds.has('string')) return raw;
|
|
81
|
+
if (kinds.has('number') && cliNumberPattern.test(raw)) return Number(raw);
|
|
82
|
+
if (kinds.has('boolean')) {
|
|
83
|
+
if ('true' === raw) return true;
|
|
84
|
+
if ('false' === raw) return false;
|
|
85
|
+
}
|
|
86
|
+
return kinds.has('unknown') ? parseValue(raw) : raw;
|
|
87
|
+
}
|
|
88
|
+
function parseCliArgs(args, def) {
|
|
57
89
|
const result = {};
|
|
90
|
+
const fieldByCliName = def ? buildCliFieldIndex(def) : void 0;
|
|
58
91
|
walkCliArgs(args, (key, value)=>{
|
|
59
92
|
const existing = result[key];
|
|
60
93
|
if (void 0 === existing) {
|
|
@@ -70,7 +103,7 @@ function parseCliArgs(args) {
|
|
|
70
103
|
existing,
|
|
71
104
|
value
|
|
72
105
|
];
|
|
73
|
-
});
|
|
106
|
+
}, fieldByCliName);
|
|
74
107
|
return result;
|
|
75
108
|
}
|
|
76
109
|
function formatCliOptionName(name) {
|
|
@@ -198,7 +198,7 @@ async function runToolsCLI(tools, scriptName, options) {
|
|
|
198
198
|
}
|
|
199
199
|
const parsedArgs = {
|
|
200
200
|
...positionalArgs,
|
|
201
|
-
...(0, external_cli_args_js_namespaceObject.parseCliArgs)(restArgs.slice(optionStartIndex))
|
|
201
|
+
...(0, external_cli_args_js_namespaceObject.parseCliArgs)(restArgs.slice(optionStartIndex), match.def)
|
|
202
202
|
};
|
|
203
203
|
if (true === parsedArgs.help) {
|
|
204
204
|
debug('showing command help for: %s', match.name);
|
|
@@ -37,7 +37,7 @@ const external_utils_js_namespaceObject = require("../utils.js");
|
|
|
37
37
|
const external_helper_js_namespaceObject = require("./helper.js");
|
|
38
38
|
const external_init_debug_js_namespaceObject = require("./init-debug.js");
|
|
39
39
|
const MODEL_CONFIG_DOC_URL = 'https://midscenejs.com/model-common-config.html';
|
|
40
|
-
const getCurrentVersion = ()=>"1.12.
|
|
40
|
+
const getCurrentVersion = ()=>"1.12.7-beta-20260911063016.0";
|
|
41
41
|
const getInvalidModelFamilyMessage = (modelFamily)=>`Invalid MIDSCENE_MODEL_FAMILY value: ${modelFamily}. Current version v${getCurrentVersion()} accepts the following model families: ${external_types_js_namespaceObject.MODEL_FAMILY_VALUES.join(', ')}. You can also visit ${MODEL_CONFIG_DOC_URL} for the latest configuration information.`;
|
|
42
42
|
const KEYS_MAP = {
|
|
43
43
|
insight: external_constants_js_namespaceObject.INSIGHT_MODEL_CONFIG_KEYS,
|
|
@@ -26,6 +26,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
getZodDescription: ()=>getZodDescription,
|
|
28
28
|
getZodTypeName: ()=>getZodTypeName,
|
|
29
|
+
getZodValueKinds: ()=>getZodValueKinds,
|
|
29
30
|
isMidsceneLocatorField: ()=>isMidsceneLocatorField,
|
|
30
31
|
unwrapZodField: ()=>unwrapZodField
|
|
31
32
|
});
|
|
@@ -39,6 +40,60 @@ function unwrapZodField(field) {
|
|
|
39
40
|
}
|
|
40
41
|
return f;
|
|
41
42
|
}
|
|
43
|
+
function getLiteralValueKind(value) {
|
|
44
|
+
if ('string' == typeof value) return 'string';
|
|
45
|
+
if ('number' == typeof value) return 'number';
|
|
46
|
+
if ('boolean' == typeof value) return 'boolean';
|
|
47
|
+
return 'unknown';
|
|
48
|
+
}
|
|
49
|
+
function getNativeEnumValueKinds(values) {
|
|
50
|
+
const enumValues = Object.entries(values ?? {}).filter(([key])=>Number.isNaN(Number(key))).map(([, value])=>value);
|
|
51
|
+
return new Set(enumValues.map(getLiteralValueKind));
|
|
52
|
+
}
|
|
53
|
+
function getZodValueKinds(field) {
|
|
54
|
+
const actualField = unwrapZodField(field);
|
|
55
|
+
const definition = actualField._def;
|
|
56
|
+
switch(definition?.typeName){
|
|
57
|
+
case 'ZodString':
|
|
58
|
+
case 'ZodEnum':
|
|
59
|
+
return new Set([
|
|
60
|
+
'string'
|
|
61
|
+
]);
|
|
62
|
+
case 'ZodNumber':
|
|
63
|
+
return new Set([
|
|
64
|
+
'number'
|
|
65
|
+
]);
|
|
66
|
+
case 'ZodBoolean':
|
|
67
|
+
return new Set([
|
|
68
|
+
'boolean'
|
|
69
|
+
]);
|
|
70
|
+
case 'ZodArray':
|
|
71
|
+
case 'ZodTuple':
|
|
72
|
+
return new Set([
|
|
73
|
+
'array'
|
|
74
|
+
]);
|
|
75
|
+
case 'ZodObject':
|
|
76
|
+
case 'ZodRecord':
|
|
77
|
+
case 'ZodDiscriminatedUnion':
|
|
78
|
+
return new Set([
|
|
79
|
+
'object'
|
|
80
|
+
]);
|
|
81
|
+
case 'ZodLiteral':
|
|
82
|
+
return new Set([
|
|
83
|
+
getLiteralValueKind(definition.value)
|
|
84
|
+
]);
|
|
85
|
+
case 'ZodNativeEnum':
|
|
86
|
+
return getNativeEnumValueKinds(definition.values);
|
|
87
|
+
case 'ZodUnion':
|
|
88
|
+
return new Set((definition.options ?? []).flatMap((option)=>[
|
|
89
|
+
...getZodValueKinds(option)
|
|
90
|
+
]));
|
|
91
|
+
default:
|
|
92
|
+
return new Set([
|
|
93
|
+
'unknown'
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
42
97
|
function isMidsceneLocatorField(field) {
|
|
43
98
|
const actualField = unwrapZodField(field);
|
|
44
99
|
if (actualField._def?.typeName === 'ZodObject') {
|
|
@@ -80,11 +135,13 @@ function getZodDescription(field) {
|
|
|
80
135
|
}
|
|
81
136
|
exports.getZodDescription = __webpack_exports__.getZodDescription;
|
|
82
137
|
exports.getZodTypeName = __webpack_exports__.getZodTypeName;
|
|
138
|
+
exports.getZodValueKinds = __webpack_exports__.getZodValueKinds;
|
|
83
139
|
exports.isMidsceneLocatorField = __webpack_exports__.isMidsceneLocatorField;
|
|
84
140
|
exports.unwrapZodField = __webpack_exports__.unwrapZodField;
|
|
85
141
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
86
142
|
"getZodDescription",
|
|
87
143
|
"getZodTypeName",
|
|
144
|
+
"getZodValueKinds",
|
|
88
145
|
"isMidsceneLocatorField",
|
|
89
146
|
"unwrapZodField"
|
|
90
147
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ToolCliOption, ToolDefinition } from '../agent-tools/types';
|
|
2
2
|
export declare function parseValue(raw: string): unknown;
|
|
3
|
-
export declare function parseCliArgs(args: string[]): Record<string, unknown>;
|
|
3
|
+
export declare function parseCliArgs(args: string[], def?: ToolDefinition): Record<string, unknown>;
|
|
4
4
|
export declare function getCliOptionDisplay(key: string, cliOption?: ToolCliOption): {
|
|
5
5
|
label: string;
|
|
6
6
|
aliases: string[];
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
|
+
export type ZodValueKind = 'string' | 'number' | 'boolean' | 'array' | 'object' | 'unknown';
|
|
2
3
|
/**
|
|
3
4
|
* Recursively unwrap optional, nullable, default, and effects wrapper types
|
|
4
5
|
* to get the actual inner Zod type
|
|
5
6
|
*/
|
|
6
7
|
export declare function unwrapZodField(field: unknown): unknown;
|
|
8
|
+
/**
|
|
9
|
+
* Return every top-level value kind accepted by a Zod field. Unlike
|
|
10
|
+
* `getZodTypeName`, this normalizes enums, literals, and unions so consumers
|
|
11
|
+
* can make type-directed decisions without parsing its display label.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getZodValueKinds(field: unknown): Set<ZodValueKind>;
|
|
7
14
|
/**
|
|
8
15
|
* Check if a field is a Midscene locator field
|
|
9
16
|
* Locator input schemas are identified by their prompt field.
|
package/package.json
CHANGED
package/src/cli/cli-args.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { ToolCliOption, ToolDefinition } from '../agent-tools/types';
|
|
3
3
|
import { getKeyAliases } from '../key-alias-utils';
|
|
4
|
+
import { getZodValueKinds } from '../zod-schema-utils';
|
|
4
5
|
import { CLIError } from './cli-error';
|
|
5
6
|
|
|
7
|
+
const cliNumberPattern = /^-?\d+(\.\d+)?$/;
|
|
8
|
+
|
|
6
9
|
export function parseValue(raw: string): unknown {
|
|
7
10
|
if (raw.startsWith('{') || raw.startsWith('[')) {
|
|
8
11
|
try {
|
|
@@ -12,7 +15,7 @@ export function parseValue(raw: string): unknown {
|
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
if (
|
|
18
|
+
if (cliNumberPattern.test(raw)) {
|
|
16
19
|
return Number(raw);
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -22,6 +25,7 @@ export function parseValue(raw: string): unknown {
|
|
|
22
25
|
function walkCliArgs(
|
|
23
26
|
args: string[],
|
|
24
27
|
setArgValue: (key: string, value: unknown) => void,
|
|
28
|
+
fieldByCliName?: ReadonlyMap<string, z.ZodTypeAny>,
|
|
25
29
|
): void {
|
|
26
30
|
for (let i = 0; i < args.length; i++) {
|
|
27
31
|
const arg = args[i];
|
|
@@ -31,34 +35,98 @@ function walkCliArgs(
|
|
|
31
35
|
const eqIdx = body.indexOf('=');
|
|
32
36
|
|
|
33
37
|
if (eqIdx >= 0) {
|
|
34
|
-
|
|
38
|
+
const key = body.slice(0, eqIdx);
|
|
39
|
+
setArgValue(
|
|
40
|
+
key,
|
|
41
|
+
parseCliValue(body.slice(eqIdx + 1), fieldByCliName?.get(key)),
|
|
42
|
+
);
|
|
35
43
|
} else if (args[i + 1] && !args[i + 1].startsWith('--')) {
|
|
36
44
|
i++;
|
|
37
|
-
setArgValue(body,
|
|
45
|
+
setArgValue(body, parseCliValue(args[i], fieldByCliName?.get(body)));
|
|
38
46
|
} else {
|
|
39
47
|
setArgValue(body, true);
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
function buildCliFieldIndex(
|
|
53
|
+
def: ToolDefinition,
|
|
54
|
+
): ReadonlyMap<string, z.ZodTypeAny> {
|
|
55
|
+
const fieldByCliName = new Map<string, z.ZodTypeAny>();
|
|
56
|
+
|
|
57
|
+
for (const [schemaKey, field] of Object.entries(def.schema)) {
|
|
58
|
+
for (const cliName of getAcceptedCliOptionNames(
|
|
59
|
+
schemaKey,
|
|
60
|
+
def.cli?.options?.[schemaKey],
|
|
61
|
+
)) {
|
|
62
|
+
fieldByCliName.set(cliName, field);
|
|
52
63
|
}
|
|
64
|
+
}
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
return fieldByCliName;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseJsonValue(raw: string): unknown {
|
|
70
|
+
if (!raw.startsWith('{') && !raw.startsWith('[')) return raw;
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(raw);
|
|
74
|
+
} catch {
|
|
75
|
+
return raw;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseCliValue(raw: string, field?: z.ZodTypeAny): unknown {
|
|
80
|
+
if (!field) return parseValue(raw);
|
|
81
|
+
|
|
82
|
+
const kinds = getZodValueKinds(field);
|
|
83
|
+
if (kinds.has('object') || kinds.has('array')) {
|
|
84
|
+
const parsedJson = parseJsonValue(raw);
|
|
85
|
+
if (parsedJson !== raw) return parsedJson;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// CLI input cannot distinguish a numeric-looking identifier from a number.
|
|
89
|
+
// Prefer the lossless representation whenever the schema accepts strings.
|
|
90
|
+
if (kinds.has('string')) return raw;
|
|
59
91
|
|
|
60
|
-
|
|
61
|
-
|
|
92
|
+
if (kinds.has('number') && cliNumberPattern.test(raw)) {
|
|
93
|
+
return Number(raw);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (kinds.has('boolean')) {
|
|
97
|
+
if (raw === 'true') return true;
|
|
98
|
+
if (raw === 'false') return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return kinds.has('unknown') ? parseValue(raw) : raw;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function parseCliArgs(
|
|
105
|
+
args: string[],
|
|
106
|
+
def?: ToolDefinition,
|
|
107
|
+
): Record<string, unknown> {
|
|
108
|
+
const result: Record<string, unknown> = {};
|
|
109
|
+
const fieldByCliName = def ? buildCliFieldIndex(def) : undefined;
|
|
110
|
+
|
|
111
|
+
walkCliArgs(
|
|
112
|
+
args,
|
|
113
|
+
(key, value) => {
|
|
114
|
+
const existing = result[key];
|
|
115
|
+
if (existing === undefined) {
|
|
116
|
+
result[key] = value;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (Array.isArray(existing)) {
|
|
121
|
+
existing.push(value);
|
|
122
|
+
result[key] = existing;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
result[key] = [existing, value];
|
|
127
|
+
},
|
|
128
|
+
fieldByCliName,
|
|
129
|
+
);
|
|
62
130
|
|
|
63
131
|
return result;
|
|
64
132
|
}
|
package/src/cli/cli-runner.ts
CHANGED
|
@@ -295,7 +295,7 @@ export async function runToolsCLI(
|
|
|
295
295
|
}
|
|
296
296
|
const parsedArgs = {
|
|
297
297
|
...positionalArgs,
|
|
298
|
-
...parseCliArgs(restArgs.slice(optionStartIndex)),
|
|
298
|
+
...parseCliArgs(restArgs.slice(optionStartIndex), match.def),
|
|
299
299
|
};
|
|
300
300
|
if (parsedArgs.help === true) {
|
|
301
301
|
debug('showing command help for: %s', match.name);
|
package/src/zod-schema-utils.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
2
|
|
|
3
|
+
export type ZodValueKind =
|
|
4
|
+
| 'string'
|
|
5
|
+
| 'number'
|
|
6
|
+
| 'boolean'
|
|
7
|
+
| 'array'
|
|
8
|
+
| 'object'
|
|
9
|
+
| 'unknown';
|
|
10
|
+
|
|
3
11
|
/**
|
|
4
12
|
* Recursively unwrap optional, nullable, default, and effects wrapper types
|
|
5
13
|
* to get the actual inner Zod type
|
|
@@ -31,6 +39,68 @@ export function unwrapZodField(field: unknown): unknown {
|
|
|
31
39
|
return f;
|
|
32
40
|
}
|
|
33
41
|
|
|
42
|
+
function getLiteralValueKind(value: unknown): ZodValueKind {
|
|
43
|
+
if (typeof value === 'string') return 'string';
|
|
44
|
+
if (typeof value === 'number') return 'number';
|
|
45
|
+
if (typeof value === 'boolean') return 'boolean';
|
|
46
|
+
return 'unknown';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getNativeEnumValueKinds(
|
|
50
|
+
values: Record<string, unknown> | undefined,
|
|
51
|
+
): Set<ZodValueKind> {
|
|
52
|
+
const enumValues = Object.entries(values ?? {})
|
|
53
|
+
.filter(([key]) => Number.isNaN(Number(key)))
|
|
54
|
+
.map(([, value]) => value);
|
|
55
|
+
return new Set(enumValues.map(getLiteralValueKind));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Return every top-level value kind accepted by a Zod field. Unlike
|
|
60
|
+
* `getZodTypeName`, this normalizes enums, literals, and unions so consumers
|
|
61
|
+
* can make type-directed decisions without parsing its display label.
|
|
62
|
+
*/
|
|
63
|
+
export function getZodValueKinds(field: unknown): Set<ZodValueKind> {
|
|
64
|
+
const actualField = unwrapZodField(field) as {
|
|
65
|
+
_def?: {
|
|
66
|
+
typeName?: string;
|
|
67
|
+
options?: unknown[];
|
|
68
|
+
value?: unknown;
|
|
69
|
+
values?: Record<string, unknown>;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
const definition = actualField._def;
|
|
73
|
+
|
|
74
|
+
switch (definition?.typeName) {
|
|
75
|
+
case 'ZodString':
|
|
76
|
+
case 'ZodEnum':
|
|
77
|
+
return new Set(['string']);
|
|
78
|
+
case 'ZodNumber':
|
|
79
|
+
return new Set(['number']);
|
|
80
|
+
case 'ZodBoolean':
|
|
81
|
+
return new Set(['boolean']);
|
|
82
|
+
case 'ZodArray':
|
|
83
|
+
case 'ZodTuple':
|
|
84
|
+
return new Set(['array']);
|
|
85
|
+
case 'ZodObject':
|
|
86
|
+
case 'ZodRecord':
|
|
87
|
+
case 'ZodDiscriminatedUnion':
|
|
88
|
+
return new Set(['object']);
|
|
89
|
+
case 'ZodLiteral':
|
|
90
|
+
return new Set([getLiteralValueKind(definition.value)]);
|
|
91
|
+
case 'ZodNativeEnum':
|
|
92
|
+
return getNativeEnumValueKinds(definition.values);
|
|
93
|
+
case 'ZodUnion':
|
|
94
|
+
return new Set(
|
|
95
|
+
(definition.options ?? []).flatMap((option) => [
|
|
96
|
+
...getZodValueKinds(option),
|
|
97
|
+
]),
|
|
98
|
+
);
|
|
99
|
+
default:
|
|
100
|
+
return new Set(['unknown']);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
34
104
|
/**
|
|
35
105
|
* Check if a field is a Midscene locator field
|
|
36
106
|
* Locator input schemas are identified by their prompt field.
|