@zqagent/shared 0.0.0-stage → 0.1.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 +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 +1163 -0
- package/dist/wire/index.cjs.map +1 -0
- package/dist/wire/index.d.cts +166 -0
- package/dist/wire/index.d.ts +166 -0
- package/dist/wire/index.js +1081 -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/index.cjs
ADDED
|
@@ -0,0 +1,861 @@
|
|
|
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/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
APPROVAL_COLUMNS: () => APPROVAL_COLUMNS,
|
|
34
|
+
APPROVAL_VALUE_MAX: () => APPROVAL_VALUE_MAX,
|
|
35
|
+
BarkNotifier: () => BarkNotifier,
|
|
36
|
+
CONTENT_DELTA_TYPES: () => CONTENT_DELTA_TYPES,
|
|
37
|
+
DEFAULT_CLOCK_SKEW_MS: () => DEFAULT_CLOCK_SKEW_MS,
|
|
38
|
+
EmailNotifier: () => EmailNotifier,
|
|
39
|
+
FLEET_CMD_TYPES: () => FLEET_CMD_TYPES,
|
|
40
|
+
FLEET_TOPIC_PREFIX: () => FLEET_TOPIC_PREFIX,
|
|
41
|
+
LLM_PRESETS: () => LLM_PRESETS,
|
|
42
|
+
NonceTracker: () => NonceTracker,
|
|
43
|
+
NotificationHub: () => NotificationHub,
|
|
44
|
+
SecretBox: () => SecretBox,
|
|
45
|
+
ServerChanNotifier: () => ServerChanNotifier,
|
|
46
|
+
WebhookNotifier: () => WebhookNotifier,
|
|
47
|
+
approvalFields: () => approvalFields,
|
|
48
|
+
approvalInputFromData: () => approvalInputFromData,
|
|
49
|
+
approvalToHtmlTable: () => approvalToHtmlTable,
|
|
50
|
+
approvalToMarkdownTable: () => approvalToMarkdownTable,
|
|
51
|
+
channelWants: () => channelWants,
|
|
52
|
+
contentRangeHeader: () => contentRangeHeader,
|
|
53
|
+
createNotificationHub: () => createNotificationHub,
|
|
54
|
+
decryptWithKey: () => decryptWithKey,
|
|
55
|
+
docPreviewMime: () => docPreviewMime,
|
|
56
|
+
encryptWithKey: () => encryptWithKey,
|
|
57
|
+
fileEtag: () => fileEtag,
|
|
58
|
+
fleetAckTopic: () => fleetAckTopic,
|
|
59
|
+
fleetCmdTopic: () => fleetCmdTopic,
|
|
60
|
+
fleetEventsTopic: () => fleetEventsTopic,
|
|
61
|
+
fleetInfoTopic: () => fleetInfoTopic,
|
|
62
|
+
fleetNotifyTopic: () => fleetNotifyTopic,
|
|
63
|
+
fleetStatusTopic: () => fleetStatusTopic,
|
|
64
|
+
generateToken: () => generateToken,
|
|
65
|
+
isFreshTimestamp: () => isFreshTimestamp,
|
|
66
|
+
llmPreset: () => llmPreset,
|
|
67
|
+
loadOrCreateMasterKey: () => loadOrCreateMasterKey,
|
|
68
|
+
masterKeyFromHex: () => masterKeyFromHex,
|
|
69
|
+
mediaInfo: () => mediaInfo,
|
|
70
|
+
mediaKind: () => mediaKind,
|
|
71
|
+
mediaMime: () => mediaMime,
|
|
72
|
+
notifyBody: () => notifyBody,
|
|
73
|
+
notifyTitle: () => notifyTitle,
|
|
74
|
+
parseByteRange: () => parseByteRange,
|
|
75
|
+
parseFleetEnvelope: () => parseFleetEnvelope,
|
|
76
|
+
previewMime: () => previewMime,
|
|
77
|
+
signFleetCmd: () => signFleetCmd,
|
|
78
|
+
verifyFleetSig: () => verifyFleetSig
|
|
79
|
+
});
|
|
80
|
+
module.exports = __toCommonJS(src_exports);
|
|
81
|
+
|
|
82
|
+
// src/fleet.ts
|
|
83
|
+
var crypto2 = __toESM(require("crypto"), 1);
|
|
84
|
+
|
|
85
|
+
// src/common.ts
|
|
86
|
+
var crypto = __toESM(require("crypto"), 1);
|
|
87
|
+
var DEFAULT_CLOCK_SKEW_MS = 6e4;
|
|
88
|
+
function generateToken(bytes = 32) {
|
|
89
|
+
return crypto.randomBytes(bytes).toString("base64url");
|
|
90
|
+
}
|
|
91
|
+
function isFreshTimestamp(t, now = Date.now(), skewMs = DEFAULT_CLOCK_SKEW_MS) {
|
|
92
|
+
return typeof t === "number" && Number.isFinite(t) && Math.abs(now - t) <= skewMs;
|
|
93
|
+
}
|
|
94
|
+
var NonceTracker = class {
|
|
95
|
+
constructor(ttlMs = DEFAULT_CLOCK_SKEW_MS * 5) {
|
|
96
|
+
this.ttlMs = ttlMs;
|
|
97
|
+
}
|
|
98
|
+
ttlMs;
|
|
99
|
+
seen = /* @__PURE__ */ new Map();
|
|
100
|
+
/** 返回 true 表示首次见到(可用);false 表示重放 */
|
|
101
|
+
checkAndRecord(nonce, now = Date.now()) {
|
|
102
|
+
this.prune(now);
|
|
103
|
+
if (this.seen.has(nonce)) return false;
|
|
104
|
+
this.seen.set(nonce, now);
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
prune(now) {
|
|
108
|
+
for (const [k, ts] of this.seen) {
|
|
109
|
+
if (now - ts > this.ttlMs) this.seen.delete(k);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// src/fleet.ts
|
|
115
|
+
var FLEET_TOPIC_PREFIX = "zqagent/fleet";
|
|
116
|
+
var FLEET_CMD_TYPES = [
|
|
117
|
+
"ping",
|
|
118
|
+
"get_node_info",
|
|
119
|
+
"get_node_host",
|
|
120
|
+
"list_projects",
|
|
121
|
+
"create_project",
|
|
122
|
+
"delete_project",
|
|
123
|
+
"list_sessions",
|
|
124
|
+
"get_session_states",
|
|
125
|
+
"create_session",
|
|
126
|
+
"delete_session",
|
|
127
|
+
"get_state",
|
|
128
|
+
"get_events",
|
|
129
|
+
"get_session_turns",
|
|
130
|
+
"get_session_turn_reply",
|
|
131
|
+
"read_session_attachment",
|
|
132
|
+
"get_session_changes",
|
|
133
|
+
"get_session_change_diff",
|
|
134
|
+
"restore_session_change",
|
|
135
|
+
"get_config",
|
|
136
|
+
"update_config",
|
|
137
|
+
"list_models",
|
|
138
|
+
"list_dirs",
|
|
139
|
+
"make_dir",
|
|
140
|
+
"search_dirs",
|
|
141
|
+
"list_files",
|
|
142
|
+
"read_file",
|
|
143
|
+
"read_file_range",
|
|
144
|
+
"file_ticket",
|
|
145
|
+
"download_file",
|
|
146
|
+
"write_file",
|
|
147
|
+
"write_file_base64",
|
|
148
|
+
"create_dir",
|
|
149
|
+
"create_file",
|
|
150
|
+
"delete_files",
|
|
151
|
+
"search_files",
|
|
152
|
+
"search_content",
|
|
153
|
+
"rename_path",
|
|
154
|
+
"move_paths",
|
|
155
|
+
"zip_download",
|
|
156
|
+
"list_tools",
|
|
157
|
+
"list_mcp",
|
|
158
|
+
"update_mcp",
|
|
159
|
+
"test_mcp",
|
|
160
|
+
"project_stats",
|
|
161
|
+
"run_command",
|
|
162
|
+
"list_shell_tasks",
|
|
163
|
+
"kill_shell_task",
|
|
164
|
+
"terminal_list",
|
|
165
|
+
"terminal_create",
|
|
166
|
+
"terminal_replay",
|
|
167
|
+
"terminal_close",
|
|
168
|
+
"terminal_remove",
|
|
169
|
+
"terminal_rename",
|
|
170
|
+
"terminal_history",
|
|
171
|
+
"terminal_settings",
|
|
172
|
+
"terminal_update_settings",
|
|
173
|
+
"git_repos",
|
|
174
|
+
"git_status",
|
|
175
|
+
"git_diff",
|
|
176
|
+
"git_branches",
|
|
177
|
+
"git_refs",
|
|
178
|
+
"git_log",
|
|
179
|
+
"git_show",
|
|
180
|
+
"git_fetch",
|
|
181
|
+
"git_stage",
|
|
182
|
+
"git_unstage",
|
|
183
|
+
"git_commit",
|
|
184
|
+
"git_commit_message",
|
|
185
|
+
"git_checkout",
|
|
186
|
+
"git_pull",
|
|
187
|
+
"git_push",
|
|
188
|
+
"set_node_label",
|
|
189
|
+
"get_usage_summary",
|
|
190
|
+
"get_llm_balance",
|
|
191
|
+
"get_usage_records",
|
|
192
|
+
"get_usage_pricing",
|
|
193
|
+
"update_usage_pricing",
|
|
194
|
+
"get_node_llm",
|
|
195
|
+
"update_node_llm",
|
|
196
|
+
"self_update",
|
|
197
|
+
"refresh_builtin_llm",
|
|
198
|
+
"list_node_llm_models",
|
|
199
|
+
"set_fleet_cred",
|
|
200
|
+
"rename_session",
|
|
201
|
+
"set_session_model",
|
|
202
|
+
"set_session_llm",
|
|
203
|
+
"set_session_mode",
|
|
204
|
+
"set_session_lang",
|
|
205
|
+
"set_session_draft",
|
|
206
|
+
"submit_turn",
|
|
207
|
+
"steer",
|
|
208
|
+
"unsteer",
|
|
209
|
+
"interrupt",
|
|
210
|
+
"resume",
|
|
211
|
+
"approval_answer",
|
|
212
|
+
"question_answer",
|
|
213
|
+
"batch"
|
|
214
|
+
];
|
|
215
|
+
function fleetCmdTopic(fleetToken, nodeId) {
|
|
216
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/cmd`;
|
|
217
|
+
}
|
|
218
|
+
function fleetNotifyTopic(fleetToken, nodeId) {
|
|
219
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/notify`;
|
|
220
|
+
}
|
|
221
|
+
function fleetEventsTopic(fleetToken, nodeId) {
|
|
222
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/events`;
|
|
223
|
+
}
|
|
224
|
+
function fleetStatusTopic(fleetToken, nodeId) {
|
|
225
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/status`;
|
|
226
|
+
}
|
|
227
|
+
function fleetInfoTopic(fleetToken, nodeId) {
|
|
228
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/info`;
|
|
229
|
+
}
|
|
230
|
+
function fleetAckTopic(fleetToken, nodeId, clientId) {
|
|
231
|
+
return `${FLEET_TOPIC_PREFIX}/${fleetToken}/node/${nodeId}/ack/${clientId}`;
|
|
232
|
+
}
|
|
233
|
+
function canonical(env) {
|
|
234
|
+
return JSON.stringify([
|
|
235
|
+
env.t,
|
|
236
|
+
env.nonce,
|
|
237
|
+
env.reqId,
|
|
238
|
+
env.type,
|
|
239
|
+
env.clientId,
|
|
240
|
+
env.nodeId,
|
|
241
|
+
env.projectId ?? "",
|
|
242
|
+
env.sessionId ?? "",
|
|
243
|
+
env.payload
|
|
244
|
+
]);
|
|
245
|
+
}
|
|
246
|
+
function signFleetCmd(secret, env) {
|
|
247
|
+
return crypto2.createHmac("sha256", Buffer.from(secret, "utf8")).update(canonical(env)).digest("base64url");
|
|
248
|
+
}
|
|
249
|
+
function verifyFleetSig(secret, env) {
|
|
250
|
+
if (typeof env.sig !== "string" || env.sig.length === 0) return false;
|
|
251
|
+
const expected = signFleetCmd(secret, env);
|
|
252
|
+
const a = Buffer.from(expected, "utf8");
|
|
253
|
+
const b = Buffer.from(env.sig, "utf8");
|
|
254
|
+
if (a.length !== b.length) return false;
|
|
255
|
+
return crypto2.timingSafeEqual(a, b);
|
|
256
|
+
}
|
|
257
|
+
function parseFleetEnvelope(raw) {
|
|
258
|
+
if (!raw || typeof raw !== "object") return null;
|
|
259
|
+
const o = raw;
|
|
260
|
+
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") {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
if (!FLEET_CMD_TYPES.includes(o.type)) return null;
|
|
264
|
+
if (!o.payload || typeof o.payload !== "object") return null;
|
|
265
|
+
return {
|
|
266
|
+
t: o.t,
|
|
267
|
+
nonce: o.nonce,
|
|
268
|
+
reqId: o.reqId,
|
|
269
|
+
type: o.type,
|
|
270
|
+
clientId: o.clientId,
|
|
271
|
+
nodeId: o.nodeId,
|
|
272
|
+
projectId: typeof o.projectId === "string" ? o.projectId : void 0,
|
|
273
|
+
sessionId: typeof o.sessionId === "string" ? o.sessionId : void 0,
|
|
274
|
+
payload: o.payload,
|
|
275
|
+
sig: o.sig
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/secrets.ts
|
|
280
|
+
var crypto3 = __toESM(require("crypto"), 1);
|
|
281
|
+
var fs = __toESM(require("fs"), 1);
|
|
282
|
+
var path = __toESM(require("path"), 1);
|
|
283
|
+
function encryptWithKey(key, plain) {
|
|
284
|
+
const iv = crypto3.randomBytes(12);
|
|
285
|
+
const cipher = crypto3.createCipheriv("aes-256-gcm", key, iv);
|
|
286
|
+
const enc = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
287
|
+
const tag = cipher.getAuthTag();
|
|
288
|
+
return [
|
|
289
|
+
"v1",
|
|
290
|
+
iv.toString("base64"),
|
|
291
|
+
tag.toString("base64"),
|
|
292
|
+
enc.toString("base64")
|
|
293
|
+
].join(":");
|
|
294
|
+
}
|
|
295
|
+
function decryptWithKey(key, payload) {
|
|
296
|
+
try {
|
|
297
|
+
const parts = payload.split(":");
|
|
298
|
+
if (parts.length !== 4 || parts[0] !== "v1") return null;
|
|
299
|
+
const iv = Buffer.from(parts[1], "base64");
|
|
300
|
+
const tag = Buffer.from(parts[2], "base64");
|
|
301
|
+
const data = Buffer.from(parts[3], "base64");
|
|
302
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", key, iv);
|
|
303
|
+
decipher.setAuthTag(tag);
|
|
304
|
+
return Buffer.concat([
|
|
305
|
+
decipher.update(data),
|
|
306
|
+
decipher.final()
|
|
307
|
+
]).toString("utf8");
|
|
308
|
+
} catch {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function loadOrCreateMasterKey(masterKeyFile) {
|
|
313
|
+
if (fs.existsSync(masterKeyFile)) {
|
|
314
|
+
const hex = fs.readFileSync(masterKeyFile, "utf8").trim();
|
|
315
|
+
if (/^[0-9a-f]{64}$/i.test(hex)) {
|
|
316
|
+
return Buffer.from(hex, "hex");
|
|
317
|
+
}
|
|
318
|
+
console.warn(`\u26A0\uFE0F \u4E3B\u5BC6\u94A5\u6587\u4EF6\u635F\u574F\uFF0C\u5DF2\u91CD\u65B0\u751F\u6210\uFF08\u65E7\u5BC6\u6587\u5C06\u65E0\u6CD5\u89E3\u5BC6\uFF09`);
|
|
319
|
+
}
|
|
320
|
+
const key = crypto3.randomBytes(32);
|
|
321
|
+
fs.mkdirSync(path.dirname(masterKeyFile), { recursive: true, mode: 448 });
|
|
322
|
+
fs.writeFileSync(masterKeyFile, key.toString("hex"), {
|
|
323
|
+
mode: 384,
|
|
324
|
+
encoding: "utf8"
|
|
325
|
+
});
|
|
326
|
+
return key;
|
|
327
|
+
}
|
|
328
|
+
function masterKeyFromHex(hex) {
|
|
329
|
+
const h = hex.trim();
|
|
330
|
+
return /^[0-9a-f]{64}$/i.test(h) ? Buffer.from(h, "hex") : null;
|
|
331
|
+
}
|
|
332
|
+
var SecretBox = class _SecretBox {
|
|
333
|
+
constructor(key) {
|
|
334
|
+
this.key = key;
|
|
335
|
+
}
|
|
336
|
+
key;
|
|
337
|
+
/** 主密钥来源一:本机密钥文件(不存在则创建) */
|
|
338
|
+
static fromFile(masterKeyFile) {
|
|
339
|
+
return new _SecretBox(loadOrCreateMasterKey(masterKeyFile));
|
|
340
|
+
}
|
|
341
|
+
/** 主密钥来源二:hex 字符串(如环境变量 SECRET_KEY);非法返回 null */
|
|
342
|
+
static fromHex(hex) {
|
|
343
|
+
const key = masterKeyFromHex(hex);
|
|
344
|
+
return key ? new _SecretBox(key) : null;
|
|
345
|
+
}
|
|
346
|
+
encrypt(plain) {
|
|
347
|
+
return encryptWithKey(this.key, plain);
|
|
348
|
+
}
|
|
349
|
+
decrypt(payload) {
|
|
350
|
+
return decryptWithKey(this.key, payload);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// src/approval-view.ts
|
|
355
|
+
var APPROVAL_VALUE_MAX = 120;
|
|
356
|
+
var APPROVAL_COLUMNS = ["\u9879\u76EE", "\u8BE6\u60C5"];
|
|
357
|
+
var TOOL_LABEL = "\u{1F527} \u5DE5\u5177";
|
|
358
|
+
var REASON_LABEL = "\u{1F4AC} \u539F\u56E0";
|
|
359
|
+
function formatValue(v, maxLen) {
|
|
360
|
+
let text;
|
|
361
|
+
if (v == null) {
|
|
362
|
+
text = "";
|
|
363
|
+
} else if (typeof v === "string") {
|
|
364
|
+
text = v;
|
|
365
|
+
} else {
|
|
366
|
+
try {
|
|
367
|
+
text = JSON.stringify(v);
|
|
368
|
+
} catch {
|
|
369
|
+
text = String(v);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
text = text.replace(/\r?\n/g, "\u21B5");
|
|
373
|
+
return text.length > maxLen ? text.slice(0, maxLen) + "\u2026" : text;
|
|
374
|
+
}
|
|
375
|
+
function approvalInputFromData(data) {
|
|
376
|
+
const args = data["arguments"];
|
|
377
|
+
return {
|
|
378
|
+
toolName: String(data["toolName"] ?? ""),
|
|
379
|
+
reason: String(data["reason"] ?? ""),
|
|
380
|
+
arguments: args && typeof args === "object" ? args : void 0
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function approvalFields(input, maxLen = APPROVAL_VALUE_MAX) {
|
|
384
|
+
const fields = [
|
|
385
|
+
{ label: TOOL_LABEL, value: formatValue(input.toolName, maxLen) },
|
|
386
|
+
{ label: REASON_LABEL, value: formatValue(input.reason, maxLen) }
|
|
387
|
+
];
|
|
388
|
+
for (const [key, value] of Object.entries(input.arguments ?? {})) {
|
|
389
|
+
fields.push({ label: formatValue(key, maxLen), value: formatValue(value, maxLen) });
|
|
390
|
+
}
|
|
391
|
+
return fields;
|
|
392
|
+
}
|
|
393
|
+
function escapeCell(text) {
|
|
394
|
+
return text.replace(/\|/g, "\\|").replace(/\r?\n/g, "\u21B5");
|
|
395
|
+
}
|
|
396
|
+
function approvalToMarkdownTable(input, opts = {}) {
|
|
397
|
+
const lines = [];
|
|
398
|
+
if (opts.title) lines.push(opts.title, "");
|
|
399
|
+
lines.push(`| ${APPROVAL_COLUMNS[0]} | ${APPROVAL_COLUMNS[1]} |`, "| --- | --- |");
|
|
400
|
+
for (const f of approvalFields(input, opts.maxLen)) {
|
|
401
|
+
lines.push(`| ${escapeCell(f.label)} | ${escapeCell(f.value)} |`);
|
|
402
|
+
}
|
|
403
|
+
return lines.join("\n");
|
|
404
|
+
}
|
|
405
|
+
function escapeHtml(text) {
|
|
406
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
407
|
+
}
|
|
408
|
+
function approvalToHtmlTable(input, maxLen = APPROVAL_VALUE_MAX) {
|
|
409
|
+
const rows = approvalFields(input, maxLen).map(
|
|
410
|
+
(f) => `<tr><th style="text-align:left;padding:4px 12px 4px 0;color:#6b7280;font-weight:500;white-space:nowrap;vertical-align:top;">${escapeHtml(f.label)}</th><td style="padding:4px 0;font-family:ui-monospace,Menlo,Consolas,monospace;">${escapeHtml(f.value)}</td></tr>`
|
|
411
|
+
).join("");
|
|
412
|
+
return `<table style="border-collapse:collapse;font-size:13px;">${rows}</table>`;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// src/llm-presets.ts
|
|
416
|
+
var LLM_PRESETS = [
|
|
417
|
+
{
|
|
418
|
+
id: "openai",
|
|
419
|
+
name: "OpenAI",
|
|
420
|
+
baseURL: "https://api.openai.com/v1",
|
|
421
|
+
// 不预填模型:预填等于替用户拍板一个他既没选过、也可能没有权限的型号,
|
|
422
|
+
// 之后控制台的模型下拉就凭空多出这个「系统默认模型」。填完 Key 刷新模型,
|
|
423
|
+
// 由供应商实际返回的列表来选。
|
|
424
|
+
model: "",
|
|
425
|
+
supportsReasoningEffort: true
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
id: "deepseek",
|
|
429
|
+
name: "DeepSeek",
|
|
430
|
+
baseURL: "https://api.deepseek.com",
|
|
431
|
+
model: "deepseek-flash",
|
|
432
|
+
supportsReasoningEffort: false,
|
|
433
|
+
hint: "deepseek-flash = \u901A\u7528\u5BF9\u8BDD, deepseek-reasoner = \u6DF1\u5EA6\u63A8\u7406"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
id: "qwen",
|
|
437
|
+
name: "\u901A\u4E49\u5343\u95EE",
|
|
438
|
+
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
439
|
+
model: "qwen-plus",
|
|
440
|
+
supportsReasoningEffort: false
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
id: "zhipu",
|
|
444
|
+
name: "\u667A\u8C31 GLM",
|
|
445
|
+
baseURL: "https://open.bigmodel.cn/api/paas/v4",
|
|
446
|
+
model: "glm-4-plus",
|
|
447
|
+
supportsReasoningEffort: false
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
id: "moonshot",
|
|
451
|
+
name: "\u6708\u4E4B\u6697\u9762 Kimi",
|
|
452
|
+
baseURL: "https://api.moonshot.cn/v1",
|
|
453
|
+
model: "moonshot-v1-8k",
|
|
454
|
+
supportsReasoningEffort: false
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
id: "xiaomi",
|
|
458
|
+
name: "\u5C0F\u7C73 MiMo",
|
|
459
|
+
baseURL: "",
|
|
460
|
+
model: "",
|
|
461
|
+
supportsReasoningEffort: false,
|
|
462
|
+
hint: "\u9700\u81EA\u884C\u586B\u5199\u7AEF\u70B9\u4E0E\u6A21\u578B"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
id: "custom",
|
|
466
|
+
name: "\u5176\u5B83 (OpenAI \u517C\u5BB9)",
|
|
467
|
+
baseURL: "",
|
|
468
|
+
model: "",
|
|
469
|
+
supportsReasoningEffort: true,
|
|
470
|
+
hint: "\u4EFB\u610F\u517C\u5BB9 OpenAI API \u7684\u670D\u52A1\u7AEF\u70B9\uFF08\u5982\u672C\u5730 vLLM \u7B49\uFF09"
|
|
471
|
+
}
|
|
472
|
+
];
|
|
473
|
+
function llmPreset(id) {
|
|
474
|
+
return LLM_PRESETS.find((p) => p.id === id);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/media.ts
|
|
478
|
+
var MEDIA_MIME = {
|
|
479
|
+
// 视频
|
|
480
|
+
mp4: { mime: "video/mp4", kind: "video" },
|
|
481
|
+
m4v: { mime: "video/mp4", kind: "video" },
|
|
482
|
+
webm: { mime: "video/webm", kind: "video" },
|
|
483
|
+
ogv: { mime: "video/ogg", kind: "video" },
|
|
484
|
+
mov: { mime: "video/quicktime", kind: "video" },
|
|
485
|
+
// 音频
|
|
486
|
+
mp3: { mime: "audio/mpeg", kind: "audio" },
|
|
487
|
+
wav: { mime: "audio/wav", kind: "audio" },
|
|
488
|
+
m4a: { mime: "audio/mp4", kind: "audio" },
|
|
489
|
+
aac: { mime: "audio/aac", kind: "audio" },
|
|
490
|
+
flac: { mime: "audio/flac", kind: "audio" },
|
|
491
|
+
ogg: { mime: "audio/ogg", kind: "audio" },
|
|
492
|
+
oga: { mime: "audio/ogg", kind: "audio" },
|
|
493
|
+
opus: { mime: "audio/ogg", kind: "audio" },
|
|
494
|
+
weba: { mime: "audio/webm", kind: "audio" }
|
|
495
|
+
};
|
|
496
|
+
function extOf(fileName) {
|
|
497
|
+
return fileName.toLowerCase().split(".").pop() ?? "";
|
|
498
|
+
}
|
|
499
|
+
function mediaInfo(fileName) {
|
|
500
|
+
return MEDIA_MIME[extOf(fileName)] ?? null;
|
|
501
|
+
}
|
|
502
|
+
function mediaMime(fileName) {
|
|
503
|
+
return MEDIA_MIME[extOf(fileName)]?.mime ?? null;
|
|
504
|
+
}
|
|
505
|
+
function mediaKind(fileName) {
|
|
506
|
+
return MEDIA_MIME[extOf(fileName)]?.kind ?? null;
|
|
507
|
+
}
|
|
508
|
+
var DOC_PREVIEW_MIME = {
|
|
509
|
+
pdf: "application/pdf"
|
|
510
|
+
};
|
|
511
|
+
function docPreviewMime(fileName) {
|
|
512
|
+
return DOC_PREVIEW_MIME[extOf(fileName)] ?? null;
|
|
513
|
+
}
|
|
514
|
+
function previewMime(fileName) {
|
|
515
|
+
return mediaMime(fileName) ?? docPreviewMime(fileName);
|
|
516
|
+
}
|
|
517
|
+
function parseByteRange(header, size) {
|
|
518
|
+
const raw = (header ?? "").trim();
|
|
519
|
+
if (!raw) return null;
|
|
520
|
+
const m = /^bytes=(\d*)-(\d*)$/i.exec(raw);
|
|
521
|
+
if (!m) return null;
|
|
522
|
+
const startRaw = m[1] ?? "";
|
|
523
|
+
const endRaw = m[2] ?? "";
|
|
524
|
+
if (!startRaw && !endRaw) return null;
|
|
525
|
+
if (size <= 0) return "unsatisfiable";
|
|
526
|
+
if (!startRaw) {
|
|
527
|
+
const suffix = Number(endRaw);
|
|
528
|
+
if (!Number.isFinite(suffix) || suffix <= 0) return "unsatisfiable";
|
|
529
|
+
return { start: Math.max(size - suffix, 0), end: size - 1 };
|
|
530
|
+
}
|
|
531
|
+
const start = Number(startRaw);
|
|
532
|
+
if (!Number.isFinite(start) || start < 0) return null;
|
|
533
|
+
if (start >= size) return "unsatisfiable";
|
|
534
|
+
if (!endRaw) return { start, end: size - 1 };
|
|
535
|
+
const end = Number(endRaw);
|
|
536
|
+
if (!Number.isFinite(end) || end < start) return null;
|
|
537
|
+
return { start, end: Math.min(end, size - 1) };
|
|
538
|
+
}
|
|
539
|
+
function contentRangeHeader(range, size) {
|
|
540
|
+
return `bytes ${range.start}-${range.end}/${size}`;
|
|
541
|
+
}
|
|
542
|
+
function fileEtag(size, mtimeMs) {
|
|
543
|
+
return `"${size.toString(16)}-${Math.trunc(mtimeMs).toString(16)}"`;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/types.ts
|
|
547
|
+
var CONTENT_DELTA_TYPES = /* @__PURE__ */ new Set([
|
|
548
|
+
"assistant_delta",
|
|
549
|
+
"reasoning_delta",
|
|
550
|
+
// 节点把「只含内容增量」的一批事件合并成 `{zqBatch:[...]}` 时用的顶层标记。
|
|
551
|
+
// 混入结构事件的一批不能打这个标记,否则整帧被丢会连正文一起丢。
|
|
552
|
+
"content_delta"
|
|
553
|
+
]);
|
|
554
|
+
|
|
555
|
+
// src/notify/Notifier.ts
|
|
556
|
+
function channelWants(channel, kind) {
|
|
557
|
+
const ev = channel.events;
|
|
558
|
+
switch (kind) {
|
|
559
|
+
case "approval_request":
|
|
560
|
+
return ev.approval;
|
|
561
|
+
case "question_asked":
|
|
562
|
+
return ev.question;
|
|
563
|
+
case "turn_completed":
|
|
564
|
+
case "turn_stopped":
|
|
565
|
+
return ev.completed;
|
|
566
|
+
case "error":
|
|
567
|
+
return ev.error;
|
|
568
|
+
case "session_status":
|
|
569
|
+
return false;
|
|
570
|
+
default:
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function notifyTitle(kind) {
|
|
575
|
+
switch (kind) {
|
|
576
|
+
case "approval_request":
|
|
577
|
+
return "\u9700\u8981\u5BA1\u6279";
|
|
578
|
+
case "question_asked":
|
|
579
|
+
return "\u9700\u8981\u56DE\u7B54";
|
|
580
|
+
case "turn_completed":
|
|
581
|
+
return "\u4EFB\u52A1\u5B8C\u6210";
|
|
582
|
+
case "turn_stopped":
|
|
583
|
+
return "\u8FBE\u5230\u8FED\u4EE3\u4E0A\u9650";
|
|
584
|
+
case "error":
|
|
585
|
+
return "\u4EFB\u52A1\u51FA\u9519";
|
|
586
|
+
default:
|
|
587
|
+
return "Agent \u901A\u77E5";
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
function notifyBody(ev, maxLen = 300) {
|
|
591
|
+
const d = ev.data;
|
|
592
|
+
switch (ev.kind) {
|
|
593
|
+
case "approval_request":
|
|
594
|
+
return approvalToMarkdownTable(approvalInputFromData(d), {
|
|
595
|
+
title: "\u{1F512} \u9700\u8981\u5BA1\u6279"
|
|
596
|
+
});
|
|
597
|
+
case "question_asked":
|
|
598
|
+
return String(d["question"] ?? "");
|
|
599
|
+
case "turn_completed":
|
|
600
|
+
return `\u72B6\u6001: ${String(d["status"] ?? "completed")}`;
|
|
601
|
+
case "turn_stopped":
|
|
602
|
+
return "\u5DF2\u8FBE\u6700\u5927\u8FED\u4EE3\u6B21\u6570\uFF0C\u53EF\u7EE7\u7EED\u5B8C\u6210\u5269\u4E0B\u7684\u4EFB\u52A1";
|
|
603
|
+
case "error":
|
|
604
|
+
return String(d["error"] ?? "\u672A\u77E5\u9519\u8BEF");
|
|
605
|
+
default:
|
|
606
|
+
return "";
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/notify/NotificationHub.ts
|
|
611
|
+
var NotificationHub = class {
|
|
612
|
+
notifiers = /* @__PURE__ */ new Map();
|
|
613
|
+
/** 注册一个通道实现(幂等,后注册覆盖) */
|
|
614
|
+
register(notifier) {
|
|
615
|
+
this.notifiers.set(notifier.type, notifier);
|
|
616
|
+
}
|
|
617
|
+
/** 已注册的通道类型 */
|
|
618
|
+
registeredTypes() {
|
|
619
|
+
return [...this.notifiers.keys()];
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* 分发通知到给定的启用通道。
|
|
623
|
+
* 单个通道失败仅记录,不影响其他通道与核心逻辑。
|
|
624
|
+
*/
|
|
625
|
+
async dispatch(channels, ev) {
|
|
626
|
+
for (const ch of channels) {
|
|
627
|
+
if (!ch.enabled) continue;
|
|
628
|
+
if (!channelWants(ch, ev.kind)) continue;
|
|
629
|
+
const notifier = this.notifiers.get(ch.type);
|
|
630
|
+
if (!notifier) continue;
|
|
631
|
+
try {
|
|
632
|
+
await notifier.send(ch, ev);
|
|
633
|
+
} catch (e) {
|
|
634
|
+
console.log(
|
|
635
|
+
`[notify] ${ch.type} \u53D1\u9001\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
// src/notify/notifiers/BarkNotifier.ts
|
|
643
|
+
var TIMEOUT_MS = 1e4;
|
|
644
|
+
var BarkNotifier = class {
|
|
645
|
+
type = "bark";
|
|
646
|
+
async send(config, ev) {
|
|
647
|
+
const key = config.config["key"];
|
|
648
|
+
if (!key) return;
|
|
649
|
+
const server = (config.config["server"] ?? "https://api.day.app").replace(/\/+$/, "");
|
|
650
|
+
const url = `${server}/${encodeURIComponent(key)}/${encodeURIComponent(notifyTitle(ev.kind))}/${encodeURIComponent(notifyBody(ev))}`;
|
|
651
|
+
const res = await fetch(url, {
|
|
652
|
+
method: "GET",
|
|
653
|
+
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
654
|
+
});
|
|
655
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
// src/notify/notifiers/ServerChanNotifier.ts
|
|
660
|
+
var TIMEOUT_MS2 = 1e4;
|
|
661
|
+
var ServerChanNotifier = class {
|
|
662
|
+
type = "serverchan";
|
|
663
|
+
async send(config, ev) {
|
|
664
|
+
const sendkey = config.config["sendkey"];
|
|
665
|
+
if (!sendkey) return;
|
|
666
|
+
const url = `https://sctapi.ftqq.com/${encodeURIComponent(sendkey)}.send`;
|
|
667
|
+
const body = new URLSearchParams({
|
|
668
|
+
title: notifyTitle(ev.kind),
|
|
669
|
+
desp: notifyBody(ev)
|
|
670
|
+
});
|
|
671
|
+
const res = await fetch(url, {
|
|
672
|
+
method: "POST",
|
|
673
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
674
|
+
body,
|
|
675
|
+
signal: AbortSignal.timeout(TIMEOUT_MS2)
|
|
676
|
+
});
|
|
677
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
// src/notify/notifiers/WebhookNotifier.ts
|
|
682
|
+
var TIMEOUT_MS3 = 1e4;
|
|
683
|
+
var WebhookNotifier = class {
|
|
684
|
+
type = "webhook";
|
|
685
|
+
async send(config, ev) {
|
|
686
|
+
const url = config.config["url"];
|
|
687
|
+
if (!url) return;
|
|
688
|
+
const res = await fetch(url, {
|
|
689
|
+
method: "POST",
|
|
690
|
+
headers: { "Content-Type": "application/json" },
|
|
691
|
+
body: JSON.stringify({
|
|
692
|
+
title: notifyTitle(ev.kind),
|
|
693
|
+
body: notifyBody(ev),
|
|
694
|
+
kind: ev.kind,
|
|
695
|
+
sessionId: ev.sessionId,
|
|
696
|
+
ts: ev.ts,
|
|
697
|
+
data: ev.data
|
|
698
|
+
}),
|
|
699
|
+
signal: AbortSignal.timeout(TIMEOUT_MS3)
|
|
700
|
+
});
|
|
701
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
// src/notify/notifiers/EmailNotifier.ts
|
|
706
|
+
var import_nodemailer = __toESM(require("nodemailer"), 1);
|
|
707
|
+
function defaultTransportFactory(opts) {
|
|
708
|
+
return import_nodemailer.default.createTransport(opts);
|
|
709
|
+
}
|
|
710
|
+
function buildText(ev) {
|
|
711
|
+
const d = ev.data;
|
|
712
|
+
switch (ev.kind) {
|
|
713
|
+
case "turn_completed":
|
|
714
|
+
case "turn_stopped": {
|
|
715
|
+
const lines = [];
|
|
716
|
+
lines.push(`\u4F1A\u8BDD: ${ev.sessionId}`);
|
|
717
|
+
lines.push(`\u72B6\u6001: ${String(d["status"] ?? ev.kind)}`);
|
|
718
|
+
if (d["iterations"] !== void 0)
|
|
719
|
+
lines.push(`\u8FED\u4EE3\u6B21\u6570: ${String(d["iterations"])}`);
|
|
720
|
+
const files = d["produced_files"];
|
|
721
|
+
if (Array.isArray(files) && files.length > 0)
|
|
722
|
+
lines.push(`\u4EA7\u51FA\u6587\u4EF6:
|
|
723
|
+
${files.join("\n ")}`);
|
|
724
|
+
const summary = typeof d["summary"] === "string" ? d["summary"] : "";
|
|
725
|
+
if (summary.trim()) lines.push(`
|
|
726
|
+
\u6458\u8981:
|
|
727
|
+
${summary}`);
|
|
728
|
+
return lines.join("\n");
|
|
729
|
+
}
|
|
730
|
+
case "approval_request":
|
|
731
|
+
return `${approvalToMarkdownTable(approvalInputFromData(d), {
|
|
732
|
+
title: "\u{1F512} \u9700\u8981\u5BA1\u6279"
|
|
733
|
+
})}
|
|
734
|
+
\u4F1A\u8BDD: ${ev.sessionId}`;
|
|
735
|
+
case "question_asked":
|
|
736
|
+
return `\u95EE\u9898: ${String(d["question"] ?? "")}
|
|
737
|
+
\u4F1A\u8BDD: ${ev.sessionId}`;
|
|
738
|
+
case "error":
|
|
739
|
+
return `\u9519\u8BEF: ${String(d["error"] ?? "\u672A\u77E5\u9519\u8BEF")}
|
|
740
|
+
\u4F1A\u8BDD: ${ev.sessionId}`;
|
|
741
|
+
default:
|
|
742
|
+
return `\u4F1A\u8BDD: ${ev.sessionId}
|
|
743
|
+
\u65F6\u95F4: ${ev.ts}`;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
function escapeHtml2(text) {
|
|
747
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
748
|
+
}
|
|
749
|
+
function buildHtml(ev) {
|
|
750
|
+
if (ev.kind === "approval_request") {
|
|
751
|
+
const table = approvalToHtmlTable(approvalInputFromData(ev.data));
|
|
752
|
+
return table + `<p style="color:#6b7280;font-size:12px;margin:10px 0 0;">\u4F1A\u8BDD: ${escapeHtml2(ev.sessionId)}</p>`;
|
|
753
|
+
}
|
|
754
|
+
return `<pre style="white-space:pre-wrap;font-family:inherit;">${escapeHtml2(buildText(ev))}</pre>`;
|
|
755
|
+
}
|
|
756
|
+
var EmailNotifier = class {
|
|
757
|
+
constructor(transportFactory = defaultTransportFactory) {
|
|
758
|
+
this.transportFactory = transportFactory;
|
|
759
|
+
}
|
|
760
|
+
transportFactory;
|
|
761
|
+
type = "email";
|
|
762
|
+
async send(config, ev) {
|
|
763
|
+
if (ev.kind === "turn_completed") {
|
|
764
|
+
const minSec = Number(config.config["minDurationSeconds"] ?? 60);
|
|
765
|
+
const durationMs = ev.data["durationMs"];
|
|
766
|
+
if (typeof durationMs === "number" && durationMs < minSec * 1e3) {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
const host = config.config["host"];
|
|
771
|
+
const to = config.config["to"];
|
|
772
|
+
if (!host || !to) return;
|
|
773
|
+
const secure = config.config["secure"] === "true";
|
|
774
|
+
const port = Number(config.config["port"]) || (secure ? 465 : 587);
|
|
775
|
+
const user = config.config["user"] ?? "";
|
|
776
|
+
const pass = config.config["pass"] ?? "";
|
|
777
|
+
const from = config.config["from"] ?? user;
|
|
778
|
+
if (!from) return;
|
|
779
|
+
const prefix = config.config["subjectPrefix"] ?? "[zqagent]";
|
|
780
|
+
const transport = this.transportFactory({
|
|
781
|
+
host,
|
|
782
|
+
port,
|
|
783
|
+
secure,
|
|
784
|
+
auth: user ? { user, pass } : void 0
|
|
785
|
+
});
|
|
786
|
+
try {
|
|
787
|
+
await transport.sendMail({
|
|
788
|
+
from,
|
|
789
|
+
to,
|
|
790
|
+
subject: `${prefix}${notifyTitle(ev.kind)}`,
|
|
791
|
+
text: buildText(ev),
|
|
792
|
+
html: buildHtml(ev)
|
|
793
|
+
});
|
|
794
|
+
} finally {
|
|
795
|
+
try {
|
|
796
|
+
transport.close();
|
|
797
|
+
} catch {
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
// src/notify/index.ts
|
|
804
|
+
function createNotificationHub() {
|
|
805
|
+
const hub = new NotificationHub();
|
|
806
|
+
hub.register(new BarkNotifier());
|
|
807
|
+
hub.register(new ServerChanNotifier());
|
|
808
|
+
hub.register(new WebhookNotifier());
|
|
809
|
+
hub.register(new EmailNotifier());
|
|
810
|
+
return hub;
|
|
811
|
+
}
|
|
812
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
813
|
+
0 && (module.exports = {
|
|
814
|
+
APPROVAL_COLUMNS,
|
|
815
|
+
APPROVAL_VALUE_MAX,
|
|
816
|
+
BarkNotifier,
|
|
817
|
+
CONTENT_DELTA_TYPES,
|
|
818
|
+
DEFAULT_CLOCK_SKEW_MS,
|
|
819
|
+
EmailNotifier,
|
|
820
|
+
FLEET_CMD_TYPES,
|
|
821
|
+
FLEET_TOPIC_PREFIX,
|
|
822
|
+
LLM_PRESETS,
|
|
823
|
+
NonceTracker,
|
|
824
|
+
NotificationHub,
|
|
825
|
+
SecretBox,
|
|
826
|
+
ServerChanNotifier,
|
|
827
|
+
WebhookNotifier,
|
|
828
|
+
approvalFields,
|
|
829
|
+
approvalInputFromData,
|
|
830
|
+
approvalToHtmlTable,
|
|
831
|
+
approvalToMarkdownTable,
|
|
832
|
+
channelWants,
|
|
833
|
+
contentRangeHeader,
|
|
834
|
+
createNotificationHub,
|
|
835
|
+
decryptWithKey,
|
|
836
|
+
docPreviewMime,
|
|
837
|
+
encryptWithKey,
|
|
838
|
+
fileEtag,
|
|
839
|
+
fleetAckTopic,
|
|
840
|
+
fleetCmdTopic,
|
|
841
|
+
fleetEventsTopic,
|
|
842
|
+
fleetInfoTopic,
|
|
843
|
+
fleetNotifyTopic,
|
|
844
|
+
fleetStatusTopic,
|
|
845
|
+
generateToken,
|
|
846
|
+
isFreshTimestamp,
|
|
847
|
+
llmPreset,
|
|
848
|
+
loadOrCreateMasterKey,
|
|
849
|
+
masterKeyFromHex,
|
|
850
|
+
mediaInfo,
|
|
851
|
+
mediaKind,
|
|
852
|
+
mediaMime,
|
|
853
|
+
notifyBody,
|
|
854
|
+
notifyTitle,
|
|
855
|
+
parseByteRange,
|
|
856
|
+
parseFleetEnvelope,
|
|
857
|
+
previewMime,
|
|
858
|
+
signFleetCmd,
|
|
859
|
+
verifyFleetSig
|
|
860
|
+
});
|
|
861
|
+
//# sourceMappingURL=index.cjs.map
|