@midscene/test 1.12.4-beta-20260903111111.0 → 1.12.4

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 (40) hide show
  1. package/dist/es/android/index.mjs +50 -106
  2. package/dist/es/android/index.mjs.map +1 -1
  3. package/dist/es/cli/index.mjs +99 -149
  4. package/dist/es/cli/index.mjs.map +1 -1
  5. package/dist/es/harmony/index.mjs +119 -0
  6. package/dist/es/harmony/index.mjs.map +1 -0
  7. package/dist/es/index.mjs +36 -87
  8. package/dist/es/index.mjs.map +1 -1
  9. package/dist/es/ios/index.mjs +51 -101
  10. package/dist/es/ios/index.mjs.map +1 -1
  11. package/dist/es/midscene/index.mjs +37 -235
  12. package/dist/es/midscene/index.mjs.map +1 -1
  13. package/dist/es/playwright/index.mjs +14 -10
  14. package/dist/es/playwright/index.mjs.map +1 -1
  15. package/dist/es/test-cli.mjs +102 -150
  16. package/dist/es/test-cli.mjs.map +1 -1
  17. package/dist/lib/android/index.js +151 -178
  18. package/dist/lib/android/index.js.map +1 -1
  19. package/dist/lib/cli/index.js +99 -149
  20. package/dist/lib/cli/index.js.map +1 -1
  21. package/dist/lib/harmony/index.js +188 -0
  22. package/dist/lib/harmony/index.js.map +1 -0
  23. package/dist/lib/index.js +37 -100
  24. package/dist/lib/index.js.map +1 -1
  25. package/dist/lib/ios/index.js +152 -173
  26. package/dist/lib/ios/index.js.map +1 -1
  27. package/dist/lib/midscene/index.js +264 -412
  28. package/dist/lib/midscene/index.js.map +1 -1
  29. package/dist/lib/playwright/index.js +14 -10
  30. package/dist/lib/playwright/index.js.map +1 -1
  31. package/dist/lib/test-cli.js +102 -150
  32. package/dist/lib/test-cli.js.map +1 -1
  33. package/dist/types/android/index.d.ts +27 -101
  34. package/dist/types/cli/index.d.ts +9 -32
  35. package/dist/types/harmony/index.d.ts +124 -0
  36. package/dist/types/index.d.ts +18 -45
  37. package/dist/types/ios/index.d.ts +28 -107
  38. package/dist/types/midscene/index.d.ts +54 -153
  39. package/dist/types/playwright/index.d.ts +9 -63
  40. package/package.json +25 -6
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ var __webpack_modules__ = {
3
+ "./src/errors.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
+ __webpack_require__.d(__webpack_exports__, {
5
+ ww: ()=>NodeDefinitionError
6
+ });
7
+ function _define_property(obj, key, value) {
8
+ if (key in obj) Object.defineProperty(obj, key, {
9
+ value: value,
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true
13
+ });
14
+ else obj[key] = value;
15
+ return obj;
16
+ }
17
+ class WorkflowError extends Error {
18
+ toJSON() {
19
+ return {
20
+ name: this.name,
21
+ message: this.message,
22
+ code: this.code,
23
+ ...void 0 === this.details ? {} : {
24
+ details: this.details
25
+ }
26
+ };
27
+ }
28
+ constructor(message, options = {}){
29
+ super(message, {
30
+ cause: options.cause
31
+ }), _define_property(this, "code", void 0), _define_property(this, "details", void 0);
32
+ this.name = new.target.name;
33
+ this.code = options.code ?? 'WORKFLOW_ERROR';
34
+ this.details = options.details;
35
+ }
36
+ }
37
+ class NodeDefinitionError extends WorkflowError {
38
+ constructor(message, details){
39
+ super(message, {
40
+ code: 'NODE_DEFINITION_ERROR',
41
+ details
42
+ });
43
+ }
44
+ }
45
+ },
46
+ "./src/midscene/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
47
+ __webpack_require__.d(__webpack_exports__, {
48
+ createAgentTestRunnerNodes: ()=>createAgentTestRunnerNodes
49
+ });
50
+ require("@midscene/core/agent/test-runner");
51
+ const v4_namespaceObject = require("zod/v4");
52
+ var errors = __webpack_require__("./src/errors.ts");
53
+ const validateOptionalText = (value, field, node)=>{
54
+ if (void 0 !== value && ('string' != typeof value || 0 === value.trim().length)) throw new errors.ww(`Node "${node}" ${field} must be a non-empty string.`, {
55
+ node,
56
+ field
57
+ });
58
+ };
59
+ const validateInputSchema = (schema, node)=>{
60
+ if (void 0 === schema) return;
61
+ if (!(schema instanceof v4_namespaceObject.z.ZodObject)) throw new errors.ww(`Node "${node}" inputSchema must be a Zod object schema.`, {
62
+ node,
63
+ field: 'inputSchema'
64
+ });
65
+ if ('$' in schema.shape) throw new errors.ww(`Node "${node}" inputSchema must not declare "$" as an input property.`, {
66
+ node,
67
+ field: 'inputSchema.$'
68
+ });
69
+ };
70
+ const validateDefinition = (options)=>{
71
+ if (!options || 'object' != typeof options) throw new errors.ww('Node definition must be an object.');
72
+ if ('string' != typeof options.name || 0 === options.name.trim().length) throw new errors.ww('Node name must be a non-empty string.');
73
+ validateOptionalText(options.title, 'title', options.name);
74
+ validateOptionalText(options.description, "description", options.name);
75
+ if (void 0 !== options.stringInputKey && false !== options.stringInputKey && ('string' != typeof options.stringInputKey || 0 === options.stringInputKey.trim().length)) throw new errors.ww(`Node "${options.name}" stringInputKey must be a non-empty string or false.`, {
76
+ node: options.name,
77
+ field: 'stringInputKey'
78
+ });
79
+ validateInputSchema(options.inputSchema, options.name);
80
+ if ('string' == typeof options.stringInputKey && options.inputSchema instanceof v4_namespaceObject.z.ZodObject && !(options.stringInputKey in options.inputSchema.shape)) throw new errors.ww(`Node "${options.name}" stringInputKey must reference a field in inputSchema.`, {
81
+ node: options.name,
82
+ field: 'stringInputKey'
83
+ });
84
+ if ('function' != typeof options.execute) throw new errors.ww(`Node "${options.name}" must provide an execute function.`, {
85
+ node: options.name
86
+ });
87
+ };
88
+ function define_node_defineNode(options) {
89
+ validateDefinition(options);
90
+ return options;
91
+ }
92
+ const nonBlankPrompt = (description)=>v4_namespaceObject.z.string().regex(/\S/, 'prompt must contain a non-whitespace character').describe(description);
93
+ v4_namespaceObject.z.strictObject({
94
+ duration: v4_namespaceObject.z.number().positive().describe('How long to wait.'),
95
+ unit: v4_namespaceObject.z["enum"]([
96
+ 'ms',
97
+ 's',
98
+ 'min'
99
+ ]).default('ms').describe('Duration unit: milliseconds, seconds, or minutes.')
100
+ });
101
+ v4_namespaceObject.z.strictObject({
102
+ prompt: nonBlankPrompt('A self-contained task, including allowed tools and success conditions.')
103
+ });
104
+ const createAgentTestRunnerNodes = (definitions, getAgent)=>definitions.map((definition)=>define_node_defineNode({
105
+ name: definition.name,
106
+ ...void 0 === definition.title ? {} : {
107
+ title: definition.title
108
+ },
109
+ ...void 0 === definition.description ? {} : {
110
+ description: definition.description
111
+ },
112
+ ...void 0 === definition.stringInputKey ? {} : {
113
+ stringInputKey: definition.stringInputKey
114
+ },
115
+ inputSchema: definition.inputSchema,
116
+ async execute (ctx) {
117
+ const agent = await getAgent(ctx);
118
+ return definition.execute(agent, ctx.input, {
119
+ signal: ctx.signal
120
+ });
121
+ }
122
+ }));
123
+ }
124
+ };
125
+ var __webpack_module_cache__ = {};
126
+ function __webpack_require__(moduleId) {
127
+ var cachedModule = __webpack_module_cache__[moduleId];
128
+ if (void 0 !== cachedModule) return cachedModule.exports;
129
+ var module = __webpack_module_cache__[moduleId] = {
130
+ exports: {}
131
+ };
132
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
133
+ return module.exports;
134
+ }
135
+ (()=>{
136
+ __webpack_require__.d = (exports1, definition)=>{
137
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
138
+ enumerable: true,
139
+ get: definition[key]
140
+ });
141
+ };
142
+ })();
143
+ (()=>{
144
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
145
+ })();
146
+ (()=>{
147
+ __webpack_require__.r = (exports1)=>{
148
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
149
+ value: 'Module'
150
+ });
151
+ Object.defineProperty(exports1, '__esModule', {
152
+ value: true
153
+ });
154
+ };
155
+ })();
156
+ var __webpack_exports__ = {};
157
+ (()=>{
158
+ __webpack_require__.r(__webpack_exports__);
159
+ __webpack_require__.d(__webpack_exports__, {
160
+ runHdcShellInputSchema: ()=>test_runner_namespaceObject.runHdcShellInputSchema,
161
+ createHarmonyNodes: ()=>createHarmonyNodes,
162
+ terminateInputSchema: ()=>test_runner_namespaceObject.terminateInputSchema,
163
+ launchInputSchema: ()=>test_runner_namespaceObject.launchInputSchema
164
+ });
165
+ const test_runner_namespaceObject = require("@midscene/harmony/test-runner");
166
+ var errors = __webpack_require__("./src/errors.ts");
167
+ var midscene = __webpack_require__("./src/midscene/index.ts");
168
+ function createHarmonyNodes(options) {
169
+ if (!options || 'object' != typeof options) throw new errors.ww('createHarmonyNodes() options must be an object.');
170
+ if ('function' != typeof options.getAgent) throw new errors.ww('createHarmonyNodes() requires getAgent().');
171
+ return (0, midscene.createAgentTestRunnerNodes)(test_runner_namespaceObject.harmonyAgentTestRunnerNodeDefinitions, options.getAgent);
172
+ }
173
+ })();
174
+ exports.createHarmonyNodes = __webpack_exports__.createHarmonyNodes;
175
+ exports.launchInputSchema = __webpack_exports__.launchInputSchema;
176
+ exports.runHdcShellInputSchema = __webpack_exports__.runHdcShellInputSchema;
177
+ exports.terminateInputSchema = __webpack_exports__.terminateInputSchema;
178
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
179
+ "createHarmonyNodes",
180
+ "launchInputSchema",
181
+ "runHdcShellInputSchema",
182
+ "terminateInputSchema"
183
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
184
+ Object.defineProperty(exports, '__esModule', {
185
+ value: true
186
+ });
187
+
188
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harmony/index.js","sources":["../../../src/errors.ts","../../../src/node/define-node.ts","../../../src/midscene/index.ts","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/harmony/index.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\nexport interface WorkflowErrorOptions {\n code?: string;\n details?: unknown;\n cause?: unknown;\n}\n\nexport class WorkflowError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, options: WorkflowErrorOptions = {}) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code ?? 'WORKFLOW_ERROR';\n this.details = options.details;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n ...(this.details === undefined ? {} : { details: this.details }),\n };\n }\n}\n\nexport class WorkflowParseError extends WorkflowError {\n constructor(message: string, details?: unknown, cause?: unknown) {\n super(message, { code: 'WORKFLOW_PARSE_ERROR', details, cause });\n }\n}\n\nexport class NodeDefinitionError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_DEFINITION_ERROR', details });\n }\n}\n\nexport class DuplicateNodeError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is already registered.`, {\n code: 'DUPLICATE_NODE',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeNotFoundError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is not registered.`, {\n code: 'NODE_NOT_FOUND',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeInputValidationError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_INPUT_VALIDATION_ERROR', details });\n }\n\n static fromZod(node: string, error: z.ZodError): NodeInputValidationError {\n const issues = error.issues.map((issue) => ({\n code: issue.code,\n path: issue.path.map(String).join('.'),\n message: issue.message,\n }));\n const firstIssue = issues[0];\n const path = firstIssue?.path || '<root>';\n const message = firstIssue?.message ?? 'invalid input';\n return new NodeInputValidationError(\n `Node \"${node}\" input validation failed at \"${path}\": ${message}`,\n { node, issues },\n );\n }\n}\n\nexport class StepTimeoutError extends WorkflowError {\n readonly timeoutMs: number;\n readonly node?: string;\n\n constructor(timeoutMs: number, node?: string) {\n super(\n node\n ? `Node \"${node}\" timed out after ${timeoutMs}ms.`\n : `Step timed out after ${timeoutMs}ms.`,\n {\n code: 'STEP_TIMEOUT',\n details: { timeoutMs, ...(node === undefined ? {} : { node }) },\n },\n );\n this.timeoutMs = timeoutMs;\n this.node = node;\n }\n}\n\nexport class NodeExecutionError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string, cause: unknown) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Node \"${node}\" failed: ${causeMessage}`, {\n code: 'NODE_EXECUTION_ERROR',\n details: { node },\n cause,\n });\n this.node = node;\n }\n}\n\nexport class WorkflowLifecycleError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'WORKFLOW_LIFECYCLE_ERROR', details });\n }\n}\n\nexport class ProjectSetupError extends WorkflowError {\n constructor(cause: unknown, details: { projectName: string }) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" setup failed: ${causeMessage}`, {\n code: 'PROJECT_SETUP_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class ProjectTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: { projectName: string; registrationIndex: number },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" teardown failed: ${causeMessage}`, {\n code: 'PROJECT_TEARDOWN_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class NodeScopeTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: {\n scope: 'case' | 'document';\n scopeId: string;\n node: string;\n registrationIndex: number;\n },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(\n `${details.scope === 'case' ? 'Case attempt' : 'Workflow document'} node teardown failed for \"${details.node}\": ${causeMessage}`,\n { code: 'NODE_SCOPE_TEARDOWN_ERROR', details, cause },\n );\n }\n}\n\nexport class FatalDeviceError extends WorkflowError {\n constructor(message: string, cause?: unknown) {\n super(message, { code: 'FATAL_DEVICE_ERROR', cause });\n }\n}\n\nexport const isFatalDeviceError = (error: unknown): boolean => {\n if (error instanceof FatalDeviceError) return true;\n if (error instanceof WorkflowError && error.code === 'FATAL_DEVICE_ERROR') {\n return true;\n }\n if (\n error instanceof Error &&\n /device offline|device not found|(?:adb|bdc|device) connection (?:was )?closed/i.test(\n error.message,\n )\n ) {\n return true;\n }\n return error instanceof Error && error.cause !== undefined\n ? isFatalDeviceError(error.cause)\n : false;\n};\n\nexport class CaseExecutionError extends WorkflowError {\n readonly result: import('./engine/types').CaseRunResult;\n\n constructor(result: import('./engine/types').CaseRunResult) {\n super(`Case \"${result.name}\" failed.`, {\n code: 'CASE_EXECUTION_FAILED',\n details: { caseId: result.caseId, runId: result.runId },\n });\n this.result = result;\n }\n}\n\nexport class WorkflowDocumentExecutionError extends WorkflowError {\n readonly result: import('./engine/types').WorkflowDocumentRunResult;\n\n constructor(result: import('./engine/types').WorkflowDocumentRunResult) {\n super(`Workflow document \"${result.sourcePath}\" failed.`, {\n code: 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n details: {\n documentId: result.documentId,\n documentRunId: result.documentRunId,\n },\n });\n this.result = result;\n }\n}\n\nexport function normalizeNodeExecutionError(\n error: unknown,\n node: string,\n): WorkflowError {\n return error instanceof WorkflowError\n ? error\n : new NodeExecutionError(node, error);\n}\n","import { z } from 'zod/v4';\nimport { NodeDefinitionError } from '../errors';\nimport type {\n DefineNodeOptions,\n DefineNodeWithSchemaOptions,\n NodeDefinition,\n NodeDefinitionWithSchema,\n NodeInputSchema,\n} from './types';\n\nconst validateOptionalText = (\n value: unknown,\n field: 'title' | 'description',\n node: string,\n): void => {\n if (\n value !== undefined &&\n (typeof value !== 'string' || value.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${node}\" ${field} must be a non-empty string.`,\n { node, field },\n );\n }\n};\n\nconst validateInputSchema = (schema: unknown, node: string): void => {\n if (schema === undefined) return;\n if (!(schema instanceof z.ZodObject)) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must be a Zod object schema.`,\n { node, field: 'inputSchema' },\n );\n }\n if ('$' in schema.shape) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must not declare \"$\" as an input property.`,\n { node, field: 'inputSchema.$' },\n );\n }\n};\n\nconst validateDefinition = (options: {\n name: string;\n title?: unknown;\n description?: unknown;\n stringInputKey?: unknown;\n inputSchema?: unknown;\n execute: unknown;\n}): void => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError('Node definition must be an object.');\n }\n\n if (typeof options.name !== 'string' || options.name.trim().length === 0) {\n throw new NodeDefinitionError('Node name must be a non-empty string.');\n }\n\n validateOptionalText(options.title, 'title', options.name);\n validateOptionalText(options.description, 'description', options.name);\n if (\n options.stringInputKey !== undefined &&\n options.stringInputKey !== false &&\n (typeof options.stringInputKey !== 'string' ||\n options.stringInputKey.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must be a non-empty string or false.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n validateInputSchema(options.inputSchema, options.name);\n\n if (\n typeof options.stringInputKey === 'string' &&\n options.inputSchema instanceof z.ZodObject &&\n !(options.stringInputKey in options.inputSchema.shape)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must reference a field in inputSchema.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n\n if (typeof options.execute !== 'function') {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" must provide an execute function.`,\n { node: options.name },\n );\n }\n};\n\nexport function defineNode<\n TSchema extends NodeInputSchema,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeWithSchemaOptions<TSchema, TData, TContext>,\n): NodeDefinitionWithSchema<TSchema, TData, TContext>;\n\nexport function defineNode<\n TInput = unknown,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeOptions<TInput, TData, TContext>,\n): NodeDefinition<TInput, TData, TContext>;\n\nexport function defineNode(\n options: DefineNodeOptions<any, any, any>,\n): NodeDefinition<any, any, any> {\n validateDefinition(options);\n return options;\n}\n","import {\n type AgentTestRunnerNodeDefinition,\n type AgentTestRunnerNodeProvider,\n type CommonAgentTestRunnerApi,\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n} from '@midscene/core/agent/test-runner';\nimport { z } from 'zod/v4';\nimport type { Awaitable } from '../engine/types';\nimport { NodeDefinitionError, NodeExecutionError } from '../errors';\nimport { defineNode } from '../node/define-node';\nimport type {\n NodeDefinition,\n NodeExecutionContext,\n NodeResult,\n} from '../node/types';\n\nexport type MidsceneUIAgent = CommonAgentTestRunnerApi;\n\nexport {\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n};\n\nexport interface AgentProvider<TContext> {\n getAgent(\n runId: string,\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n // biome-ignore lint/suspicious/noConfusingVoidType: providers without a report intentionally return void.\n releaseAgent?(runId: string): Awaitable<AgentReleaseResult | void>;\n dispose?(): Awaitable<void>;\n}\n\nexport interface AgentReleaseResult {\n /** Absolute path to the finalized report for this Agent scope. */\n reportPath?: string;\n}\n\nexport interface AgentExecutorInput<TContext> {\n prompt: string;\n context: TContext;\n signal: AbortSignal;\n execution:\n | { scope: 'case'; runId: string }\n | { scope: 'document'; runId: string };\n}\n\nexport interface AgentExecutor<TContext> {\n // biome-ignore lint/suspicious/noConfusingVoidType: executors may perform side effects without returning a summary.\n execute(input: AgentExecutorInput<TContext>): Awaitable<NodeResult | void>;\n}\n\nconst nonBlankPrompt = (description: string) =>\n z\n .string()\n .regex(/\\S/, 'prompt must contain a non-whitespace character')\n .describe(description);\n\nexport const waitInputSchema = z.strictObject({\n duration: z.number().positive().describe('How long to wait.'),\n unit: z\n .enum(['ms', 's', 'min'])\n .default('ms')\n .describe('Duration unit: milliseconds, seconds, or minutes.'),\n});\n\nexport const agentInputSchema = z.strictObject({\n prompt: nonBlankPrompt(\n 'A self-contained task, including allowed tools and success conditions.',\n ),\n});\n\nexport type AiActNodeInput = z.infer<typeof aiActInputSchema>;\nexport type AiAssertNodeInput = z.infer<typeof aiAssertInputSchema>;\nexport type AiTapNodeInput = z.infer<typeof aiTapInputSchema>;\nexport type InsightNodeInput = z.infer<typeof insightInputSchema>;\nexport type RecordToReportNodeInput = z.infer<typeof recordToReportInputSchema>;\nexport type WaitNodeInput = z.infer<typeof waitInputSchema>;\nexport type AgentNodeInput = z.infer<typeof agentInputSchema>;\n\nexport interface CreateMidsceneNodesOptions<TContext> {\n getAgent?(\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n agentProvider?: AgentProvider<TContext>;\n /** Agent class that declares the Agent-backed Nodes to register. */\n agentClass: AgentTestRunnerNodeProvider;\n agentExecutor?: AgentExecutor<TContext>;\n}\n\nconst waitFor = async (durationMs: number, signal: AbortSignal) => {\n if (signal.aborted) {\n throw signal.reason ?? new Error('Wait aborted.');\n }\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n signal.removeEventListener('abort', abort);\n resolve();\n }, durationMs);\n const abort = () => {\n clearTimeout(timeout);\n reject(signal.reason ?? new Error('Wait aborted.'));\n };\n signal.addEventListener('abort', abort, { once: true });\n });\n};\n\n/** Adapt Agent-owned descriptions to executable Test Runner Nodes. */\nexport const createAgentTestRunnerNodes = <TContext>(\n definitions: readonly AgentTestRunnerNodeDefinition[],\n getAgent: (\n ctx: NodeExecutionContext<unknown, TContext>,\n ) => Awaitable<unknown>,\n): readonly NodeDefinition<any, any, TContext>[] =>\n definitions.map((definition) =>\n defineNode({\n name: definition.name,\n ...(definition.title === undefined ? {} : { title: definition.title }),\n ...(definition.description === undefined\n ? {}\n : { description: definition.description }),\n ...(definition.stringInputKey === undefined\n ? {}\n : { stringInputKey: definition.stringInputKey }),\n inputSchema: definition.inputSchema,\n async execute(ctx) {\n const agent = await getAgent(ctx);\n return definition.execute(agent, ctx.input, {\n signal: ctx.signal,\n });\n },\n }),\n );\n\nexport function createMidsceneNodes<TContext>(\n options: CreateMidsceneNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() options must be an object.',\n );\n }\n if (\n typeof options.agentProvider?.getAgent !== 'function' &&\n typeof options.getAgent !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires getAgent or agentProvider.getAgent.',\n );\n }\n if (\n !options.agentClass ||\n typeof options.agentClass.getTestRunnerNodeDefinitions !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires agentClass.getTestRunnerNodeDefinitions().',\n );\n }\n\n const registeredAgentScopes = new Set<string>();\n const getExecutionId = (ctx: NodeExecutionContext<unknown, TContext>) =>\n ctx.scope === 'case' ? ctx.case.runId : ctx.document.documentRunId;\n const getAgent = async (\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Promise<MidsceneUIAgent> => {\n if (!options.agentProvider) return options.getAgent!(ctx);\n const runId = getExecutionId(ctx);\n if (\n options.agentProvider.releaseAgent &&\n !registeredAgentScopes.has(runId)\n ) {\n registeredAgentScopes.add(runId);\n ctx.onTeardown(async () => {\n try {\n const released = await options.agentProvider!.releaseAgent!(runId);\n return released?.reportPath\n ? { reportPaths: [released.reportPath] }\n : undefined;\n } finally {\n registeredAgentScopes.delete(runId);\n }\n });\n }\n return options.agentProvider.getAgent(runId, ctx);\n };\n\n const agentDefinitions = options.agentClass.getTestRunnerNodeDefinitions();\n\n return [\n ...createAgentTestRunnerNodes(agentDefinitions, getAgent),\n defineNode<typeof waitInputSchema, unknown, TContext>({\n name: 'wait',\n description: 'Wait for a fixed duration while honoring cancellation.',\n stringInputKey: false,\n inputSchema: waitInputSchema,\n async execute(ctx) {\n const multiplier =\n ctx.input.unit === 'min'\n ? 60_000\n : ctx.input.unit === 's'\n ? 1_000\n : 1;\n const durationMs = ctx.input.duration * multiplier;\n await waitFor(durationMs, ctx.signal);\n return { summary: `Waited ${durationMs}ms` };\n },\n }),\n defineNode<typeof agentInputSchema, unknown, TContext>({\n name: 'agent',\n description:\n 'Execute one self-contained natural-language task with an injected Agent executor.',\n stringInputKey: 'prompt',\n inputSchema: agentInputSchema,\n async execute(ctx) {\n if (!options.agentExecutor) {\n throw new NodeExecutionError(\n 'agent',\n new TypeError('createMidsceneNodes() requires an agentExecutor.'),\n );\n }\n const execution =\n ctx.scope === 'case'\n ? { scope: 'case' as const, runId: ctx.case.runId }\n : {\n scope: 'document' as const,\n runId: ctx.document.documentRunId,\n };\n const result = await options.agentExecutor.execute({\n prompt: ctx.input.prompt,\n context: ctx.context,\n signal: ctx.signal,\n execution,\n });\n return result ?? { summary: 'Agent task completed.' };\n },\n }),\n ];\n}\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { HarmonyAgent } from '@midscene/harmony';\nimport {\n harmonyAgentTestRunnerNodeDefinitions,\n launchInputSchema,\n runHdcShellInputSchema,\n terminateInputSchema,\n} from '@midscene/harmony/test-runner';\nexport type {\n LaunchNodeInput,\n RunHdcShellNodeInput,\n TerminateNodeInput,\n} from '@midscene/harmony/test-runner';\nimport type { Awaitable } from '../engine/types';\nimport { NodeDefinitionError } from '../errors';\nimport { createAgentTestRunnerNodes } from '../midscene';\nimport type { NodeDefinition, NodeExecutionContext } from '../node/types';\n\nexport { launchInputSchema, runHdcShellInputSchema, terminateInputSchema };\n\nexport type HarmonyRunnerAgent = Pick<\n HarmonyAgent,\n 'launch' | 'terminate' | 'runHdcShell' | 'back' | 'home' | 'recentApps'\n>;\n\nexport interface CreateHarmonyNodesOptions<TContext> {\n getAgent(\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<HarmonyRunnerAgent>;\n}\n\nexport function createHarmonyNodes<TContext>(\n options: CreateHarmonyNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createHarmonyNodes() options must be an object.',\n );\n }\n if (typeof options.getAgent !== 'function') {\n throw new NodeDefinitionError('createHarmonyNodes() requires getAgent().');\n }\n\n return createAgentTestRunnerNodes(\n harmonyAgentTestRunnerNodeDefinitions,\n options.getAgent,\n );\n}\n"],"names":["WorkflowError","Error","undefined","message","options","NodeDefinitionError","details","validateOptionalText","value","field","node","validateInputSchema","schema","z","validateDefinition","defineNode","nonBlankPrompt","description","createAgentTestRunnerNodes","definitions","getAgent","definition","ctx","agent","__webpack_require__","key","Object","obj","prop","Symbol","createHarmonyNodes","harmonyAgentTestRunnerNodeDefinitions"],"mappings":"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"}
package/dist/lib/index.js CHANGED
@@ -27,14 +27,12 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  NodeInputValidationError: ()=>NodeInputValidationError,
28
28
  createCaseRunner: ()=>createCaseRunner,
29
29
  isFatalDeviceError: ()=>isFatalDeviceError,
30
- normalizeSteps: ()=>normalizeSteps,
31
- toHistoryEntry: ()=>toHistoryEntry,
30
+ collectWorkflowDocument: ()=>collectWorkflowDocument,
32
31
  FatalDeviceError: ()=>FatalDeviceError,
33
32
  runWorkflowDocument: ()=>runWorkflowDocument,
34
33
  defineNode: ()=>defineNode,
35
34
  z: ()=>v4_namespaceObject.z,
36
35
  createProjectRuntime: ()=>createProjectRuntime,
37
- createHistory: ()=>createHistory,
38
36
  createWorkflowDocumentId: ()=>createWorkflowDocumentId,
39
37
  NodeDefinitionError: ()=>NodeDefinitionError,
40
38
  normalizeNodeExecutionError: ()=>normalizeNodeExecutionError,
@@ -48,8 +46,6 @@ __webpack_require__.d(__webpack_exports__, {
48
46
  NodeRegistry: ()=>NodeRegistry,
49
47
  CaseRunner: ()=>CaseRunner,
50
48
  StepTimeoutError: ()=>StepTimeoutError,
51
- assertJsonSerializable: ()=>assertJsonSerializable,
52
- validateCommonNodeInput: ()=>validateCommonNodeInput,
53
49
  WorkflowParseError: ()=>WorkflowParseError,
54
50
  NodeScopeTeardownError: ()=>NodeScopeTeardownError,
55
51
  WorkflowDocumentExecutionError: ()=>WorkflowDocumentExecutionError,
@@ -58,7 +54,7 @@ __webpack_require__.d(__webpack_exports__, {
58
54
  resolveWorkflowVariables: ()=>resolveWorkflowVariables,
59
55
  createCaseId: ()=>createCaseId,
60
56
  createDocumentRuntime: ()=>createDocumentRuntime,
61
- collectWorkflowDocument: ()=>collectWorkflowDocument
57
+ normalizeSteps: ()=>normalizeSteps
62
58
  });
63
59
  function _define_property(obj, key, value) {
64
60
  if (key in obj) Object.defineProperty(obj, key, {
@@ -296,13 +292,7 @@ function normalizeMeta(value, index) {
296
292
  continueOnError: continueOnError ?? false
297
293
  };
298
294
  }
299
- function validateCommonNodeInput(input, index) {
300
- if (void 0 !== input.prompt && 'string' != typeof input.prompt) throw new WorkflowParseError(`${formatStep(index)} "prompt" must be a string.`, {
301
- index,
302
- prompt: input.prompt
303
- });
304
- }
305
- function normalizeStep(value, index = 0) {
295
+ function normalizeStep(value, index = 0, resolveNode) {
306
296
  if (!isMapping(value)) throw new WorkflowParseError(`${formatStep(index)} must be a mapping.`, {
307
297
  index
308
298
  });
@@ -315,30 +305,37 @@ function normalizeStep(value, index = 0) {
315
305
  if (0 === node.trim().length) throw new WorkflowParseError(`${formatStep(index)} node name must not be empty.`, {
316
306
  index
317
307
  });
318
- if ('string' == typeof rawValue) return {
319
- node,
320
- input: {
321
- prompt: rawValue
322
- },
323
- meta: {
324
- continueOnError: false
325
- }
326
- };
308
+ if ('string' == typeof rawValue) {
309
+ const resolvedNode = resolveNode?.(node);
310
+ const stringInputKey = resolvedNode ? resolvedNode.stringInputKey : 'prompt';
311
+ if (false === stringInputKey || void 0 === stringInputKey) throw new WorkflowParseError(`${formatStep(index)} node "${node}" does not accept string shorthand.`, {
312
+ index,
313
+ node
314
+ });
315
+ return {
316
+ node,
317
+ input: {
318
+ [stringInputKey]: rawValue
319
+ },
320
+ meta: {
321
+ continueOnError: false
322
+ }
323
+ };
324
+ }
327
325
  if (!isMapping(rawValue)) throw new WorkflowParseError(`${formatStep(index)} value must be a string shorthand or a mapping.`, {
328
326
  index,
329
327
  node
330
328
  });
331
329
  const { $: rawMeta, ...input } = rawValue;
332
- validateCommonNodeInput(input, index);
333
330
  return {
334
331
  node,
335
332
  input,
336
333
  meta: normalizeMeta(rawMeta, index)
337
334
  };
338
335
  }
339
- function normalizeSteps(steps) {
336
+ function normalizeSteps(steps, resolveNode) {
340
337
  if (!Array.isArray(steps)) throw new WorkflowParseError('Steps must be an array.');
341
- return steps.map((step, index)=>normalizeStep(step, index));
338
+ return steps.map((step, index)=>normalizeStep(step, index, resolveNode));
342
339
  }
343
340
  const v4_namespaceObject = require("zod/v4");
344
341
  const validateOptionalText = (value, field, node)=>{
@@ -363,7 +360,15 @@ const validateDefinition = (options)=>{
363
360
  if ('string' != typeof options.name || 0 === options.name.trim().length) throw new NodeDefinitionError('Node name must be a non-empty string.');
364
361
  validateOptionalText(options.title, 'title', options.name);
365
362
  validateOptionalText(options.description, "description", options.name);
363
+ if (void 0 !== options.stringInputKey && false !== options.stringInputKey && ('string' != typeof options.stringInputKey || 0 === options.stringInputKey.trim().length)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must be a non-empty string or false.`, {
364
+ node: options.name,
365
+ field: 'stringInputKey'
366
+ });
366
367
  validateInputSchema(options.inputSchema, options.name);
368
+ if ('string' == typeof options.stringInputKey && options.inputSchema instanceof v4_namespaceObject.z.ZodObject && !(options.stringInputKey in options.inputSchema.shape)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must reference a field in inputSchema.`, {
369
+ node: options.name,
370
+ field: 'stringInputKey'
371
+ });
367
372
  if ('function' != typeof options.execute) throw new NodeDefinitionError(`Node "${options.name}" must provide an execute function.`, {
368
373
  node: options.name
369
374
  });
@@ -451,45 +456,6 @@ const assertJsonSerializable = (value, label, node)=>{
451
456
  throw new NodeExecutionError(node, error);
452
457
  }
453
458
  };
454
- const cloneAndFreezeJson = (value)=>{
455
- if (Array.isArray(value)) return Object.freeze(value.map(cloneAndFreezeJson));
456
- if ('object' == typeof value && null !== value) return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, child])=>[
457
- key,
458
- cloneAndFreezeJson(child)
459
- ])));
460
- return value;
461
- };
462
- const toHistoryEntry = (result, scope)=>{
463
- assertJsonSerializable(result.input, 'input', result.node);
464
- if (result.output?.data !== void 0) assertJsonSerializable(result.output.data, 'output.data', result.node);
465
- return Object.freeze({
466
- scope,
467
- phase: result.phase,
468
- stepIndex: result.stepIndex,
469
- node: result.node,
470
- input: cloneAndFreezeJson(result.input),
471
- ...'string' == typeof result.input?.prompt ? {
472
- intent: result.input.prompt
473
- } : {},
474
- status: 'success' === result.status ? 'passed' : 'failed',
475
- ...result.output?.summary === void 0 ? {} : {
476
- summary: result.output.summary
477
- },
478
- ...result.output?.data === void 0 ? {} : {
479
- data: cloneAndFreezeJson(result.output.data)
480
- },
481
- ...result.error ? {
482
- error: Object.freeze({
483
- name: result.error.name,
484
- message: result.error.message
485
- })
486
- } : {}
487
- });
488
- };
489
- const createHistory = (prefix, results, scope)=>Object.freeze([
490
- ...prefix,
491
- ...results.map((result)=>toHistoryEntry(result, scope))
492
- ]);
493
459
  function validateNodeOutput(output, node) {
494
460
  if (void 0 === output) return;
495
461
  if ('object' != typeof output || null === output || Array.isArray(output)) throw new NodeExecutionError(node, new TypeError('Node output must be an object or undefined.'));
@@ -511,7 +477,6 @@ function createStepResultBase(step, startedAt, phase, stepIndex) {
511
477
  };
512
478
  }
513
479
  async function executeNode(step, execute, phase, stepIndex, options) {
514
- validateCommonNodeInput(step.input, stepIndex);
515
480
  const startedAt = new Date();
516
481
  const abortController = new AbortController();
517
482
  const parentSignal = options.parentSignal;
@@ -595,7 +560,6 @@ async function executeStep(step, node, target, context, execution = {}) {
595
560
  $: step.meta,
596
561
  signal,
597
562
  context,
598
- history: execution.history ?? Object.freeze([]),
599
563
  onTeardown: (teardown)=>{
600
564
  if (!execution.onTeardown) throw new NodeExecutionError(step.node, new Error('The current execution scope cannot register teardown.'));
601
565
  execution.onTeardown(step.node, teardown);
@@ -644,7 +608,6 @@ async function runCollectedCase(collectedCase, options) {
644
608
  const beforeEach = [];
645
609
  const steps = [];
646
610
  const afterEach = [];
647
- const completedNodes = [];
648
611
  const teardownStack = [];
649
612
  let acceptingTeardowns = true;
650
613
  const onTeardown = (node, teardown)=>{
@@ -673,13 +636,7 @@ async function runCollectedCase(collectedCase, options) {
673
636
  sourcePath: collectedCase.sourcePath,
674
637
  caseIndex: collectedCase.caseIndex,
675
638
  phase,
676
- stepIndex,
677
- completedSteps: Object.freeze([
678
- ...steps
679
- ]),
680
- completedNodes: Object.freeze([
681
- ...completedNodes
682
- ])
639
+ stepIndex
683
640
  };
684
641
  const stepInfo = {
685
642
  scope: 'case',
@@ -692,14 +649,12 @@ async function runCollectedCase(collectedCase, options) {
692
649
  scope: 'case',
693
650
  case: caseContext
694
651
  }, options.context, {
695
- history: createHistory(options.documentHistory ?? [], completedNodes, 'case'),
696
652
  signal,
697
653
  defaultTimeoutMs: options.defaultTimeoutMs,
698
654
  onTeardown
699
655
  });
700
656
  await options.onStepResult?.(stepInfo, result);
701
657
  results.push(result);
702
- completedNodes.push(result);
703
658
  if ('failed' === result.status && !result.continuedAfterError) break;
704
659
  }
705
660
  };
@@ -739,7 +694,7 @@ async function runCollectedCase(collectedCase, options) {
739
694
  name: collectedCase.definition.name,
740
695
  sourcePath: collectedCase.sourcePath,
741
696
  caseIndex: collectedCase.caseIndex,
742
- status: completedNodes.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
697
+ status: beforeEach.some((step)=>'failed' === step.status) || steps.some((step)=>'failed' === step.status) || afterEach.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
743
698
  beforeEach,
744
699
  steps,
745
700
  afterEach,
@@ -782,7 +737,7 @@ class CaseRunner {
782
737
  definition: {
783
738
  name: input.name ?? 'case',
784
739
  tags: input.tags ?? [],
785
- steps: normalizeSteps(input.steps)
740
+ steps: normalizeSteps(input.steps, (name)=>this.registry.get(name))
786
741
  }
787
742
  };
788
743
  const result = await runCollectedCase(collectedCase, {
@@ -809,7 +764,6 @@ function createDocumentRuntime(document, options) {
809
764
  const startedAt = new Date();
810
765
  const beforeAll = [];
811
766
  const afterAll = [];
812
- const completedNodes = [];
813
767
  const nodes = {
814
768
  beforeAll: document.lifecycle.beforeAll.map((step)=>options.resolveNode(step.node)),
815
769
  afterAll: document.lifecycle.afterAll.map((step)=>options.resolveNode(step.node))
@@ -840,7 +794,7 @@ function createDocumentRuntime(document, options) {
840
794
  projectId: document.projectId,
841
795
  projectName: project.name,
842
796
  sourcePath: document.sourcePath,
843
- status: completedNodes.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
797
+ status: beforeAll.some((step)=>'failed' === step.status) || afterAll.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
844
798
  startedAt: startedAt.toISOString(),
845
799
  endedAt: endedAt.toISOString(),
846
800
  durationMs: Math.max(0, endedAt.getTime() - startedAt.getTime()),
@@ -869,10 +823,7 @@ function createDocumentRuntime(document, options) {
869
823
  projectName: project.name,
870
824
  sourcePath: document.sourcePath,
871
825
  phase,
872
- stepIndex,
873
- completedNodes: Object.freeze([
874
- ...completedNodes
875
- ])
826
+ stepIndex
876
827
  };
877
828
  const stepInfo = {
878
829
  scope: 'document',
@@ -885,7 +836,6 @@ function createDocumentRuntime(document, options) {
885
836
  scope: 'document',
886
837
  document: documentContext
887
838
  }, context, {
888
- history: createHistory([], completedNodes, 'document'),
889
839
  signal: executionSignal,
890
840
  defaultTimeoutMs: options.defaultTimeoutMs,
891
841
  onTeardown (node, teardown) {
@@ -908,7 +858,6 @@ function createDocumentRuntime(document, options) {
908
858
  });
909
859
  await options.onStepResult?.(stepInfo, result);
910
860
  results.push(result);
911
- completedNodes.push(result);
912
861
  if ('failed' === result.status && !result.continuedAfterError) break;
913
862
  }
914
863
  };
@@ -916,9 +865,6 @@ function createDocumentRuntime(document, options) {
916
865
  get context () {
917
866
  return context;
918
867
  },
919
- get history () {
920
- return createHistory([], completedNodes, 'document');
921
- },
922
868
  get canRunCases () {
923
869
  return started && !signal.aborted && !beforeAll.some((step)=>'failed' === step.status);
924
870
  },
@@ -1013,7 +959,6 @@ async function runWorkflowDocument(document, options) {
1013
959
  context: runtime.context,
1014
960
  projectName,
1015
961
  attemptIndex,
1016
- documentHistory: runtime.history,
1017
962
  signal: options.signal,
1018
963
  defaultTimeoutMs: options.defaultTimeoutMs,
1019
964
  onStepStart: options.onStepStart,
@@ -1276,7 +1221,7 @@ function collectWorkflowDocument(source, options) {
1276
1221
  if (!Array.isArray(value)) throw new WorkflowParseError(`Workflow document ${phase} must be an array.`, {
1277
1222
  phase
1278
1223
  });
1279
- return normalizeSteps(value).map((normalized, stepIndex)=>{
1224
+ return normalizeSteps(value, options.resolveNode).map((normalized, stepIndex)=>{
1280
1225
  const resolved = options.resolveNode(normalized.node);
1281
1226
  if (!resolved) throw new WorkflowParseError(`Workflow document ${phase} step ${stepIndex + 1} references unknown node "${normalized.node}".`, {
1282
1227
  phase,
@@ -1312,7 +1257,7 @@ function collectWorkflowDocument(source, options) {
1312
1257
  if (!Array.isArray(tags) || tags.some((tag)=>'string' != typeof tag || 0 === tag.trim().length)) throw new WorkflowParseError(`Case ${caseIndex + 1} tags must be an array of non-empty strings.`, {
1313
1258
  caseIndex
1314
1259
  });
1315
- const steps = normalizeSteps(definition.steps).map((normalized, stepIndex)=>{
1260
+ const steps = normalizeSteps(definition.steps, options.resolveNode).map((normalized, stepIndex)=>{
1316
1261
  if (!options.resolveNode(normalized.node)) throw new WorkflowParseError(`Case ${caseIndex + 1} step ${stepIndex + 1} references unknown node "${normalized.node}".`, {
1317
1262
  caseIndex,
1318
1263
  stepIndex,
@@ -1362,12 +1307,10 @@ exports.WorkflowDocumentExecutionError = __webpack_exports__.WorkflowDocumentExe
1362
1307
  exports.WorkflowError = __webpack_exports__.WorkflowError;
1363
1308
  exports.WorkflowLifecycleError = __webpack_exports__.WorkflowLifecycleError;
1364
1309
  exports.WorkflowParseError = __webpack_exports__.WorkflowParseError;
1365
- exports.assertJsonSerializable = __webpack_exports__.assertJsonSerializable;
1366
1310
  exports.collectWorkflowDocument = __webpack_exports__.collectWorkflowDocument;
1367
1311
  exports.createCaseId = __webpack_exports__.createCaseId;
1368
1312
  exports.createCaseRunner = __webpack_exports__.createCaseRunner;
1369
1313
  exports.createDocumentRuntime = __webpack_exports__.createDocumentRuntime;
1370
- exports.createHistory = __webpack_exports__.createHistory;
1371
1314
  exports.createProjectRuntime = __webpack_exports__.createProjectRuntime;
1372
1315
  exports.createWorkflowDocumentId = __webpack_exports__.createWorkflowDocumentId;
1373
1316
  exports.defineNode = __webpack_exports__.defineNode;
@@ -1377,8 +1320,6 @@ exports.normalizeStep = __webpack_exports__.normalizeStep;
1377
1320
  exports.normalizeSteps = __webpack_exports__.normalizeSteps;
1378
1321
  exports.resolveWorkflowVariables = __webpack_exports__.resolveWorkflowVariables;
1379
1322
  exports.runWorkflowDocument = __webpack_exports__.runWorkflowDocument;
1380
- exports.toHistoryEntry = __webpack_exports__.toHistoryEntry;
1381
- exports.validateCommonNodeInput = __webpack_exports__.validateCommonNodeInput;
1382
1323
  exports.z = __webpack_exports__.z;
1383
1324
  for(var __rspack_i in __webpack_exports__)if (-1 === [
1384
1325
  "CaseExecutionError",
@@ -1398,12 +1339,10 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
1398
1339
  "WorkflowError",
1399
1340
  "WorkflowLifecycleError",
1400
1341
  "WorkflowParseError",
1401
- "assertJsonSerializable",
1402
1342
  "collectWorkflowDocument",
1403
1343
  "createCaseId",
1404
1344
  "createCaseRunner",
1405
1345
  "createDocumentRuntime",
1406
- "createHistory",
1407
1346
  "createProjectRuntime",
1408
1347
  "createWorkflowDocumentId",
1409
1348
  "defineNode",
@@ -1413,8 +1352,6 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
1413
1352
  "normalizeSteps",
1414
1353
  "resolveWorkflowVariables",
1415
1354
  "runWorkflowDocument",
1416
- "toHistoryEntry",
1417
- "validateCommonNodeInput",
1418
1355
  "z"
1419
1356
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
1420
1357
  Object.defineProperty(exports, '__esModule', {