@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,248 @@
|
|
|
1
|
+
import { resolveResourcePaths, type ControllerPlan, type DeviceLike, type LoadedInterface } from '../interface/index.js';
|
|
2
|
+
import { type DaemonClient, type SpawnOptions } from '../client/daemon.js';
|
|
3
|
+
/** 设备会话的连接参数(手动路径)。kind/target 之外全部来自 maafw 的控制器能力。
|
|
4
|
+
* playcover/macos 仅 macOS、linux 仅 Linux;device_list 只枚举 adb/win32,
|
|
5
|
+
* 其余三种没有自动发现,靠 connect 的 target/config 显式指定(doc: daemon-protocol.md:49)。 */
|
|
6
|
+
export interface ManualConnect {
|
|
7
|
+
kind: 'adb' | 'win32' | 'gamepad' | 'playcover' | 'macos' | 'linux';
|
|
8
|
+
target?: string;
|
|
9
|
+
/** playcover:uuid(也可写在 target 里) */
|
|
10
|
+
uuid?: string;
|
|
11
|
+
/** linux:等价于 target 的 JSON */
|
|
12
|
+
config?: string;
|
|
13
|
+
/** 截图缩放覆盖(会改变 Tasker 识别图像的坐标系,模板/roi 随之变化) */
|
|
14
|
+
shortSide?: number;
|
|
15
|
+
longSide?: number;
|
|
16
|
+
rawSize?: boolean;
|
|
17
|
+
screencap?: string;
|
|
18
|
+
mouse?: string;
|
|
19
|
+
keyboard?: string;
|
|
20
|
+
gamepadType?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ConnectSession {
|
|
23
|
+
ok: boolean;
|
|
24
|
+
error?: string;
|
|
25
|
+
session?: Record<string, unknown> | null;
|
|
26
|
+
/** 本次连接重建了控制器、因而停掉了上一轮的帧流(需要看帧就重新 stream_start) */
|
|
27
|
+
streamStopped?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 给命令一个 daemon 客户端:ctx.client 有就借用(REPL / 命名会话,**不关**——
|
|
31
|
+
* 会话的生命周期不归命令管);没有才 spawn 一次性的,跑完即关。
|
|
32
|
+
* 统一入口的意义:命令只需写一遍,`--session` 转发与 REPL 复用走的是同一份实现。
|
|
33
|
+
*/
|
|
34
|
+
export declare function withDaemon<T>(ctx: {
|
|
35
|
+
client?: DaemonClient;
|
|
36
|
+
}, fn: (client: DaemonClient) => Promise<T>, options?: SpawnOptions): Promise<T>;
|
|
37
|
+
export declare const probe: (c: DaemonClient) => Promise<Record<string, unknown>>;
|
|
38
|
+
export declare const deviceList: (c: DaemonClient, kind?: "all" | "adb" | "win32") => Promise<DeviceLike[]>;
|
|
39
|
+
export declare const connect: (c: DaemonClient, args: Record<string, unknown>) => Promise<ConnectSession>;
|
|
40
|
+
export declare const disconnect: (c: DaemonClient) => Promise<{
|
|
41
|
+
ok: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
export declare const screencap: (c: DaemonClient, out?: string) => Promise<Record<string, unknown>>;
|
|
44
|
+
/**
|
|
45
|
+
* 一次性命令的"先产生一次观测":截一帧进 daemon 的 L0,然后**把临时文件删掉**。
|
|
46
|
+
*
|
|
47
|
+
* 为什么需要这一帧:L0 是进程态,一次性命令(`crop` / `annotate` / `color`)每次 spawn 自己的
|
|
48
|
+
* daemon,不先截一帧就没有原图可用。为什么必须删:daemon 收帧时就把像素读进缓冲了,
|
|
49
|
+
* 落盘那份只为喂它一次——不删就是每跑一次在系统临时目录留一张 720p 截图(实测攒到 42 张 / 54MB)。
|
|
50
|
+
* 失败不抛:没有观测时命令自己会报"先 screencap / stream"这类可行动的错。
|
|
51
|
+
*/
|
|
52
|
+
export declare function seedObservation(c: DaemonClient, prefix: string): Promise<void>;
|
|
53
|
+
export declare const streamStart: (c: DaemonClient, args?: {
|
|
54
|
+
fps?: number;
|
|
55
|
+
scale?: number;
|
|
56
|
+
maxFrames?: number;
|
|
57
|
+
l0Roll?: number;
|
|
58
|
+
l0Anchor?: number;
|
|
59
|
+
l0Bytes?: number;
|
|
60
|
+
blockThresh?: number;
|
|
61
|
+
changeGlobal?: number;
|
|
62
|
+
}) => Promise<Record<string, unknown>>;
|
|
63
|
+
export declare const streamStop: (c: DaemonClient) => Promise<{
|
|
64
|
+
ok: boolean;
|
|
65
|
+
}>;
|
|
66
|
+
export declare const streamStatus: (c: DaemonClient) => Promise<Record<string, unknown>>;
|
|
67
|
+
/** 事件环查询:一次性 CLI 用。事件环活在 daemon 里,跨进程只能现查(REPL 另有本地副本)。 */
|
|
68
|
+
export declare const eventsList: (c: DaemonClient, args?: {
|
|
69
|
+
since?: number;
|
|
70
|
+
limit?: number;
|
|
71
|
+
}) => Promise<{
|
|
72
|
+
ok: boolean;
|
|
73
|
+
total: number;
|
|
74
|
+
matched: number;
|
|
75
|
+
cap: number;
|
|
76
|
+
truncated: boolean;
|
|
77
|
+
events: Array<Record<string, unknown>>;
|
|
78
|
+
}>;
|
|
79
|
+
export declare const frameGet: (c: DaemonClient, args: {
|
|
80
|
+
seq?: number;
|
|
81
|
+
roi?: number[];
|
|
82
|
+
out?: string;
|
|
83
|
+
src?: "auto" | "full" | "ring";
|
|
84
|
+
}) => Promise<Record<string, unknown>>;
|
|
85
|
+
/** 等状态谓词成立:stable=画面静下来 / change=画面动了。取代调用方硬睡时钟。 */
|
|
86
|
+
export declare const waitState: (c: DaemonClient, args?: {
|
|
87
|
+
mode?: "stable" | "change";
|
|
88
|
+
timeout?: number;
|
|
89
|
+
quiet?: number;
|
|
90
|
+
roi?: number[];
|
|
91
|
+
threshold?: number;
|
|
92
|
+
}) => Promise<Record<string, unknown>>;
|
|
93
|
+
/** 两帧在若干 ROI 上的差分:回答"这一步改了哪几格"。 */
|
|
94
|
+
export declare const frameDiff: (c: DaemonClient, args: {
|
|
95
|
+
a: number;
|
|
96
|
+
b: number;
|
|
97
|
+
rois: number[][];
|
|
98
|
+
}) => Promise<Record<string, unknown>>;
|
|
99
|
+
export declare const colorProbe: (c: DaemonClient, args: {
|
|
100
|
+
seq?: number;
|
|
101
|
+
roi?: number[];
|
|
102
|
+
}) => Promise<Record<string, unknown>>;
|
|
103
|
+
/** 裁剪源 = 关键帧库留存帧(离线解析出来的身份 + 路径;daemon 会复核 sha256 与像素尺寸)。 */
|
|
104
|
+
export interface CropKfSource {
|
|
105
|
+
id: string;
|
|
106
|
+
path: string;
|
|
107
|
+
sha256: string;
|
|
108
|
+
ctrlW: number;
|
|
109
|
+
ctrlH: number;
|
|
110
|
+
captureSeq: number | null;
|
|
111
|
+
capturedAt: string | null;
|
|
112
|
+
}
|
|
113
|
+
export declare const tplCrop: (c: DaemonClient, args: {
|
|
114
|
+
seq?: number;
|
|
115
|
+
roi?: number[];
|
|
116
|
+
point?: number[];
|
|
117
|
+
pad?: number;
|
|
118
|
+
out?: string;
|
|
119
|
+
resourceDir?: string;
|
|
120
|
+
cross?: boolean;
|
|
121
|
+
kfSource?: CropKfSource;
|
|
122
|
+
prov?: boolean;
|
|
123
|
+
/** 出处侧车改写到该目录下(保持同名);缺省写在模板旁 */
|
|
124
|
+
provOut?: string;
|
|
125
|
+
/** 热缓存路径下把本次实际用的那一帧升格进库,出处随即带上可复核的 `kf:` 身份 */
|
|
126
|
+
keepSource?: boolean;
|
|
127
|
+
/** snap 收紧阈值的**测量用覆盖**(定标 A/B);缺省即生产常数 */
|
|
128
|
+
snapTol?: number;
|
|
129
|
+
snapFrac?: number;
|
|
130
|
+
/** 边缘收紧那一路(默认 false):true 时把"局部对比度"判据也放进候选池。
|
|
131
|
+
* 常数可再覆盖(定标用):edgeZ 环上对比度 p90 倍数(默认 2)、edgeMin 绝对地板(默认 24)、
|
|
132
|
+
* edgeFrac 行/列命中比例门槛(默认 0.02)。 */
|
|
133
|
+
edge?: boolean;
|
|
134
|
+
edgeZ?: number;
|
|
135
|
+
edgeMin?: number;
|
|
136
|
+
edgeFrac?: number;
|
|
137
|
+
}) => Promise<Record<string, unknown>>;
|
|
138
|
+
export declare const annotate: (c: DaemonClient, args: {
|
|
139
|
+
seq?: number;
|
|
140
|
+
out?: string;
|
|
141
|
+
resourceDir?: string;
|
|
142
|
+
kfSource?: CropKfSource;
|
|
143
|
+
/** 候选上限(缺省 30;截断按横向分带轮转,`mergedTotal` 才是去重后的真实规模) */
|
|
144
|
+
somLimit?: number;
|
|
145
|
+
/** 边缘源门槛的**测量用覆盖**(定标 A/B);缺省即生产常数 */
|
|
146
|
+
somEdgeZ?: number;
|
|
147
|
+
somEdgeMin?: number;
|
|
148
|
+
/** 连通域合并 IoU 的测量用覆盖 */
|
|
149
|
+
somIoU?: number;
|
|
150
|
+
/** 巨框剔除阈值(画面面积比,缺省 0.12;OCR 框不参与)——背景/立绘/整屏变化区不该占表 */
|
|
151
|
+
somMaxAreaRatio?: number;
|
|
152
|
+
/** 只保留落在该区域(控制器空间)内的候选,且在**取上限之前**过滤:
|
|
153
|
+
* 区域内的候选只跟自己竞争。上限截断的正解是收小搜索面,不是把上限调大。 */
|
|
154
|
+
roi?: number[];
|
|
155
|
+
/** 检测面:full(缺省,有 L0 时用控制器分辨率原图) | small(强制降采样小图,快但小目标会漏) */
|
|
156
|
+
somScale?: "full" | "small";
|
|
157
|
+
}) => Promise<Record<string, unknown>>;
|
|
158
|
+
export declare const calibrate: (c: DaemonClient, args?: {
|
|
159
|
+
frames?: number;
|
|
160
|
+
interval?: number;
|
|
161
|
+
}) => Promise<Record<string, unknown>>;
|
|
162
|
+
export declare const runStop: (c: DaemonClient) => Promise<{
|
|
163
|
+
ok: boolean;
|
|
164
|
+
}>;
|
|
165
|
+
export declare const l0Status: (c: DaemonClient) => Promise<Record<string, unknown>>;
|
|
166
|
+
export declare const kfPromote: (c: DaemonClient, args: {
|
|
167
|
+
seq?: number;
|
|
168
|
+
latest?: boolean;
|
|
169
|
+
note?: string;
|
|
170
|
+
}) => Promise<Record<string, unknown>>;
|
|
171
|
+
export declare function run(c: DaemonClient, args: Record<string, unknown>, timeoutMs?: number): Promise<Record<string, unknown>>;
|
|
172
|
+
export declare const input: (c: DaemonClient, payload: Record<string, unknown>, timeoutMs?: number) => Promise<Record<string, unknown>>;
|
|
173
|
+
/** 截图能力探测(A 路前提):两次 post_screencap 间隔比 hash/亮度。timeout 给 interval+10s。 */
|
|
174
|
+
export declare const screencapProbe: (c: DaemonClient, intervalMs?: number, occluded?: boolean) => Promise<Record<string, unknown>>;
|
|
175
|
+
/** 识别单测。`timeoutMs` 供**多候选**调用方放宽(候选逐例串行,耗时随候选数线性增长:
|
|
176
|
+
* daemon 侧的子进程预算也跟着用例数放宽,见 framed.mjs 的 recoChildBudget)。 */
|
|
177
|
+
export declare const recoTest: (c: DaemonClient, args: Record<string, unknown>, timeoutMs?: number) => Promise<Record<string, unknown>>;
|
|
178
|
+
/**
|
|
179
|
+
* 控制器类型 → 需要扫描的设备类型;**无设备可枚举的类型返回 null**(调用方跳过扫描)。
|
|
180
|
+
* daemon 的 device_list 只枚举 adb/win32——PlayCover/MacOS/Linux 给 'win32' 会白白发起
|
|
181
|
+
* 一次必然失败的扫描(曾经就是这样,把无关窗口列表塞进计划错误里)。
|
|
182
|
+
*/
|
|
183
|
+
export declare function deviceKindFor(loaded: LoadedInterface, controllerName: string | null): 'adb' | 'win32' | null;
|
|
184
|
+
export interface ProjectPlan {
|
|
185
|
+
loaded: LoadedInterface;
|
|
186
|
+
plan: ControllerPlan | null;
|
|
187
|
+
controllerName: string | null;
|
|
188
|
+
resource: ReturnType<typeof resolveResourcePaths> | null;
|
|
189
|
+
error?: string;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 载入项目 → 扫设备 → 规划控制器 → 解析资源路径。
|
|
193
|
+
*
|
|
194
|
+
* 为什么不猜设备:interface.json 的 controller[] 已经声明了 Adb/Win32、窗口类名与标题正则、
|
|
195
|
+
* 截图与输入方法、以及识别缩放(display_short_side)——猜错不只是连错窗口,还会把 roi 与
|
|
196
|
+
* 模板的坐标系一起猜错。interface.json 的读法只有 src/interface/ 一份,别处不许再解析一遍。
|
|
197
|
+
*/
|
|
198
|
+
export declare function planProject(c: DaemonClient, dir: string, overrides?: {
|
|
199
|
+
controller?: string;
|
|
200
|
+
hwnd?: string;
|
|
201
|
+
gamepadHwnd?: string;
|
|
202
|
+
address?: string;
|
|
203
|
+
resource?: string;
|
|
204
|
+
manualTarget?: string;
|
|
205
|
+
cwd?: string;
|
|
206
|
+
}): Promise<ProjectPlan>;
|
|
207
|
+
/** `run` 的项目模式装配:入口解析、任务适用性、四级 override、agent 桥接。 */
|
|
208
|
+
export interface ProjectRunInput {
|
|
209
|
+
/** 已规划的项目(`planProject` / REPL `connect project` 的产物) */
|
|
210
|
+
project: ProjectPlan;
|
|
211
|
+
/** interface 的 task 名或 pipeline 入口名(两者都认,与一次性 CLI 同规则) */
|
|
212
|
+
entry: string;
|
|
213
|
+
/** preset 名:取值覆盖 default_case(PI v2.3.0) */
|
|
214
|
+
presetName?: string | null;
|
|
215
|
+
/** CLI 按次取值:option 键 → case 名(select/switch 单值;checkbox 数组) */
|
|
216
|
+
optionCases?: Record<string, string | string[]>;
|
|
217
|
+
/** CLI 按次取值:option 键 → { 字段名: 原文 }(input / hotkey) */
|
|
218
|
+
optionFields?: Record<string, Record<string, string>>;
|
|
219
|
+
/** 用户 --override:对象=追加一层 / 数组=逐层追加(最高优先级),框架逐层继承 */
|
|
220
|
+
override?: Record<string, unknown> | Record<string, unknown>[];
|
|
221
|
+
}
|
|
222
|
+
/** 装配结果:要么可直接交给 `act.run`,要么是一份可行动的错误(不抛异常)。 */
|
|
223
|
+
export type ProjectRunPrep = {
|
|
224
|
+
ok: true;
|
|
225
|
+
/** 直接交给 act.run 的参数(资源整链 + 入口 + 合成 override + agent 声明) */
|
|
226
|
+
args: Record<string, unknown>;
|
|
227
|
+
/** 解析后的 pipeline 入口名(interface task 名 → task.entry) */
|
|
228
|
+
entry: string;
|
|
229
|
+
taskName: string | null;
|
|
230
|
+
/** 生效记录:option=值(级别,via preset/default) */
|
|
231
|
+
applied: string[];
|
|
232
|
+
/** 需要人工注意的事项(option 无取值、agent 缺位等) */
|
|
233
|
+
warns: string[];
|
|
234
|
+
} | {
|
|
235
|
+
ok: false;
|
|
236
|
+
code: string;
|
|
237
|
+
error: string;
|
|
238
|
+
hint?: string;
|
|
239
|
+
warns: string[];
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* 项目模式 run 的唯一装配点:一次性 CLI 与 REPL `run` 都走这里。
|
|
243
|
+
*
|
|
244
|
+
* 为什么必须共享:REPL 曾经只吃 `--override`、不叠 interface 的四级链,同一项目同一入口
|
|
245
|
+
* 在 REPL 里 option / preset / default_case 全部不生效——agent 主路径与一次性命令跑出两套
|
|
246
|
+
* 行为,而且不报错。入口解析、task 适用性、pretask/agent 警示也一并收口,避免第二份规则。
|
|
247
|
+
*/
|
|
248
|
+
export declare function prepareProjectRun(input: ProjectRunInput): ProjectRunPrep;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare const KF_SCHEMA = 1;
|
|
2
|
+
export interface KfRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
file: string;
|
|
5
|
+
sha256: string;
|
|
6
|
+
session: {
|
|
7
|
+
daemon: string;
|
|
8
|
+
gen: number;
|
|
9
|
+
kind: string | null;
|
|
10
|
+
target: string | null;
|
|
11
|
+
};
|
|
12
|
+
capturedAt: string;
|
|
13
|
+
captureSeq: number;
|
|
14
|
+
ctrlW: number;
|
|
15
|
+
ctrlH: number;
|
|
16
|
+
smallW: number | null;
|
|
17
|
+
smallH: number | null;
|
|
18
|
+
scale: number | null;
|
|
19
|
+
source: string;
|
|
20
|
+
note: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface KfManifest {
|
|
23
|
+
schema: number;
|
|
24
|
+
libraryId: string;
|
|
25
|
+
next: number;
|
|
26
|
+
frames: KfRecord[];
|
|
27
|
+
}
|
|
28
|
+
export type KfResolveStatus = 'available' | 'missing' | 'corrupt' | 'unsupported';
|
|
29
|
+
export declare function defaultFramesDir(): string;
|
|
30
|
+
/** 读 manifest。坏文件/未知 schema 明确报错,不默认为当前版。 */
|
|
31
|
+
export declare function loadManifest(dir: string): {
|
|
32
|
+
manifest?: KfManifest;
|
|
33
|
+
error?: string;
|
|
34
|
+
};
|
|
35
|
+
/** 按完整 ID 帧解析:available 时给出经过完整性校验的路径;missing/corrupt/unsupported 各自可诊断。 */
|
|
36
|
+
export declare function resolveFrame(dir: string, id: string): {
|
|
37
|
+
status: KfResolveStatus;
|
|
38
|
+
record?: KfRecord;
|
|
39
|
+
path?: string;
|
|
40
|
+
reason?: string;
|
|
41
|
+
};
|
|
42
|
+
/** list 用:一行人类可读摘要(与 --json 的 data 各自完整,不共用裁剪)。 */
|
|
43
|
+
export declare function describeRecord(r: KfRecord): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface WatchOptions {
|
|
2
|
+
/** 要跟随的日志文件(绝对路径或相对 cwd) */
|
|
3
|
+
paths?: string[];
|
|
4
|
+
/** 条目级跟随:文件 / glob(含 * ? [ ])/ 目录(取每 tick 最新 mtime 的一个文件);
|
|
5
|
+
* 每次 tick 重新解析——日更文件名(跨午夜换新名)不丢尾巴。 */
|
|
6
|
+
entries?: string[];
|
|
7
|
+
/** 推送间隔(ms):攒够这么久的行再一次性回调,避免逐行刷屏 */
|
|
8
|
+
intervalMs?: number;
|
|
9
|
+
/** 只推送匹配这些正则的行;缺省推全部 */
|
|
10
|
+
include?: RegExp[];
|
|
11
|
+
/** 丢弃匹配这些正则的行 */
|
|
12
|
+
exclude?: RegExp[];
|
|
13
|
+
/** 每次推送最多带多少行(超出折叠成一句「还有 N 行」) */
|
|
14
|
+
maxLinesPerFlush?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface WatchHandle {
|
|
17
|
+
/** 停止跟随并返回累计统计 */
|
|
18
|
+
stop(): WatchStats;
|
|
19
|
+
}
|
|
20
|
+
export interface WatchStats {
|
|
21
|
+
/** 累计读到的原始行数 */
|
|
22
|
+
lines: number;
|
|
23
|
+
/** 其中被推送给调用方的行数 */
|
|
24
|
+
pushed: number;
|
|
25
|
+
/** 实际跟随成功的文件 */
|
|
26
|
+
files: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function watchLogs(opts: WatchOptions, onFlush: (lines: string[]) => void): WatchHandle;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** 读 `--xxx-file <path>`:`-` 读 stdin(一次性命令才有意义,REPL 里 stdin 是命令流) */
|
|
2
|
+
export declare function readJsoncArg(spec: string, flag: string): {
|
|
3
|
+
value?: unknown;
|
|
4
|
+
error?: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* 节点表识别:文件里是 `{ "<节点名>": {…}, … }` 而不是一个节点。
|
|
8
|
+
*
|
|
9
|
+
* 判据:**单节点必有 `recognition`**(V1 字符串或 V2 对象),且节点表的每个值都是对象、
|
|
10
|
+
* 至少有一个带 `recognition`。要求"至少一个带 recognition"是为了把 `{"action":{…}}` 这种
|
|
11
|
+
* **缺 recognition 的单节点**留给"缺字段"的报错——它看起来也像"所有值都是对象"。
|
|
12
|
+
* 这条只服务于报错文案(提示去用 `--node-name`),不构成"pipeline 文件"能力,也不改变执行路径。
|
|
13
|
+
*/
|
|
14
|
+
export declare function isNodeTable(value: Record<string, unknown>): boolean;
|
|
15
|
+
/** `--node-file` → 单个节点 */
|
|
16
|
+
export declare function readNodeFile(spec: string): {
|
|
17
|
+
node?: Record<string, unknown>;
|
|
18
|
+
error?: string;
|
|
19
|
+
hint?: string;
|
|
20
|
+
};
|
|
21
|
+
/** `--param-file` → recognition.param 那一层参数对象 */
|
|
22
|
+
export declare function readParamFile(spec: string): {
|
|
23
|
+
param?: Record<string, unknown>;
|
|
24
|
+
error?: string;
|
|
25
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type OcrModelStatus = 'present' | 'missing';
|
|
2
|
+
/**
|
|
3
|
+
* 资源链上是否能找到 OCR 模型。`modelName` 是节点/参数里声明的模型名(缺省空串)。
|
|
4
|
+
*
|
|
5
|
+
* 只查文件存在性、不解析 onnx:判断的是"框架会不会找到它",不是"模型能不能跑"。
|
|
6
|
+
* 按框架的合并规则判:det 与 rec 可以来自不同段,rec 与 keys 必须同段。
|
|
7
|
+
*/
|
|
8
|
+
export declare function ocrModelStatus(resourceDirs: string[], modelName?: string | null): OcrModelStatus;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent 子进程的 `PI_*` 环境变量(PI v2.5.0 起)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要这一层:项目里的 agent 常用 `PI_CONTROLLER` / `PI_RESOURCE` / `PI_CLIENT_MAAFW_VERSION`
|
|
5
|
+
* 决定"选哪套资源、用哪种语言、能不能跑"。不注入时它们**不报错**——直接落到 agent 自带的默认值,
|
|
6
|
+
* 于是任务"跑通了,但不是同一个东西"。协议用规范性"应"要求 Client 注入,同时允许逐项缺省,
|
|
7
|
+
* 所以这里只填拿得到值的项:拿不到就不写,不编默认值。
|
|
8
|
+
*
|
|
9
|
+
* 出处:MaaFramework 5.14.2 `3.3-ProjectInterfaceV2协议` 环境变量表
|
|
10
|
+
* (pinned commit 8061d5bcaa3f07afcc1008795913663f64de46c8)。5.14.2 共 8 个变量;
|
|
11
|
+
* `PI_USER_DATA_DIR` 是 PI v2.11.0 / MaaFW 5.15.0 才引入的,本仓锁 5.14.2,**不要**加。
|
|
12
|
+
*
|
|
13
|
+
* 已知偏差:本工具不解析 i18n 的 `$` 键,所以 `PI_CONTROLLER` / `PI_RESOURCE` 里的
|
|
14
|
+
* label / description 可能是原始 `$key` 而不是展示文本(协议要求已解析)。项目没配
|
|
15
|
+
* `languages` 时不存在这个问题;i18n 落地后这里要跟着改。
|
|
16
|
+
*/
|
|
17
|
+
import type { LoadedInterface } from '../interface/load.js';
|
|
18
|
+
export interface PiEnvInput {
|
|
19
|
+
loaded: LoadedInterface;
|
|
20
|
+
controllerName: string | null;
|
|
21
|
+
resourceName: string | null;
|
|
22
|
+
}
|
|
23
|
+
/** 生成要注入 agent 子进程的环境变量;返回空对象表示本次没有可注入的项。 */
|
|
24
|
+
export declare function buildAgentEnv(i: PiEnvInput): Record<string, string>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { InterfacePretask, LoadedInterface } from '../interface/load.js';
|
|
2
|
+
import { type OptionValueCtx } from '../interface/override.js';
|
|
3
|
+
export interface PretaskOutcome {
|
|
4
|
+
name: string;
|
|
5
|
+
exec: string;
|
|
6
|
+
argv: string[];
|
|
7
|
+
code: number | null;
|
|
8
|
+
signal: string | null;
|
|
9
|
+
ms: number;
|
|
10
|
+
/** stdout+stderr 尾部(失败时给人看) */
|
|
11
|
+
tail: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PretaskResult {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
ran: PretaskOutcome[];
|
|
16
|
+
/** 因过滤/缺 exec 未执行的那些(带原因) */
|
|
17
|
+
skipped: string[];
|
|
18
|
+
notes: string[];
|
|
19
|
+
warns: string[];
|
|
20
|
+
error?: {
|
|
21
|
+
code: string;
|
|
22
|
+
message: string;
|
|
23
|
+
hint?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface PretaskInput {
|
|
27
|
+
loaded: LoadedInterface;
|
|
28
|
+
controllerName: string | null;
|
|
29
|
+
resourceName: string | null;
|
|
30
|
+
optionCases?: Record<string, string | string[]>;
|
|
31
|
+
optionFields?: Record<string, Record<string, string>>;
|
|
32
|
+
/** 单条 pretask 的总时限;<=0 不限时。缺省 MAAFW_PRETASK_TIMEOUT_MS → 120s。 */
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 拼一条 pretask 的完整 argv(含末位 JSON)。**纯函数**:执行与参数构造分开,
|
|
37
|
+
* 参数形状可以离线单测——这部分错了就是"脚本收到了奇怪的参数但没人报错"。
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildPretaskArgv(p: InterfacePretask, loaded: LoadedInterface, ctx: {
|
|
40
|
+
controllerName: string | null;
|
|
41
|
+
resourceName: string | null;
|
|
42
|
+
valueCtx: OptionValueCtx;
|
|
43
|
+
}): {
|
|
44
|
+
argv: string[];
|
|
45
|
+
warns: string[];
|
|
46
|
+
};
|
|
47
|
+
/** pretask 超时缺省 120s:够"启动模拟器到可连"的常态,又兜住真正挂死的脚本。 */
|
|
48
|
+
export declare const PRETASK_TIMEOUT_MS = 120000;
|
|
49
|
+
/**
|
|
50
|
+
* 按声明序执行全部适用的 pretask。任一条失败即返回 ok:false(调用方据此中止连接)。
|
|
51
|
+
* 不抛异常:失败是一种结果,由调用方决定怎么呈现。
|
|
52
|
+
*/
|
|
53
|
+
export declare function runPretasks(input: PretaskInput): Promise<PretaskResult>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function runsDir(): string;
|
|
2
|
+
/** 回执文件名:`run-<ISO 时间戳去分隔符>-<entry>.json`(时间戳保留到毫秒,含 Z 时区标记)。
|
|
3
|
+
* `now` 可注入:单测据此制造"同一毫秒撞名",不必靠 sleep。 */
|
|
4
|
+
export declare function receiptFileName(entry: string, now?: Date): string;
|
|
5
|
+
export declare function writeRunReceipt(record: unknown, entry: string, now?: Date): {
|
|
6
|
+
path?: string;
|
|
7
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reco 参数面的共享判据:**roi 空间**校验。
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独立一个文件:repl 与一次性 CLI 都要能给「roi 越出所用图像尺寸」下一个明确结论,
|
|
5
|
+
* 判据必须只有一份 —— 两处各写一遍,迟早分叉成「CLI 报错、repl 静默」,而静默的正是最贵的那种
|
|
6
|
+
* (G16:ctrl 坐标的 roi 打在 L1 小图上 → `results: []`,看起来像"模板没读到")。
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* roi(控制器/图像空间)是否越出图像尺寸。越界就是**参数用错空间**,不是"没识别到":
|
|
10
|
+
* 边界相等不算越界(`x+w === w` 是贴右边)。
|
|
11
|
+
*
|
|
12
|
+
* **左上边界同样要判**:负坐标是最典型的"空间算错"(L1↔ctrl 换算时先减了偏移),
|
|
13
|
+
* 而它只比右下是看不出来的(`[-50,200,80,300]` 的右下 = 30/500,落在画面里)。
|
|
14
|
+
* 漏判的代价正是本判据要防的那件事:回落到"静默未中 + 指向模板/资源"。
|
|
15
|
+
*
|
|
16
|
+
* 返回 null 表示在界内或无法判定(缺尺寸)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function roiOutOfBounds(roi: number[] | undefined, w: unknown, h: unknown): string | null;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 识别未命中的原因与计数:**只有这一份判据**,一次性 CLI 与 REPL 都读它。
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独立文件:miss 的病因直接决定下一步查什么(roi 里没有字 / expected 过滤掉了 /
|
|
5
|
+
* 分数不够 / 模板根本读不到),两个壳各推一遍必然分叉,而分叉的代价是把"expected 不匹配"
|
|
6
|
+
* 当成"模板读不到"去翻资源目录。
|
|
7
|
+
*
|
|
8
|
+
* 名字按**算法**分开给,不共用一套 OCR 口径:OCR 没有阈值这回事,模板匹配也没有 `expected`
|
|
9
|
+
* 这回事——共用口径就会编出不存在的病因。表以外的算法不猜,如实不给原因。
|
|
10
|
+
*
|
|
11
|
+
* OCR 的空结果还有一个同形病因:**模型没加载时框架不报错,只回空结果**。这条不在本文件的
|
|
12
|
+
* 职责内(要查文件系统),由调用方用 `runtime/ocr-model` 判好、以 `options.ocrModel` 传进来。
|
|
13
|
+
*
|
|
14
|
+
* 派生的前提是**先看 hit**:`noConfidence` 旧式判据(`threshold 建议为 null`)在 OCR 命中时
|
|
15
|
+
* 也成立(OCR 无数值分),不看 `ok` 就会把命中标成"无置信度"。
|
|
16
|
+
*/
|
|
17
|
+
export interface RecoResultLike {
|
|
18
|
+
ok?: boolean;
|
|
19
|
+
detail?: unknown;
|
|
20
|
+
/** 子进程捕获到的识别调用异常(此时 detail 为 null);不是"未命中",是"没跑成" */
|
|
21
|
+
error?: unknown;
|
|
22
|
+
}
|
|
23
|
+
/** 打分摘要(与 `suggestThreshold` 同源,跨层传结构而不传函数,避免 runtime → commands 反向依赖) */
|
|
24
|
+
export interface ScoreSummary {
|
|
25
|
+
bestScore: number;
|
|
26
|
+
lowMatch: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** 派生原因时需要调用方补的外部事实:本文件保持纯函数,文件系统检查由调用方做(runtime/ocr-model) */
|
|
29
|
+
export interface MissOptions {
|
|
30
|
+
/** OCR 模型是否在资源链里;'missing' 时"空结果"先指向模型,不是 roi */
|
|
31
|
+
ocrModel?: 'present' | 'missing';
|
|
32
|
+
}
|
|
33
|
+
export interface MissDetail {
|
|
34
|
+
missReason: string | null;
|
|
35
|
+
rawCount: number | null;
|
|
36
|
+
filteredCount: number | null;
|
|
37
|
+
/** 识别调用本身报错(detail 缺失),不是"未命中"——渲染层要分开标,别打 [未中] */
|
|
38
|
+
failed: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface MissVerdict {
|
|
41
|
+
/** 回执级原因:所有未命中的原因一致时才有值 */
|
|
42
|
+
missReason: string | null;
|
|
43
|
+
/** 回执级去重后的原因(多例扫描可能不止一种) */
|
|
44
|
+
missReasons: string[];
|
|
45
|
+
/** 只在单例回执上给:多例求和会被读成"候选有多少个",而它其实是逐例之和 */
|
|
46
|
+
rawCount: number | null;
|
|
47
|
+
filteredCount: number | null;
|
|
48
|
+
perResult: MissDetail[];
|
|
49
|
+
}
|
|
50
|
+
export declare function describeMisses(results: RecoResultLike[], type: string, scores: ScoreSummary | null, options?: MissOptions): MissVerdict;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export type Roi = number[];
|
|
2
|
+
/** 图像尺寸(未知时传 undefined:判不动就不判,不猜)。 */
|
|
3
|
+
export interface FrameSize {
|
|
4
|
+
w?: unknown;
|
|
5
|
+
h?: unknown;
|
|
6
|
+
}
|
|
7
|
+
/** 允许说"分不出来"的并列带宽度:最优与次优分差小于它就不下结论。 */
|
|
8
|
+
export declare const DEFAULT_GAP = 0.15;
|
|
9
|
+
/** 一个候选位置。`origin` = 输入候选列表里的下标(输出可还原回输入)。 */
|
|
10
|
+
export interface Candidate {
|
|
11
|
+
roi: Roi;
|
|
12
|
+
origin: number;
|
|
13
|
+
}
|
|
14
|
+
/** 被越界判据挡下的候选:**跳过并报出是谁**,不静默丢弃。 */
|
|
15
|
+
export interface SkippedCandidate {
|
|
16
|
+
roi: Roi;
|
|
17
|
+
origin: number;
|
|
18
|
+
reason: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CandidateSet {
|
|
21
|
+
candidates: Candidate[];
|
|
22
|
+
skipped: SkippedCandidate[];
|
|
23
|
+
}
|
|
24
|
+
/** 显式全套:每个元素就是 `[x,y,w,h]`。位置假设已经知道时用这条(**没有周期假设**)。 */
|
|
25
|
+
export declare function fromRois(rois: unknown[], size?: FrameSize): CandidateSet;
|
|
26
|
+
export interface Offset {
|
|
27
|
+
dx: number;
|
|
28
|
+
dy: number;
|
|
29
|
+
}
|
|
30
|
+
/** 相对一个基准位置的平移:x / y 分量都允许,列表允许非均匀(逐行不同的列距照样能表达)。 */
|
|
31
|
+
export declare function fromOffsets(offsets: Offset[], base: Roi, size?: FrameSize): CandidateSet;
|
|
32
|
+
/** 扫描轴:闭区间 `from..to`、步长 `step`(正数)。`from === to` 就是单点。 */
|
|
33
|
+
export interface ScanAxis {
|
|
34
|
+
from: number;
|
|
35
|
+
to: number;
|
|
36
|
+
step: number;
|
|
37
|
+
}
|
|
38
|
+
export interface ScanSpec {
|
|
39
|
+
dx?: ScanAxis;
|
|
40
|
+
dy?: ScanAxis;
|
|
41
|
+
}
|
|
42
|
+
/** 一个轴的取值列表(单点恒为 1 个值)。 */
|
|
43
|
+
export declare function axisValues(axis: ScanAxis | undefined): number[];
|
|
44
|
+
export interface ScanInfo {
|
|
45
|
+
dx: ScanAxis | null;
|
|
46
|
+
dy: ScanAxis | null;
|
|
47
|
+
count: number;
|
|
48
|
+
}
|
|
49
|
+
export declare function scanInfo(spec: ScanSpec): ScanInfo;
|
|
50
|
+
/** 发现模式:笛卡尔积 dx × dy 全部落在**同一个基准 roi** 上(不是判据,见命令层文案)。 */
|
|
51
|
+
export declare function fromScan(spec: ScanSpec, base: Roi, size?: FrameSize): CandidateSet;
|
|
52
|
+
/**
|
|
53
|
+
* `--scan` 语法解析:`dx=-160..160/8,dy=0`(逗号分段,轴是 dx / dy,值是 `<n>` 或 `<from>..<to>/<step>`)。
|
|
54
|
+
*
|
|
55
|
+
* 范围**必须带步长**:候选数是 (to−from)/step 线性增长、而耗时按候选数线性增长,
|
|
56
|
+
* 缺省步长等于让一次手滑变成几百个候选。
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseScan(raw: string): {
|
|
59
|
+
value?: ScanSpec;
|
|
60
|
+
error?: string;
|
|
61
|
+
};
|
|
62
|
+
/** 一例识别的可比较部分。分数在详情内层(miss 时 best 为 null、all 仍带候选得分)。 */
|
|
63
|
+
export interface Sample {
|
|
64
|
+
score: number | null;
|
|
65
|
+
ok: boolean;
|
|
66
|
+
box: number[];
|
|
67
|
+
}
|
|
68
|
+
export declare function sampleOf(result: {
|
|
69
|
+
ok?: unknown;
|
|
70
|
+
detail?: unknown;
|
|
71
|
+
} | undefined): Sample;
|
|
72
|
+
export interface CompareItem extends Sample {
|
|
73
|
+
roi: Roi;
|
|
74
|
+
origin: number;
|
|
75
|
+
}
|
|
76
|
+
export interface RankedItem extends CompareItem {
|
|
77
|
+
rank: number;
|
|
78
|
+
/** 落在"与最优的差 < gap"这条并列带里(带是按分数降序的前缀) */
|
|
79
|
+
inBand: boolean;
|
|
80
|
+
}
|
|
81
|
+
export type Verdict = 'HIT' | 'MISS' | 'AMBIGUOUS';
|
|
82
|
+
export type CompareReason =
|
|
83
|
+
/** 唯一最优 */
|
|
84
|
+
'unique'
|
|
85
|
+
/** 与最优并列的 ≥ 2 个,分不开 */
|
|
86
|
+
| 'ambiguous'
|
|
87
|
+
/** 最优没过 --threshold */
|
|
88
|
+
| 'below-threshold'
|
|
89
|
+
/** 一个候选都没得分:目标在这张图上什么都没匹配上 */
|
|
90
|
+
| 'no-evidence'
|
|
91
|
+
/** 没有候选(全部越界 / 空输入) */
|
|
92
|
+
| 'no-candidates';
|
|
93
|
+
export interface CompareOutcome {
|
|
94
|
+
/** **只有拿得到分数的候选**,按分数降序编号 1..M(没有分数就没有名次) */
|
|
95
|
+
ranked: RankedItem[];
|
|
96
|
+
bestGap: number | null;
|
|
97
|
+
gap: number;
|
|
98
|
+
/** 与最优并列的 **rank** 列表(1 起) */
|
|
99
|
+
withinGap: number[];
|
|
100
|
+
verdict: Verdict;
|
|
101
|
+
reason: CompareReason;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 三态判据。优先序(**别重排**):**先把没有证据的候选剔除,再谈歧义**——
|
|
105
|
+
* ① 可评估候选 0 个 → 未命中;② 最优未过 threshold → 未命中;
|
|
106
|
+
* ③ 与最优并列(|Δ| < gap)的 ≥ 2 → AMBIGUOUS;④ 否则唯一最优。
|
|
107
|
+
*
|
|
108
|
+
* "剔除"以**输出形状**兑现:`score: null` 的候选**不在 `ranked` 里**——没有分数就没有名次,
|
|
109
|
+
* 也进不了并列带("没有证据"既不是 0 分,也不许被当成垫底来把最优衬托成唯一)。
|
|
110
|
+
* 剩下有证据的那些谁更优,才是这里回答的问题;"还有候选没被评估过"由调用方写进退出码(3)
|
|
111
|
+
* 与逐例回执,不改变这里的结论——一次 41 点的扫描里,落在背景上的点本来就拿不到相关系数
|
|
112
|
+
* (实测 `all: []`),把它们算成"分不出来"会淹没真正的信号。
|
|
113
|
+
*/
|
|
114
|
+
export declare function aggregate(items: CompareItem[], options?: {
|
|
115
|
+
gap?: number;
|
|
116
|
+
threshold?: number;
|
|
117
|
+
}): CompareOutcome;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type CommandResult } from '../protocol.js';
|
|
2
|
+
/**
|
|
3
|
+
* 从命令行 argv(含命令名)剥掉 `--session` 旗标本体,剩下的就是要送去会话执行的命令。
|
|
4
|
+
*/
|
|
5
|
+
export declare function stripSessionFlag(argv: string[]): string[];
|
|
6
|
+
/**
|
|
7
|
+
* 转发一条命令到命名会话。返回的 CommandResult 就当作本命令的结果——
|
|
8
|
+
* 调用方(index.ts)直接 emit,不再二次加工。
|
|
9
|
+
*/
|
|
10
|
+
export declare function forwardToSession(name: string, argv: string[]): Promise<CommandResult>;
|