@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,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 候选集合比较的判据内核:**给定外来目标 + 一组位置假设 → 排序表 + bestGap + 并列带 + 三态结论**。
|
|
3
|
+
*
|
|
4
|
+
* 为什么把它从 `roi-check` 里拆出来:旧形态把候选写死成"沿 x 偏移 ±pitch/2"——y 从不偏移,
|
|
5
|
+
* 还要求你先知道周期。而真实棋盘的行距 ≠ 列距、列距本身也逐行不同(单一标量周期不成立),
|
|
6
|
+
* 所以"半周期关系"只是近似。判据的正确形状是**候选集合比较**:候选从哪来(显式全套 / 相对平移 /
|
|
7
|
+
* 发现模式)是调用方的事,这里只负责"生成 → 逐个取分 → 排序 → 下结论"。
|
|
8
|
+
*
|
|
9
|
+
* 三条不许动的性质:
|
|
10
|
+
* 1. **没有证据 ≠ 0 分**:`score: null` 的候选不进 `ranked`(没有分数就没有名次),也不许被当成
|
|
11
|
+
* 垫底来"把最优衬托成唯一";
|
|
12
|
+
* 2. **`bestGap` 无上限地照给**:永远报第 1 与第 2 名的真实分差,不做阈值截断——
|
|
13
|
+
* 只报"带内"的差值等于把"差多少"这件事藏起来;
|
|
14
|
+
* 3. **顺序可追溯**:候选带 `origin`(输入列表下标),排序稳定(同分按 origin),
|
|
15
|
+
* 于是输出能被还原回输入,而不是"看起来像排序过"。
|
|
16
|
+
*
|
|
17
|
+
* 纯函数、不碰 IO、不碰协议:退出码与文案归命令层。
|
|
18
|
+
*/
|
|
19
|
+
import { roiOutOfBounds } from './reco-args.js';
|
|
20
|
+
/** 允许说"分不出来"的并列带宽度:最优与次优分差小于它就不下结论。 */
|
|
21
|
+
export const DEFAULT_GAP = 0.15;
|
|
22
|
+
const round3 = (n) => Math.round(n * 1000) / 1000;
|
|
23
|
+
function finiteRoi(value) {
|
|
24
|
+
if (!Array.isArray(value) || value.length !== 4)
|
|
25
|
+
return null;
|
|
26
|
+
const roi = value.map(Number);
|
|
27
|
+
return roi.every((n) => Number.isFinite(n)) ? roi : null;
|
|
28
|
+
}
|
|
29
|
+
/** 唯一的越界口径:一律走 `roiOutOfBounds`(它连左上负坐标一起判)。 */
|
|
30
|
+
function collect(raw, size) {
|
|
31
|
+
const candidates = [];
|
|
32
|
+
const skipped = [];
|
|
33
|
+
for (const e of raw) {
|
|
34
|
+
if (!e.roi) {
|
|
35
|
+
skipped.push({ roi: e.echo, origin: e.origin, reason: '不是 4 个有限数字,无法当 roi' });
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const oob = roiOutOfBounds(e.roi, size?.w, size?.h);
|
|
39
|
+
if (oob) {
|
|
40
|
+
skipped.push({ roi: e.roi, origin: e.origin, reason: oob });
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
candidates.push({ roi: e.roi, origin: e.origin });
|
|
44
|
+
}
|
|
45
|
+
return { candidates, skipped };
|
|
46
|
+
}
|
|
47
|
+
/** 显式全套:每个元素就是 `[x,y,w,h]`。位置假设已经知道时用这条(**没有周期假设**)。 */
|
|
48
|
+
export function fromRois(rois, size) {
|
|
49
|
+
return collect(rois.map((r, origin) => ({
|
|
50
|
+
roi: finiteRoi(r),
|
|
51
|
+
echo: Array.isArray(r) ? r.map(Number) : [],
|
|
52
|
+
origin,
|
|
53
|
+
})), size);
|
|
54
|
+
}
|
|
55
|
+
/** 相对一个基准位置的平移:x / y 分量都允许,列表允许非均匀(逐行不同的列距照样能表达)。 */
|
|
56
|
+
export function fromOffsets(offsets, base, size) {
|
|
57
|
+
return collect(offsets.map((o, origin) => {
|
|
58
|
+
const roi = [base[0] + o.dx, base[1] + o.dy, base[2], base[3]];
|
|
59
|
+
return { roi: finiteRoi(roi), echo: roi, origin };
|
|
60
|
+
}), size);
|
|
61
|
+
}
|
|
62
|
+
/** 一个轴的取值列表(单点恒为 1 个值)。 */
|
|
63
|
+
export function axisValues(axis) {
|
|
64
|
+
if (!axis)
|
|
65
|
+
return [0];
|
|
66
|
+
const step = Number.isFinite(axis.step) && axis.step > 0 ? axis.step : 1;
|
|
67
|
+
const out = [];
|
|
68
|
+
for (let v = axis.from; v <= axis.to + 1e-9; v += step)
|
|
69
|
+
out.push(round3(v));
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
export function scanInfo(spec) {
|
|
73
|
+
return {
|
|
74
|
+
dx: spec.dx ?? null,
|
|
75
|
+
dy: spec.dy ?? null,
|
|
76
|
+
count: axisValues(spec.dx).length * axisValues(spec.dy).length,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** 发现模式:笛卡尔积 dx × dy 全部落在**同一个基准 roi** 上(不是判据,见命令层文案)。 */
|
|
80
|
+
export function fromScan(spec, base, size) {
|
|
81
|
+
const xs = axisValues(spec.dx);
|
|
82
|
+
const ys = axisValues(spec.dy);
|
|
83
|
+
const raw = [];
|
|
84
|
+
let origin = 0;
|
|
85
|
+
for (const dx of xs) {
|
|
86
|
+
for (const dy of ys) {
|
|
87
|
+
const roi = [base[0] + dx, base[1] + dy, base[2], base[3]];
|
|
88
|
+
raw.push({ roi: finiteRoi(roi), echo: roi, origin: origin++ });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return collect(raw, size);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* `--scan` 语法解析:`dx=-160..160/8,dy=0`(逗号分段,轴是 dx / dy,值是 `<n>` 或 `<from>..<to>/<step>`)。
|
|
95
|
+
*
|
|
96
|
+
* 范围**必须带步长**:候选数是 (to−from)/step 线性增长、而耗时按候选数线性增长,
|
|
97
|
+
* 缺省步长等于让一次手滑变成几百个候选。
|
|
98
|
+
*/
|
|
99
|
+
export function parseScan(raw) {
|
|
100
|
+
const spec = {};
|
|
101
|
+
for (const part of String(raw).split(',')) {
|
|
102
|
+
const seg = part.trim();
|
|
103
|
+
if (!seg)
|
|
104
|
+
continue;
|
|
105
|
+
const eq = seg.indexOf('=');
|
|
106
|
+
if (eq < 0)
|
|
107
|
+
return { error: '--scan 每段要写成 <轴>=<值>:' + seg + '(形如 dx=-160..160/8,dy=0)' };
|
|
108
|
+
const axis = seg.slice(0, eq).trim();
|
|
109
|
+
if (axis !== 'dx' && axis !== 'dy')
|
|
110
|
+
return { error: '--scan 只认识 dx / dy 两个轴,不认识:' + seg };
|
|
111
|
+
const body = seg.slice(eq + 1).trim();
|
|
112
|
+
const m = /^(-?\d+(?:\.\d+)?)(?:\.\.(-?\d+(?:\.\d+)?)(?:\/(\d+(?:\.\d+)?))?)?$/.exec(body);
|
|
113
|
+
if (!m)
|
|
114
|
+
return { error: '--scan 的值要写成 <n> 或 <from>..<to>/<step>:' + seg };
|
|
115
|
+
const from = Number(m[1]);
|
|
116
|
+
if (m[2] === undefined) {
|
|
117
|
+
spec[axis] = { from, to: from, step: 1 };
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (m[3] === undefined) {
|
|
121
|
+
return { error: '--scan 的范围要给步长(' + seg + ' 应写成 ' + body + '/<step>):耗时随候选数线性增长,缺步长会让候选数失控' };
|
|
122
|
+
}
|
|
123
|
+
const to = Number(m[2]);
|
|
124
|
+
const step = Number(m[3]);
|
|
125
|
+
if (!(step > 0))
|
|
126
|
+
return { error: '--scan 的步长要正数:' + seg };
|
|
127
|
+
if (to < from)
|
|
128
|
+
return { error: '--scan 的区间为空(from > to):' + seg };
|
|
129
|
+
spec[axis] = { from, to, step };
|
|
130
|
+
}
|
|
131
|
+
if (spec.dx === undefined && spec.dy === undefined) {
|
|
132
|
+
return { error: '--scan 至少要给一个轴:dx=… 或 dy=…' };
|
|
133
|
+
}
|
|
134
|
+
return { value: spec };
|
|
135
|
+
}
|
|
136
|
+
export function sampleOf(result) {
|
|
137
|
+
const inner = result?.detail?.detail;
|
|
138
|
+
const best = inner?.best?.score;
|
|
139
|
+
const boxes = (inner?.all ?? [])
|
|
140
|
+
.map((x) => Number(x.score))
|
|
141
|
+
.filter((n) => Number.isFinite(n))
|
|
142
|
+
.concat(Number.isFinite(Number(best)) ? [Number(best)] : []);
|
|
143
|
+
const box = inner?.best?.box;
|
|
144
|
+
return {
|
|
145
|
+
score: boxes.length ? Math.max(...boxes) : null,
|
|
146
|
+
ok: result?.ok === true,
|
|
147
|
+
box: Array.isArray(box) ? box : [],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 三态判据。优先序(**别重排**):**先把没有证据的候选剔除,再谈歧义**——
|
|
152
|
+
* ① 可评估候选 0 个 → 未命中;② 最优未过 threshold → 未命中;
|
|
153
|
+
* ③ 与最优并列(|Δ| < gap)的 ≥ 2 → AMBIGUOUS;④ 否则唯一最优。
|
|
154
|
+
*
|
|
155
|
+
* "剔除"以**输出形状**兑现:`score: null` 的候选**不在 `ranked` 里**——没有分数就没有名次,
|
|
156
|
+
* 也进不了并列带("没有证据"既不是 0 分,也不许被当成垫底来把最优衬托成唯一)。
|
|
157
|
+
* 剩下有证据的那些谁更优,才是这里回答的问题;"还有候选没被评估过"由调用方写进退出码(3)
|
|
158
|
+
* 与逐例回执,不改变这里的结论——一次 41 点的扫描里,落在背景上的点本来就拿不到相关系数
|
|
159
|
+
* (实测 `all: []`),把它们算成"分不出来"会淹没真正的信号。
|
|
160
|
+
*/
|
|
161
|
+
export function aggregate(items, options = {}) {
|
|
162
|
+
const gap = options.gap ?? DEFAULT_GAP;
|
|
163
|
+
const threshold = options.threshold;
|
|
164
|
+
const byScore = items
|
|
165
|
+
.filter((x) => x.score !== null)
|
|
166
|
+
.sort((a, b) => (b.score - a.score) || (a.origin - b.origin));
|
|
167
|
+
const best = byScore.length ? byScore[0].score : null;
|
|
168
|
+
const second = byScore.length > 1 ? byScore[1].score : null;
|
|
169
|
+
const bestGap = best !== null && second !== null ? round3(best - second) : null;
|
|
170
|
+
const band = best === null ? [] : byScore.filter((x) => best - x.score < gap);
|
|
171
|
+
const withinGap = band.map((_, i) => i + 1);
|
|
172
|
+
const ranked = byScore.map((x, i) => ({
|
|
173
|
+
...x,
|
|
174
|
+
rank: i + 1,
|
|
175
|
+
inBand: i < band.length,
|
|
176
|
+
}));
|
|
177
|
+
let verdict = 'MISS';
|
|
178
|
+
let reason = 'no-candidates';
|
|
179
|
+
if (items.length === 0) {
|
|
180
|
+
reason = 'no-candidates';
|
|
181
|
+
}
|
|
182
|
+
else if (!byScore.length) {
|
|
183
|
+
reason = 'no-evidence';
|
|
184
|
+
}
|
|
185
|
+
else if (threshold !== undefined && best < threshold) {
|
|
186
|
+
reason = 'below-threshold';
|
|
187
|
+
}
|
|
188
|
+
else if (band.length >= 2) {
|
|
189
|
+
verdict = 'AMBIGUOUS';
|
|
190
|
+
reason = 'ambiguous';
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
verdict = 'HIT';
|
|
194
|
+
reason = 'unique';
|
|
195
|
+
}
|
|
196
|
+
return { ranked, bestGap, gap, withinGap, verdict, reason };
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=roi-compare.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--session <name>` 转发:一次性 CLI 把 argv 送进命名会话的常驻进程执行。
|
|
3
|
+
*
|
|
4
|
+
* 为什么命令自己不用关心:转发发生在命令分发**之前**(index.ts 的拦截),命令拿到的
|
|
5
|
+
* 是会话侧 dispatchArgv 注入 client 后跑出来的同一个 CommandResult——信封、退出码、
|
|
6
|
+
* data 与直接执行同形(设计审查 P0-3 L2)。
|
|
7
|
+
*
|
|
8
|
+
* 死会话自愈:meta 在但 pid 已死时,用 meta.connectArgs 原样重起(连接参数在
|
|
9
|
+
* 起会话时就存了),调用方不必记得这条会话当初怎么连的。
|
|
10
|
+
*/
|
|
11
|
+
import { cliPackage } from '../pkg.js';
|
|
12
|
+
import { pidAlive, readSessionMeta, sendToSessionExec, sessionServeLogTail, spawnSessionServer, stopSession, waitPipeReady, } from './session-ipc.js';
|
|
13
|
+
import { EXIT, fail } from '../protocol.js';
|
|
14
|
+
const FORWARD_TIMEOUT_MS = 600_000;
|
|
15
|
+
/**
|
|
16
|
+
* 从命令行 argv(含命令名)剥掉 `--session` 旗标本体,剩下的就是要送去会话执行的命令。
|
|
17
|
+
*/
|
|
18
|
+
export function stripSessionFlag(argv) {
|
|
19
|
+
const out = [];
|
|
20
|
+
for (let i = 0; i < argv.length; i++) {
|
|
21
|
+
const t = argv[i];
|
|
22
|
+
if (t === '--session') {
|
|
23
|
+
i++;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (t.startsWith('--session='))
|
|
27
|
+
continue;
|
|
28
|
+
out.push(t);
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 转发一条命令到命名会话。返回的 CommandResult 就当作本命令的结果——
|
|
34
|
+
* 调用方(index.ts)直接 emit,不再二次加工。
|
|
35
|
+
*/
|
|
36
|
+
export async function forwardToSession(name, argv) {
|
|
37
|
+
let meta = readSessionMeta(name);
|
|
38
|
+
if (!meta) {
|
|
39
|
+
return fail('SESSION_NOT_FOUND', `会话 '${name}' 不存在(没有 meta)`, `先起会话:maafw-live repl --session ${name} --project <dir>(或 --kind win32 --target <title>)`, EXIT.USAGE);
|
|
40
|
+
}
|
|
41
|
+
if (!pidAlive(meta.pid)) {
|
|
42
|
+
/* 死会话自愈:清掉残留后用 meta 里存的连接参数原样重起 */
|
|
43
|
+
const savedArgs = meta.connectArgs;
|
|
44
|
+
stopSession(name);
|
|
45
|
+
meta = spawnSessionServer(name, process.argv[1] ?? '', savedArgs);
|
|
46
|
+
const ready = await waitPipeReady(meta.pipe, 20000);
|
|
47
|
+
if (!ready) {
|
|
48
|
+
const tail = sessionServeLogTail(name);
|
|
49
|
+
stopSession(name);
|
|
50
|
+
return fail('SESSION_NOT_READY', `会话 '${name}' 已死且自动重起失败:管道 ${meta.pipe} 20s 内不可连`, (tail.length ? '常驻进程日志尾部:\n ' + tail.join('\n ') : '重起参数 ' + JSON.stringify(savedArgs)), EXIT.FAIL);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const rep = await sendToSessionExec(meta, argv, FORWARD_TIMEOUT_MS);
|
|
55
|
+
if (rep.result) {
|
|
56
|
+
/* rep.lines = 待认领输出(异步收尾、连接横幅)+ 本命令 human。直接当 human 用:
|
|
57
|
+
* 比只看 result.human 多了异步尾巴,与非转发形态观感一致。 */
|
|
58
|
+
if (rep.lines.length)
|
|
59
|
+
rep.result.human = rep.lines;
|
|
60
|
+
/* 混版可见:meta 里记了起会话的 CLI 版本——npm test / npm install 升级后老会话仍跑
|
|
61
|
+
* 旧 lib,行为会漂;不硬断(旧会话仍能服务),只在 human 里留一行让人查得到。 */
|
|
62
|
+
const running = cliPackage().version;
|
|
63
|
+
if (meta.cliVersion && meta.cliVersion !== running) {
|
|
64
|
+
rep.result.human = [
|
|
65
|
+
'⚠ 会话 ' + JSON.stringify(name) + ' 由 maafw-live ' + meta.cliVersion + ' 起,' +
|
|
66
|
+
'当前 CLI 是 ' + running + '——行为可能已漂移(--session-stop ' + name + ' 后重连可拿到新代码)',
|
|
67
|
+
...(rep.result.human ?? []),
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
return rep.result;
|
|
71
|
+
}
|
|
72
|
+
/* exec 回执却没有 result:常驻进程版本过旧(起会话用的还是旧包),让它明说怎么修 */
|
|
73
|
+
return fail('SESSION_REPLY', `会话 '${name}' 的回执里没有结构化结果(常驻进程是旧版本起的)`, `maafw-live repl --session-stop ${name} 后重试`, EXIT.FAIL);
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
return fail('SESSION_IO', `会话 '${name}' 不可达:${e instanceof Error ? e.message : String(e)}`, `用 maafw-live repl --session-status ${name} 查状态;死了会自动重起`, EXIT.FAIL);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=session-forward.js.map
|