@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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +278 -2
  3. package/bin/maafw-live.mjs +25 -0
  4. package/docs/daemon-protocol.md +116 -0
  5. package/docs/keyframe-evidence-contract-v0.md +61 -0
  6. package/docs/keyframe-retention-contract-v0.md +236 -0
  7. package/lib/client/daemon.js +234 -0
  8. package/lib/client/daemon.js.map +1 -0
  9. package/lib/commands/annotate.js +172 -0
  10. package/lib/commands/annotate.js.map +1 -0
  11. package/lib/commands/calibrate.js +61 -0
  12. package/lib/commands/calibrate.js.map +1 -0
  13. package/lib/commands/color.js +73 -0
  14. package/lib/commands/color.js.map +1 -0
  15. package/lib/commands/crop.js +228 -0
  16. package/lib/commands/crop.js.map +1 -0
  17. package/lib/commands/env.js +215 -0
  18. package/lib/commands/env.js.map +1 -0
  19. package/lib/commands/index.js +64 -0
  20. package/lib/commands/index.js.map +1 -0
  21. package/lib/commands/input.js +219 -0
  22. package/lib/commands/input.js.map +1 -0
  23. package/lib/commands/kf.js +131 -0
  24. package/lib/commands/kf.js.map +1 -0
  25. package/lib/commands/reco.js +211 -0
  26. package/lib/commands/reco.js.map +1 -0
  27. package/lib/commands/repl.js +698 -0
  28. package/lib/commands/repl.js.map +1 -0
  29. package/lib/commands/runtime.js +514 -0
  30. package/lib/commands/runtime.js.map +1 -0
  31. package/lib/commands/skill.js +169 -0
  32. package/lib/commands/skill.js.map +1 -0
  33. package/lib/commands/timing.js +229 -0
  34. package/lib/commands/timing.js.map +1 -0
  35. package/lib/commands/version.js +66 -0
  36. package/lib/commands/version.js.map +1 -0
  37. package/lib/daemon/framed.mjs +2850 -0
  38. package/lib/daemon/reco_child.mjs +146 -0
  39. package/lib/exec.js +96 -0
  40. package/lib/exec.js.map +1 -0
  41. package/lib/flags.js +42 -0
  42. package/lib/flags.js.map +1 -0
  43. package/lib/image.js +90 -0
  44. package/lib/image.js.map +1 -0
  45. package/lib/index.js +139 -0
  46. package/lib/index.js.map +1 -0
  47. package/lib/interface/index.js +12 -0
  48. package/lib/interface/index.js.map +1 -0
  49. package/lib/interface/jsonc.js +95 -0
  50. package/lib/interface/jsonc.js.map +1 -0
  51. package/lib/interface/load.js +307 -0
  52. package/lib/interface/load.js.map +1 -0
  53. package/lib/interface/override.js +103 -0
  54. package/lib/interface/override.js.map +1 -0
  55. package/lib/interface/plan.js +188 -0
  56. package/lib/interface/plan.js.map +1 -0
  57. package/lib/pkg.js +18 -0
  58. package/lib/pkg.js.map +1 -0
  59. package/lib/protocol.js +90 -0
  60. package/lib/protocol.js.map +1 -0
  61. package/lib/runtime/actions.js +110 -0
  62. package/lib/runtime/actions.js.map +1 -0
  63. package/lib/runtime/keyframes.js +73 -0
  64. package/lib/runtime/keyframes.js.map +1 -0
  65. package/lib/runtime/session.js +86 -0
  66. package/lib/runtime/session.js.map +1 -0
  67. package/lib/types/client/daemon.d.ts +86 -0
  68. package/lib/types/commands/annotate.d.ts +3 -0
  69. package/lib/types/commands/calibrate.d.ts +7 -0
  70. package/lib/types/commands/color.d.ts +9 -0
  71. package/lib/types/commands/crop.d.ts +3 -0
  72. package/lib/types/commands/env.d.ts +2 -0
  73. package/lib/types/commands/index.d.ts +13 -0
  74. package/lib/types/commands/input.d.ts +17 -0
  75. package/lib/types/commands/kf.d.ts +10 -0
  76. package/lib/types/commands/reco.d.ts +23 -0
  77. package/lib/types/commands/repl.d.ts +2 -0
  78. package/lib/types/commands/runtime.d.ts +48 -0
  79. package/lib/types/commands/skill.d.ts +17 -0
  80. package/lib/types/commands/timing.d.ts +64 -0
  81. package/lib/types/commands/version.d.ts +3 -0
  82. package/lib/types/exec.d.ts +31 -0
  83. package/lib/types/flags.d.ts +58 -0
  84. package/lib/types/image.d.ts +27 -0
  85. package/lib/types/index.d.ts +1 -0
  86. package/lib/types/interface/index.d.ts +11 -0
  87. package/lib/types/interface/jsonc.d.ts +9 -0
  88. package/lib/types/interface/load.d.ts +113 -0
  89. package/lib/types/interface/override.d.ts +33 -0
  90. package/lib/types/interface/plan.d.ts +47 -0
  91. package/lib/types/pkg.d.ts +6 -0
  92. package/lib/types/protocol.d.ts +108 -0
  93. package/lib/types/runtime/actions.d.ts +166 -0
  94. package/lib/types/runtime/keyframes.d.ts +43 -0
  95. package/lib/types/runtime/session.d.ts +53 -0
  96. package/lib/types/update-check.d.ts +20 -0
  97. package/lib/types/usage.d.ts +3 -0
  98. package/lib/update-check.js +97 -0
  99. package/lib/update-check.js.map +1 -0
  100. package/lib/usage.js +50 -0
  101. package/lib/usage.js.map +1 -0
  102. package/package.json +81 -4
  103. package/skills/README.md +51 -0
  104. package/skills/maafw-live/SKILL.md +263 -0
  105. package/skills/maafw-live/references/examples.md +238 -0
  106. package/skills/maafw-live/references/pitfalls.md +118 -0
  107. package/skills/maafw-live/references/workflows.md +159 -0
@@ -0,0 +1,131 @@
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 { EXIT, fail } from '../protocol.js';
9
+ import { defaultFramesDir, describeRecord, loadManifest, resolveFrame } from '../runtime/keyframes.js';
10
+ import { kfPromote, l0Status, withDaemon } from '../runtime/actions.js';
11
+ import { ensureSession } from '../runtime/session.js';
12
+ import { CONNECT_OPTIONS, daemonFail, sessionOptions } from './runtime.js';
13
+ const DIR_HINT = '库根默认 ~/.maafw-live/frames(与 daemon 的 runDir 一致)';
14
+ export const kfCommand = {
15
+ name: 'kf',
16
+ summary: '关键帧:status 看 L0 缓存,promote 升格原图进本地库,list/resolve 离线解析',
17
+ usage: 'maafw-live kf status [--project <dir>|--kind ...]\n' +
18
+ ' maafw-live kf promote <seq>|latest [--note <s>] [--project <dir>|--kind ...]\n' +
19
+ ' maafw-live kf list [--dir <frames>] (离线,不需要设备)\n' +
20
+ ' maafw-live kf resolve <kf:...> [--dir <frames>] (离线)',
21
+ options: { ...CONNECT_OPTIONS, note: { type: 'string' }, dir: { type: 'string' }, latest: { type: 'boolean' } },
22
+ async run(ctx) {
23
+ const sub = ctx.positionals[0] ?? 'status';
24
+ if (sub === 'list' || sub === 'resolve') {
25
+ const dir = typeof ctx.values.dir === 'string' ? ctx.values.dir : defaultFramesDir();
26
+ if (sub === 'list') {
27
+ const { manifest, error } = loadManifest(dir);
28
+ if (error)
29
+ return fail('KF_MANIFEST', error, DIR_HINT, EXIT.FINDINGS);
30
+ if (!manifest) {
31
+ return {
32
+ exitCode: EXIT.OK,
33
+ human: ['关键帧库 ' + dir + ':尚无留存(manifest 未创建;升格后会自动生成)'],
34
+ data: { dir, count: 0, frames: [] },
35
+ };
36
+ }
37
+ return {
38
+ exitCode: EXIT.OK,
39
+ human: [
40
+ '关键帧库 ' + dir + ':' + manifest.frames.length + ' 条(libraryId ' + manifest.libraryId + ')',
41
+ ...manifest.frames.map(describeRecord),
42
+ ],
43
+ data: { dir, count: manifest.frames.length, frames: manifest.frames },
44
+ };
45
+ }
46
+ const id = ctx.positionals[1];
47
+ if (!id)
48
+ return fail('BAD_ARGUMENTS', '用法:maafw-live kf resolve <kf:库UUID:序号>', undefined, EXIT.USAGE);
49
+ const r = resolveFrame(dir, id);
50
+ const human = ['解析 ' + id + ':' + r.status + (r.reason ? '(' + r.reason + ')' : '')];
51
+ if (r.record)
52
+ human.push(' ' + describeRecord(r.record));
53
+ if (r.path)
54
+ human.push(' path: ' + r.path);
55
+ if (r.record)
56
+ human.push(' sha256: ' + r.record.sha256);
57
+ return { exitCode: EXIT.OK, human, data: r };
58
+ }
59
+ if (sub === 'status') {
60
+ try {
61
+ return await withDaemon(async (client) => {
62
+ const st = await l0Status(client);
63
+ const roll = st.roll;
64
+ const anchor = st.anchor;
65
+ return {
66
+ exitCode: EXIT.OK,
67
+ human: [
68
+ 'L0 原图缓存:滚动区 ' + String(roll?.count) + '/' + String(roll?.cap) +
69
+ '(' + String(roll?.bytes) + ' bytes),锚区 ' + String(anchor?.count) + '/' + String(anchor?.cap) +
70
+ '(' + String(anchor?.bytes) + ' bytes),seq=' + String(st.seq),
71
+ '关键帧库:' + String(st.framesDir),
72
+ '锚区条目(seq, source):',
73
+ ...(anchor?.entries ?? [])
74
+ .map((e) => ' seq=' + e.seq + ' ' + String(e.source)),
75
+ ],
76
+ data: st,
77
+ };
78
+ });
79
+ }
80
+ catch (e) {
81
+ return daemonFail(e);
82
+ }
83
+ }
84
+ if (sub === 'promote') {
85
+ const o = sessionOptions(ctx.values);
86
+ const seqRaw = ctx.positionals[1];
87
+ let args;
88
+ if (seqRaw !== undefined && /^\d+$/.test(seqRaw))
89
+ args = { seq: Number(seqRaw) };
90
+ else if (seqRaw === 'latest' || ctx.values.latest === true)
91
+ args = { latest: true };
92
+ else
93
+ args = {};
94
+ if (typeof ctx.values.note === 'string')
95
+ args.note = ctx.values.note;
96
+ if (!args.seq && !args.latest) {
97
+ return fail('BAD_ARGUMENTS', '给序号(kf promote 42)或 kf promote latest;身份在接受请求时固定,已淘汰则失败', '升格要在捕获它的 daemon 会话里做(repl:stream/输入/run 后立刻升格);一次性命令的 L0 通常只有边界帧', EXIT.USAGE);
98
+ }
99
+ try {
100
+ return await withDaemon(async (client) => {
101
+ if (o.project || o.kind) {
102
+ /* 设备会话存在才值得连:L0 缓存是进程态,连一次至少能把输入/截图边界帧留下 */
103
+ await ensureSession(client, o);
104
+ }
105
+ const r = await kfPromote(client, args);
106
+ if (r.ok === false) {
107
+ return fail('KF_PROMOTE', String(r.error ?? '升格失败'), 'L0 淘汰是诚实失败:换 frame_get 导 L1 参考帧,或重采', EXIT.FINDINGS);
108
+ }
109
+ const rec = r.record;
110
+ return {
111
+ exitCode: EXIT.OK,
112
+ human: [
113
+ '已升格:' + String(r.id) + (r.idempotent ? '(幂等重试,返回原对象)' : ''),
114
+ ...(rec ? [' 捕获 seq=' + rec.captureSeq + ',控制器尺寸 ' + rec.ctrlW + 'x' + rec.ctrlH + ',source=' + rec.source] : []),
115
+ ' path: ' + String(r.path),
116
+ ' sha256: ' + String(r.sha256),
117
+ ],
118
+ data: r,
119
+ written: [String(r.path)],
120
+ };
121
+ });
122
+ }
123
+ catch (e) {
124
+ return daemonFail(e);
125
+ }
126
+ }
127
+ return fail('BAD_ARGUMENTS', '用法:kf status | kf promote [seq|latest] | kf list | kf resolve <id>', undefined, EXIT.USAGE);
128
+ },
129
+ };
130
+ export const KF_COMMANDS = [kfCommand];
131
+ //# sourceMappingURL=kf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kf.js","sourceRoot":"","sources":["../../src/commands/kf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * 识别单测:maafw-live reco。
3
+ *
4
+ * 走 daemon 的 reco_test —— 它把识别放进一次性子进程执行(beta 绑定在无效模板上会原生崩溃,
5
+ * 子进程炸掉只损失一次测试,不带走调用方)。支持阈值扫描:一次调用给出阈值-命中曲线。
6
+ * 项目模式下资源目录从 interface.json 解析,避免手写路径与项目声明不一致。
7
+ */
8
+ import { EXIT, fail } from '../protocol.js';
9
+ import { recoTest, withDaemon } from '../runtime/actions.js';
10
+ import { defaultFramesDir, resolveFrame } from '../runtime/keyframes.js';
11
+ import { describeSession, ensureSession, offlineResource } from '../runtime/session.js';
12
+ import { CONNECT_OPTIONS, daemonFail, sessionOptions } from './runtime.js';
13
+ function parseJson(raw, what) {
14
+ if (raw === undefined)
15
+ return {};
16
+ if (typeof raw !== 'string')
17
+ return {};
18
+ try {
19
+ return { value: JSON.parse(raw) };
20
+ }
21
+ catch (e) {
22
+ return { error: what + ' 不是合法 JSON:' + String(e.message) };
23
+ }
24
+ }
25
+ export function suggestThreshold(results) {
26
+ let best = -1;
27
+ for (const r of results) {
28
+ const inner = r.detail?.detail;
29
+ const candidates = [Number(inner?.best?.score), ...(inner?.all ?? []).map((x) => Number(x.score))];
30
+ for (const s of candidates)
31
+ if (Number.isFinite(s) && s > best)
32
+ best = s;
33
+ }
34
+ if (best < 0)
35
+ return null;
36
+ const bestScore = Math.round(best * 1000) / 1000;
37
+ const lowMatch = best < 0.5;
38
+ return {
39
+ bestScore,
40
+ suggest: lowMatch ? null : Math.max(0, Math.round((best - 0.1) * 1000) / 1000),
41
+ lowMatch,
42
+ };
43
+ }
44
+ export const recoCommand = {
45
+ name: 'reco',
46
+ summary: '识别单测(子进程隔离):--param/--sweep 阈值扫描,或 --node 整节点 JSON 透传;--act 真机执行动作半',
47
+ usage: 'maafw-live reco --type TemplateMatch --resource-dir <dir> --image <png|kf:ID> [--param <json>] [--sweep <json>] [--project <dir>]\n' +
48
+ ' maafw-live reco --node <json> --resource-dir <dir> --image <png|kf:ID> (V1 扁平 / V2 嵌套节点均原样透传)\n' +
49
+ ' maafw-live reco --node <json> --resource-dir <dir> --from-kf <kf:库UUID:序号> (库内留存帧:离线、不需要设备)\n' +
50
+ ' maafw-live reco --node <json> --act --project <dir> (识别拿框 → 用框 run_action 真机执行)',
51
+ options: {
52
+ ...CONNECT_OPTIONS,
53
+ type: { type: 'string' },
54
+ 'resource-dir': { type: 'string' },
55
+ image: { type: 'string' },
56
+ seq: { type: 'string' },
57
+ param: { type: 'string' },
58
+ sweep: { type: 'string' },
59
+ node: { type: 'string' },
60
+ act: { type: 'boolean' },
61
+ 'from-kf': { type: 'string' },
62
+ 'frames-dir': { type: 'string' },
63
+ },
64
+ async run(ctx) {
65
+ const o = sessionOptions(ctx.values);
66
+ const type = typeof ctx.values.type === 'string' ? ctx.values.type : 'TemplateMatch';
67
+ const imageRaw = typeof ctx.values.image === 'string' && ctx.values.image !== '' ? ctx.values.image : undefined;
68
+ /* `--image kf:…:0011` 是 SKILL / roadmap 里记过的写法:以 kf: 开头就按**库帧 ID**解释,
69
+ * 而不是文件路径(否则一路走到 ENOENT,实测踩过)。规范入口仍是 --from-kf。 */
70
+ const kfFromImage = imageRaw?.startsWith('kf:') === true ? imageRaw : undefined;
71
+ const image = kfFromImage ? undefined : imageRaw;
72
+ const seq = typeof ctx.values.seq === 'string' ? Number(ctx.values.seq) : undefined;
73
+ const nodeRaw = typeof ctx.values.node === 'string' ? ctx.values.node : undefined;
74
+ let node;
75
+ if (nodeRaw !== undefined) {
76
+ const parsed = parseJson(nodeRaw, '--node');
77
+ if (parsed.error)
78
+ return fail('BAD_ARGUMENTS', parsed.error, undefined, EXIT.USAGE);
79
+ if (!parsed.value || typeof parsed.value !== 'object' || Array.isArray(parsed.value)) {
80
+ return fail('BAD_ARGUMENTS', '--node 必须是 JSON 对象(pipeline 节点)', undefined, EXIT.USAGE);
81
+ }
82
+ node = parsed.value;
83
+ }
84
+ const param = parseJson(ctx.values.param, '--param');
85
+ if (param.error)
86
+ return fail('BAD_ARGUMENTS', param.error, undefined, EXIT.USAGE);
87
+ const sweep = parseJson(ctx.values.sweep, '--sweep');
88
+ if (sweep.error)
89
+ return fail('BAD_ARGUMENTS', sweep.error, undefined, EXIT.USAGE);
90
+ const act = ctx.values.act === true;
91
+ /* 库帧来源(离线,镜像 crop / annotate 的 --from-kf):先走离线读侧解析,daemon 只接身份与路径 */
92
+ const fromKf = typeof ctx.values['from-kf'] === 'string' && ctx.values['from-kf'] !== ''
93
+ ? ctx.values['from-kf']
94
+ : kfFromImage;
95
+ if (fromKf !== undefined && seq !== undefined) {
96
+ return fail('BAD_ARGUMENTS', '--from-kf 与 --seq 互斥:前者在库内留存帧上跑,后者在本会话缓冲帧上跑', '取库里有哪些帧:maafw-live kf list', EXIT.USAGE);
97
+ }
98
+ let kfSource;
99
+ if (fromKf !== undefined) {
100
+ const dir = typeof ctx.values['frames-dir'] === 'string' ? ctx.values['frames-dir'] : defaultFramesDir();
101
+ const rf = resolveFrame(dir, fromKf);
102
+ if (rf.status !== 'available' || !rf.path || !rf.record) {
103
+ const code = rf.status === 'corrupt' ? 'KF_CORRUPT' : (rf.status === 'unsupported' ? 'KF_UNSUPPORTED' : 'KF_MISSING');
104
+ return fail(code, '库帧不可用(' + rf.status + '):' + String(rf.reason ?? '') + '(库 ' + dir + ')', 'kf list 看库内有哪些帧;missing 表示本机不可复核,不代表历史从未观测', EXIT.FINDINGS);
105
+ }
106
+ const rec = rf.record;
107
+ kfSource = {
108
+ id: rec.id, path: rf.path, sha256: rec.sha256, ctrlW: rec.ctrlW, ctrlH: rec.ctrlH,
109
+ captureSeq: rec.captureSeq, capturedAt: rec.capturedAt,
110
+ };
111
+ }
112
+ const offline = kfSource !== undefined;
113
+ if (act && offline) {
114
+ return fail('BAD_ARGUMENTS', '--act 要在真机上执行动作、图像取自当前画面:不能与 --from-kf 同用', '离线只做识别判据;要连真机就把 --from-kf 换成 --project 跑 --act', EXIT.USAGE);
115
+ }
116
+ try {
117
+ return await withDaemon(async (client) => {
118
+ const s = offline ? { connected: false } : await ensureSession(client, o);
119
+ let resourceDir = (typeof ctx.values['resource-dir'] === 'string' ? ctx.values['resource-dir'] : undefined)
120
+ ?? s.plan?.resource?.paths[0];
121
+ if (!resourceDir && offline && o.project) {
122
+ /* 离线:项目只作资源来源(模板与 OCR 模型),不扫设备不连接 */
123
+ const off = offlineResource(o.project, o.controller, o.resource);
124
+ if (off.error) {
125
+ return fail('PLAN_FAILED', '离线解析项目资源失败:' + off.error, '也可以直接给 --resource-dir <dir>', EXIT.FINDINGS);
126
+ }
127
+ resourceDir = off.paths[0];
128
+ }
129
+ if (!resourceDir) {
130
+ return fail('BAD_ARGUMENTS', '缺少资源目录:给 --resource-dir <dir>,或用 --project <dir> 让 interface.json 决定', undefined, EXIT.USAGE);
131
+ }
132
+ if (act) {
133
+ /* --act:识别拿框 → 真机 run_action。图像来自当前画面(daemon 抓帧),不吃 --image/--seq */
134
+ if (!node) {
135
+ return fail('BAD_ARGUMENTS', '--act 需要同时给 --node <json>(整节点,含 action)', undefined, EXIT.USAGE);
136
+ }
137
+ if (!o.project && !o.kind) {
138
+ return fail('BAD_ARGUMENTS', '--act 要真机执行动作:给 --project <dir> 或 --kind 连接设备', '多步操作用 maafw-live repl', EXIT.USAGE);
139
+ }
140
+ const r = await recoTest(client, { resourceDir, act: true, node });
141
+ if (r.ok === false) {
142
+ return fail('RECO_ACT', String(r.error ?? '动作单测失败'), r.stage === 'recognition' ? '识别未命中/报错——动作半未执行' : undefined, EXIT.FINDINGS);
143
+ }
144
+ const reco = r.reco;
145
+ const retention = r.retention;
146
+ return {
147
+ exitCode: EXIT.OK,
148
+ human: [
149
+ ...describeSession(s),
150
+ '节点单测(识别→动作,真机执行):',
151
+ ' 识别框 ' + JSON.stringify(reco?.box ?? null),
152
+ ' 动作回执 ' + JSON.stringify(r.action ?? null),
153
+ ' 边界帧 seq ' + String(retention?.before?.seq) + ' → ' + String(retention?.after?.seq) +
154
+ '(frame_get / kf promote 可复核动作效果)',
155
+ ],
156
+ data: r,
157
+ };
158
+ }
159
+ if (!image && seq === undefined && !offline) {
160
+ return fail('BAD_ARGUMENTS', '缺少图像:一次性命令给 --image <png>;用缓冲帧(--seq)需要在 maafw-live repl 里先 stream start', '库里留存帧用 --from-kf <kf:…>(离线、不需要设备)', EXIT.USAGE);
161
+ }
162
+ const r = await recoTest(client, {
163
+ resourceDir, type,
164
+ ...(image ? { image } : {}),
165
+ ...(seq !== undefined ? { seq } : {}),
166
+ ...(kfSource ? { kfSource } : {}),
167
+ ...(node ? { node } : {}),
168
+ ...(!node && param.value ? { param: param.value } : {}),
169
+ ...(!node && sweep.value ? { sweep: sweep.value } : {}),
170
+ });
171
+ const results = r.results ?? [];
172
+ const human = [
173
+ ...describeSession(s),
174
+ '识别 ' + String(r.type ?? type) + ':' + results.length + ' 例' + (node ? '(整节点透传)' : ''),
175
+ ...results.map((x) => ' ' + (x.ok ? '[命中]' : '[未中]') + ' ' + JSON.stringify(x.param) + ' ' + x.ms + 'ms'),
176
+ ];
177
+ const th = suggestThreshold(r.results ?? []);
178
+ if (th && th.suggest !== null) {
179
+ human.push(' 实测最高置信度 ' + th.bestScore + ' → threshold 起点建议 ' + th.suggest +
180
+ '(实测 − 0.1 留余量,换场景会掉;ROI 收紧可再提)');
181
+ }
182
+ else if (th && th.lowMatch) {
183
+ human.push(' 实测最高置信度 ' + th.bestScore + ':模板与该画面不匹配——threshold 建议不适用,' +
184
+ '先核对模板来源画面与当前画面(识别未命中不是调低阈值的理由)');
185
+ }
186
+ else if (results.length > 0) {
187
+ /* 第三形态:识别跑了,但一个置信度都没带回来(实测:模板文件读不到时就是这个签名——
188
+ * ~230ms、`[未中]`、detail.best 空、all 为空)。它和"分数低的未命中"必须分得开:
189
+ * 后者是画面不匹配(有分数),前者是**输入当时读不到**,处置方向完全不同。 */
190
+ human.push(' 识别未返回任何置信度(' + results.length + ' 例):这与"分数低的未命中"不同——' +
191
+ '多半是模板/资源当时没读到(资源包未加载、模板文件缺失或不可读、临时文件正被杀软扫描)。' +
192
+ '先核对 --resource-dir 与模板是否存在,再重跑一次看是否复现;别当成"画面不匹配"去调阈值');
193
+ }
194
+ if (r.ok === false)
195
+ human.push('error: ' + String(r.error));
196
+ /* 机器侧也要能一眼认出第三形态(阈值建议缺席 ≠ 没跑) */
197
+ const noConfidence = th === null && results.length > 0;
198
+ return {
199
+ exitCode: r.ok === false ? EXIT.FINDINGS : EXIT.OK,
200
+ human,
201
+ data: { ...r, ...(th ? { thresholdSuggestion: th } : {}), ...(noConfidence ? { noConfidence: true } : {}) },
202
+ };
203
+ });
204
+ }
205
+ catch (e) {
206
+ return daemonFail(e);
207
+ }
208
+ },
209
+ };
210
+ export const RECO_COMMANDS = [recoCommand];
211
+ //# sourceMappingURL=reco.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reco.js","sourceRoot":"","sources":["../../src/commands/reco.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAoC,MAAM,gBAAgB,CAAA;AAC7E,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAqB,MAAM,uBAAuB,CAAA;AAC/E,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAiB,MAAM,yBAAyB,CAAA;AACvF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAqB,MAAM,uBAAuB,CAAA;AAC1G,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE1E,SAAS,SAAS,CAAI,GAAY,EAAE,IAAY;IAC9C,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,CAAA;IAChC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAA;IACtC,IAAI,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,EAAE,CAAA;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,aAAa,GAAG,MAAM,CAAE,CAAW,CAAC,OAAO,CAAC,EAAE,CAAA;IACvE,CAAC;AACH,CAAC;AAYD,MAAM,UAAU,gBAAgB,CAC9B,OAAiD;IAEjD,IAAI,IAAI,GAAG,CAAC,CAAC,CAAA;IACb,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAI,CAAC,CAAC,MAA2G,EAAE,MAAM,CAAA;QACpI,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAClG,KAAK,MAAM,CAAC,IAAI,UAAU;YAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI;gBAAE,IAAI,GAAG,CAAC,CAAA;IAC1E,CAAC;IACD,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACzB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,GAAG,CAAA;IAC3B,OAAO;QACL,SAAS;QACT,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAC9E,QAAQ;KACT,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,qEAAqE;IAC9E,KAAK,EAAE,qIAAqI;QAC1I,0GAA0G;QAC1G,wGAAwG;QACxG,sGAAsG;IACxG,OAAO,EAAE;QACP,GAAG,eAAe;QAClB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAClC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACvB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACxB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACjC;IAED,KAAK,CAAC,GAAG,CAAC,GAAG;QACX,MAAM,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACpC,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAA;QACpF,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;QAC/G;2DACmD;QACnD,MAAM,WAAW,GAAG,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;QAC/E,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;QAChD,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACnF,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;QACjF,IAAI,IAAyC,CAAA;QAC7C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,SAAS,CAA0B,OAAO,EAAE,QAAQ,CAAC,CAAA;YACpE,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;YACnF,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrF,OAAO,IAAI,CAAC,eAAe,EAAE,iCAAiC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;YACxF,CAAC;YACD,IAAI,GAAG,MAAM,CAAC,KAAK,CAAA;QACrB,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAA0B,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;QAC7E,IAAI,KAAK,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QACjF,MAAM,KAAK,GAAG,SAAS,CAA0B,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;QAC7E,IAAI,KAAK,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAEjF,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI,CAAA;QAEnC,qEAAqE;QACrE,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE;YACtF,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;YACvB,CAAC,CAAC,WAAW,CAAA;QACf,IAAI,MAAM,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,eAAe,EAAE,6CAA6C,EACxE,4BAA4B,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7C,CAAC;QACD,IAAI,QAAkC,CAAA;QACtC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAA;YACxG,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACpC,IAAI,EAAE,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;gBACxD,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAA;gBACrH,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG,EACzF,4CAA4C,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;YAChE,CAAC;YACD,MAAM,GAAG,GAAG,EAAE,CAAC,MAAkB,CAAA;YACjC,QAAQ,GAAG;gBACT,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK;gBACjF,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU;aACvD,CAAA;QACH,CAAC;QACD,MAAM,OAAO,GAAG,QAAQ,KAAK,SAAS,CAAA;QACtC,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,eAAe,EAAE,2CAA2C,EACtE,gDAAgD,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QACjE,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBACvC,MAAM,CAAC,GAAiB,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;gBACvF,IAAI,WAAW,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;uBACtG,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC/B,IAAI,CAAC,WAAW,IAAI,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;oBACzC,qCAAqC;oBACrC,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAA;oBAChE,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;wBACd,OAAO,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,GAAG,CAAC,KAAK,EAAE,6BAA6B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;oBACrG,CAAC;oBACD,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC5B,CAAC;gBACD,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,OAAO,IAAI,CAAC,eAAe,EAAE,sEAAsE,EACjG,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;gBAC1B,CAAC;gBACD,IAAI,GAAG,EAAE,CAAC;oBACR,qEAAqE;oBACrE,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,OAAO,IAAI,CAAC,eAAe,EAAE,yCAAyC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;oBAChG,CAAC;oBACD,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;wBAC1B,OAAO,IAAI,CAAC,eAAe,EAAE,+CAA+C,EAC1E,uBAAuB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;oBACxC,CAAC;oBACD,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;oBAClE,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;wBACnB,OAAO,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC,EACjD,CAAC,CAAC,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;oBAC9E,CAAC;oBACD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAsC,CAAA;oBACrD,MAAM,SAAS,GAAG,CAAC,CAAC,SAAgF,CAAA;oBACpG,OAAO;wBACL,QAAQ,EAAE,IAAI,CAAC,EAAE;wBACjB,KAAK,EAAE;4BACL,GAAG,eAAe,CAAC,CAAC,CAAC;4BACrB,mBAAmB;4BACnB,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC;4BAC5C,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;4BAC5C,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC;gCACnF,kCAAkC;yBACrC;wBACD,IAAI,EAAE,CAAC;qBACR,CAAA;gBACH,CAAC;gBACD,IAAI,CAAC,KAAK,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;oBAC5C,OAAO,IAAI,CAAC,eAAe,EAAE,0EAA0E,EACrG,mCAAmC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;gBACpD,CAAC;gBACD,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE;oBAC/B,WAAW,EAAE,IAAI;oBACjB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3B,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACjC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACzB,GAAG,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvD,GAAG,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACxD,CAAC,CAAA;gBACF,MAAM,OAAO,GAAI,CAAC,CAAC,OAA0F,IAAI,EAAE,CAAA;gBACnH,MAAM,KAAK,GAAG;oBACZ,GAAG,eAAe,CAAC,CAAC,CAAC;oBACrB,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;oBACtF,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;iBAC5G,CAAA;gBACD,MAAM,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,OAA+D,IAAI,EAAE,CAAC,CAAA;gBACpG,IAAI,EAAE,IAAI,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;oBAC9B,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,SAAS,GAAG,oBAAoB,GAAG,EAAE,CAAC,OAAO;wBACxE,gCAAgC,CAAC,CAAA;gBACrC,CAAC;qBAAM,IAAI,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC;oBAC7B,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,SAAS,GAAG,8BAA8B;wBACrE,gCAAgC,CAAC,CAAA;gBACrC,CAAC;qBAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9B;;gEAE4C;oBAC5C,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,qBAAqB;wBACjE,8CAA8C;wBAC9C,sDAAsD,CAAC,CAAA;gBAC3D,CAAC;gBACD,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK;oBAAE,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC3D,iCAAiC;gBACjC,MAAM,YAAY,GAAG,EAAE,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;gBACtD,OAAO;oBACL,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;oBAClD,KAAK;oBACL,IAAI,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;iBAC5G,CAAA;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,UAAU,CAAC,CAAC,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;CACF,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAc,CAAC,WAAW,CAAC,CAAA"}