@windsland52/maafw-live 0.0.0-stage → 0.3.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 +278 -2
- package/bin/maafw-live.mjs +25 -0
- package/docs/daemon-protocol.md +116 -0
- package/docs/keyframe-evidence-contract-v0.md +61 -0
- package/docs/keyframe-retention-contract-v0.md +236 -0
- package/lib/client/daemon.js +234 -0
- package/lib/client/daemon.js.map +1 -0
- package/lib/commands/annotate.js +172 -0
- package/lib/commands/annotate.js.map +1 -0
- package/lib/commands/calibrate.js +61 -0
- package/lib/commands/calibrate.js.map +1 -0
- package/lib/commands/color.js +73 -0
- package/lib/commands/color.js.map +1 -0
- package/lib/commands/crop.js +228 -0
- package/lib/commands/crop.js.map +1 -0
- package/lib/commands/env.js +215 -0
- package/lib/commands/env.js.map +1 -0
- package/lib/commands/index.js +64 -0
- package/lib/commands/index.js.map +1 -0
- package/lib/commands/input.js +219 -0
- package/lib/commands/input.js.map +1 -0
- package/lib/commands/kf.js +131 -0
- package/lib/commands/kf.js.map +1 -0
- package/lib/commands/reco.js +211 -0
- package/lib/commands/reco.js.map +1 -0
- package/lib/commands/repl.js +698 -0
- package/lib/commands/repl.js.map +1 -0
- package/lib/commands/runtime.js +514 -0
- package/lib/commands/runtime.js.map +1 -0
- package/lib/commands/skill.js +169 -0
- package/lib/commands/skill.js.map +1 -0
- package/lib/commands/timing.js +229 -0
- package/lib/commands/timing.js.map +1 -0
- package/lib/commands/version.js +66 -0
- package/lib/commands/version.js.map +1 -0
- package/lib/daemon/framed.mjs +2850 -0
- package/lib/daemon/reco_child.mjs +146 -0
- package/lib/exec.js +96 -0
- package/lib/exec.js.map +1 -0
- package/lib/flags.js +42 -0
- package/lib/flags.js.map +1 -0
- package/lib/image.js +90 -0
- package/lib/image.js.map +1 -0
- package/lib/index.js +139 -0
- package/lib/index.js.map +1 -0
- package/lib/interface/index.js +12 -0
- package/lib/interface/index.js.map +1 -0
- package/lib/interface/jsonc.js +95 -0
- package/lib/interface/jsonc.js.map +1 -0
- package/lib/interface/load.js +307 -0
- package/lib/interface/load.js.map +1 -0
- package/lib/interface/override.js +103 -0
- package/lib/interface/override.js.map +1 -0
- package/lib/interface/plan.js +188 -0
- package/lib/interface/plan.js.map +1 -0
- package/lib/pkg.js +18 -0
- package/lib/pkg.js.map +1 -0
- package/lib/protocol.js +90 -0
- package/lib/protocol.js.map +1 -0
- package/lib/runtime/actions.js +110 -0
- package/lib/runtime/actions.js.map +1 -0
- package/lib/runtime/keyframes.js +73 -0
- package/lib/runtime/keyframes.js.map +1 -0
- package/lib/runtime/session.js +86 -0
- package/lib/runtime/session.js.map +1 -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/env.d.ts +2 -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/reco.d.ts +23 -0
- package/lib/types/commands/repl.d.ts +2 -0
- package/lib/types/commands/runtime.d.ts +48 -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 +58 -0
- package/lib/types/image.d.ts +27 -0
- package/lib/types/index.d.ts +1 -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 +113 -0
- package/lib/types/interface/override.d.ts +33 -0
- package/lib/types/interface/plan.d.ts +47 -0
- package/lib/types/pkg.d.ts +6 -0
- package/lib/types/protocol.d.ts +108 -0
- package/lib/types/runtime/actions.d.ts +166 -0
- package/lib/types/runtime/keyframes.d.ts +43 -0
- package/lib/types/runtime/session.d.ts +53 -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/update-check.js.map +1 -0
- package/lib/usage.js +50 -0
- package/lib/usage.js.map +1 -0
- package/package.json +81 -4
- package/skills/README.md +51 -0
- package/skills/maafw-live/SKILL.md +263 -0
- package/skills/maafw-live/references/examples.md +238 -0
- package/skills/maafw-live/references/pitfalls.md +118 -0
- package/skills/maafw-live/references/workflows.md +159 -0
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
};
|
|
36
|
+
export declare function sessionOptions(values: Record<string, unknown>): SessionOptions;
|
|
37
|
+
/** daemon 抛出的错误一律翻译成结构化失败,不让堆栈进模型上下文。 */
|
|
38
|
+
export declare function daemonFail(e: unknown, hint?: string): CommandResult;
|
|
39
|
+
export declare const probeCommand: Command;
|
|
40
|
+
export declare const deviceCommand: Command;
|
|
41
|
+
export declare const connectCommand: Command;
|
|
42
|
+
export declare const disconnectCommand: Command;
|
|
43
|
+
export declare const screencapCommand: Command;
|
|
44
|
+
export declare const frameCommand: Command;
|
|
45
|
+
export declare const waitCommand: Command;
|
|
46
|
+
export declare const runCommand: Command;
|
|
47
|
+
export declare const stopCommand: Command;
|
|
48
|
+
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,58 @@
|
|
|
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
|
+
};
|
|
35
|
+
export interface GlobalFlags {
|
|
36
|
+
json: boolean;
|
|
37
|
+
/** 预留位:当前没有"只计算不落盘"的实现,值不被消费 */
|
|
38
|
+
dryRun: boolean;
|
|
39
|
+
/** 预留授权位:当前版本没有确认步骤,值不被消费 */
|
|
40
|
+
yes: boolean;
|
|
41
|
+
/** 预留门控位:当前版本没有交互式提问,值不被消费 */
|
|
42
|
+
interactive: boolean;
|
|
43
|
+
color: boolean;
|
|
44
|
+
cwd: string;
|
|
45
|
+
/** 预留位:当前没有输出条数上限,值不被消费 */
|
|
46
|
+
limit: number;
|
|
47
|
+
/** 预留位:当前没有详细输出,值不被消费 */
|
|
48
|
+
verbose: boolean;
|
|
49
|
+
help: boolean;
|
|
50
|
+
version: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 从 parseArgs 的 values 推导全局标志。
|
|
54
|
+
*
|
|
55
|
+
* `--no-color` 只关闭颜色;未指定时按 TTY 自动判断(管道里自动无色)。
|
|
56
|
+
* 注意不能用 NO_COLOR 环境变量以外的方式覆盖显式传入的值。
|
|
57
|
+
*/
|
|
58
|
+
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,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, mergeOverride, 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;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export interface InterfaceProblem {
|
|
2
|
+
message: string;
|
|
3
|
+
}
|
|
4
|
+
/** 控制器的显示声明;映射为 daemon connect 的 shortSide / longSide / rawSize。 */
|
|
5
|
+
export interface DisplayDecl {
|
|
6
|
+
shortSide?: number;
|
|
7
|
+
longSide?: number;
|
|
8
|
+
raw?: boolean;
|
|
9
|
+
expand?: [number, number];
|
|
10
|
+
}
|
|
11
|
+
export interface Win32Decl {
|
|
12
|
+
classRegex?: string;
|
|
13
|
+
windowRegex?: string;
|
|
14
|
+
screencap?: string;
|
|
15
|
+
mouse?: string;
|
|
16
|
+
keyboard?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface GamepadDecl {
|
|
19
|
+
classRegex?: string;
|
|
20
|
+
windowRegex?: string;
|
|
21
|
+
gamepadType?: string;
|
|
22
|
+
screencap?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface InterfaceController {
|
|
25
|
+
name: string;
|
|
26
|
+
/** Adb / Win32 / Gamepad / MacOS / PlayCover / Linux */
|
|
27
|
+
type: string;
|
|
28
|
+
display?: DisplayDecl;
|
|
29
|
+
win32?: Win32Decl;
|
|
30
|
+
gamepad?: GamepadDecl;
|
|
31
|
+
/** v2.2.0:在 resource.path 之后追加加载的资源目录(相对 interface.json 所在目录) */
|
|
32
|
+
attachResourcePath: string[];
|
|
33
|
+
/** v2.3.0:控制器级配置项名单(override 链第三级) */
|
|
34
|
+
option?: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface InterfaceResource {
|
|
37
|
+
name: string;
|
|
38
|
+
/** 资源根目录(含 pipeline / image / model),相对 interface.json 所在目录,声明顺序即加载顺序 */
|
|
39
|
+
paths: string[];
|
|
40
|
+
/** 只对这些控制器生效;空数组 = 全部 */
|
|
41
|
+
controllers: string[];
|
|
42
|
+
/** v2.3.0:资源级配置项名单(override 链第二级) */
|
|
43
|
+
option?: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface InterfaceTask {
|
|
46
|
+
name: string;
|
|
47
|
+
/** pipeline 入口节点名;缺省时入口即任务名 */
|
|
48
|
+
entry?: string;
|
|
49
|
+
/** 只在这些控制器下可用(隐藏/禁用语义);空 = 全部 */
|
|
50
|
+
controller?: string[];
|
|
51
|
+
/** 只在这些资源下可用;空 = 全部 */
|
|
52
|
+
resource?: string[];
|
|
53
|
+
/** 配置项键名(按展示顺序);对应 InterfaceOption 字典的键 */
|
|
54
|
+
option?: string[];
|
|
55
|
+
}
|
|
56
|
+
/** option 字典条目:switch/select/checkbox 的 case 携带 pipeline_override。 */
|
|
57
|
+
export interface OptionCase {
|
|
58
|
+
name: string;
|
|
59
|
+
pipelineOverride?: Record<string, unknown>;
|
|
60
|
+
/** 选中该 case 后生效的子配置项 */
|
|
61
|
+
option?: string[];
|
|
62
|
+
}
|
|
63
|
+
export interface InterfaceOption {
|
|
64
|
+
name: string;
|
|
65
|
+
type: string;
|
|
66
|
+
cases: OptionCase[];
|
|
67
|
+
/** 初始选中:switch/select 单 case 名;checkbox 为 case 名数组 */
|
|
68
|
+
defaultCase?: string | string[];
|
|
69
|
+
/** 适用性过滤(v2.3.1:不满足的 option 不得产生 pipeline_override) */
|
|
70
|
+
controller?: string[];
|
|
71
|
+
resource?: string[];
|
|
72
|
+
}
|
|
73
|
+
/** preset:任务与 option 取值的快照(v2.3.0),应用时覆盖 default_case。 */
|
|
74
|
+
export interface InterfacePreset {
|
|
75
|
+
name: string;
|
|
76
|
+
task: Array<{
|
|
77
|
+
name: string;
|
|
78
|
+
enabled?: boolean;
|
|
79
|
+
option?: Record<string, unknown>;
|
|
80
|
+
}>;
|
|
81
|
+
}
|
|
82
|
+
/** PI `agent` 声明:宿主侧子进程(如 uv run python agent/main.py),经 agent 协议注册 custom
|
|
83
|
+
* action / recognition。maa-node 绑定未暴露 AgentClient 桥接——本工具只能诊断,不能 spawn。 */
|
|
84
|
+
export interface InterfaceAgent {
|
|
85
|
+
exec: string;
|
|
86
|
+
args: string[];
|
|
87
|
+
}
|
|
88
|
+
export interface LoadedInterface {
|
|
89
|
+
/** interface.json 绝对路径;未找到为 null */
|
|
90
|
+
file: string | null;
|
|
91
|
+
/** 所在目录——resource.path 与 attach_resource_path 的相对基准 */
|
|
92
|
+
dir: string | null;
|
|
93
|
+
version: number | null;
|
|
94
|
+
name: string | null;
|
|
95
|
+
controllers: InterfaceController[];
|
|
96
|
+
resources: InterfaceResource[];
|
|
97
|
+
tasks: InterfaceTask[];
|
|
98
|
+
/** option 字典(主文件 + import 合并,后导入覆盖同名) */
|
|
99
|
+
options: Record<string, InterfaceOption>;
|
|
100
|
+
presets: InterfacePreset[];
|
|
101
|
+
/** 全局配置项键名(override 链最低级) */
|
|
102
|
+
globalOption: string[];
|
|
103
|
+
/** controller 启动前任务;CLI 不执行,仅用于警告 */
|
|
104
|
+
pretask: Array<{
|
|
105
|
+
name?: string;
|
|
106
|
+
exec?: string;
|
|
107
|
+
}>;
|
|
108
|
+
/** agent 子进程声明;CLI 未桥接(绑定无 AgentClient),仅用于警告与失败归因 */
|
|
109
|
+
agents: InterfaceAgent[];
|
|
110
|
+
problems: InterfaceProblem[];
|
|
111
|
+
}
|
|
112
|
+
export declare function findInterfaceFile(dir: string): string | null;
|
|
113
|
+
export declare function loadInterface(dir: string): LoadedInterface;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pipeline_override 四级合并链(PI v2 v2.3.x):global_option → resource.option →
|
|
3
|
+
* controller.option → task.option,后合并覆盖先合并;适用性过滤(option 自带的
|
|
4
|
+
* controller/resource 条件不满足时不产生 override);checkbox 多选按 cases 声明序合并;
|
|
5
|
+
* 嵌套 option 在其父 case 之后合并。
|
|
6
|
+
*
|
|
7
|
+
* 取值解析顺序:preset 显式值 > default_case。两级都没有 → 警告并跳过(不猜)。
|
|
8
|
+
* 本 CLI 是无人值守消费面:不做交互选择,preset 是把 MaaPiCli 用户选择带进来的唯一通道。
|
|
9
|
+
*/
|
|
10
|
+
import type { LoadedInterface } from './load.js';
|
|
11
|
+
export interface OverrideInput {
|
|
12
|
+
loaded: LoadedInterface;
|
|
13
|
+
controllerName: string | null;
|
|
14
|
+
resourceName: string | null;
|
|
15
|
+
taskName: string | null;
|
|
16
|
+
presetName?: string | null;
|
|
17
|
+
}
|
|
18
|
+
export interface OverrideResult {
|
|
19
|
+
override: Record<string, unknown>;
|
|
20
|
+
/** 需要人工注意的事项(选项无取值、preset 未找到等) */
|
|
21
|
+
warns: string[];
|
|
22
|
+
/** 人类可读的生效记录:option=值(级别) */
|
|
23
|
+
applied: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 把一份 pipeline_override 并入累计结果:同节点字段替换(与协议"不深度合并"一致)。
|
|
27
|
+
*
|
|
28
|
+
* **唯一一份实现**:四级链、`run --override`、`timing --override` 都走这里。这三处曾经各写一份,
|
|
29
|
+
* 代价是同一个参数在不同命令里表现不同。非对象值必须**原样替换、不能展开**:字符串会被摊成
|
|
30
|
+
* `{0:'a',1:'b'}`,`null` / 数字会静默变成空对象——等于把用户写的节点悄悄丢掉。
|
|
31
|
+
*/
|
|
32
|
+
export declare function mergeOverride(acc: Record<string, unknown>, po: Record<string, unknown>): void;
|
|
33
|
+
export declare function computePipelineOverride(input: OverrideInput): OverrideResult;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { LoadedInterface } from './load.js';
|
|
2
|
+
/** daemon device_list 的条目:adb 的 id 是 address,win32 的 id 是 hwnd。 */
|
|
3
|
+
export interface DeviceLike {
|
|
4
|
+
kind?: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
cls?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface PlanOverrides {
|
|
10
|
+
controller?: string;
|
|
11
|
+
win32?: {
|
|
12
|
+
hwnd?: string | null;
|
|
13
|
+
};
|
|
14
|
+
gamepad?: {
|
|
15
|
+
hwnd?: string | null;
|
|
16
|
+
};
|
|
17
|
+
adb?: {
|
|
18
|
+
address?: string | null;
|
|
19
|
+
};
|
|
20
|
+
/** 手动 target(--target):playcover=<address>/<uuid>;linux=<config JSON> */
|
|
21
|
+
manualTarget?: string | null;
|
|
22
|
+
}
|
|
23
|
+
export interface ControllerPlan {
|
|
24
|
+
ok: boolean;
|
|
25
|
+
code?: string;
|
|
26
|
+
error?: string;
|
|
27
|
+
controllerName: string | null;
|
|
28
|
+
/** 直接展开给 daemon 的 connect 参数 */
|
|
29
|
+
connect: Record<string, unknown>;
|
|
30
|
+
/** 失败时的候选设备,供调用方提示用户显式指定 */
|
|
31
|
+
candidates?: DeviceLike[];
|
|
32
|
+
notes?: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface ResourcePlan {
|
|
35
|
+
paths: string[];
|
|
36
|
+
names: string[];
|
|
37
|
+
/** 本次实际选中的 resource 名(attach_resource_path 之外的来源条目) */
|
|
38
|
+
selected: string | null;
|
|
39
|
+
}
|
|
40
|
+
export declare function planController(loaded: LoadedInterface, overrides: PlanOverrides, devices: DeviceLike[]): ControllerPlan;
|
|
41
|
+
/**
|
|
42
|
+
* 解析资源路径:resource[] 是互斥单选(Client 语义)——不传 override 时取第一个适用于
|
|
43
|
+
* 所选控制器的条目,条目自身多路径按声明顺序叠加(如"B 服"= base + bilibili);
|
|
44
|
+
* attach_resource_path 在选中控制器后追加。override(--resource)先按资源名匹配,
|
|
45
|
+
* 匹配不上再按文件系统路径解释(原有行为)。
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveResourcePaths(loaded: LoadedInterface, controllerName?: string, override?: string): ResourcePlan;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI 协议层:统一 JSON 信封 + 命令契约 + 退出码语义。
|
|
3
|
+
*
|
|
4
|
+
* 信封结构抄 create-maa-project 的 `--report`——它已被真实消费方验证过,
|
|
5
|
+
* 属于本生态的既有事实标准。目的:让「技能 / 脚本 / CI / 人」消费同一份稳定结构,
|
|
6
|
+
* 不必各自解析文本输出,也不必各自发明字段名。
|
|
7
|
+
*
|
|
8
|
+
* 注意(这是本文件的唯一不变量):信封字段只增不改。技能会按字段名读取,
|
|
9
|
+
* 改名等于静默破坏所有消费方。
|
|
10
|
+
*/
|
|
11
|
+
import type { ParseArgsOptionsConfig } from 'node:util';
|
|
12
|
+
import type { GlobalFlags } from './flags.js';
|
|
13
|
+
/** 信封结构版本。字段增删时递增,消费方可据此拒绝不认识的形状。 */
|
|
14
|
+
export declare const SCHEMA_VERSION = 1;
|
|
15
|
+
/**
|
|
16
|
+
* 退出码语义。
|
|
17
|
+
*
|
|
18
|
+
* 关键区分:`FAIL` 是「命令没跑成」,`FINDINGS` 是「跑成了,但发现了问题」。
|
|
19
|
+
* 技能与 CI 必须能分开这两种情况——reco 识别未命中不是执行失败,
|
|
20
|
+
* 但也不该返回 0 让调用方以为一切正常。
|
|
21
|
+
*/
|
|
22
|
+
export declare const EXIT: {
|
|
23
|
+
/** 命令正常完成,未发现问题 */
|
|
24
|
+
readonly OK: 0;
|
|
25
|
+
/** 命令自身失败(未预期异常、IO 错误) */
|
|
26
|
+
readonly FAIL: 1;
|
|
27
|
+
/** 参数 / 用法错误 */
|
|
28
|
+
readonly USAGE: 2;
|
|
29
|
+
/** 命令正常跑完,但发现了问题(reco 未命中、run 调用级失败、观测类命令的警告等) */
|
|
30
|
+
readonly FINDINGS: 3;
|
|
31
|
+
/** 前置环境缺失(缺 maa-node / 缺 checkout / 缺设备) */
|
|
32
|
+
readonly ENV: 4;
|
|
33
|
+
};
|
|
34
|
+
export type ExitCode = (typeof EXIT)[keyof typeof EXIT];
|
|
35
|
+
export interface CliError {
|
|
36
|
+
message: string;
|
|
37
|
+
/** 稳定的机器可读标识,供技能分支判断;不要用 message 做判断 */
|
|
38
|
+
code: string;
|
|
39
|
+
hint?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface Envelope {
|
|
42
|
+
schemaVersion: number;
|
|
43
|
+
command: string;
|
|
44
|
+
/** 命令本身是否执行成功。FINDINGS 仍算 ok=true——它跑成了,只是有发现 */
|
|
45
|
+
ok: boolean;
|
|
46
|
+
exitCode: number;
|
|
47
|
+
/** 本次操作的项目根,无法确定时为 null */
|
|
48
|
+
root: string | null;
|
|
49
|
+
written: string[];
|
|
50
|
+
removed: string[];
|
|
51
|
+
skipped: string[];
|
|
52
|
+
/** 需要人工跟进的事项(如「先跑 maa project sync」) */
|
|
53
|
+
pending: string[];
|
|
54
|
+
suggestedCommands: string[];
|
|
55
|
+
warnings: string[];
|
|
56
|
+
/** 命令特定载荷 */
|
|
57
|
+
data: unknown;
|
|
58
|
+
error: CliError | null;
|
|
59
|
+
}
|
|
60
|
+
/** 命令返回的结果。信封字段在此给默认值,命令只填关心的部分。 */
|
|
61
|
+
export interface CommandResult {
|
|
62
|
+
exitCode: ExitCode;
|
|
63
|
+
data?: unknown;
|
|
64
|
+
/** 非 --json 时逐行打印的内容。命令自己决定怎么排版 */
|
|
65
|
+
human?: string[];
|
|
66
|
+
warnings?: string[];
|
|
67
|
+
written?: string[];
|
|
68
|
+
removed?: string[];
|
|
69
|
+
skipped?: string[];
|
|
70
|
+
pending?: string[];
|
|
71
|
+
suggestedCommands?: string[];
|
|
72
|
+
error?: CliError;
|
|
73
|
+
root?: string | null;
|
|
74
|
+
}
|
|
75
|
+
export interface CommandContext {
|
|
76
|
+
/** 命令名之后的位置参数 */
|
|
77
|
+
positionals: string[];
|
|
78
|
+
/** 已解析的全部选项(含全局选项) */
|
|
79
|
+
values: Record<string, unknown>;
|
|
80
|
+
flags: GlobalFlags;
|
|
81
|
+
/** 已解析并校验过存在性的工作目录(绝对路径) */
|
|
82
|
+
cwd: string;
|
|
83
|
+
}
|
|
84
|
+
export interface Command {
|
|
85
|
+
name: string;
|
|
86
|
+
/** 一行说明,用于顶层 help 列表 */
|
|
87
|
+
summary: string;
|
|
88
|
+
/** 完整用法行,如 `maafw-live env [--deep] [--maafw <dir>]` */
|
|
89
|
+
usage: string;
|
|
90
|
+
/** 命令私有选项;全局选项由入口自动合并 */
|
|
91
|
+
options?: ParseArgsOptionsConfig;
|
|
92
|
+
run(ctx: CommandContext): Promise<CommandResult>;
|
|
93
|
+
}
|
|
94
|
+
export declare function toEnvelope(command: string, r: CommandResult): Envelope;
|
|
95
|
+
export interface EmitOptions {
|
|
96
|
+
json: boolean;
|
|
97
|
+
color: boolean;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 输出命令结果。
|
|
101
|
+
*
|
|
102
|
+
* --json 时只输出信封(stdout 保持纯 JSON,可被管道解析);
|
|
103
|
+
* 否则输出命令自己的 human 渲染 + 警告 + 建议命令。
|
|
104
|
+
* 错误与警告一律走 stderr,避免污染 stdout 的 JSON。
|
|
105
|
+
*/
|
|
106
|
+
export declare function emit(command: string, r: CommandResult, o: EmitOptions): void;
|
|
107
|
+
/** 失败结果的快捷构造 */
|
|
108
|
+
export declare function fail(code: string, message: string, hint?: string, exitCode?: ExitCode): CommandResult;
|