assistsx-js 0.2.2 → 0.2.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.
- package/README.md +16 -7
- package/dist/index.cjs +728 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +236 -18
- package/dist/index.d.ts +236 -18
- package/dist/index.global.js +3 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +720 -152
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
- package/src/assistsx-async.ts +33 -0
- package/src/assistsx.ts +33 -0
- package/src/call-method.ts +1 -0
- package/src/db/db-call-method.ts +11 -0
- package/src/db/db.ts +254 -0
- package/src/global.d.ts +8 -0
- package/src/index.ts +6 -0
- package/src/log/log-call-method.ts +3 -0
- package/src/log/log.ts +124 -19
- package/src/pinia-ensure.ts +15 -0
- package/src/plugin-info.ts +70 -0
- package/src/screenshot/screenshot-call-method.ts +16 -0
- package/src/screenshot/screenshot.ts +200 -0
- package/src/step-flow/legacy-handoff.ts +50 -0
- package/src/step-flow/outcome.ts +16 -0
- package/src/step-flow/payload.ts +23 -0
- package/src/step-flow/runner.ts +128 -0
- package/src/step.ts +48 -14
- package/src/window-flags.ts +21 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Step, type StepImpl } from "../step";
|
|
2
|
+
import { StepError } from "../step-error";
|
|
3
|
+
import type { StepFlowConfig, StepFlowData, StepFlowOutcome } from "./types";
|
|
4
|
+
|
|
5
|
+
function ensureFlowMeta(step: Step, config: StepFlowConfig): void {
|
|
6
|
+
const data = step.data as StepFlowData;
|
|
7
|
+
if (!data.__flow) {
|
|
8
|
+
data.__flow = { id: config.id, state: config.initial };
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function setFlowState(step: Step, state: string, config: StepFlowConfig): void {
|
|
13
|
+
const data = step.data as StepFlowData;
|
|
14
|
+
if (!data.__flow) {
|
|
15
|
+
data.__flow = { id: config.id, state };
|
|
16
|
+
} else {
|
|
17
|
+
data.__flow.state = state;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveOutcome(
|
|
22
|
+
config: StepFlowConfig,
|
|
23
|
+
currentState: string,
|
|
24
|
+
outcome: StepFlowOutcome
|
|
25
|
+
): string | null | undefined | "legacy" {
|
|
26
|
+
if (outcome.type === "end") {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
if (outcome.type === "repeat") {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (outcome.type === "legacy") {
|
|
33
|
+
return "legacy";
|
|
34
|
+
}
|
|
35
|
+
const stateDef = config.states[currentState];
|
|
36
|
+
if (!stateDef) {
|
|
37
|
+
throw new StepError(`StepFlow: unknown state "${currentState}"`, {
|
|
38
|
+
flowId: config.id,
|
|
39
|
+
state: currentState,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const nextState = stateDef.on[outcome.name];
|
|
43
|
+
if (!nextState) {
|
|
44
|
+
throw new StepError(
|
|
45
|
+
`StepFlow: no transition for event "${outcome.name}" in state "${currentState}"`,
|
|
46
|
+
{ flowId: config.id, state: currentState, event: outcome.name }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return nextState;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function createDispatcher(config: StepFlowConfig): StepImpl {
|
|
53
|
+
const dispatcher: StepImpl = async (step) => {
|
|
54
|
+
ensureFlowMeta(step, config);
|
|
55
|
+
const data = step.data as StepFlowData;
|
|
56
|
+
const currentState = data.__flow!.state;
|
|
57
|
+
const stateDef = config.states[currentState];
|
|
58
|
+
if (!stateDef) {
|
|
59
|
+
throw new StepError(`StepFlow: unknown state "${currentState}"`, {
|
|
60
|
+
flowId: config.id,
|
|
61
|
+
state: currentState,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const outcome = await stateDef.run(step);
|
|
66
|
+
const resolved = resolveOutcome(config, currentState, outcome);
|
|
67
|
+
|
|
68
|
+
if (resolved === undefined) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (resolved === null) {
|
|
72
|
+
return step.repeat();
|
|
73
|
+
}
|
|
74
|
+
if (resolved === "legacy") {
|
|
75
|
+
if (outcome.type !== "legacy") {
|
|
76
|
+
throw new StepError("StepFlow: internal legacy outcome mismatch");
|
|
77
|
+
}
|
|
78
|
+
return step.next(outcome.impl);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setFlowState(step, resolved, config);
|
|
82
|
+
return step.next(dispatcher);
|
|
83
|
+
};
|
|
84
|
+
return dispatcher;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 创建流程调度 StepImpl(需先填充 config.states,见 createLaunchState) */
|
|
88
|
+
export function createFlowDispatcher(config: StepFlowConfig): StepImpl {
|
|
89
|
+
return createDispatcher(config);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function buildFlowInitialData(config: StepFlowConfig): StepFlowData {
|
|
93
|
+
return {
|
|
94
|
+
payload: config.data ?? {},
|
|
95
|
+
__flow: {
|
|
96
|
+
id: config.id,
|
|
97
|
+
state: config.initial,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class StepFlow {
|
|
103
|
+
/**
|
|
104
|
+
* 按状态机配置运行流程,内部复用 Step.run 与现有步骤循环。
|
|
105
|
+
*/
|
|
106
|
+
static async run(
|
|
107
|
+
config: StepFlowConfig,
|
|
108
|
+
options?: {
|
|
109
|
+
stepId?: string;
|
|
110
|
+
tag?: string;
|
|
111
|
+
delayMs?: number;
|
|
112
|
+
exceptionRetryCountMax?: number;
|
|
113
|
+
}
|
|
114
|
+
): Promise<Step | undefined> {
|
|
115
|
+
if (!config.states[config.initial]) {
|
|
116
|
+
throw new StepError(
|
|
117
|
+
`StepFlow: initial state "${config.initial}" is not defined`,
|
|
118
|
+
{ flowId: config.id }
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const dispatcher = createDispatcher(config);
|
|
122
|
+
return Step.run(dispatcher, {
|
|
123
|
+
...options,
|
|
124
|
+
tag: options?.tag ?? config.id,
|
|
125
|
+
data: buildFlowInitialData(config),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
package/src/step.ts
CHANGED
|
@@ -6,11 +6,15 @@ import { AssistsX } from "./assistsx";
|
|
|
6
6
|
import { Node } from "./node";
|
|
7
7
|
import { CallMethod } from "./call-method";
|
|
8
8
|
import { useStepStore } from "./step-state-store";
|
|
9
|
+
import { ensureAssistsXPinia } from "./pinia-ensure";
|
|
9
10
|
import { generateUUID } from "./utils";
|
|
10
11
|
import { StepError, StepStopError } from "./step-error";
|
|
11
12
|
import { StepAsync } from "./step-async";
|
|
12
13
|
import type { NodeLookupScope } from "./node-lookup-scope";
|
|
13
14
|
|
|
15
|
+
// 步骤数据类型,始终为普通对象
|
|
16
|
+
export type StepData = Record<string, any>;
|
|
17
|
+
|
|
14
18
|
// 步骤结果类型,可以是Step实例或undefined
|
|
15
19
|
export type StepResult = Step | undefined;
|
|
16
20
|
|
|
@@ -27,6 +31,34 @@ export class Step {
|
|
|
27
31
|
static showLog: boolean = false;
|
|
28
32
|
static exceptionRetryCountMaxDefault: number = 3;
|
|
29
33
|
|
|
34
|
+
/**
|
|
35
|
+
* 判断步骤数据是否有效(非空且为普通对象)
|
|
36
|
+
*/
|
|
37
|
+
private static isValidStepData(data: unknown): data is StepData {
|
|
38
|
+
return (
|
|
39
|
+
data !== null &&
|
|
40
|
+
data !== undefined &&
|
|
41
|
+
typeof data === "object" &&
|
|
42
|
+
!Array.isArray(data)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 解析步骤数据:优先使用传入值,否则使用当前值,均无效时返回空对象
|
|
48
|
+
*/
|
|
49
|
+
private static resolveStepData(
|
|
50
|
+
provided?: StepData,
|
|
51
|
+
fallback?: StepData
|
|
52
|
+
): StepData {
|
|
53
|
+
if (provided !== undefined && Step.isValidStepData(provided)) {
|
|
54
|
+
return provided;
|
|
55
|
+
}
|
|
56
|
+
if (fallback !== undefined && Step.isValidStepData(fallback)) {
|
|
57
|
+
return fallback;
|
|
58
|
+
}
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
|
|
30
62
|
/**
|
|
31
63
|
* 当前执行步骤的ID
|
|
32
64
|
*/
|
|
@@ -60,13 +92,15 @@ export class Step {
|
|
|
60
92
|
}: {
|
|
61
93
|
stepId?: string | undefined;
|
|
62
94
|
tag?: string | undefined;
|
|
63
|
-
data?:
|
|
95
|
+
data?: StepData;
|
|
64
96
|
delayMs?: number;
|
|
65
97
|
exceptionRetryCountMax?: number;
|
|
66
98
|
} = {}
|
|
67
99
|
): Promise<Step | undefined> {
|
|
68
100
|
this.exception = undefined;
|
|
101
|
+
ensureAssistsXPinia();
|
|
69
102
|
const stepStore = useStepStore();
|
|
103
|
+
const resolvedData = Step.resolveStepData(data);
|
|
70
104
|
let implnName = impl.name;
|
|
71
105
|
let currentStep: Step | undefined;
|
|
72
106
|
let nextStep: Step | undefined;
|
|
@@ -84,12 +118,12 @@ export class Step {
|
|
|
84
118
|
}
|
|
85
119
|
}
|
|
86
120
|
|
|
87
|
-
stepStore.startStep(this._stepId, tag,
|
|
121
|
+
stepStore.startStep(this._stepId, tag, resolvedData);
|
|
88
122
|
currentStep = new Step({
|
|
89
123
|
stepId: this._stepId,
|
|
90
124
|
impl,
|
|
91
125
|
tag,
|
|
92
|
-
data,
|
|
126
|
+
data: resolvedData,
|
|
93
127
|
delayMs,
|
|
94
128
|
exceptionRetryCountMax,
|
|
95
129
|
});
|
|
@@ -228,7 +262,7 @@ export class Step {
|
|
|
228
262
|
const errorMsg = JSON.stringify({
|
|
229
263
|
impl: implnName,
|
|
230
264
|
tag: tag,
|
|
231
|
-
data:
|
|
265
|
+
data: resolvedData,
|
|
232
266
|
error: e?.message ?? String(e),
|
|
233
267
|
});
|
|
234
268
|
stepStore.setError(errorMsg);
|
|
@@ -402,7 +436,7 @@ export class Step {
|
|
|
402
436
|
/**
|
|
403
437
|
* 步骤数据
|
|
404
438
|
*/
|
|
405
|
-
data:
|
|
439
|
+
data: StepData;
|
|
406
440
|
|
|
407
441
|
/**
|
|
408
442
|
* 步骤延迟时间(毫秒)
|
|
@@ -435,7 +469,7 @@ export class Step {
|
|
|
435
469
|
stepId: string;
|
|
436
470
|
impl: StepImpl | undefined;
|
|
437
471
|
tag?: string | undefined;
|
|
438
|
-
data?:
|
|
472
|
+
data?: StepData;
|
|
439
473
|
delayMs?: number;
|
|
440
474
|
repeatCountMax?: number;
|
|
441
475
|
exceptionRetryCountMax?: number;
|
|
@@ -443,7 +477,7 @@ export class Step {
|
|
|
443
477
|
}) {
|
|
444
478
|
this.tag = tag;
|
|
445
479
|
this.stepId = stepId;
|
|
446
|
-
this.data = data
|
|
480
|
+
this.data = Step.resolveStepData(data);
|
|
447
481
|
this.impl = impl;
|
|
448
482
|
this.delayMs = delayMs;
|
|
449
483
|
this.repeatCountMax = repeatCountMax;
|
|
@@ -472,7 +506,7 @@ export class Step {
|
|
|
472
506
|
exceptionRetryCountMax = Step.exceptionRetryCountMaxDefault,
|
|
473
507
|
}: {
|
|
474
508
|
tag?: string | undefined;
|
|
475
|
-
data?:
|
|
509
|
+
data?: StepData;
|
|
476
510
|
delayMs?: number;
|
|
477
511
|
repeatCountMax?: number;
|
|
478
512
|
exceptionRetryCountMax?: number;
|
|
@@ -483,7 +517,7 @@ export class Step {
|
|
|
483
517
|
stepId: this.stepId,
|
|
484
518
|
impl,
|
|
485
519
|
tag,
|
|
486
|
-
data: data
|
|
520
|
+
data: Step.resolveStepData(data, this.data),
|
|
487
521
|
delayMs,
|
|
488
522
|
repeatCountMax,
|
|
489
523
|
exceptionRetryCountMax,
|
|
@@ -498,7 +532,7 @@ export class Step {
|
|
|
498
532
|
exceptionRetryCountMax = Step.exceptionRetryCountMaxDefault,
|
|
499
533
|
}: {
|
|
500
534
|
tag?: string | undefined;
|
|
501
|
-
data?:
|
|
535
|
+
data?: StepData;
|
|
502
536
|
delayMs?: number;
|
|
503
537
|
repeatCountMax?: number;
|
|
504
538
|
exceptionRetryCountMax?: number;
|
|
@@ -509,7 +543,7 @@ export class Step {
|
|
|
509
543
|
stepId: this.stepId,
|
|
510
544
|
impl: undefined,
|
|
511
545
|
tag,
|
|
512
|
-
data: data
|
|
546
|
+
data: Step.resolveStepData(data, this.data),
|
|
513
547
|
delayMs,
|
|
514
548
|
repeatCountMax,
|
|
515
549
|
exceptionRetryCountMax,
|
|
@@ -528,14 +562,14 @@ export class Step {
|
|
|
528
562
|
repeat({
|
|
529
563
|
stepId = this.stepId,
|
|
530
564
|
tag = this.tag,
|
|
531
|
-
data
|
|
565
|
+
data,
|
|
532
566
|
delayMs = this.delayMs,
|
|
533
567
|
repeatCountMax = this.repeatCountMax,
|
|
534
568
|
exceptionRetryCountMax = this.exceptionRetryCountMax,
|
|
535
569
|
}: {
|
|
536
570
|
stepId?: string;
|
|
537
571
|
tag?: string | undefined;
|
|
538
|
-
data?:
|
|
572
|
+
data?: StepData;
|
|
539
573
|
delayMs?: number;
|
|
540
574
|
repeatCountMax?: number;
|
|
541
575
|
exceptionRetryCountMax?: number;
|
|
@@ -544,7 +578,7 @@ export class Step {
|
|
|
544
578
|
this.repeatCount++;
|
|
545
579
|
this.stepId = stepId;
|
|
546
580
|
this.tag = tag;
|
|
547
|
-
this.data = data;
|
|
581
|
+
this.data = Step.resolveStepData(data, this.data);
|
|
548
582
|
this.delayMs = delayMs;
|
|
549
583
|
this.repeatCountMax = repeatCountMax;
|
|
550
584
|
this.exceptionRetryCountMax = exceptionRetryCountMax;
|
package/src/window-flags.ts
CHANGED
|
@@ -90,6 +90,27 @@ export class WindowFlags {
|
|
|
90
90
|
return flags & ~flag;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** 输入框获取焦点时使用的悬浮窗 flag 组合(不含 FLAG_NOT_FOCUSABLE) */
|
|
94
|
+
static getOverlayInputFocusFlagList(): number[] {
|
|
95
|
+
return [
|
|
96
|
+
WindowFlags.FLAG_WATCH_OUTSIDE_TOUCH,
|
|
97
|
+
WindowFlags.FLAG_NOT_TOUCH_MODAL,
|
|
98
|
+
WindowFlags.FLAG_LAYOUT_NO_LIMITS,
|
|
99
|
+
WindowFlags.FLAG_LAYOUT_IN_SCREEN,
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** 输入框失去焦点时使用的悬浮窗 flag 组合(含 FLAG_NOT_FOCUSABLE) */
|
|
104
|
+
static getOverlayInputBlurFlagList(): number[] {
|
|
105
|
+
return [
|
|
106
|
+
WindowFlags.FLAG_WATCH_OUTSIDE_TOUCH,
|
|
107
|
+
WindowFlags.FLAG_NOT_TOUCH_MODAL,
|
|
108
|
+
WindowFlags.FLAG_LAYOUT_NO_LIMITS,
|
|
109
|
+
WindowFlags.FLAG_NOT_FOCUSABLE,
|
|
110
|
+
WindowFlags.FLAG_LAYOUT_IN_SCREEN,
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
/**
|
|
94
115
|
* 获取所有标志位的描述信息
|
|
95
116
|
* @returns 标志位描述对象数组
|