@windsland52/maafw-live 0.0.0-stage → 0.4.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/LICENSE +21 -0
- package/README.md +293 -2
- package/bin/maafw-live.mjs +25 -0
- package/docs/daemon-protocol.md +121 -0
- package/docs/keyframe-retention-contract-v0.md +225 -0
- package/docs/session-unify-v0.md +115 -0
- package/lib/client/daemon.js +276 -0
- package/lib/commands/annotate.js +179 -0
- package/lib/commands/calibrate.js +61 -0
- package/lib/commands/color.js +73 -0
- package/lib/commands/crop.js +228 -0
- package/lib/commands/dispatch.js +121 -0
- package/lib/commands/env.js +409 -0
- package/lib/commands/index.js +70 -0
- package/lib/commands/input.js +257 -0
- package/lib/commands/kf.js +167 -0
- package/lib/commands/probe.js +70 -0
- package/lib/commands/reco.js +440 -0
- package/lib/commands/repl.js +1501 -0
- package/lib/commands/roi-check.js +273 -0
- package/lib/commands/roi-compare.js +388 -0
- package/lib/commands/runtime.js +718 -0
- package/lib/commands/skill.js +169 -0
- package/lib/commands/timing.js +247 -0
- package/lib/commands/version.js +66 -0
- package/lib/daemon/framed.mjs +3680 -0
- package/lib/daemon/reco_child.mjs +287 -0
- package/lib/exec.js +96 -0
- package/lib/flags.js +44 -0
- package/lib/image.js +90 -0
- package/lib/index.js +143 -0
- package/lib/interface/hotkey.js +142 -0
- package/lib/interface/index.js +12 -0
- package/lib/interface/jsonc.js +95 -0
- package/lib/interface/load.js +397 -0
- package/lib/interface/override.js +287 -0
- package/lib/interface/plan.js +279 -0
- package/lib/option-args.js +29 -0
- package/lib/pkg.js +54 -0
- package/lib/protocol.js +94 -0
- package/lib/runtime/actions.js +225 -0
- package/lib/runtime/keyframes.js +73 -0
- package/lib/runtime/log-watch.js +160 -0
- package/lib/runtime/node-source.js +100 -0
- package/lib/runtime/ocr-model.js +45 -0
- package/lib/runtime/pi-env.js +34 -0
- package/lib/runtime/pretask.js +217 -0
- package/lib/runtime/prune.js +28 -0
- package/lib/runtime/receipts.js +57 -0
- package/lib/runtime/reco-args.js +38 -0
- package/lib/runtime/reco-verdict.js +82 -0
- package/lib/runtime/roi-compare.js +198 -0
- package/lib/runtime/session-forward.js +79 -0
- package/lib/runtime/session-ipc.js +471 -0
- package/lib/runtime/session.js +135 -0
- package/lib/runtime/signal-guard.js +35 -0
- package/lib/types/client/daemon.d.ts +86 -0
- package/lib/types/commands/annotate.d.ts +3 -0
- package/lib/types/commands/calibrate.d.ts +7 -0
- package/lib/types/commands/color.d.ts +9 -0
- package/lib/types/commands/crop.d.ts +3 -0
- package/lib/types/commands/dispatch.d.ts +22 -0
- package/lib/types/commands/env.d.ts +21 -0
- package/lib/types/commands/index.d.ts +13 -0
- package/lib/types/commands/input.d.ts +17 -0
- package/lib/types/commands/kf.d.ts +10 -0
- package/lib/types/commands/probe.d.ts +15 -0
- package/lib/types/commands/reco.d.ts +27 -0
- package/lib/types/commands/repl.d.ts +10 -0
- package/lib/types/commands/roi-check.d.ts +3 -0
- package/lib/types/commands/roi-compare.d.ts +3 -0
- package/lib/types/commands/runtime.d.ts +66 -0
- package/lib/types/commands/skill.d.ts +17 -0
- package/lib/types/commands/timing.d.ts +64 -0
- package/lib/types/commands/version.d.ts +3 -0
- package/lib/types/exec.d.ts +31 -0
- package/lib/types/flags.d.ts +62 -0
- package/lib/types/image.d.ts +27 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/interface/hotkey.d.ts +36 -0
- package/lib/types/interface/index.d.ts +11 -0
- package/lib/types/interface/jsonc.d.ts +9 -0
- package/lib/types/interface/load.d.ts +190 -0
- package/lib/types/interface/override.d.ts +78 -0
- package/lib/types/interface/plan.d.ts +68 -0
- package/lib/types/option-args.d.ts +19 -0
- package/lib/types/pkg.d.ts +14 -0
- package/lib/types/protocol.d.ts +124 -0
- package/lib/types/runtime/actions.d.ts +248 -0
- package/lib/types/runtime/keyframes.d.ts +43 -0
- package/lib/types/runtime/log-watch.d.ts +28 -0
- package/lib/types/runtime/node-source.d.ts +25 -0
- package/lib/types/runtime/ocr-model.d.ts +8 -0
- package/lib/types/runtime/pi-env.d.ts +24 -0
- package/lib/types/runtime/pretask.d.ts +53 -0
- package/lib/types/runtime/prune.d.ts +4 -0
- package/lib/types/runtime/receipts.d.ts +7 -0
- package/lib/types/runtime/reco-args.d.ts +18 -0
- package/lib/types/runtime/reco-verdict.d.ts +50 -0
- package/lib/types/runtime/roi-compare.d.ts +117 -0
- package/lib/types/runtime/session-forward.d.ts +10 -0
- package/lib/types/runtime/session-ipc.d.ts +117 -0
- package/lib/types/runtime/session.d.ts +77 -0
- package/lib/types/runtime/signal-guard.d.ts +19 -0
- package/lib/types/update-check.d.ts +20 -0
- package/lib/types/usage.d.ts +3 -0
- package/lib/update-check.js +97 -0
- package/lib/usage.js +50 -0
- package/package.json +94 -4
- package/skills/README.md +51 -0
- package/skills/maafw-live/SKILL.md +293 -0
- package/skills/maafw-live/references/examples.md +238 -0
- package/skills/maafw-live/references/pitfalls.md +211 -0
- package/skills/maafw-live/references/workflows.md +164 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** 帧元数据(像素默认不出 daemon;预览帧落盘后给路径)。 */
|
|
2
|
+
export interface FrameMeta {
|
|
3
|
+
seq: number;
|
|
4
|
+
t: number;
|
|
5
|
+
diff?: number;
|
|
6
|
+
w?: number;
|
|
7
|
+
h?: number;
|
|
8
|
+
preview?: string;
|
|
9
|
+
}
|
|
10
|
+
/** 帧流事件:画面变化/稳定,以及 Tasker 的节点级消息(按帧序对齐)。 */
|
|
11
|
+
export interface StreamEvent {
|
|
12
|
+
type: string;
|
|
13
|
+
seq?: number;
|
|
14
|
+
t: number;
|
|
15
|
+
diff?: number;
|
|
16
|
+
node?: string | null;
|
|
17
|
+
msg?: string;
|
|
18
|
+
id?: number | string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface DaemonEvents {
|
|
21
|
+
frames: FrameMeta[];
|
|
22
|
+
events: StreamEvent[];
|
|
23
|
+
/** 流级异常与通知:`stream_error`(设备掉线等)与 `stream_stopped`(控制器销毁导致流被停) */
|
|
24
|
+
errors: string[];
|
|
25
|
+
logs: string[];
|
|
26
|
+
/** 最新预览帧路径(daemon 收到 init 的 runDir 后写入 runDir/preview.png) */
|
|
27
|
+
preview: string | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* daemon 推送的消息种类。`subscribe` 的回调按种类拿不同载荷:
|
|
31
|
+
* `frame` → FrameMeta、`event` → StreamEvent、`stream_error` → 错误文本、`stream_stopped` → 停流原因。
|
|
32
|
+
*/
|
|
33
|
+
export type DaemonMessageKind = 'frame' | 'event' | 'stream_error' | 'stream_stopped';
|
|
34
|
+
/** `init` 的回执:daemon 身份与落点(客户端 spawn 后立刻握手的那一次)。 */
|
|
35
|
+
export interface DaemonInit {
|
|
36
|
+
previewPath: string | null;
|
|
37
|
+
daemonId: string;
|
|
38
|
+
framesDir: string;
|
|
39
|
+
kfQuota: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 握手结果。**失败不抛异常**:老实现用 `id:-1` 发出去就不管,回执在分发链里被丢弃,
|
|
43
|
+
* init 失败无从得知;现在如实回报,同时不把"daemon 不回 init"变成调用方的致命错误
|
|
44
|
+
* (协议要求每条请求都有应答,但客户端不该因为对方没回一条就全盘不进)。
|
|
45
|
+
*/
|
|
46
|
+
export type DaemonInitResult = {
|
|
47
|
+
ok: true;
|
|
48
|
+
data: DaemonInit;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
error: string;
|
|
52
|
+
};
|
|
53
|
+
export interface DaemonClient {
|
|
54
|
+
readonly events: DaemonEvents;
|
|
55
|
+
/** spawn 后那次 `init` 握手的回执(framesDir / daemonId / kfQuota);需要时才会 spawn daemon。 */
|
|
56
|
+
init(): Promise<DaemonInitResult>;
|
|
57
|
+
/** 发一条命令并等应答;超时会硬杀 daemon(下次调用自动重生)。 */
|
|
58
|
+
call<T = unknown>(cmd: string, args?: Record<string, unknown>, timeoutMs?: number): Promise<T>;
|
|
59
|
+
/** daemon stderr + 非 JSON stdout 行(maa 原生日志,识别失败根因常在这)。 */
|
|
60
|
+
logTail(n?: number): string[];
|
|
61
|
+
/** 订阅帧/事件/流错误/流停止;返回退订函数。 */
|
|
62
|
+
subscribe(kind: DaemonMessageKind, cb: (message: unknown) => void): () => void;
|
|
63
|
+
stats(): {
|
|
64
|
+
calls: number;
|
|
65
|
+
restarts: number;
|
|
66
|
+
alive: boolean;
|
|
67
|
+
pid: number | null;
|
|
68
|
+
daemonPath: string;
|
|
69
|
+
};
|
|
70
|
+
/** 停流 + 断开 + 结束子进程。 */
|
|
71
|
+
close(): void;
|
|
72
|
+
}
|
|
73
|
+
export interface SpawnOptions {
|
|
74
|
+
/** 预览帧与临时产物的目录;默认 ~/.maafw-live */
|
|
75
|
+
runDir?: string;
|
|
76
|
+
/** 显式 daemon 路径;默认包内 lib/daemon/framed.mjs,可用 MAA_DAEMON 覆盖 */
|
|
77
|
+
daemonPath?: string;
|
|
78
|
+
/** 默认调用超时 */
|
|
79
|
+
timeoutMs?: number;
|
|
80
|
+
/** 关键帧库磁盘配额(字节,>0 生效;缺省 1GiB,daemon 侧 env MAAFW_KF_QUOTA_BYTES 亦可覆盖) */
|
|
81
|
+
kfQuotaBytes?: number;
|
|
82
|
+
}
|
|
83
|
+
export declare function defaultRunDir(): string;
|
|
84
|
+
/** 定位 daemon 脚本:显式参数 → MAA_DAEMON → 包内 lib/daemon/framed.mjs。 */
|
|
85
|
+
export declare function resolveDaemonPath(explicit?: string): string;
|
|
86
|
+
export declare function spawnDaemon(options?: SpawnOptions): DaemonClient;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 探色命令:ROI 实测主色/均值(RGB/HSV/灰度)——模型只选色不报色值。
|
|
3
|
+
*
|
|
4
|
+
* 为什么不靠模型读像素:色值必须来自实测(降采样小图按该帧捕获尺寸换算后的 ROI),
|
|
5
|
+
* 模型选完色后用 reco ColorMatch 出框(走已修好的参数透传链),出框与否是事实不是判断。
|
|
6
|
+
*/
|
|
7
|
+
import { type Command } from '../protocol.js';
|
|
8
|
+
export declare const colorCommand: Command;
|
|
9
|
+
export declare const COLOR_COMMANDS: Command[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DaemonClient } from '../client/daemon.js';
|
|
2
|
+
import { type GlobalFlags } from '../flags.js';
|
|
3
|
+
import { type Command, type CommandResult } from '../protocol.js';
|
|
4
|
+
export interface DispatchEnv {
|
|
5
|
+
/** 复用既有 daemon(命名会话 / REPL 注入);一次性路径留空,由 withDaemon 现起现关。 */
|
|
6
|
+
client?: DaemonClient;
|
|
7
|
+
/** 命令看到的工作目录(一次性 CLI 是 --cwd 解析结果;会话侧是 serve 进程的 cwd) */
|
|
8
|
+
cwd: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DispatchOutcome {
|
|
11
|
+
cmd: Command | null;
|
|
12
|
+
/** emit 需要的全局旗标(--json / --color 也在这里解析过) */
|
|
13
|
+
flags: GlobalFlags;
|
|
14
|
+
result: CommandResult;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 分发一条 argv(含命令名,即 `argv[0]` 是命令名)。
|
|
18
|
+
* 永不抛异常:BAD_ARGUMENTS / UNKNOWN_COMMAND / SESSION_REQUIRED / UNEXPECTED 都收敛成
|
|
19
|
+
* CommandResult——会话常驻进程不能因为一条坏命令挂掉。
|
|
20
|
+
*/
|
|
21
|
+
export declare function dispatchArgv(argv: string[], env: DispatchEnv): Promise<DispatchOutcome>;
|
|
22
|
+
export declare function isDirectory(p: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Command } from '../protocol.js';
|
|
2
|
+
/**
|
|
3
|
+
* qualifier 归一化:同一个 pre-release 在两个生态里写法不同,比较前先落到同一形态。
|
|
4
|
+
* `-beta.1` / `beta.1` / `beta1` / `b1` → `b1`;`alpha` → `a`;`rc` / `pre` / `preview` → `rc`;
|
|
5
|
+
* `.dev1` → `dev1`;`.post1` → `post1`;没有后缀 → 空串(正式版)。
|
|
6
|
+
* 认不出的后缀原样保留:宁可把它判成不一致,也不要凭猜测把两个不相干的后缀当同一个。
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeQualifier(qualifier: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* 把精确版本拆成 release 线与**归一化后的** qualifier:`5.15.0b1` → `5.15.0` + `b1`,
|
|
11
|
+
* `5.15.0-beta.1` 同样落到 `5.15.0` + `b1`。
|
|
12
|
+
*
|
|
13
|
+
* 对账要分别看两段:release 线不同是换了个版本;release 相同而 qualifier 不同是**同一条线上的
|
|
14
|
+
* 另一份构建**(正式版 vs 预发布、b1 vs rc1 都是)。只比字符串会把两种拼写当不一致;
|
|
15
|
+
* 只比 release 又会把正式版与预发布报成一致——两头都错。
|
|
16
|
+
*/
|
|
17
|
+
export declare function splitRelease(version: string): {
|
|
18
|
+
release: string;
|
|
19
|
+
qualifier: string;
|
|
20
|
+
} | null;
|
|
21
|
+
export declare const envCommand: Command;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令注册表。
|
|
3
|
+
*
|
|
4
|
+
* 只注册**已经实现且能跑通**的命令。未实现的能力不在这里挂空壳,也不进 `--help`——
|
|
5
|
+
* 挂空壳会让 `maafw <cmd>` 的失败原因从「没这个命令」变成「没实现」,技能无法区分;
|
|
6
|
+
* help 描述未来就会过期撒谎,只描述现状。
|
|
7
|
+
*/
|
|
8
|
+
import type { Command } from '../protocol.js';
|
|
9
|
+
/** 展示顺序:探针 → 运行时/设备 → 输入 → 识别 → 验真 → 探色 → 裁剪 → SoM → 校准 → 关键帧 → timing → 会话 → skill 自检。 */
|
|
10
|
+
export declare const COMMANDS: Command[];
|
|
11
|
+
export declare function findCommand(name: string): Command | undefined;
|
|
12
|
+
/** 未知命令时给出「最接近的名字」建议(编辑距离),避免用户猜 */
|
|
13
|
+
export declare function suggestCommand(name: string, maxDistance?: number): string | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 输入注入命令:click / swipe / key / text。
|
|
3
|
+
*
|
|
4
|
+
* 全部经 maafw 控制器本体注入(不直接调 adb),坐标是控制器分辨率空间——默认短边 720,
|
|
5
|
+
* 与 pipeline 里 roi / 模板图同一坐标系。要设备就必须给 --project(推荐)或 --kind。
|
|
6
|
+
*/
|
|
7
|
+
import { type Command } from '../protocol.js';
|
|
8
|
+
export declare const clickCommand: Command;
|
|
9
|
+
export declare const swipeCommand: Command;
|
|
10
|
+
export declare const keyCommand: Command;
|
|
11
|
+
export declare const keysCommand: Command;
|
|
12
|
+
export declare const pressCommand: Command;
|
|
13
|
+
export declare const dbclickCommand: Command;
|
|
14
|
+
export declare const scrollCommand: Command;
|
|
15
|
+
export declare const moveCommand: Command;
|
|
16
|
+
export declare const textCommand: Command;
|
|
17
|
+
export declare const INPUT_COMMANDS: Command[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 关键帧命令:kf status / kf promote / kf list / kf resolve。
|
|
3
|
+
*
|
|
4
|
+
* 升格(promote)是 daemon 内存操作——从 L0 缓存取原图落盘并登记,必须在捕获它的那个
|
|
5
|
+
* daemon 会话里做( REPL 里 stream/输入/run 之后立刻升格,"看到即升格,不攒到最后")。
|
|
6
|
+
* list / resolve 是纯离线文件操作,不依赖 daemon 存活(契约 §4.1)。
|
|
7
|
+
*/
|
|
8
|
+
import { type Command } from '../protocol.js';
|
|
9
|
+
export declare const kfCommand: Command;
|
|
10
|
+
export declare const KF_COMMANDS: Command[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `maafw-live screencap-probe` —— 截图能力探测:判定"后台可截"(A 路前提)。
|
|
3
|
+
*
|
|
4
|
+
* 方法(契约 demo-trace §3):用另一个窗口把目标**完全盖住**,两次 `post_screencap`
|
|
5
|
+
* 间隔比 blockHash 与亮度。探针不知道"此刻是否真的遮挡"——所以 `--occluded` 让用户
|
|
6
|
+
* 显式声明;不给时判定结果如实标 `occluded:null`,不把"未声明遮挡"混成"前台结论"。
|
|
7
|
+
*
|
|
8
|
+
* 判据:
|
|
9
|
+
* changed==true + occluded → 后台可截(A 路前提成立)
|
|
10
|
+
* changed==true + !occluded → 像素在变——要判"后台可截"得在遮挡下重测
|
|
11
|
+
* changed==false + 正常亮度 → 静止(目标停止渲染?改应用设置)
|
|
12
|
+
* 黑图 / post_screencap 报错 → 截图方法不兼容,换 `win32.screencap` 方法
|
|
13
|
+
*/
|
|
14
|
+
import { type Command } from '../protocol.js';
|
|
15
|
+
export declare const screencapProbeCommand: Command;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Command } from '../protocol.js';
|
|
2
|
+
/** threshold 起点建议(maafw-pipeline 技能口径):实测最高置信度 − 0.1 留余量,换场景会掉。
|
|
3
|
+
* 得分在识别详情内层(detail.detail.best/all——miss 时 best 为 null,all 仍带各候选得分);
|
|
4
|
+
* 无数值得分的类型(OCR 等)返回 null,不编造。低于 0.5 视为模板与画面不匹配:
|
|
5
|
+
* 未命中不是调低阈值的理由,建议不适用。 */
|
|
6
|
+
export interface ThresholdSuggestion {
|
|
7
|
+
bestScore: number;
|
|
8
|
+
suggest: number | null;
|
|
9
|
+
lowMatch: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function suggestThreshold(results: Array<{
|
|
12
|
+
ok: boolean;
|
|
13
|
+
detail?: unknown;
|
|
14
|
+
}>): ThresholdSuggestion | null;
|
|
15
|
+
/**
|
|
16
|
+
* OCR 模型名:框架按 `model/ocr/<name>/` 找模型,缺省空串 = 直接放在 `model/ocr/` 下。
|
|
17
|
+
* 优先级:资源 dump(V2 缺省也填满)> 手写节点的 V2 param / V1 顶层 model > `--type` 的 `--param`。
|
|
18
|
+
*/
|
|
19
|
+
export declare function ocrModelName(node: Record<string, unknown> | undefined, param: Record<string, unknown> | undefined, dump: {
|
|
20
|
+
recognition?: {
|
|
21
|
+
param?: {
|
|
22
|
+
model?: unknown;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
} | undefined): string | undefined;
|
|
26
|
+
export declare const recoCommand: Command;
|
|
27
|
+
export declare const RECO_COMMANDS: Command[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Command } from '../protocol.js';
|
|
2
|
+
/** repl `reco <type> k=v …` 的参数解析:沿用既有惯例(数字转 number),列表参数转数组。 */
|
|
3
|
+
export declare function recoParam(tokens: string[]): Record<string, unknown>;
|
|
4
|
+
export declare const replCommand: Command;
|
|
5
|
+
/**
|
|
6
|
+
* REPL 行 → argv 的方言翻译表。翻不了(REPL 私有命令)返回 null,调用方走 line 路径。
|
|
7
|
+
* 这是会话"两个实现漂移"的止血带:翻译完进的是 dispatchArgv,与一次性 CLI 同一份
|
|
8
|
+
* 实现——`run T --option` 在 --cmd 里从此生效(P0-3)。
|
|
9
|
+
*/
|
|
10
|
+
export declare function replToArgv(line: string): string[] | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type Command, type CommandResult } from '../protocol.js';
|
|
2
|
+
import { type SessionOptions } from '../runtime/session.js';
|
|
3
|
+
/** 连接类选项:凡是要设备的命令都接受同一组,保证"怎么连"只有一套说法。 */
|
|
4
|
+
export declare const CONNECT_OPTIONS: {
|
|
5
|
+
project: {
|
|
6
|
+
type: "string";
|
|
7
|
+
};
|
|
8
|
+
controller: {
|
|
9
|
+
type: "string";
|
|
10
|
+
};
|
|
11
|
+
resource: {
|
|
12
|
+
type: "string";
|
|
13
|
+
};
|
|
14
|
+
hwnd: {
|
|
15
|
+
type: "string";
|
|
16
|
+
};
|
|
17
|
+
address: {
|
|
18
|
+
type: "string";
|
|
19
|
+
};
|
|
20
|
+
kind: {
|
|
21
|
+
type: "string";
|
|
22
|
+
};
|
|
23
|
+
target: {
|
|
24
|
+
type: "string";
|
|
25
|
+
};
|
|
26
|
+
'short-side': {
|
|
27
|
+
type: "string";
|
|
28
|
+
};
|
|
29
|
+
'long-side': {
|
|
30
|
+
type: "string";
|
|
31
|
+
};
|
|
32
|
+
raw: {
|
|
33
|
+
type: "boolean";
|
|
34
|
+
};
|
|
35
|
+
'no-pretask': {
|
|
36
|
+
type: "boolean";
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 路径参数的解析基准:调用方给的目录就是 `ctx.cwd`(CLI 的 --cwd),不是 process.cwd()。
|
|
41
|
+
* 只处理**纯路径参数**(--project / --resource-dir / --out / --image / --frames-dir 等)——
|
|
42
|
+
* `--resource` 同时是"资源名",能不能按路径解析要留给 resolveResourcePaths(名字优先),
|
|
43
|
+
* 所以它在 SessionOptions.cwd 里透传,不在这里 resolve。
|
|
44
|
+
*/
|
|
45
|
+
export declare function argPath(ctx: {
|
|
46
|
+
cwd: string;
|
|
47
|
+
}, v: string | undefined): string | undefined;
|
|
48
|
+
export declare function sessionOptions(ctx: {
|
|
49
|
+
values: Record<string, unknown>;
|
|
50
|
+
cwd: string;
|
|
51
|
+
}): SessionOptions;
|
|
52
|
+
/** daemon 抛出的错误翻译成结构化失败。退出码按错误的**性质**分:
|
|
53
|
+
* 前置缺失(脚本找不到 / 会话规划失败)退 4;运行时故障(调用超时、进程退出、发送失败)退 1——
|
|
54
|
+
* 同一个 code 在所有路径退同一个码,agent 才不会按"缺环境"去查"daemon 卡住"。 */
|
|
55
|
+
export declare function daemonFail(e: unknown, hint?: string): CommandResult;
|
|
56
|
+
export declare const probeCommand: Command;
|
|
57
|
+
export declare const deviceCommand: Command;
|
|
58
|
+
export declare const connectCommand: Command;
|
|
59
|
+
export declare const disconnectCommand: Command;
|
|
60
|
+
export declare const screencapCommand: Command;
|
|
61
|
+
export declare const eventsCommand: Command;
|
|
62
|
+
export declare const frameCommand: Command;
|
|
63
|
+
export declare const waitCommand: Command;
|
|
64
|
+
export declare const runCommand: Command;
|
|
65
|
+
export declare const stopCommand: Command;
|
|
66
|
+
export declare const RUNTIME_COMMANDS: Command[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Command } from '../protocol.js';
|
|
2
|
+
/** 包内 skill 目录:lib/commands/ → <包根>/skills/maafw-live(本地 checkout 同构) */
|
|
3
|
+
export declare function skillPayloadDir(): string;
|
|
4
|
+
export interface SkillFileStatus {
|
|
5
|
+
path: string;
|
|
6
|
+
status: 'same' | 'different' | 'missing' | 'extra';
|
|
7
|
+
/** different 时的成因提示;行尾差异常来自跨平台工具改写,值得单独指出 */
|
|
8
|
+
note?: string;
|
|
9
|
+
bytes?: number;
|
|
10
|
+
sha256?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 逐文件比对(纯函数,单测直接喂两个目录)。只比字节:任何不同都是 different,
|
|
14
|
+
* 但在**仅行尾不同**(CRLF ↔ LF)时补一条 note——那不是内容分叉,是工具改写。
|
|
15
|
+
*/
|
|
16
|
+
export declare function compareSkillTrees(payload: string, target: string): SkillFileStatus[];
|
|
17
|
+
export declare const skillCommand: Command;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* timing:从帧流与节点事件反推 pipeline 的 delay / timeout 建议值。
|
|
3
|
+
*
|
|
4
|
+
* 做法:自动开流 → 跑任务(--runs n 次采样)→ 对齐两类时间线——
|
|
5
|
+
* - 节点时长(record.nodes)→ 节点级 timeout 建议(P95 × 1.5 余量)
|
|
6
|
+
* - 节点完成后的画面稳定时间(完成事件到下一个 stable 事件的时距)→ post-delay /
|
|
7
|
+
* wait_freezes 建议;下一节点先于 stable 开始则标"未稳定"(连续动画/识别窗口过紧)。
|
|
8
|
+
* 分布口径:建议值只取成功 run(失败 run 的时长是提前终止的,对 timeout 建议是误导);
|
|
9
|
+
* 单次采样退化为 P50=P95=该值,与历史单次行为逐字段一致。
|
|
10
|
+
*/
|
|
11
|
+
import { type Command } from '../protocol.js';
|
|
12
|
+
interface TimedNode {
|
|
13
|
+
name: string;
|
|
14
|
+
ms: number;
|
|
15
|
+
status: string;
|
|
16
|
+
settle: number | null;
|
|
17
|
+
nextBeforeStable: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** 单次采样的产物:一次 run 的任务结果 + 该 run 事件区间内的对齐分析 */
|
|
20
|
+
export interface RunSample {
|
|
21
|
+
index: number;
|
|
22
|
+
ok: boolean;
|
|
23
|
+
durationMs: number;
|
|
24
|
+
nodes: TimedNode[];
|
|
25
|
+
events: number;
|
|
26
|
+
}
|
|
27
|
+
export interface NodeStat {
|
|
28
|
+
name: string;
|
|
29
|
+
status: string;
|
|
30
|
+
/** 成功 run 中该节点出现的 run 数(少于成功总数 = 有分支/跳过) */
|
|
31
|
+
runs: number;
|
|
32
|
+
/** 总执行次数——同名节点在同一 run 内可能重复(重试/JumpBack/Next 环),
|
|
33
|
+
* 分布统计按全部出现算,丢掉重复会漏掉真正的慢样本 */
|
|
34
|
+
occurrences: number;
|
|
35
|
+
msP50: number;
|
|
36
|
+
msP95: number;
|
|
37
|
+
settleP50: number | null;
|
|
38
|
+
settleP95: number | null;
|
|
39
|
+
settleSamples: number;
|
|
40
|
+
nextBeforeStable: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface TimingAggregate {
|
|
43
|
+
successful: number;
|
|
44
|
+
failed: number;
|
|
45
|
+
durationP50: number;
|
|
46
|
+
durationP95: number;
|
|
47
|
+
/** 各 run 最长节点时长的 P95——建议值的基准(覆盖"最慢节点"这一任务级口径) */
|
|
48
|
+
maxNodeP95: number;
|
|
49
|
+
/** 各 run 最长稳定时间的 P95;全无 stable 样本时为 null */
|
|
50
|
+
maxSettleP95: number | null;
|
|
51
|
+
nodeStats: NodeStat[];
|
|
52
|
+
suggest: {
|
|
53
|
+
nodeTimeoutMs: number;
|
|
54
|
+
taskTimeoutMs: number;
|
|
55
|
+
postDelayMs: number | null;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** 最近邻秩百分位:sorted 升序;n=1 时任意 p 返回该值,n 小时偏保守端(P95 取最大) */
|
|
59
|
+
export declare function percentile(values: number[], p: number): number;
|
|
60
|
+
/** 跨 run 聚合(纯函数,单测直断言):节点统计与建议值都只算成功样本 */
|
|
61
|
+
export declare function aggregateTiming(samples: RunSample[]): TimingAggregate;
|
|
62
|
+
export declare const timingCommand: Command;
|
|
63
|
+
export declare const TIMING_COMMANDS: Command[];
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ExecResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
/** 进程退出码;被信号杀死或启动失败时为 null */
|
|
4
|
+
code: number | null;
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
/** 启动失败的原因(ENOENT 等) */
|
|
8
|
+
spawnError?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ExecOptions {
|
|
11
|
+
timeout?: number;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
/** 传入 stdin 的内容 */
|
|
14
|
+
input?: string;
|
|
15
|
+
/** 内部用:把参数按原样交给子进程(实现 cmd 的引号规则时需要,见 run()) */
|
|
16
|
+
verbatim?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 执行外部命令。
|
|
20
|
+
*
|
|
21
|
+
* Windows 上 `.cmd` / `.bat`(npm、npx、pnpm)不是可执行文件:execFile 直接跑会**同步抛 EINVAL**
|
|
22
|
+
* (Node 对 CVE-2024-27980 的修复,本模块曾因此让 `env` 在只缺 adb 的机器上整条失败),
|
|
23
|
+
* 所以先 `where` 解析出可执行路径,再经 `ComSpec` 执行。而 cmd 的引号规则有讲究:`/s` 会剥掉最外层
|
|
24
|
+
* 引号,所以命令串要**整体再包一层引号**并配 `windowsVerbatimArguments`——实测
|
|
25
|
+
* `cmd /d /s /c ""C:\Program Files\nodejs\npm.cmd" --version"` 是唯一能跑通的拼法。
|
|
26
|
+
* 不直接用 `shell: true`:给 shell 传参会触发 `DEP0190` 弃用警告,且"命令不存在"会退化成
|
|
27
|
+
* "cmd 跑起来了但退出 1"(本地化报错,判不准)。
|
|
28
|
+
*/
|
|
29
|
+
export declare function run(bin: string, args?: string[], opts?: ExecOptions): Promise<ExecResult>;
|
|
30
|
+
/** 取首行有效输出,供「版本号探测」这类场景用 */
|
|
31
|
+
export declare function firstLine(s: string): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export declare const GLOBAL_OPTIONS: {
|
|
2
|
+
json: {
|
|
3
|
+
type: "boolean";
|
|
4
|
+
};
|
|
5
|
+
'dry-run': {
|
|
6
|
+
type: "boolean";
|
|
7
|
+
};
|
|
8
|
+
yes: {
|
|
9
|
+
type: "boolean";
|
|
10
|
+
};
|
|
11
|
+
'no-interactive': {
|
|
12
|
+
type: "boolean";
|
|
13
|
+
};
|
|
14
|
+
'no-color': {
|
|
15
|
+
type: "boolean";
|
|
16
|
+
};
|
|
17
|
+
cwd: {
|
|
18
|
+
type: "string";
|
|
19
|
+
};
|
|
20
|
+
limit: {
|
|
21
|
+
type: "string";
|
|
22
|
+
};
|
|
23
|
+
verbose: {
|
|
24
|
+
type: "boolean";
|
|
25
|
+
};
|
|
26
|
+
help: {
|
|
27
|
+
type: "boolean";
|
|
28
|
+
short: string;
|
|
29
|
+
};
|
|
30
|
+
version: {
|
|
31
|
+
type: "boolean";
|
|
32
|
+
short: string;
|
|
33
|
+
};
|
|
34
|
+
/** 把命令转发到命名会话的常驻 daemon(`repl --session <name>` 起的那个) */
|
|
35
|
+
session: {
|
|
36
|
+
type: "string";
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export interface GlobalFlags {
|
|
40
|
+
json: boolean;
|
|
41
|
+
/** 预留位:当前没有"只计算不落盘"的实现,值不被消费 */
|
|
42
|
+
dryRun: boolean;
|
|
43
|
+
/** 预留授权位:当前版本没有确认步骤,值不被消费 */
|
|
44
|
+
yes: boolean;
|
|
45
|
+
/** 预留门控位:当前版本没有交互式提问,值不被消费 */
|
|
46
|
+
interactive: boolean;
|
|
47
|
+
color: boolean;
|
|
48
|
+
cwd: string;
|
|
49
|
+
/** 预留位:当前没有输出条数上限,值不被消费 */
|
|
50
|
+
limit: number;
|
|
51
|
+
/** 预留位:当前没有详细输出,值不被消费 */
|
|
52
|
+
verbose: boolean;
|
|
53
|
+
help: boolean;
|
|
54
|
+
version: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 从 parseArgs 的 values 推导全局标志。
|
|
58
|
+
*
|
|
59
|
+
* `--no-color` 只关闭颜色;未指定时按 TTY 自动判断(管道里自动无色)。
|
|
60
|
+
* 注意不能用 NO_COLOR 环境变量以外的方式覆盖显式传入的值。
|
|
61
|
+
*/
|
|
62
|
+
export declare function readGlobalFlags(values: Record<string, unknown>, cwd: string): GlobalFlags;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 纯 JS 图像工具:复用 daemon 里那套无依赖 PNG 编解码(不做第二份实现)。
|
|
3
|
+
*
|
|
4
|
+
* daemon(daemon/framed.mjs)本来就带 PNG 解码 / 缩放 / 编码 —— 它要在没有 native 依赖的
|
|
5
|
+
* 前提下处理帧 —— 但只在子进程里用。这里用非字面量说明符动态 import 取它的 __test 导出:
|
|
6
|
+
* 避免为一个 .mjs 引入声明文件、把构建链复杂化,同时用下面的接口把契约钉死。
|
|
7
|
+
*
|
|
8
|
+
* 与 daemon 帧流共用同一条降采样路径,因此"面板预览看到的缩放"和"识别用的缩放"不会分叉。
|
|
9
|
+
*/
|
|
10
|
+
/** PNG Buffer 的尺寸。 */
|
|
11
|
+
export declare function pngSize(buf: Buffer): Promise<{
|
|
12
|
+
w: number;
|
|
13
|
+
h: number;
|
|
14
|
+
}>;
|
|
15
|
+
/** 按"长边不超过 maxSide"缩放 PNG(只缩不放,原图更小时原样返回)。 */
|
|
16
|
+
export declare function scalePngLongSide(buf: Buffer, maxSide: number): Promise<Buffer>;
|
|
17
|
+
/**
|
|
18
|
+
* 按矩形裁一块出来(控制器分辨率坐标系,越界自动夹紧)。
|
|
19
|
+
*
|
|
20
|
+
* 面板的"模板匹配即时校验"用它:把人框的这块裁成模板图,再交给识别去比对 —— 因此这一步
|
|
21
|
+
* 必须与帧流/识别走同一条解码路径,不能各自实现(否则裁出来的像素与识别看到的不是同一份)。
|
|
22
|
+
*/
|
|
23
|
+
export declare function cropPng(buf: Buffer, rect: [number, number, number, number]): Promise<Buffer>;
|
|
24
|
+
/** data URL → PNG Buffer;非图片 data URL 返回 null。 */
|
|
25
|
+
export declare function dataUrlToPng(dataUrl: string): Buffer | null;
|
|
26
|
+
/** PNG Buffer → data URL(面板侧统一 data:image/png)。 */
|
|
27
|
+
export declare function pngToDataUrl(buf: Buffer): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(argv: string[]): Promise<number>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hotkey 占位符 → 当前控制器的虚拟按键码(PI v2.8.0+)。
|
|
3
|
+
*
|
|
4
|
+
* 协议只给规则、不给表:`{名称}` / `{名称}.primary` / `{名称}.modifier1` / `{名称}.modifier2`
|
|
5
|
+
* 要替换成"**当前控制器 type** 支持的虚拟按键码",且"映射规则应与 ClickKey、KeyDown 等动作所用
|
|
6
|
+
* 键码表一致"(MaaFW 5.14.2 `3.3-ProjectInterfaceV2协议`,pinned commit 8061d5bc)。
|
|
7
|
+
*
|
|
8
|
+
* 这里四张表的数值是各 OS **公开的键码常量**,不是谁发明的东西:
|
|
9
|
+
* - `Win32` → Windows Virtual-Key Codes(`VK_*`,见 winuser.h)
|
|
10
|
+
* - `Adb` → Android `KeyEvent`(`KEYCODE_*`)
|
|
11
|
+
* - `MacOS` → Carbon `Events.h`(`kVK_*`,ANSI 键盘物理位置)
|
|
12
|
+
* - `WlRoots`/`Linux` → Linux `input-event-codes.h`(`KEY_*`/evdev)
|
|
13
|
+
*
|
|
14
|
+
* 取值与 MXU 的实现交叉核对过(MXU 是 AGPL-3.0,本仓 MIT:**只核数值,不搬代码**)。
|
|
15
|
+
* 键名按 MXU 的持久化约定规范化(大写、`+` 连接、末段为主键),因为它就是协议里"人类可读
|
|
16
|
+
* 快捷键字符串"的实际来源之一。
|
|
17
|
+
*/
|
|
18
|
+
/** 一张表:规范化键名 → 虚拟按键码 */
|
|
19
|
+
export type HotkeyTable = Record<string, number>;
|
|
20
|
+
/** 按控制器 **type** 取表(不是 name)。没有表的类型返回 null——调用方要告警,不能退回 Win32 猜。 */
|
|
21
|
+
export declare function hotkeyTableFor(controllerType: string | null, useWin32VkCode?: boolean): HotkeyTable | null;
|
|
22
|
+
/** "Ctrl+Shift+A" → { primary: "A", modifiers: ["Ctrl","Shift"] };末段为主键。 */
|
|
23
|
+
export declare function splitHotkeyCombo(value: string): {
|
|
24
|
+
primary: string;
|
|
25
|
+
modifiers: string[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* 把一个 hotkey 字段解析成四种占位符的取值。
|
|
29
|
+
*
|
|
30
|
+
* 缺修饰键不是错(单键 "E" 本来就没有修饰键),补 0 = 无按键;**主键查不到是错**——
|
|
31
|
+
* 写个 0 进去等于"按了空键",任务会静默点不动。
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveHotkeyTokens(fieldName: string, raw: string, table: HotkeyTable): {
|
|
34
|
+
tokens: Record<string, number>;
|
|
35
|
+
error?: string;
|
|
36
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目声明(interface.json / ProjectInterface v2)的窄解析与连接规划。
|
|
3
|
+
*
|
|
4
|
+
* 这是"认识项目"的唯一一份实现:控制器声明 → daemon connect 参数、
|
|
5
|
+
* 资源声明 → resource 目录、task 声明 → run 入口解析、
|
|
6
|
+
* option/preset → pipeline_override 四级合并链。
|
|
7
|
+
*/
|
|
8
|
+
export { parseJsonc } from './jsonc.js';
|
|
9
|
+
export { loadInterface, findInterfaceFile, type DisplayDecl, type GamepadDecl, type InterfaceController, type InterfaceOption, type InterfacePreset, type InterfaceProblem, type InterfaceResource, type InterfaceTask, type LoadedInterface, type OptionCase, type Win32Decl, } from './load.js';
|
|
10
|
+
export { planController, resolveResourcePaths, type ControllerPlan, type DeviceLike, type PlanOverrides, type ResourcePlan, } from './plan.js';
|
|
11
|
+
export { computePipelineOverride, appendOverride, type OverrideInput, type OverrideResult } from './override.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 容错 JSON:真实项目的 interface.json 带 `//` 注释(官方解析器基于 meojson),
|
|
3
|
+
* strict JSON.parse 会直接拒绝,因此先做最小脱敏——字符串外的注释与尾随逗号去掉。
|
|
4
|
+
*
|
|
5
|
+
* 取舍:只做这两件**最小**的事,不做单引号 / 无引号键 / 多行字符串那类扩展——
|
|
6
|
+
* 越是"看起来像 JSON"的输入,越容易被静默改写成作者没写的意思。
|
|
7
|
+
* 另:开头的 BOM(Windows 记事本等会写)先剥掉,它会让 JSON.parse 报 "Unexpected token"。
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseJsonc(text: string): unknown;
|