@co0ontty/wand 4.72.2-beta.gcc5d57e → 4.73.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/dist/build-info.json +4 -4
- package/dist/config.js +20 -0
- package/dist/daemon-connection.d.ts +9 -0
- package/dist/daemon-connection.js +86 -0
- package/dist/distribution-manager.d.ts +5 -0
- package/dist/distribution-manager.js +79 -1
- package/dist/git-quick-commit.js +12 -0
- package/dist/message-truncator.js +6 -0
- package/dist/native/darwin-arm64/wand-render +0 -0
- package/dist/native/darwin-arm64/wand-render.sha256 +1 -0
- package/dist/native/darwin-arm64/wand-render.version +1 -0
- package/dist/native/darwin-x64/wand-render +0 -0
- package/dist/native/darwin-x64/wand-render.sha256 +1 -0
- package/dist/native/darwin-x64/wand-render.version +1 -0
- package/dist/native/linux-arm64/wand-render +0 -0
- package/dist/native/linux-arm64/wand-render.sha256 +1 -0
- package/dist/native/linux-arm64/wand-render.version +1 -0
- package/dist/native/linux-x64/wand-render +0 -0
- package/dist/native/linux-x64/wand-render.sha256 +1 -0
- package/dist/native/linux-x64/wand-render.version +1 -0
- package/dist/process-manager.d.ts +10 -0
- package/dist/process-manager.js +73 -4
- package/dist/render-binary.d.ts +61 -0
- package/dist/render-binary.js +204 -0
- package/dist/render-daemon-client.d.ts +171 -0
- package/dist/render-daemon-client.js +1114 -0
- package/dist/render-host.d.ts +64 -0
- package/dist/render-host.js +301 -0
- package/dist/render-protocol.d.ts +128 -0
- package/dist/render-protocol.js +99 -0
- package/dist/render-structured-client.d.ts +80 -0
- package/dist/render-structured-client.js +513 -0
- package/dist/render-structured-host.d.ts +31 -0
- package/dist/render-structured-host.js +218 -0
- package/dist/render-structured-protocol.d.ts +101 -0
- package/dist/render-structured-protocol.js +35 -0
- package/dist/server-session-routes.js +72 -9
- package/dist/server-task-routes.js +52 -3
- package/dist/server-update-routes.d.ts +2 -0
- package/dist/server-update-routes.js +44 -0
- package/dist/server.js +31 -9
- package/dist/session-transport.js +1 -1
- package/dist/storage.d.ts +2 -1
- package/dist/storage.js +14 -5
- package/dist/structured-client-protocol.d.ts +3 -1
- package/dist/structured-client-protocol.js +85 -25
- package/dist/structured-content.d.ts +20 -3
- package/dist/structured-content.js +80 -1
- package/dist/structured-exec-host.js +7 -1
- package/dist/structured-exec-pump.js +6 -2
- package/dist/structured-pi-adapter.js +18 -2
- package/dist/structured-session-manager.d.ts +2 -0
- package/dist/structured-session-manager.js +27 -3
- package/dist/task-types.d.ts +2 -0
- package/dist/terminal-daemon-client.d.ts +9 -2
- package/dist/terminal-daemon-client.js +119 -46
- package/dist/terminal-daemon-server.js +20 -4
- package/dist/terminal-host.d.ts +6 -0
- package/dist/terminal-host.js +3 -0
- package/dist/tui/ipc-server.js +12 -0
- package/dist/types.d.ts +19 -1
- package/dist/unix-socket-keepalive.d.ts +3 -0
- package/dist/unix-socket-keepalive.js +94 -0
- package/dist/web-ui/content/scripts.js +68 -68
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/content/tailwind.css +12 -0
- package/dist/web-ui/embedded-assets.js +2 -2
- package/dist/ws-broadcast.d.ts +1 -1
- package/dist/ws-broadcast.js +17 -5
- package/package.json +8 -3
- package/scripts/install-render-binary.js +499 -0
- package/scripts/stage-render-binaries.js +626 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { execFile, spawnSync } from "node:child_process";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
/** 仓库根:src/ 与 dist/ 都在根下一层,所以两种运行方式解析结果一致。 */
|
|
7
|
+
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
|
+
const VERSION_PROBE_TIMEOUT_MS = 2_000;
|
|
9
|
+
const ARCH_PROBE_TIMEOUT_MS = 1_000;
|
|
10
|
+
/**
|
|
11
|
+
* 支持的分发三元组。
|
|
12
|
+
*
|
|
13
|
+
* 与 `render-bin/manifest.json` 的版本条目键、`render/release.json` 的
|
|
14
|
+
* `supportedTriples` 必须一致;新增平台要同时改这三处与 CI 矩阵。
|
|
15
|
+
*/
|
|
16
|
+
export const SUPPORTED_RENDER_TRIPLES = ["darwin-arm64", "darwin-x64", "linux-x64", "linux-arm64"];
|
|
17
|
+
/** `uname -m` 的架构别名 → Node 的 `process.arch` 命名(两个生态叫法不同)。 */
|
|
18
|
+
const MACHINE_ARCH_ALIASES = {
|
|
19
|
+
arm64: "arm64",
|
|
20
|
+
aarch64: "arm64",
|
|
21
|
+
x86_64: "x64",
|
|
22
|
+
amd64: "x64",
|
|
23
|
+
x64: "x64",
|
|
24
|
+
};
|
|
25
|
+
/** `uname -m` 的输出归一成 Node 的 arch 名;认不出返回 null(调用方回退 process.arch)。 */
|
|
26
|
+
export function normalizeMachineArch(machine) {
|
|
27
|
+
if (typeof machine !== "string")
|
|
28
|
+
return null;
|
|
29
|
+
return MACHINE_ARCH_ALIASES[machine.trim().toLowerCase()] ?? null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 平台三元组(`darwin-arm64` 等)。
|
|
33
|
+
*
|
|
34
|
+
* 为什么不直接用 `process.arch`:macOS 上 Node 跑在 Rosetta 里时它报 `x64`,
|
|
35
|
+
* 而机器其实是 arm64 —— 于是会去找一个不存在(或架构不符)的产物,最后表现成
|
|
36
|
+
* 「自动模式下 Rust 引擎莫名其妙不生效」。`uname -m` 才反映真实硬件;只有
|
|
37
|
+
* `uname` 不可用(PATH 被清空、Windows)时才回退 `process.arch`。
|
|
38
|
+
*
|
|
39
|
+
* `rosettaTranslated` 是反向兜底:翻译态下 `uname -m` 同样报 `x86_64`,
|
|
40
|
+
* 只有 `sysctl.proc_translated` 能说明「这个 x64 进程跑在 arm64 机器上」。
|
|
41
|
+
* 少了它,上面那条规则在它最该生效的场景里形同虚设。
|
|
42
|
+
*/
|
|
43
|
+
export function resolveRenderTriple(platform, nodeArch, unameMachine, rosettaTranslated = false) {
|
|
44
|
+
let arch = normalizeMachineArch(unameMachine) ?? nodeArch;
|
|
45
|
+
if (platform === "darwin" && arch === "x64" && rosettaTranslated)
|
|
46
|
+
arch = "arm64";
|
|
47
|
+
return `${platform}-${arch}`;
|
|
48
|
+
}
|
|
49
|
+
let cachedPlatformArchProbe = null;
|
|
50
|
+
/**
|
|
51
|
+
* 真实架构探测(进程级缓存):`resolveRenderBinaryPath` 在一次启动里会被调用多次,
|
|
52
|
+
* 不该每次都 spawn 两个进程。
|
|
53
|
+
*/
|
|
54
|
+
export function probePlatformArch() {
|
|
55
|
+
if (!cachedPlatformArchProbe) {
|
|
56
|
+
cachedPlatformArchProbe = {
|
|
57
|
+
unameMachine: runUnameMachine(),
|
|
58
|
+
rosettaTranslated: isRosettaTranslated(),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return cachedPlatformArchProbe;
|
|
62
|
+
}
|
|
63
|
+
/** 当前进程应使用的三元组。 */
|
|
64
|
+
export function currentRenderTriple() {
|
|
65
|
+
const probe = probePlatformArch();
|
|
66
|
+
return resolveRenderTriple(process.platform, process.arch, probe.unameMachine, probe.rosettaTranslated);
|
|
67
|
+
}
|
|
68
|
+
function runUnameMachine() {
|
|
69
|
+
if (process.platform === "win32")
|
|
70
|
+
return null;
|
|
71
|
+
try {
|
|
72
|
+
const result = spawnSync("uname", ["-m"], {
|
|
73
|
+
encoding: "utf8",
|
|
74
|
+
timeout: ARCH_PROBE_TIMEOUT_MS,
|
|
75
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
76
|
+
});
|
|
77
|
+
if (result.error || result.status !== 0)
|
|
78
|
+
return null;
|
|
79
|
+
return (result.stdout ?? "").trim() || null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** `sysctl.proc_translated` == 1 表示当前进程被 Rosetta 翻译(只在 darwin 上有意义)。 */
|
|
86
|
+
function isRosettaTranslated() {
|
|
87
|
+
if (process.platform !== "darwin")
|
|
88
|
+
return false;
|
|
89
|
+
try {
|
|
90
|
+
const result = spawnSync("sysctl", ["-n", "sysctl.proc_translated"], {
|
|
91
|
+
encoding: "utf8",
|
|
92
|
+
timeout: ARCH_PROBE_TIMEOUT_MS,
|
|
93
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
94
|
+
});
|
|
95
|
+
if (result.error || result.status !== 0)
|
|
96
|
+
return false;
|
|
97
|
+
return (result.stdout ?? "").trim() === "1";
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 约定候选路径(不含 `WAND_RENDER_BIN` 与 `PATH`,调用方单独处理)。
|
|
105
|
+
*
|
|
106
|
+
* 顺序刻意把「刚 cargo build 出来的」排在分发位置之前:开发机上调 Rust 引擎时
|
|
107
|
+
* 期望立刻生效,而不是被上一次安装的旧二进制盖住。
|
|
108
|
+
*
|
|
109
|
+
* 旧布局(`wand-rs/`、仓库根 `native/`)已不存在,候选里不留兼容分支:
|
|
110
|
+
* 留着只会让「引擎没生效」这类问题多一个静默的假来源。
|
|
111
|
+
*/
|
|
112
|
+
export function renderBinaryCandidates(configDir, triple) {
|
|
113
|
+
const binaryName = process.platform === "win32" ? "wand-render.exe" : "wand-render";
|
|
114
|
+
return [
|
|
115
|
+
path.join(REPO_ROOT, "render", "target", "release", binaryName),
|
|
116
|
+
path.join(REPO_ROOT, "render", "target", "debug", binaryName),
|
|
117
|
+
path.join(configDir, "bin", binaryName),
|
|
118
|
+
// npm 包内嵌的正式位置:scripts/stage-render-binaries.js 把 render-bin 的产物写在这里,
|
|
119
|
+
// dist/ 在 package.json 的 files 里,所以全局安装后也有二进制。
|
|
120
|
+
path.join(REPO_ROOT, "dist", "native", triple, binaryName),
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 解析 wand-render 可执行文件。
|
|
125
|
+
*
|
|
126
|
+
* 顺序:`WAND_RENDER_BIN` → `<repo>/render/target/{release,debug}` → `<configDir>/bin`
|
|
127
|
+
* → `<repo>/dist/native/<triple>` → `PATH`。返回 null 表示「这台机器没有」,由调用方
|
|
128
|
+
* 按 engine 决定告警还是报错。
|
|
129
|
+
*/
|
|
130
|
+
export function resolveRenderBinaryPath(configPath) {
|
|
131
|
+
const binaryName = process.platform === "win32" ? "wand-render.exe" : "wand-render";
|
|
132
|
+
const fromEnv = process.env.WAND_RENDER_BIN?.trim();
|
|
133
|
+
if (fromEnv) {
|
|
134
|
+
if (isExecutableFile(fromEnv))
|
|
135
|
+
return fromEnv;
|
|
136
|
+
// 显式配置但不存在属于配置错误,必须可见,不能静默滑到仓库构建产物。
|
|
137
|
+
process.stderr.write(`[wand] WAND_RENDER_BIN points at ${fromEnv}, which is not an executable file; falling back to discovery.\n`);
|
|
138
|
+
}
|
|
139
|
+
const configDir = path.dirname(path.resolve(configPath));
|
|
140
|
+
const triple = currentRenderTriple();
|
|
141
|
+
for (const candidate of renderBinaryCandidates(configDir, triple)) {
|
|
142
|
+
if (isExecutableFile(candidate))
|
|
143
|
+
return candidate;
|
|
144
|
+
}
|
|
145
|
+
for (const dir of (process.env.PATH ?? "").split(path.delimiter)) {
|
|
146
|
+
if (!dir)
|
|
147
|
+
continue;
|
|
148
|
+
const candidate = path.join(dir, binaryName);
|
|
149
|
+
if (isExecutableFile(candidate))
|
|
150
|
+
return candidate;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 读取 wand-render 的版本。
|
|
156
|
+
*
|
|
157
|
+
* 先读二进制旁边的 `wand-render.version` sidecar(就位脚本会写),读不到才去跑
|
|
158
|
+
* `wand-render --version` —— 启动路径上不该无谓地执行一个进程。
|
|
159
|
+
* 两种方式都失败时返回 null:调用方只要一个展示用版本号,拿不到不能影响启动。
|
|
160
|
+
*/
|
|
161
|
+
export function readRenderBinaryVersion(binaryPath) {
|
|
162
|
+
const sidecar = readVersionSidecar(binaryPath);
|
|
163
|
+
if (sidecar)
|
|
164
|
+
return Promise.resolve(sidecar);
|
|
165
|
+
return new Promise((resolve) => {
|
|
166
|
+
execFile(binaryPath, ["--version"], { timeout: VERSION_PROBE_TIMEOUT_MS }, (error, stdout) => {
|
|
167
|
+
if (error) {
|
|
168
|
+
resolve(null);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const firstLine = stdout.split("\n").map((line) => line.trim()).find((line) => line.length > 0) ?? "";
|
|
172
|
+
const version = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.]+)?)/.exec(firstLine);
|
|
173
|
+
resolve(version ? version[1] : null);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function readVersionSidecar(binaryPath) {
|
|
178
|
+
try {
|
|
179
|
+
const raw = readFileSync(path.join(path.dirname(binaryPath), "wand-render.version"), "utf8").trim();
|
|
180
|
+
const version = /^(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.]+)?)$/.exec(raw);
|
|
181
|
+
return version ? version[1] : null;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export function isExecutableFile(candidate) {
|
|
188
|
+
try {
|
|
189
|
+
if (!existsSync(candidate) || !statSync(candidate).isFile())
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (process.platform === "win32")
|
|
196
|
+
return true;
|
|
197
|
+
try {
|
|
198
|
+
accessSync(candidate, constants.X_OK);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { type RenderMethod } from "./render-protocol.js";
|
|
2
|
+
import { type TerminalAttachResult, type TerminalHost, type TerminalSessionState, type TerminalSpawnRequest } from "./terminal-host.js";
|
|
3
|
+
/**
|
|
4
|
+
* 鉴权层面的失败(与网络抖动区分)。
|
|
5
|
+
*
|
|
6
|
+
* 特征:连接建立成功、hello 发出后对端**一个字节都没回**就关闭 —— Render 对
|
|
7
|
+
* token 不符/协议不符的处理就是直接 `close()`。单独一个类型是为了让重连策略
|
|
8
|
+
* 能把「同一把废 token」和「daemon 不在了」区分开,而不是一律 10s 重试。
|
|
9
|
+
*/
|
|
10
|
+
export declare class RenderAuthError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Render(常驻 PTY 持有者)的 Node 客户端。
|
|
15
|
+
*
|
|
16
|
+
* 与 legacy `TerminalDaemonClient` 的关键差异:**这里只有 PTY**,没有结构化运行;
|
|
17
|
+
* 另外 `disconnect()` 只解绑 socket,Render 进程与其 PTY 全部保留 —— 这正是
|
|
18
|
+
* Server 因 `npm update` 重启而 PTY 不丢的前提。
|
|
19
|
+
*/
|
|
20
|
+
export declare class RenderDaemonClient implements TerminalHost {
|
|
21
|
+
private readonly socketPath;
|
|
22
|
+
private readonly token;
|
|
23
|
+
/**
|
|
24
|
+
* token 文件路径。给了它就在**每次 connect 时重读**:Render 崩溃/升级重启后
|
|
25
|
+
* 会 `generate_token()` 轮换 token,只缓存构造期的那一把会让重连永远鉴权失败
|
|
26
|
+
* (现象是 `createOrAttach` 全部失败、错误只显示 unavailable,旧会话被永久报成 running)。
|
|
27
|
+
*/
|
|
28
|
+
private readonly tokenPath;
|
|
29
|
+
/** Persisted PTY IDs used only if v1 `list` exceeds its aggregate frame limit. */
|
|
30
|
+
private readonly knownSessionIds;
|
|
31
|
+
readonly persistent = true;
|
|
32
|
+
private socket;
|
|
33
|
+
private nextRequestId;
|
|
34
|
+
private readonly pending;
|
|
35
|
+
private readonly inventory;
|
|
36
|
+
private readonly handles;
|
|
37
|
+
private readonly pendingEvents;
|
|
38
|
+
private readonly pendingEventOverflows;
|
|
39
|
+
private readonly refreshingSessions;
|
|
40
|
+
private reconciling;
|
|
41
|
+
private eventsDuringReconcile;
|
|
42
|
+
private reconcileDuringSync;
|
|
43
|
+
private headerParts;
|
|
44
|
+
private headerBytes;
|
|
45
|
+
private bodyParts;
|
|
46
|
+
private bodyBytes;
|
|
47
|
+
private frameLength;
|
|
48
|
+
private disposed;
|
|
49
|
+
private reconnectTimer;
|
|
50
|
+
private reconnectDelayMs;
|
|
51
|
+
private reconnectFailureLogged;
|
|
52
|
+
private offlineOperationLogged;
|
|
53
|
+
/** 协议版本不匹配是终态:重试无意义,也不允许降级运行。 */
|
|
54
|
+
private fatalProtocolError;
|
|
55
|
+
private daemonVersion;
|
|
56
|
+
/** 最近一次 connect 时实际使用的凭据。 */
|
|
57
|
+
private activeToken;
|
|
58
|
+
/** 最后一次成功读到的凭据;token 文件暂时读不到时用它,避免重连因一次 IO 失败直接放弃。 */
|
|
59
|
+
private lastKnownToken;
|
|
60
|
+
/** 已经因为「读不到 token 文件」告警过,避免每次重连都刷一行。 */
|
|
61
|
+
private tokenReadFailureLogged;
|
|
62
|
+
/** 当前 socket 上已解出的帧数,用来区分「未鉴权被直接关闭」与网络错误。 */
|
|
63
|
+
private framesOnCurrentSocket;
|
|
64
|
+
private connecting;
|
|
65
|
+
private stopHeartbeat;
|
|
66
|
+
constructor(socketPath: string, token: string,
|
|
67
|
+
/**
|
|
68
|
+
* token 文件路径。给了它就在**每次 connect 时重读**:Render 崩溃/升级重启后
|
|
69
|
+
* 会 `generate_token()` 轮换 token,只缓存构造期的那一把会让重连永远鉴权失败
|
|
70
|
+
* (现象是 `createOrAttach` 全部失败、错误只显示 unavailable,旧会话被永久报成 running)。
|
|
71
|
+
*/
|
|
72
|
+
tokenPath?: string | null,
|
|
73
|
+
/** Persisted PTY IDs used only if v1 `list` exceeds its aggregate frame limit. */
|
|
74
|
+
knownSessionIds?: readonly string[]);
|
|
75
|
+
get version(): string;
|
|
76
|
+
connect(): Promise<void>;
|
|
77
|
+
private open;
|
|
78
|
+
/**
|
|
79
|
+
* 对端一个字节都没回就断开:daemon 对 token/协议不符的处理是直接 `close()`
|
|
80
|
+
* (`wand-renderd` 的 `server.rs`),所以这是鉴权/版本问题的特征,不是网络抖动。
|
|
81
|
+
* 归类为 `RenderAuthError`,由重连策略决定「别再 10s 一次拿同一把废 token 试」。
|
|
82
|
+
*/
|
|
83
|
+
private describeConnectFailure;
|
|
84
|
+
/**
|
|
85
|
+
* 读取当前凭据:每次都用 token 文件里的**最新**值(daemon 重启会轮换)。
|
|
86
|
+
* 文件暂时读不到(渲染器正在退出、路径还没建)不是致命错误,回落到上一次成功
|
|
87
|
+
* 读到的值并告警一次;下一次连接会重试读文件。
|
|
88
|
+
*/
|
|
89
|
+
private readToken;
|
|
90
|
+
private warnTokenFileUnusable;
|
|
91
|
+
/** resize 走的是异步 RPC,但 inventory 必须立刻反映新尺寸(见 RemoteRenderProcess.resize)。 */
|
|
92
|
+
noteTerminalResize(sessionId: string, cols: number, rows: number): void;
|
|
93
|
+
attach(sessionId: string, afterSeq?: number): TerminalAttachResult | null;
|
|
94
|
+
createOrAttach(request: TerminalSpawnRequest, afterSeq?: number): Promise<TerminalAttachResult>;
|
|
95
|
+
forget(sessionId: string): void;
|
|
96
|
+
/**
|
|
97
|
+
* 只解绑:关闭 socket、清掉内存句柄,**Render 进程与它的所有 PTY 都保持运行**。
|
|
98
|
+
* 这是 Server / Render 分离的核心 —— 下一次启动 attach 回来仍拿到同一批会话。
|
|
99
|
+
*/
|
|
100
|
+
disconnect(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Best-effort 操作:Render 不可用时打 stderr,绝不把异常抛回调用方,
|
|
103
|
+
* 否则一次 PTY 抖动会顺着 ProcessManager 把整个会话路径打断。
|
|
104
|
+
*/
|
|
105
|
+
fireOperation(sessionId: string, method: RenderMethod, params?: Record<string, unknown>): void;
|
|
106
|
+
confirmWrite(sessionId: string, data: string): Promise<void>;
|
|
107
|
+
reportOperationError(sessionId: string, method: RenderMethod, error: unknown): void;
|
|
108
|
+
private listSessions;
|
|
109
|
+
/** `list` locates sessions; each `attach` is the authoritative recovery state. */
|
|
110
|
+
private loadAuthoritativeSessions;
|
|
111
|
+
private parseHello;
|
|
112
|
+
private request;
|
|
113
|
+
private consume;
|
|
114
|
+
private resetFrameDecoder;
|
|
115
|
+
private handleFrame;
|
|
116
|
+
private handleResponse;
|
|
117
|
+
private routeEvent;
|
|
118
|
+
private queuePendingEvent;
|
|
119
|
+
/** Repair a bounded event-buffer overflow without replaying a partial stream. */
|
|
120
|
+
private refreshSession;
|
|
121
|
+
/**
|
|
122
|
+
* Render 主动告知当前会话集合(例如自身清掉了已 forget 的会话)。不在
|
|
123
|
+
* 集合里的会话要给既有句柄补一个退出事件,否则 ProcessManager 会永远停在 running。
|
|
124
|
+
*/
|
|
125
|
+
private handleReconcileEvent;
|
|
126
|
+
/**
|
|
127
|
+
* Socket 断开后的重连。不做重连的话,Render 重启一次所有
|
|
128
|
+
* RemoteRenderProcess 就会静默失效,而 ProcessManager 仍显示 running。
|
|
129
|
+
*/
|
|
130
|
+
private handleDisconnect;
|
|
131
|
+
/** 被同一个凭据反复拒绝时置位:下一次重连改用长退避(见 `scheduleReconnect`)。 */
|
|
132
|
+
private authBackoff;
|
|
133
|
+
/**
|
|
134
|
+
* 安排下一次重连(已有定时器时不重排:一次失败可能会从 close/error 两条路径
|
|
135
|
+
* 各调一次,重排会把退避倍率叠成指数增长)。需要**覆盖**已有定时器的场景
|
|
136
|
+
* (鉴权失败要把 10s 换成 60s)由调用方显式清掉再调。
|
|
137
|
+
*/
|
|
138
|
+
private scheduleReconnect;
|
|
139
|
+
private tryReconnect;
|
|
140
|
+
/**
|
|
141
|
+
* 重连失败的日志与「同一把废 token」判定。
|
|
142
|
+
*
|
|
143
|
+
* 判定依据:刚刚用掉的那把凭据(`activeToken`,每次连接开头从 token 文件重读)
|
|
144
|
+
* 与文件里**现在**这一把相同 → 再试同一个值不可能成功(对端持有的是别的 token,
|
|
145
|
+
* 多来自 `-c` 指到了另一个 config 或有人在手工改 token 文件),摆成 60s 长退避。
|
|
146
|
+
* 文件已经变了就按普通退避重试 —— 那正是 daemon 重启轮换 token 后的自愈路径。
|
|
147
|
+
* @returns 是否处于「同一把废凭据」状态(调用方据此换长退避)
|
|
148
|
+
*/
|
|
149
|
+
private noteReconnectFailure;
|
|
150
|
+
/** 只读 token 文件当前值(不改状态);读不到返回 null。 */
|
|
151
|
+
private currentTokenFileValue;
|
|
152
|
+
/**
|
|
153
|
+
* 断线期间 Render 可能新建/结束会话。用断线前的 inventory 与新的 `list` 对账:
|
|
154
|
+
* 活着的补发缺口 chunk;消失或已退出的给句柄补合成退出。
|
|
155
|
+
*/
|
|
156
|
+
private reconcileAfterReconnect;
|
|
157
|
+
private resultFromState;
|
|
158
|
+
private rejectPending;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 运行期校验 Render 的 SessionState。
|
|
162
|
+
*
|
|
163
|
+
* 协议是跨语言契约(Rust 侧字段名漂移过一次就是静默的空终端),所以这里不做
|
|
164
|
+
* 结构断言直接使用,而是逐字段检查:能修的补默认值,修不了的整条丢弃并打警告。
|
|
165
|
+
*/
|
|
166
|
+
export declare function normalizeRenderSessionState(value: unknown): TerminalSessionState | null;
|
|
167
|
+
/**
|
|
168
|
+
* 连接一个已经存在的 Render(socket + token 都在)。**不 spawn**,找不到就返回 null,
|
|
169
|
+
* 这样调用方可以区分「已被别处 adopt」和「需要自己拉起」。
|
|
170
|
+
*/
|
|
171
|
+
export declare function connectExistingRenderClient(configPath: string, knownSessionIds?: readonly string[]): Promise<RenderDaemonClient | null>;
|