@zqagent/shared 0.0.0-stage → 0.3.8
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 +190 -0
- package/README.md +21 -2
- package/dist/approval-view.cjs +99 -0
- package/dist/approval-view.cjs.map +1 -0
- package/dist/approval-view.d.cts +39 -0
- package/dist/approval-view.d.ts +39 -0
- package/dist/approval-view.js +69 -0
- package/dist/approval-view.js.map +1 -0
- package/dist/fleet.cjs +263 -0
- package/dist/fleet.cjs.map +1 -0
- package/dist/fleet.d.cts +284 -0
- package/dist/fleet.d.ts +284 -0
- package/dist/fleet.js +214 -0
- package/dist/fleet.js.map +1 -0
- package/dist/hub-api.cjs +901 -0
- package/dist/hub-api.cjs.map +1 -0
- package/dist/hub-api.d.cts +1677 -0
- package/dist/hub-api.d.ts +1677 -0
- package/dist/hub-api.js +776 -0
- package/dist/hub-api.js.map +1 -0
- package/dist/index-DokiNlGJ.d.cts +182 -0
- package/dist/index-DokiNlGJ.d.ts +182 -0
- package/dist/index.cjs +861 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +779 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-presets.cjs +92 -0
- package/dist/llm-presets.cjs.map +1 -0
- package/dist/llm-presets.d.cts +28 -0
- package/dist/llm-presets.d.ts +28 -0
- package/dist/llm-presets.js +66 -0
- package/dist/llm-presets.js.map +1 -0
- package/dist/media.cjs +111 -0
- package/dist/media.cjs.map +1 -0
- package/dist/media.d.cts +59 -0
- package/dist/media.d.ts +59 -0
- package/dist/media.js +79 -0
- package/dist/media.js.map +1 -0
- package/dist/messages-CiXjdR1Z.d.cts +257 -0
- package/dist/messages-CiXjdR1Z.d.ts +257 -0
- package/dist/model-capabilities.cjs +105 -0
- package/dist/model-capabilities.cjs.map +1 -0
- package/dist/model-capabilities.d.cts +46 -0
- package/dist/model-capabilities.d.ts +46 -0
- package/dist/model-capabilities.js +74 -0
- package/dist/model-capabilities.js.map +1 -0
- package/dist/notify/index.cjs +375 -0
- package/dist/notify/index.cjs.map +1 -0
- package/dist/notify/index.d.cts +2 -0
- package/dist/notify/index.d.ts +2 -0
- package/dist/notify/index.js +330 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/secrets.cjs +121 -0
- package/dist/secrets.cjs.map +1 -0
- package/dist/secrets.d.cts +25 -0
- package/dist/secrets.d.ts +25 -0
- package/dist/secrets.js +82 -0
- package/dist/secrets.js.map +1 -0
- package/dist/wire/index.cjs +1265 -0
- package/dist/wire/index.cjs.map +1 -0
- package/dist/wire/index.d.cts +199 -0
- package/dist/wire/index.d.ts +199 -0
- package/dist/wire/index.js +1181 -0
- package/dist/wire/index.js.map +1 -0
- package/dist/wire/node.cjs +224 -0
- package/dist/wire/node.cjs.map +1 -0
- package/dist/wire/node.d.cts +14 -0
- package/dist/wire/node.d.ts +14 -0
- package/dist/wire/node.js +195 -0
- package/dist/wire/node.js.map +1 -0
- package/package.json +99 -3
package/dist/fleet.cjs
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/fleet.ts
|
|
31
|
+
var fleet_exports = {};
|
|
32
|
+
__export(fleet_exports, {
|
|
33
|
+
DEFAULT_CLOCK_SKEW_MS: () => DEFAULT_CLOCK_SKEW_MS,
|
|
34
|
+
FLEET_CMD_TYPES: () => FLEET_CMD_TYPES,
|
|
35
|
+
FLEET_TOPIC_PREFIX: () => FLEET_TOPIC_PREFIX,
|
|
36
|
+
NonceTracker: () => NonceTracker,
|
|
37
|
+
fleetAckTopic: () => fleetAckTopic,
|
|
38
|
+
fleetCmdTopic: () => fleetCmdTopic,
|
|
39
|
+
fleetEventsTopic: () => fleetEventsTopic,
|
|
40
|
+
fleetInfoTopic: () => fleetInfoTopic,
|
|
41
|
+
fleetNotifyTopic: () => fleetNotifyTopic,
|
|
42
|
+
fleetStatusTopic: () => fleetStatusTopic,
|
|
43
|
+
generateToken: () => generateToken,
|
|
44
|
+
isFreshTimestamp: () => isFreshTimestamp,
|
|
45
|
+
parseFleetEnvelope: () => parseFleetEnvelope,
|
|
46
|
+
signFleetCmd: () => signFleetCmd,
|
|
47
|
+
verifyFleetSig: () => verifyFleetSig
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(fleet_exports);
|
|
50
|
+
var crypto2 = __toESM(require("crypto"), 1);
|
|
51
|
+
|
|
52
|
+
// src/common.ts
|
|
53
|
+
var crypto = __toESM(require("crypto"), 1);
|
|
54
|
+
var DEFAULT_CLOCK_SKEW_MS = 6e4;
|
|
55
|
+
function generateToken(bytes = 32) {
|
|
56
|
+
return crypto.randomBytes(bytes).toString("base64url");
|
|
57
|
+
}
|
|
58
|
+
function isFreshTimestamp(t, now = Date.now(), skewMs = DEFAULT_CLOCK_SKEW_MS) {
|
|
59
|
+
return typeof t === "number" && Number.isFinite(t) && Math.abs(now - t) <= skewMs;
|
|
60
|
+
}
|
|
61
|
+
var NonceTracker = class {
|
|
62
|
+
constructor(ttlMs = DEFAULT_CLOCK_SKEW_MS * 5) {
|
|
63
|
+
this.ttlMs = ttlMs;
|
|
64
|
+
}
|
|
65
|
+
ttlMs;
|
|
66
|
+
seen = /* @__PURE__ */ new Map();
|
|
67
|
+
/** 返回 true 表示首次见到(可用);false 表示重放 */
|
|
68
|
+
checkAndRecord(nonce, now = Date.now()) {
|
|
69
|
+
this.prune(now);
|
|
70
|
+
if (this.seen.has(nonce)) return false;
|
|
71
|
+
this.seen.set(nonce, now);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
prune(now) {
|
|
75
|
+
for (const [k, ts] of this.seen) {
|
|
76
|
+
if (now - ts > this.ttlMs) this.seen.delete(k);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/fleet.ts
|
|
82
|
+
var FLEET_TOPIC_PREFIX = "zqagent/fleet";
|
|
83
|
+
var FLEET_CMD_TYPES = [
|
|
84
|
+
"ping",
|
|
85
|
+
"get_node_info",
|
|
86
|
+
"get_node_host",
|
|
87
|
+
"list_projects",
|
|
88
|
+
"create_project",
|
|
89
|
+
"delete_project",
|
|
90
|
+
"list_sessions",
|
|
91
|
+
"get_session_states",
|
|
92
|
+
"create_session",
|
|
93
|
+
"delete_session",
|
|
94
|
+
"get_state",
|
|
95
|
+
"get_events",
|
|
96
|
+
"get_session_turns",
|
|
97
|
+
"get_session_turn_reply",
|
|
98
|
+
"read_session_attachment",
|
|
99
|
+
"get_session_changes",
|
|
100
|
+
"get_session_change_diff",
|
|
101
|
+
"restore_session_change",
|
|
102
|
+
"get_config",
|
|
103
|
+
"update_config",
|
|
104
|
+
"list_models",
|
|
105
|
+
"list_dirs",
|
|
106
|
+
"make_dir",
|
|
107
|
+
"search_dirs",
|
|
108
|
+
"list_files",
|
|
109
|
+
"read_file",
|
|
110
|
+
"read_file_range",
|
|
111
|
+
"file_ticket",
|
|
112
|
+
"download_file",
|
|
113
|
+
"write_file",
|
|
114
|
+
"write_file_base64",
|
|
115
|
+
"create_dir",
|
|
116
|
+
"create_file",
|
|
117
|
+
"delete_files",
|
|
118
|
+
"search_files",
|
|
119
|
+
"search_content",
|
|
120
|
+
"rename_path",
|
|
121
|
+
"move_paths",
|
|
122
|
+
"zip_download",
|
|
123
|
+
"list_tools",
|
|
124
|
+
"list_mcp",
|
|
125
|
+
"update_mcp",
|
|
126
|
+
"test_mcp",
|
|
127
|
+
"project_stats",
|
|
128
|
+
"run_command",
|
|
129
|
+
"list_shell_tasks",
|
|
130
|
+
"kill_shell_task",
|
|
131
|
+
"terminal_list",
|
|
132
|
+
"terminal_create",
|
|
133
|
+
"terminal_replay",
|
|
134
|
+
"terminal_close",
|
|
135
|
+
"terminal_remove",
|
|
136
|
+
"terminal_rename",
|
|
137
|
+
"terminal_history",
|
|
138
|
+
"terminal_settings",
|
|
139
|
+
"terminal_update_settings",
|
|
140
|
+
"git_repos",
|
|
141
|
+
"git_status",
|
|
142
|
+
"git_diff",
|
|
143
|
+
"git_branches",
|
|
144
|
+
"git_refs",
|
|
145
|
+
"git_log",
|
|
146
|
+
"git_show",
|
|
147
|
+
"git_fetch",
|
|
148
|
+
"git_stage",
|
|
149
|
+
"git_unstage",
|
|
150
|
+
"git_commit",
|
|
151
|
+
"git_commit_message",
|
|
152
|
+
"git_checkout",
|
|
153
|
+
"git_pull",
|
|
154
|
+
"git_push",
|
|
155
|
+
"set_node_label",
|
|
156
|
+
"get_usage_summary",
|
|
157
|
+
"get_llm_balance",
|
|
158
|
+
"get_usage_records",
|
|
159
|
+
"get_usage_pricing",
|
|
160
|
+
"update_usage_pricing",
|
|
161
|
+
"get_node_llm",
|
|
162
|
+
"update_node_llm",
|
|
163
|
+
"self_update",
|
|
164
|
+
"refresh_builtin_llm",
|
|
165
|
+
"list_node_llm_models",
|
|
166
|
+
"set_fleet_cred",
|
|
167
|
+
"rename_session",
|
|
168
|
+
"set_session_model",
|
|
169
|
+
"set_session_llm",
|
|
170
|
+
"set_session_mode",
|
|
171
|
+
"set_session_lang",
|
|
172
|
+
"set_session_draft",
|
|
173
|
+
"submit_turn",
|
|
174
|
+
"steer",
|
|
175
|
+
"unsteer",
|
|
176
|
+
"interrupt",
|
|
177
|
+
"resume",
|
|
178
|
+
"approval_answer",
|
|
179
|
+
"question_answer",
|
|
180
|
+
"batch"
|
|
181
|
+
];
|
|
182
|
+
function fleetCmdTopic(fleetToken, nodeId) {
|
|
183
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/cmd`;
|
|
184
|
+
}
|
|
185
|
+
function fleetNotifyTopic(fleetToken, nodeId) {
|
|
186
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/notify`;
|
|
187
|
+
}
|
|
188
|
+
function fleetEventsTopic(fleetToken, nodeId) {
|
|
189
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/events`;
|
|
190
|
+
}
|
|
191
|
+
function fleetStatusTopic(fleetToken, nodeId) {
|
|
192
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/status`;
|
|
193
|
+
}
|
|
194
|
+
function fleetInfoTopic(fleetToken, nodeId) {
|
|
195
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/info`;
|
|
196
|
+
}
|
|
197
|
+
function fleetAckTopic(fleetToken, nodeId, clientId) {
|
|
198
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/ack/${clientId}`;
|
|
199
|
+
}
|
|
200
|
+
function canonical(env) {
|
|
201
|
+
return JSON.stringify([
|
|
202
|
+
env.t,
|
|
203
|
+
env.nonce,
|
|
204
|
+
env.reqId,
|
|
205
|
+
env.type,
|
|
206
|
+
env.clientId,
|
|
207
|
+
env.nodeId,
|
|
208
|
+
env.projectId ?? "",
|
|
209
|
+
env.sessionId ?? "",
|
|
210
|
+
env.payload
|
|
211
|
+
]);
|
|
212
|
+
}
|
|
213
|
+
function signFleetCmd(secret, env) {
|
|
214
|
+
return crypto2.createHmac("sha256", Buffer.from(secret, "utf8")).update(canonical(env)).digest("base64url");
|
|
215
|
+
}
|
|
216
|
+
function verifyFleetSig(secret, env) {
|
|
217
|
+
if (typeof env.sig !== "string" || env.sig.length === 0) return false;
|
|
218
|
+
const expected = signFleetCmd(secret, env);
|
|
219
|
+
const a = Buffer.from(expected, "utf8");
|
|
220
|
+
const b = Buffer.from(env.sig, "utf8");
|
|
221
|
+
if (a.length !== b.length) return false;
|
|
222
|
+
return crypto2.timingSafeEqual(a, b);
|
|
223
|
+
}
|
|
224
|
+
function parseFleetEnvelope(raw) {
|
|
225
|
+
if (!raw || typeof raw !== "object") return null;
|
|
226
|
+
const o = raw;
|
|
227
|
+
if (typeof o.t !== "number" || typeof o.nonce !== "string" || typeof o.reqId !== "string" || typeof o.type !== "string" || typeof o.clientId !== "string" || typeof o.nodeId !== "string" || typeof o.sig !== "string") {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
if (!FLEET_CMD_TYPES.includes(o.type)) return null;
|
|
231
|
+
if (!o.payload || typeof o.payload !== "object") return null;
|
|
232
|
+
return {
|
|
233
|
+
t: o.t,
|
|
234
|
+
nonce: o.nonce,
|
|
235
|
+
reqId: o.reqId,
|
|
236
|
+
type: o.type,
|
|
237
|
+
clientId: o.clientId,
|
|
238
|
+
nodeId: o.nodeId,
|
|
239
|
+
projectId: typeof o.projectId === "string" ? o.projectId : void 0,
|
|
240
|
+
sessionId: typeof o.sessionId === "string" ? o.sessionId : void 0,
|
|
241
|
+
payload: o.payload,
|
|
242
|
+
sig: o.sig
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
246
|
+
0 && (module.exports = {
|
|
247
|
+
DEFAULT_CLOCK_SKEW_MS,
|
|
248
|
+
FLEET_CMD_TYPES,
|
|
249
|
+
FLEET_TOPIC_PREFIX,
|
|
250
|
+
NonceTracker,
|
|
251
|
+
fleetAckTopic,
|
|
252
|
+
fleetCmdTopic,
|
|
253
|
+
fleetEventsTopic,
|
|
254
|
+
fleetInfoTopic,
|
|
255
|
+
fleetNotifyTopic,
|
|
256
|
+
fleetStatusTopic,
|
|
257
|
+
generateToken,
|
|
258
|
+
isFreshTimestamp,
|
|
259
|
+
parseFleetEnvelope,
|
|
260
|
+
signFleetCmd,
|
|
261
|
+
verifyFleetSig
|
|
262
|
+
});
|
|
263
|
+
//# sourceMappingURL=fleet.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fleet.ts","../src/common.ts"],"sourcesContent":["/**\n * MQTT 节点管理协议 v2(控制台 ↔ 多终端设备)\n *\n * 与 v1(`protocol.ts`,按租户、deviceId 的手机控制)并存。v2 面向\n * 「公网控制台管理多台终端 Agent 实例」:\n *\n * - **按节点寻址**:topic 含 `node/{nodeId}`,每个节点只订阅自己的 cmd;\n * - **在线状态**:`status` retained + LWT(遗嘱)自动上线/离线,`info` retained\n * (能力/项目快照,上线即重建节点管理视图);\n * - **请求-响应关联**:命令带 `reqId`,回执(ack)回带同一 `reqId`;\n * - **签名密钥**:节点管理级 `fleetSecret`(自托管单所有者模型;每节点独立密钥留待 P3)。\n *\n * 安全前提同 v1:broker 可无认证/ACL,隔离靠「高熵 fleetToken 命名空间 + HMAC 签名」。\n */\nimport * as crypto from \"crypto\";\nimport {\n DEFAULT_CLOCK_SKEW_MS,\n NonceTracker,\n generateToken,\n isFreshTimestamp,\n} from \"./common.js\";\n\nexport { NonceTracker, generateToken, isFreshTimestamp, DEFAULT_CLOCK_SKEW_MS };\n\n/** topic 根前缀 */\nexport const FLEET_TOPIC_PREFIX = \"zqagent/fleet\";\n\n/**\n * 会话状态条目(跨节点总览的唯一数据形状)。\n *\n * 刻意只包含「标识 + 状态」:消息、模型、token 等明细由会话详情页按需拉取。\n * 节点经 info `detail.sessions` 上报全量快照,状态变化经 notify `session_status`\n * 增量推送;接口(REST / 指令)也用同一形状。\n */\n/**\n * 会话状态条目(跨节点总览的唯一数据形状)。\n *\n * - `status` 取 `SessionStatus` 的状态值;另有一个**伪状态** `\"deleted\"`:\n * 会话已删除,只出现在 `session_status` 通知里(不落盘、不进状态机),\n * 供常开的总览页面立即移除该行。\n * - 只含标识与状态:消息、模型、token 等明细由会话详情页按需拉取。\n */\nexport interface SessionStateEntry {\n projectId: string;\n /** 项目展示名(节点侧填充;详情快照里由 projects 补齐) */\n projectName: string;\n sessionId: string;\n name: string | null;\n status: string;\n /** 用户最近一条发送给 Agent 的消息(截断,供总览列表展示;无消息时 null) */\n lastUserMessage?: string | null;\n /**\n * 最近一次**任务请求的开始时刻**(ISO 8601;从未发起过任务时 null)。\n *\n * 工作台的节点/项目/任务列表统一按它倒序——用户找的是「最近在跑什么」,\n * 而不是「最近什么时候跑完的」:长任务运行中时 lastCompletedAt 还是上一轮的,\n * 按它排会把正在干活的排到后面。\n */\n lastStartedAt?: string | null;\n /** 最近一次任务成功完成的时刻(ISO 8601;从未完成时 null) */\n lastCompletedAt?: string | null;\n}\n\n/** 命令类型(控制台 → 节点) */\nexport type FleetCmdType =\n | \"ping\"\n | \"get_node_info\"\n | \"get_node_host\"\n | \"list_projects\"\n | \"create_project\"\n | \"delete_project\"\n | \"list_sessions\"\n /** 跨项目会话状态(只含标识与 status,供节点首页/工作台总览) */\n | \"get_session_states\"\n | \"create_session\"\n | \"delete_session\"\n | \"get_state\"\n | \"get_events\"\n /** 会话轮次汇总(轻量:标题 + 统计,点开某轮再取事件) */\n | \"get_session_turns\"\n /** 单轮详情:用户消息(含补充)+ 最终回复 + 产出文件 */\n | \"get_session_turn_reply\"\n /** 读取聊天记录里保存的附件(用户消息的图片 / 文件) */\n | \"read_session_attachment\"\n /** 变更追踪:本会话的快照列表(每轮一个) */\n | \"get_session_changes\"\n /** 变更追踪:某个快照的完整 patch */\n | \"get_session_change_diff\"\n /** 变更追踪:从快照恢复文件(会改工作区) */\n | \"restore_session_change\"\n | \"get_config\"\n | \"update_config\"\n | \"list_models\"\n | \"list_dirs\"\n | \"make_dir\"\n | \"search_dirs\"\n | \"list_files\"\n | \"read_file\"\n /** 按区间读取文件(音视频预览的数据面;回执为 base64 块,单块 ≤1MB) */\n | \"read_file_range\"\n /**\n * 签发媒体播放票据。\n *\n * `<video>` 发不了 Authorization 头,所以由节点用 fleetSecret 签一张只授权\n * 单个文件、10 分钟有效的票据,网关用同一密钥验签后提供 HTTP Range。\n */\n | \"file_ticket\"\n | \"download_file\"\n | \"write_file\"\n /** 按 base64 写入二进制文件(图片编辑后保存) */\n | \"write_file_base64\"\n | \"create_dir\"\n | \"create_file\"\n | \"delete_files\"\n | \"search_files\"\n /** 在文件**内容**里搜索关键字(返回行号与命中片段) */\n | \"search_content\"\n /** 重命名文件 / 目录(只改同一目录下的名字) */\n | \"rename_path\"\n /** 把文件 / 目录移动到工作区内的目标目录(拖拽移动) */\n | \"move_paths\"\n /** 压缩下载:把选中的文件 / 目录打包成 zip(超过上限直接拒绝) */\n | \"zip_download\"\n | \"list_tools\"\n | \"list_mcp\"\n /** 整体替换项目的 MCP 服务器配置(控制台设置页保存) */\n | \"update_mcp\"\n /** 连接测试单个 MCP 服务器(不落盘) */\n | \"test_mcp\"\n | \"project_stats\"\n | \"run_command\"\n | \"list_shell_tasks\"\n | \"kill_shell_task\"\n // ---------- 交互式终端(控制台「终端」面板) ----------\n // 只承载低频控制动作;用户按键(input)与窗口尺寸(resize)走\n // `FrameType.TERMINAL` 独立帧通道——那条路不等 ACK、不占单节点串行指令队列。\n /** 列出项目下的终端(含已退出未删除的) */\n | \"terminal_list\"\n /** 新建终端(多终端并行:每次一个新进程) */\n | \"terminal_create\"\n /** 取回放缓冲(≤200KB)与元信息:切页签 / 断线重连用 */\n | \"terminal_replay\"\n /** 关闭进程(SIGTERM → 2s → SIGKILL),保留历史与元信息 */\n | \"terminal_close\"\n /** 关闭并删除历史(不可恢复) */\n | \"terminal_remove\"\n | \"terminal_rename\"\n /** 命令/输出/退出历史(受保留期与落盘限速约束) */\n | \"terminal_history\"\n /** 终端设置(当前只有 retentionDays,默认 30 天) */\n | \"terminal_settings\"\n | \"terminal_update_settings\"\n | \"git_repos\"\n | \"git_status\"\n | \"git_diff\"\n | \"git_branches\"\n | \"git_refs\"\n | \"git_log\"\n | \"git_show\"\n | \"git_fetch\"\n | \"git_stage\"\n | \"git_unstage\"\n | \"git_commit\"\n /** AI 生成提交说明(节点侧调用 LLM) */\n | \"git_commit_message\"\n | \"git_checkout\"\n | \"git_pull\"\n | \"git_push\"\n | \"set_node_label\"\n | \"get_usage_summary\"\n /** 大模型账户余额(控制台「余额不足」时查看/充值用) */\n | \"get_llm_balance\"\n | \"get_usage_records\"\n | \"get_usage_pricing\"\n | \"update_usage_pricing\"\n | \"get_node_llm\"\n | \"update_node_llm\"\n /**\n * 节点自更新(自更新仅在「SEA 单文件 + 服务托管 + 配置验签公钥」时可用):\n * payload.action = \"status\" | \"check\" | \"install\"\n * payload.force = true 时立即安装(不等空闲,会打断运行中的任务)\n *\n * install 先回执、后在后台下载安装并退出进程,由 systemd/launchd 拉起新版本;\n * 因此**回执成功不等于已升级**,需再用 status 确认版本。\n */\n | \"self_update\"\n /**\n * 重新拉取平台内置模型(志前 API)的凭据。\n *\n * 内置模型在接入 Hub 时下发,正常情况下用户无需关心;这里用于\n * 「Key 在控制台被重置」或用户在控制台点「刷新」时重取。\n * 会改写节点侧的 LLM 配置,属写指令(不参与只读并发池)。\n */\n | \"refresh_builtin_llm\"\n | \"list_node_llm_models\"\n | \"set_fleet_cred\"\n | \"rename_session\"\n | \"set_session_model\"\n | \"set_session_llm\"\n | \"set_session_mode\"\n | \"set_session_lang\"\n | \"set_session_draft\"\n | \"submit_turn\"\n | \"steer\"\n | \"unsteer\"\n | \"interrupt\"\n | \"resume\"\n | \"approval_answer\"\n | \"question_answer\"\n /**\n * 批量指令:payload.commands 为子指令数组,节点顺序/并发执行后\n * 在单条回执的 data.results 中按序返回各子指令结果(减少往返与请求数)。\n */\n | \"batch\";\n\nexport const FLEET_CMD_TYPES: readonly FleetCmdType[] = [\n \"ping\",\n \"get_node_info\",\n \"get_node_host\",\n \"list_projects\",\n \"create_project\",\n \"delete_project\",\n \"list_sessions\",\n \"get_session_states\",\n \"create_session\",\n \"delete_session\",\n \"get_state\",\n \"get_events\",\n \"get_session_turns\",\n \"get_session_turn_reply\",\n \"read_session_attachment\",\n \"get_session_changes\",\n \"get_session_change_diff\",\n \"restore_session_change\",\n \"get_config\",\n \"update_config\",\n \"list_models\",\n \"list_dirs\",\n \"make_dir\",\n \"search_dirs\",\n \"list_files\",\n \"read_file\",\n \"read_file_range\",\n \"file_ticket\",\n \"download_file\",\n \"write_file\",\n \"write_file_base64\",\n \"create_dir\",\n \"create_file\",\n \"delete_files\",\n \"search_files\",\n \"search_content\",\n \"rename_path\",\n \"move_paths\",\n \"zip_download\",\n \"list_tools\",\n \"list_mcp\",\n \"update_mcp\",\n \"test_mcp\",\n \"project_stats\",\n \"run_command\",\n \"list_shell_tasks\",\n \"kill_shell_task\",\n \"terminal_list\",\n \"terminal_create\",\n \"terminal_replay\",\n \"terminal_close\",\n \"terminal_remove\",\n \"terminal_rename\",\n \"terminal_history\",\n \"terminal_settings\",\n \"terminal_update_settings\",\n \"git_repos\",\n \"git_status\",\n \"git_diff\",\n \"git_branches\",\n \"git_refs\",\n \"git_log\",\n \"git_show\",\n \"git_fetch\",\n \"git_stage\",\n \"git_unstage\",\n \"git_commit\",\n \"git_commit_message\",\n \"git_checkout\",\n \"git_pull\",\n \"git_push\",\n \"set_node_label\",\n \"get_usage_summary\",\n \"get_llm_balance\",\n \"get_usage_records\",\n \"get_usage_pricing\",\n \"update_usage_pricing\",\n \"get_node_llm\",\n \"update_node_llm\",\n \"self_update\",\n \"refresh_builtin_llm\",\n \"list_node_llm_models\",\n \"set_fleet_cred\",\n \"rename_session\",\n \"set_session_model\",\n \"set_session_llm\",\n \"set_session_mode\",\n \"set_session_lang\",\n \"set_session_draft\",\n \"submit_turn\",\n \"steer\",\n \"unsteer\",\n \"interrupt\",\n \"resume\",\n \"approval_answer\",\n \"question_answer\",\n \"batch\",\n];\n\n/** 批量指令的子指令(不含嵌套 batch) */\nexport interface FleetBatchSubCmd {\n type: Exclude<FleetCmdType, \"batch\">;\n projectId?: string;\n sessionId?: string;\n payload?: Record<string, unknown>;\n}\n\n/** 批量指令结果项(与请求按序对应) */\nexport interface FleetBatchResult {\n type: string;\n ok: boolean;\n data?: unknown;\n error?: string;\n}\n\n/** 命令信封 v2(含 HMAC 签名) */\nexport interface FleetCmdEnvelope {\n /** 时间戳(毫秒,±60s 窗口) */\n t: number;\n /** 一次性随机串(防重放) */\n nonce: string;\n /** 请求 ID(回执关联) */\n reqId: string;\n type: FleetCmdType;\n /** 发起控制台客户端 ID */\n clientId: string;\n /** 目标节点 ID */\n nodeId: string;\n /** 目标项目 ID(项目级命令) */\n projectId?: string;\n /** 目标会话 ID(会话级命令) */\n sessionId?: string;\n payload: Record<string, unknown>;\n /** HMAC-SHA256(fleetSecret, 规范化串) base64url */\n sig: string;\n}\n\n/** 命令回执(点对点回给 clientId) */\nexport interface FleetAckPayload {\n reqId: string;\n type: FleetCmdType;\n ok: boolean;\n error?: string;\n data?: unknown;\n}\n\n/** 节点在线状态(retained + LWT) */\nexport interface FleetStatus {\n nodeId: string;\n online: boolean;\n ts: string;\n /** 节点展示名(本地配置;Hub 改名后回写并随之上报) */\n label?: string;\n platform?: string;\n mode?: string;\n version?: string;\n /**\n * 节点自报的主 IP(网卡地址:首个非回环 IPv4,缺省 IPv6)。\n *\n * 它是内网地址,控制台展示节点公网 IP 时应以网关观察到的连接来源为准\n * (见 gateway `NodeStateInfo.peer_ip`)。\n */\n ip?: string;\n}\n\n/** 节点累计运行统计(info 上报;进程启动后累计) */\nexport interface FleetNodeStats {\n /** 完成的回合数(turn_end) */\n turns: number;\n /** 工具调用完成数(tool_finished) */\n toolCalls: number;\n /** 错误事件数(error) */\n errors: number;\n /** 累计输入 token(assistant_message.usage.input) */\n tokensIn: number;\n /** 累计输出 token */\n tokensOut: number;\n /** 统计起点(节点进程启动/桥接建立时间) */\n since: string;\n}\n\n/** 节点管理配对凭据(pairing API 下发) */\nexport interface FleetPairing {\n fleetToken: string;\n fleetSecret: string;\n nodeId: string;\n /** Rust 网关 wss 地址(控制面配置了才下发;节点据此直连网关) */\n gatewayUrl?: string;\n}\n\n/**\n * 节点本地持久化的云端接入凭据(`{DATA_DIR}/fleet.json`)。\n *\n * 由「凭注册码接入」(`POST /api/hub/enroll`)返回后落盘;节点启动时优先\n * 读取此文件,其次回退到环境变量(`FLEET_TOKEN` / `FLEET_SECRET`)。\n *\n * 「去 EMQX」后不再有 per-fleet broker 账号:网关鉴权用**全局** `GATEWAY_FLEET_SECRET`,\n * 因此凭据只需 fleetToken/fleetSecret(前者仅作命名空间标识)与网关地址。\n */\nexport interface FleetCredential {\n /** Hub 控制面地址(接入时使用,便于日后重新配对/展示) */\n hubUrl?: string;\n fleetToken: string;\n fleetSecret: string;\n nodeId: string;\n /**\n * Rust 网关 wss 地址(控制面在配对/接入时下发)。\n *\n * 它是节点接入云端的**唯一**传输,环境变量 `FLEET_GATEWAY_URL` 仅作覆盖。\n */\n gatewayUrl?: string;\n /** 节点展示名(可选) */\n label?: string;\n /** 接入时间(ISO 字符串) */\n enrolledAt?: string;\n /**\n * 平台内置大模型(志前 API):接入 Hub 时由控制面下发,节点侧落盘为\n * `id=__zqai__` 的不可删除供应商。\n *\n * 这里只是「接入那一刻的快照」;凭据轮换或首次缺失时,节点会调用\n * `GET /api/hub/node/builtin-llm` 重新拉取(见 core 的 builtinLlm.ts)。\n */\n builtinLlm?: BuiltinLlmGrant;\n}\n\n/** 平台内置模型的接入凭据(下发给节点) */\nexport interface BuiltinLlmGrant {\n /** 固定为 `__zqai__` */\n providerId: string;\n /** 展示名 */\n name: string;\n /** OpenAI 兼容基址,如 https://zqai-api.cd-zq.com/v1 */\n baseURL: string;\n /** 用户的 API Key(节点侧加密落盘) */\n apiKey: string;\n /** 默认模型 */\n model: string;\n /** 该账号可用的模型列表 */\n models?: string[];\n}\n\n/** topic 构建 */\nexport function fleetCmdTopic(fleetToken: string, nodeId: string): string {\n return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/cmd`;\n}\nexport function fleetNotifyTopic(fleetToken: string, nodeId: string): string {\n return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/notify`;\n}\nexport function fleetEventsTopic(fleetToken: string, nodeId: string): string {\n return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/events`;\n}\nexport function fleetStatusTopic(fleetToken: string, nodeId: string): string {\n return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/status`;\n}\nexport function fleetInfoTopic(fleetToken: string, nodeId: string): string {\n return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/info`;\n}\nexport function fleetAckTopic(\n fleetToken: string,\n nodeId: string,\n clientId: string,\n): string {\n return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/ack/${clientId}`;\n}\n\n/** 签名前的规范化串(字段顺序固定,两侧一致) */\nfunction canonical(env: Omit<FleetCmdEnvelope, \"sig\">): string {\n return JSON.stringify([\n env.t,\n env.nonce,\n env.reqId,\n env.type,\n env.clientId,\n env.nodeId,\n env.projectId ?? \"\",\n env.sessionId ?? \"\",\n env.payload,\n ]);\n}\n\n/** 计算 HMAC-SHA256 签名 */\nexport function signFleetCmd(\n secret: string,\n env: Omit<FleetCmdEnvelope, \"sig\">,\n): string {\n return crypto\n .createHmac(\"sha256\", Buffer.from(secret, \"utf8\"))\n .update(canonical(env))\n .digest(\"base64url\");\n}\n\n/** 常量时间比较校验签名 */\nexport function verifyFleetSig(secret: string, env: FleetCmdEnvelope): boolean {\n if (typeof env.sig !== \"string\" || env.sig.length === 0) return false;\n const expected = signFleetCmd(secret, env);\n const a = Buffer.from(expected, \"utf8\");\n const b = Buffer.from(env.sig, \"utf8\");\n if (a.length !== b.length) return false;\n return crypto.timingSafeEqual(a, b);\n}\n\n/** 解析并校验命令信封结构(不校验签名;签名由调用方验) */\nexport function parseFleetEnvelope(raw: unknown): FleetCmdEnvelope | null {\n if (!raw || typeof raw !== \"object\") return null;\n const o = raw as Record<string, unknown>;\n if (\n typeof o.t !== \"number\" ||\n typeof o.nonce !== \"string\" ||\n typeof o.reqId !== \"string\" ||\n typeof o.type !== \"string\" ||\n typeof o.clientId !== \"string\" ||\n typeof o.nodeId !== \"string\" ||\n typeof o.sig !== \"string\"\n ) {\n return null;\n }\n if (!FLEET_CMD_TYPES.includes(o.type as FleetCmdType)) return null;\n if (!o.payload || typeof o.payload !== \"object\") return null;\n return {\n t: o.t,\n nonce: o.nonce,\n reqId: o.reqId,\n type: o.type as FleetCmdType,\n clientId: o.clientId,\n nodeId: o.nodeId,\n projectId: typeof o.projectId === \"string\" ? o.projectId : undefined,\n sessionId: typeof o.sessionId === \"string\" ? o.sessionId : undefined,\n payload: o.payload as Record<string, unknown>,\n sig: o.sig,\n };\n}\n","/**\n * 共享通用工具(节点管理协议与 MQTT 相关)\n *\n * 从 v1 协议层抽出,供节点管理协议(node 与 hub 共用)使用,避免 shared 依赖 core。\n */\nimport * as crypto from \"crypto\";\n\n/** 时间戳允许的最大时钟偏差(毫秒) */\nexport const DEFAULT_CLOCK_SKEW_MS = 60_000;\n\n/** 生成高熵随机 token(base64url,默认 32 字节) */\nexport function generateToken(bytes = 32): string {\n return crypto.randomBytes(bytes).toString(\"base64url\");\n}\n\n/** 时间戳是否在允许窗口内(防重放) */\nexport function isFreshTimestamp(\n t: number,\n now = Date.now(),\n skewMs = DEFAULT_CLOCK_SKEW_MS,\n): boolean {\n return typeof t === \"number\" && Number.isFinite(t) && Math.abs(now - t) <= skewMs;\n}\n\n/**\n * 一次性 nonce 去重器:记录已见 nonce(带过期清理),拒绝重放。\n * 每个 MQTT 连接(租户/节点)持有一个实例。\n */\nexport class NonceTracker {\n private readonly seen = new Map<string, number>();\n\n constructor(private readonly ttlMs = DEFAULT_CLOCK_SKEW_MS * 5) {}\n\n /** 返回 true 表示首次见到(可用);false 表示重放 */\n checkAndRecord(nonce: string, now = Date.now()): boolean {\n this.prune(now);\n if (this.seen.has(nonce)) return false;\n this.seen.set(nonce, now);\n return true;\n }\n\n private prune(now: number): void {\n for (const [k, ts] of this.seen) {\n if (now - ts > this.ttlMs) this.seen.delete(k);\n }\n }\n}\n"],"mappings":"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","names":["crypto"]}
|
package/dist/fleet.d.cts
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/** 时间戳允许的最大时钟偏差(毫秒) */
|
|
2
|
+
declare const DEFAULT_CLOCK_SKEW_MS = 60000;
|
|
3
|
+
/** 生成高熵随机 token(base64url,默认 32 字节) */
|
|
4
|
+
declare function generateToken(bytes?: number): string;
|
|
5
|
+
/** 时间戳是否在允许窗口内(防重放) */
|
|
6
|
+
declare function isFreshTimestamp(t: number, now?: number, skewMs?: number): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* 一次性 nonce 去重器:记录已见 nonce(带过期清理),拒绝重放。
|
|
9
|
+
* 每个 MQTT 连接(租户/节点)持有一个实例。
|
|
10
|
+
*/
|
|
11
|
+
declare class NonceTracker {
|
|
12
|
+
private readonly ttlMs;
|
|
13
|
+
private readonly seen;
|
|
14
|
+
constructor(ttlMs?: number);
|
|
15
|
+
/** 返回 true 表示首次见到(可用);false 表示重放 */
|
|
16
|
+
checkAndRecord(nonce: string, now?: number): boolean;
|
|
17
|
+
private prune;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** topic 根前缀 */
|
|
21
|
+
declare const FLEET_TOPIC_PREFIX = "zqagent/fleet";
|
|
22
|
+
/**
|
|
23
|
+
* 会话状态条目(跨节点总览的唯一数据形状)。
|
|
24
|
+
*
|
|
25
|
+
* 刻意只包含「标识 + 状态」:消息、模型、token 等明细由会话详情页按需拉取。
|
|
26
|
+
* 节点经 info `detail.sessions` 上报全量快照,状态变化经 notify `session_status`
|
|
27
|
+
* 增量推送;接口(REST / 指令)也用同一形状。
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* 会话状态条目(跨节点总览的唯一数据形状)。
|
|
31
|
+
*
|
|
32
|
+
* - `status` 取 `SessionStatus` 的状态值;另有一个**伪状态** `"deleted"`:
|
|
33
|
+
* 会话已删除,只出现在 `session_status` 通知里(不落盘、不进状态机),
|
|
34
|
+
* 供常开的总览页面立即移除该行。
|
|
35
|
+
* - 只含标识与状态:消息、模型、token 等明细由会话详情页按需拉取。
|
|
36
|
+
*/
|
|
37
|
+
interface SessionStateEntry {
|
|
38
|
+
projectId: string;
|
|
39
|
+
/** 项目展示名(节点侧填充;详情快照里由 projects 补齐) */
|
|
40
|
+
projectName: string;
|
|
41
|
+
sessionId: string;
|
|
42
|
+
name: string | null;
|
|
43
|
+
status: string;
|
|
44
|
+
/** 用户最近一条发送给 Agent 的消息(截断,供总览列表展示;无消息时 null) */
|
|
45
|
+
lastUserMessage?: string | null;
|
|
46
|
+
/**
|
|
47
|
+
* 最近一次**任务请求的开始时刻**(ISO 8601;从未发起过任务时 null)。
|
|
48
|
+
*
|
|
49
|
+
* 工作台的节点/项目/任务列表统一按它倒序——用户找的是「最近在跑什么」,
|
|
50
|
+
* 而不是「最近什么时候跑完的」:长任务运行中时 lastCompletedAt 还是上一轮的,
|
|
51
|
+
* 按它排会把正在干活的排到后面。
|
|
52
|
+
*/
|
|
53
|
+
lastStartedAt?: string | null;
|
|
54
|
+
/** 最近一次任务成功完成的时刻(ISO 8601;从未完成时 null) */
|
|
55
|
+
lastCompletedAt?: string | null;
|
|
56
|
+
}
|
|
57
|
+
/** 命令类型(控制台 → 节点) */
|
|
58
|
+
type FleetCmdType = "ping" | "get_node_info" | "get_node_host" | "list_projects" | "create_project" | "delete_project" | "list_sessions"
|
|
59
|
+
/** 跨项目会话状态(只含标识与 status,供节点首页/工作台总览) */
|
|
60
|
+
| "get_session_states" | "create_session" | "delete_session" | "get_state" | "get_events"
|
|
61
|
+
/** 会话轮次汇总(轻量:标题 + 统计,点开某轮再取事件) */
|
|
62
|
+
| "get_session_turns"
|
|
63
|
+
/** 单轮详情:用户消息(含补充)+ 最终回复 + 产出文件 */
|
|
64
|
+
| "get_session_turn_reply"
|
|
65
|
+
/** 读取聊天记录里保存的附件(用户消息的图片 / 文件) */
|
|
66
|
+
| "read_session_attachment"
|
|
67
|
+
/** 变更追踪:本会话的快照列表(每轮一个) */
|
|
68
|
+
| "get_session_changes"
|
|
69
|
+
/** 变更追踪:某个快照的完整 patch */
|
|
70
|
+
| "get_session_change_diff"
|
|
71
|
+
/** 变更追踪:从快照恢复文件(会改工作区) */
|
|
72
|
+
| "restore_session_change" | "get_config" | "update_config" | "list_models" | "list_dirs" | "make_dir" | "search_dirs" | "list_files" | "read_file"
|
|
73
|
+
/** 按区间读取文件(音视频预览的数据面;回执为 base64 块,单块 ≤1MB) */
|
|
74
|
+
| "read_file_range"
|
|
75
|
+
/**
|
|
76
|
+
* 签发媒体播放票据。
|
|
77
|
+
*
|
|
78
|
+
* `<video>` 发不了 Authorization 头,所以由节点用 fleetSecret 签一张只授权
|
|
79
|
+
* 单个文件、10 分钟有效的票据,网关用同一密钥验签后提供 HTTP Range。
|
|
80
|
+
*/
|
|
81
|
+
| "file_ticket" | "download_file" | "write_file"
|
|
82
|
+
/** 按 base64 写入二进制文件(图片编辑后保存) */
|
|
83
|
+
| "write_file_base64" | "create_dir" | "create_file" | "delete_files" | "search_files"
|
|
84
|
+
/** 在文件**内容**里搜索关键字(返回行号与命中片段) */
|
|
85
|
+
| "search_content"
|
|
86
|
+
/** 重命名文件 / 目录(只改同一目录下的名字) */
|
|
87
|
+
| "rename_path"
|
|
88
|
+
/** 把文件 / 目录移动到工作区内的目标目录(拖拽移动) */
|
|
89
|
+
| "move_paths"
|
|
90
|
+
/** 压缩下载:把选中的文件 / 目录打包成 zip(超过上限直接拒绝) */
|
|
91
|
+
| "zip_download" | "list_tools" | "list_mcp"
|
|
92
|
+
/** 整体替换项目的 MCP 服务器配置(控制台设置页保存) */
|
|
93
|
+
| "update_mcp"
|
|
94
|
+
/** 连接测试单个 MCP 服务器(不落盘) */
|
|
95
|
+
| "test_mcp" | "project_stats" | "run_command" | "list_shell_tasks" | "kill_shell_task"
|
|
96
|
+
/** 列出项目下的终端(含已退出未删除的) */
|
|
97
|
+
| "terminal_list"
|
|
98
|
+
/** 新建终端(多终端并行:每次一个新进程) */
|
|
99
|
+
| "terminal_create"
|
|
100
|
+
/** 取回放缓冲(≤200KB)与元信息:切页签 / 断线重连用 */
|
|
101
|
+
| "terminal_replay"
|
|
102
|
+
/** 关闭进程(SIGTERM → 2s → SIGKILL),保留历史与元信息 */
|
|
103
|
+
| "terminal_close"
|
|
104
|
+
/** 关闭并删除历史(不可恢复) */
|
|
105
|
+
| "terminal_remove" | "terminal_rename"
|
|
106
|
+
/** 命令/输出/退出历史(受保留期与落盘限速约束) */
|
|
107
|
+
| "terminal_history"
|
|
108
|
+
/** 终端设置(当前只有 retentionDays,默认 30 天) */
|
|
109
|
+
| "terminal_settings" | "terminal_update_settings" | "git_repos" | "git_status" | "git_diff" | "git_branches" | "git_refs" | "git_log" | "git_show" | "git_fetch" | "git_stage" | "git_unstage" | "git_commit"
|
|
110
|
+
/** AI 生成提交说明(节点侧调用 LLM) */
|
|
111
|
+
| "git_commit_message" | "git_checkout" | "git_pull" | "git_push" | "set_node_label" | "get_usage_summary"
|
|
112
|
+
/** 大模型账户余额(控制台「余额不足」时查看/充值用) */
|
|
113
|
+
| "get_llm_balance" | "get_usage_records" | "get_usage_pricing" | "update_usage_pricing" | "get_node_llm" | "update_node_llm"
|
|
114
|
+
/**
|
|
115
|
+
* 节点自更新(自更新仅在「SEA 单文件 + 服务托管 + 配置验签公钥」时可用):
|
|
116
|
+
* payload.action = "status" | "check" | "install"
|
|
117
|
+
* payload.force = true 时立即安装(不等空闲,会打断运行中的任务)
|
|
118
|
+
*
|
|
119
|
+
* install 先回执、后在后台下载安装并退出进程,由 systemd/launchd 拉起新版本;
|
|
120
|
+
* 因此**回执成功不等于已升级**,需再用 status 确认版本。
|
|
121
|
+
*/
|
|
122
|
+
| "self_update"
|
|
123
|
+
/**
|
|
124
|
+
* 重新拉取平台内置模型(志前 API)的凭据。
|
|
125
|
+
*
|
|
126
|
+
* 内置模型在接入 Hub 时下发,正常情况下用户无需关心;这里用于
|
|
127
|
+
* 「Key 在控制台被重置」或用户在控制台点「刷新」时重取。
|
|
128
|
+
* 会改写节点侧的 LLM 配置,属写指令(不参与只读并发池)。
|
|
129
|
+
*/
|
|
130
|
+
| "refresh_builtin_llm" | "list_node_llm_models" | "set_fleet_cred" | "rename_session" | "set_session_model" | "set_session_llm" | "set_session_mode" | "set_session_lang" | "set_session_draft" | "submit_turn" | "steer" | "unsteer" | "interrupt" | "resume" | "approval_answer" | "question_answer"
|
|
131
|
+
/**
|
|
132
|
+
* 批量指令:payload.commands 为子指令数组,节点顺序/并发执行后
|
|
133
|
+
* 在单条回执的 data.results 中按序返回各子指令结果(减少往返与请求数)。
|
|
134
|
+
*/
|
|
135
|
+
| "batch";
|
|
136
|
+
declare const FLEET_CMD_TYPES: readonly FleetCmdType[];
|
|
137
|
+
/** 批量指令的子指令(不含嵌套 batch) */
|
|
138
|
+
interface FleetBatchSubCmd {
|
|
139
|
+
type: Exclude<FleetCmdType, "batch">;
|
|
140
|
+
projectId?: string;
|
|
141
|
+
sessionId?: string;
|
|
142
|
+
payload?: Record<string, unknown>;
|
|
143
|
+
}
|
|
144
|
+
/** 批量指令结果项(与请求按序对应) */
|
|
145
|
+
interface FleetBatchResult {
|
|
146
|
+
type: string;
|
|
147
|
+
ok: boolean;
|
|
148
|
+
data?: unknown;
|
|
149
|
+
error?: string;
|
|
150
|
+
}
|
|
151
|
+
/** 命令信封 v2(含 HMAC 签名) */
|
|
152
|
+
interface FleetCmdEnvelope {
|
|
153
|
+
/** 时间戳(毫秒,±60s 窗口) */
|
|
154
|
+
t: number;
|
|
155
|
+
/** 一次性随机串(防重放) */
|
|
156
|
+
nonce: string;
|
|
157
|
+
/** 请求 ID(回执关联) */
|
|
158
|
+
reqId: string;
|
|
159
|
+
type: FleetCmdType;
|
|
160
|
+
/** 发起控制台客户端 ID */
|
|
161
|
+
clientId: string;
|
|
162
|
+
/** 目标节点 ID */
|
|
163
|
+
nodeId: string;
|
|
164
|
+
/** 目标项目 ID(项目级命令) */
|
|
165
|
+
projectId?: string;
|
|
166
|
+
/** 目标会话 ID(会话级命令) */
|
|
167
|
+
sessionId?: string;
|
|
168
|
+
payload: Record<string, unknown>;
|
|
169
|
+
/** HMAC-SHA256(fleetSecret, 规范化串) base64url */
|
|
170
|
+
sig: string;
|
|
171
|
+
}
|
|
172
|
+
/** 命令回执(点对点回给 clientId) */
|
|
173
|
+
interface FleetAckPayload {
|
|
174
|
+
reqId: string;
|
|
175
|
+
type: FleetCmdType;
|
|
176
|
+
ok: boolean;
|
|
177
|
+
error?: string;
|
|
178
|
+
data?: unknown;
|
|
179
|
+
}
|
|
180
|
+
/** 节点在线状态(retained + LWT) */
|
|
181
|
+
interface FleetStatus {
|
|
182
|
+
nodeId: string;
|
|
183
|
+
online: boolean;
|
|
184
|
+
ts: string;
|
|
185
|
+
/** 节点展示名(本地配置;Hub 改名后回写并随之上报) */
|
|
186
|
+
label?: string;
|
|
187
|
+
platform?: string;
|
|
188
|
+
mode?: string;
|
|
189
|
+
version?: string;
|
|
190
|
+
/**
|
|
191
|
+
* 节点自报的主 IP(网卡地址:首个非回环 IPv4,缺省 IPv6)。
|
|
192
|
+
*
|
|
193
|
+
* 它是内网地址,控制台展示节点公网 IP 时应以网关观察到的连接来源为准
|
|
194
|
+
* (见 gateway `NodeStateInfo.peer_ip`)。
|
|
195
|
+
*/
|
|
196
|
+
ip?: string;
|
|
197
|
+
}
|
|
198
|
+
/** 节点累计运行统计(info 上报;进程启动后累计) */
|
|
199
|
+
interface FleetNodeStats {
|
|
200
|
+
/** 完成的回合数(turn_end) */
|
|
201
|
+
turns: number;
|
|
202
|
+
/** 工具调用完成数(tool_finished) */
|
|
203
|
+
toolCalls: number;
|
|
204
|
+
/** 错误事件数(error) */
|
|
205
|
+
errors: number;
|
|
206
|
+
/** 累计输入 token(assistant_message.usage.input) */
|
|
207
|
+
tokensIn: number;
|
|
208
|
+
/** 累计输出 token */
|
|
209
|
+
tokensOut: number;
|
|
210
|
+
/** 统计起点(节点进程启动/桥接建立时间) */
|
|
211
|
+
since: string;
|
|
212
|
+
}
|
|
213
|
+
/** 节点管理配对凭据(pairing API 下发) */
|
|
214
|
+
interface FleetPairing {
|
|
215
|
+
fleetToken: string;
|
|
216
|
+
fleetSecret: string;
|
|
217
|
+
nodeId: string;
|
|
218
|
+
/** Rust 网关 wss 地址(控制面配置了才下发;节点据此直连网关) */
|
|
219
|
+
gatewayUrl?: string;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 节点本地持久化的云端接入凭据(`{DATA_DIR}/fleet.json`)。
|
|
223
|
+
*
|
|
224
|
+
* 由「凭注册码接入」(`POST /api/hub/enroll`)返回后落盘;节点启动时优先
|
|
225
|
+
* 读取此文件,其次回退到环境变量(`FLEET_TOKEN` / `FLEET_SECRET`)。
|
|
226
|
+
*
|
|
227
|
+
* 「去 EMQX」后不再有 per-fleet broker 账号:网关鉴权用**全局** `GATEWAY_FLEET_SECRET`,
|
|
228
|
+
* 因此凭据只需 fleetToken/fleetSecret(前者仅作命名空间标识)与网关地址。
|
|
229
|
+
*/
|
|
230
|
+
interface FleetCredential {
|
|
231
|
+
/** Hub 控制面地址(接入时使用,便于日后重新配对/展示) */
|
|
232
|
+
hubUrl?: string;
|
|
233
|
+
fleetToken: string;
|
|
234
|
+
fleetSecret: string;
|
|
235
|
+
nodeId: string;
|
|
236
|
+
/**
|
|
237
|
+
* Rust 网关 wss 地址(控制面在配对/接入时下发)。
|
|
238
|
+
*
|
|
239
|
+
* 它是节点接入云端的**唯一**传输,环境变量 `FLEET_GATEWAY_URL` 仅作覆盖。
|
|
240
|
+
*/
|
|
241
|
+
gatewayUrl?: string;
|
|
242
|
+
/** 节点展示名(可选) */
|
|
243
|
+
label?: string;
|
|
244
|
+
/** 接入时间(ISO 字符串) */
|
|
245
|
+
enrolledAt?: string;
|
|
246
|
+
/**
|
|
247
|
+
* 平台内置大模型(志前 API):接入 Hub 时由控制面下发,节点侧落盘为
|
|
248
|
+
* `id=__zqai__` 的不可删除供应商。
|
|
249
|
+
*
|
|
250
|
+
* 这里只是「接入那一刻的快照」;凭据轮换或首次缺失时,节点会调用
|
|
251
|
+
* `GET /api/hub/node/builtin-llm` 重新拉取(见 core 的 builtinLlm.ts)。
|
|
252
|
+
*/
|
|
253
|
+
builtinLlm?: BuiltinLlmGrant;
|
|
254
|
+
}
|
|
255
|
+
/** 平台内置模型的接入凭据(下发给节点) */
|
|
256
|
+
interface BuiltinLlmGrant {
|
|
257
|
+
/** 固定为 `__zqai__` */
|
|
258
|
+
providerId: string;
|
|
259
|
+
/** 展示名 */
|
|
260
|
+
name: string;
|
|
261
|
+
/** OpenAI 兼容基址,如 https://zqai-api.cd-zq.com/v1 */
|
|
262
|
+
baseURL: string;
|
|
263
|
+
/** 用户的 API Key(节点侧加密落盘) */
|
|
264
|
+
apiKey: string;
|
|
265
|
+
/** 默认模型 */
|
|
266
|
+
model: string;
|
|
267
|
+
/** 该账号可用的模型列表 */
|
|
268
|
+
models?: string[];
|
|
269
|
+
}
|
|
270
|
+
/** topic 构建 */
|
|
271
|
+
declare function fleetCmdTopic(fleetToken: string, nodeId: string): string;
|
|
272
|
+
declare function fleetNotifyTopic(fleetToken: string, nodeId: string): string;
|
|
273
|
+
declare function fleetEventsTopic(fleetToken: string, nodeId: string): string;
|
|
274
|
+
declare function fleetStatusTopic(fleetToken: string, nodeId: string): string;
|
|
275
|
+
declare function fleetInfoTopic(fleetToken: string, nodeId: string): string;
|
|
276
|
+
declare function fleetAckTopic(fleetToken: string, nodeId: string, clientId: string): string;
|
|
277
|
+
/** 计算 HMAC-SHA256 签名 */
|
|
278
|
+
declare function signFleetCmd(secret: string, env: Omit<FleetCmdEnvelope, "sig">): string;
|
|
279
|
+
/** 常量时间比较校验签名 */
|
|
280
|
+
declare function verifyFleetSig(secret: string, env: FleetCmdEnvelope): boolean;
|
|
281
|
+
/** 解析并校验命令信封结构(不校验签名;签名由调用方验) */
|
|
282
|
+
declare function parseFleetEnvelope(raw: unknown): FleetCmdEnvelope | null;
|
|
283
|
+
|
|
284
|
+
export { type BuiltinLlmGrant, DEFAULT_CLOCK_SKEW_MS, FLEET_CMD_TYPES, FLEET_TOPIC_PREFIX, type FleetAckPayload, type FleetBatchResult, type FleetBatchSubCmd, type FleetCmdEnvelope, type FleetCmdType, type FleetCredential, type FleetNodeStats, type FleetPairing, type FleetStatus, NonceTracker, type SessionStateEntry, fleetAckTopic, fleetCmdTopic, fleetEventsTopic, fleetInfoTopic, fleetNotifyTopic, fleetStatusTopic, generateToken, isFreshTimestamp, parseFleetEnvelope, signFleetCmd, verifyFleetSig };
|