@ycodium-ai/plugin-im 0.2.3180 → 0.2.3202
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/assets/ui.js +16 -4
- package/dist/index.js +978 -376
- package/locales/en.json +51 -19
- package/locales/zh-CN.json +52 -20
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -23360,7 +23360,7 @@ var require_websocket = __commonJS({
|
|
|
23360
23360
|
var http = __require("http");
|
|
23361
23361
|
var net = __require("net");
|
|
23362
23362
|
var tls = __require("tls");
|
|
23363
|
-
var { randomBytes, createHash:
|
|
23363
|
+
var { randomBytes, createHash: createHash6 } = __require("crypto");
|
|
23364
23364
|
var { Duplex, Readable } = __require("stream");
|
|
23365
23365
|
var { URL: URL2 } = __require("url");
|
|
23366
23366
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -24028,7 +24028,7 @@ var require_websocket = __commonJS({
|
|
|
24028
24028
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
24029
24029
|
return;
|
|
24030
24030
|
}
|
|
24031
|
-
const digest =
|
|
24031
|
+
const digest = createHash6("sha1").update(key + GUID).digest("base64");
|
|
24032
24032
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
24033
24033
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
24034
24034
|
return;
|
|
@@ -24397,7 +24397,7 @@ var require_websocket_server = __commonJS({
|
|
|
24397
24397
|
var EventEmitter = __require("events");
|
|
24398
24398
|
var http = __require("http");
|
|
24399
24399
|
var { Duplex } = __require("stream");
|
|
24400
|
-
var { createHash:
|
|
24400
|
+
var { createHash: createHash6 } = __require("crypto");
|
|
24401
24401
|
var extension = require_extension();
|
|
24402
24402
|
var PerMessageDeflate = require_permessage_deflate();
|
|
24403
24403
|
var subprotocol = require_subprotocol();
|
|
@@ -24704,7 +24704,7 @@ var require_websocket_server = __commonJS({
|
|
|
24704
24704
|
);
|
|
24705
24705
|
}
|
|
24706
24706
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
24707
|
-
const digest =
|
|
24707
|
+
const digest = createHash6("sha1").update(key + GUID).digest("base64");
|
|
24708
24708
|
const headers = [
|
|
24709
24709
|
"HTTP/1.1 101 Switching Protocols",
|
|
24710
24710
|
"Upgrade: websocket",
|
|
@@ -126185,22 +126185,26 @@ var makeAcknowledgements = (core) => {
|
|
|
126185
126185
|
host.log.warn("chat could not acknowledge the message", { error: describeError(error) });
|
|
126186
126186
|
}
|
|
126187
126187
|
};
|
|
126188
|
-
const
|
|
126188
|
+
const takeWorking = (binding, threadId, outcome) => {
|
|
126189
126189
|
const adapter = adapterFor(binding.platform);
|
|
126190
|
+
const clear = adapter?.clearAcknowledge?.bind(adapter);
|
|
126190
126191
|
const pending = acknowledgements.get(threadId);
|
|
126191
|
-
if (pending === void 0 ||
|
|
126192
|
+
if (pending === void 0 || clear === void 0) return async () => void 0;
|
|
126192
126193
|
acknowledgements.delete(threadId);
|
|
126193
|
-
|
|
126194
|
-
|
|
126195
|
-
|
|
126196
|
-
|
|
126197
|
-
|
|
126198
|
-
|
|
126199
|
-
|
|
126194
|
+
return async () => {
|
|
126195
|
+
for (const entry of pending) {
|
|
126196
|
+
try {
|
|
126197
|
+
await clear(binding, entry.messageId, entry.ackId, outcome);
|
|
126198
|
+
} catch (error) {
|
|
126199
|
+
host.log.warn("chat could not clear the acknowledgement", {
|
|
126200
|
+
error: describeError(error)
|
|
126201
|
+
});
|
|
126202
|
+
}
|
|
126200
126203
|
}
|
|
126201
|
-
}
|
|
126204
|
+
};
|
|
126202
126205
|
};
|
|
126203
|
-
|
|
126206
|
+
const clearWorking = (binding, threadId, outcome) => takeWorking(binding, threadId, outcome)();
|
|
126207
|
+
return { markWorking, takeWorking, clearWorking };
|
|
126204
126208
|
};
|
|
126205
126209
|
|
|
126206
126210
|
// src/botConfig.ts
|
|
@@ -126401,7 +126405,7 @@ var makeConclusionLedger = (core) => {
|
|
|
126401
126405
|
return false;
|
|
126402
126406
|
inFlight.add(key);
|
|
126403
126407
|
try {
|
|
126404
|
-
const sent = await send();
|
|
126408
|
+
const sent = await send(() => conclusionDebtsOf(core.state)[key] !== void 0);
|
|
126405
126409
|
if (sent) settle(debt);
|
|
126406
126410
|
return sent;
|
|
126407
126411
|
} finally {
|
|
@@ -126837,6 +126841,7 @@ var readString = (row, key) => {
|
|
|
126837
126841
|
|
|
126838
126842
|
// src/settingsContract.ts
|
|
126839
126843
|
var SETTINGS_VIEW_COMMAND = "settings.view";
|
|
126844
|
+
var SETTINGS_CONNECTIONS_COMMAND = "settings.connections";
|
|
126840
126845
|
var SETTINGS_SAVE_BOT_COMMAND = "settings.saveBot";
|
|
126841
126846
|
var SETTINGS_REMOVE_BOT_COMMAND = "settings.removeBot";
|
|
126842
126847
|
var SETTINGS_SAVE_GENERAL_COMMAND = "settings.saveGeneral";
|
|
@@ -126877,6 +126882,7 @@ var foldFlowItem = (snapshot, item) => {
|
|
|
126877
126882
|
}
|
|
126878
126883
|
}
|
|
126879
126884
|
};
|
|
126885
|
+
var connectionHintKey = (hint) => hint === "notAvailable" ? "settingsSection.connection.reason.not-available" : `rowAction.checkConnection.hint.${hint}`;
|
|
126880
126886
|
|
|
126881
126887
|
// src/targetKind.ts
|
|
126882
126888
|
var TARGET_KIND_OPTIONS = [
|
|
@@ -127943,13 +127949,58 @@ var makeCommands = (core, deps) => {
|
|
|
127943
127949
|
};
|
|
127944
127950
|
|
|
127945
127951
|
// src/keyedQueue.ts
|
|
127946
|
-
var makeKeyedQueue = (onError) => {
|
|
127947
|
-
const
|
|
127948
|
-
|
|
127949
|
-
const
|
|
127950
|
-
|
|
127952
|
+
var makeKeyedQueue = (onError, options = {}) => {
|
|
127953
|
+
const queues = /* @__PURE__ */ new Map();
|
|
127954
|
+
const run = (key, work, kind = {}) => {
|
|
127955
|
+
const queue = queues.get(key) ?? { tail: Promise.resolve(), size: 0, droppable: 0 };
|
|
127956
|
+
const droppable = kind.droppable === true;
|
|
127957
|
+
if (droppable && options.limit !== void 0 && queue.droppable >= options.limit) {
|
|
127958
|
+
options.onFull?.(key, options.limit);
|
|
127959
|
+
return false;
|
|
127960
|
+
}
|
|
127961
|
+
queue.size += 1;
|
|
127962
|
+
if (droppable) queue.droppable += 1;
|
|
127963
|
+
queue.tail = queue.tail.then(work).catch(onError).then(() => {
|
|
127964
|
+
queue.size -= 1;
|
|
127965
|
+
if (droppable) queue.droppable -= 1;
|
|
127966
|
+
if (queue.size === 0 && queues.get(key) === queue) queues.delete(key);
|
|
127951
127967
|
});
|
|
127952
|
-
|
|
127968
|
+
queues.set(key, queue);
|
|
127969
|
+
return true;
|
|
127970
|
+
};
|
|
127971
|
+
return Object.assign(run, { activeKeys: () => queues.size });
|
|
127972
|
+
};
|
|
127973
|
+
|
|
127974
|
+
// src/redact.ts
|
|
127975
|
+
var DETAIL_MAX_CHARS = 200;
|
|
127976
|
+
var MASK = "***";
|
|
127977
|
+
var TOKEN_LIKE = /[A-Za-z0-9_=-]{24,}/g;
|
|
127978
|
+
var MIN_SECRET_LENGTH = 6;
|
|
127979
|
+
var botRedactor = (columns, values) => {
|
|
127980
|
+
const redactor = makeRedactor();
|
|
127981
|
+
for (const column of columns) {
|
|
127982
|
+
if (column.kind !== "password") continue;
|
|
127983
|
+
const value2 = values[column.key];
|
|
127984
|
+
redactor.register(value2);
|
|
127985
|
+
if (value2 !== void 0) redactor.register(encodeURIComponent(value2));
|
|
127986
|
+
}
|
|
127987
|
+
return redactor;
|
|
127988
|
+
};
|
|
127989
|
+
var makeRedactor = () => {
|
|
127990
|
+
const secrets = /* @__PURE__ */ new Set();
|
|
127991
|
+
const redact = (text4) => {
|
|
127992
|
+
let out = text4;
|
|
127993
|
+
for (const secret of [...secrets].sort((a, b) => b.length - a.length)) {
|
|
127994
|
+
out = out.split(secret).join(MASK);
|
|
127995
|
+
}
|
|
127996
|
+
return out.replace(TOKEN_LIKE, MASK);
|
|
127997
|
+
};
|
|
127998
|
+
return {
|
|
127999
|
+
register: (secret) => {
|
|
128000
|
+
if (typeof secret === "string" && secret.length >= MIN_SECRET_LENGTH) secrets.add(secret);
|
|
128001
|
+
},
|
|
128002
|
+
redact,
|
|
128003
|
+
detail: (text4) => redact(text4).slice(0, DETAIL_MAX_CHARS)
|
|
127953
128004
|
};
|
|
127954
128005
|
};
|
|
127955
128006
|
|
|
@@ -127967,26 +128018,61 @@ var connectionKey = (adapter, bot) => JSON.stringify([
|
|
|
127967
128018
|
var startConnections = (core, inboundHandlersFor) => {
|
|
127968
128019
|
const { host, adapterFor, ready } = core;
|
|
127969
128020
|
const live = /* @__PURE__ */ new Map();
|
|
128021
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
128022
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
128023
|
+
const notify = () => {
|
|
128024
|
+
const snapshot = Object.fromEntries(statuses);
|
|
128025
|
+
for (const listener of [...listeners]) listener(snapshot);
|
|
128026
|
+
};
|
|
128027
|
+
const record3 = (rowId, status) => {
|
|
128028
|
+
const previous = statuses.get(rowId);
|
|
128029
|
+
if (previous?.state === status.state && previous.error === status.error && previous.reason === status.reason && previous.duplicateOf === status.duplicateOf && previous.hint === status.hint)
|
|
128030
|
+
return;
|
|
128031
|
+
statuses.set(rowId, status);
|
|
128032
|
+
notify();
|
|
128033
|
+
};
|
|
128034
|
+
const remove = (rowId) => {
|
|
128035
|
+
if (statuses.delete(rowId)) notify();
|
|
128036
|
+
};
|
|
127970
128037
|
const enqueueForRow = makeKeyedQueue((error) => {
|
|
127971
128038
|
host.log.warn("chat could not start an inbound connection", { error: describeError(error) });
|
|
127972
128039
|
});
|
|
127973
128040
|
let disposed = false;
|
|
127974
128041
|
const open = (bot, key) => {
|
|
127975
128042
|
const adapter = adapterFor(bot.platform);
|
|
128043
|
+
const redactor = botRedactor(adapter?.columns ?? [], bot.values);
|
|
127976
128044
|
let closed = false;
|
|
127977
128045
|
let closeConnection;
|
|
128046
|
+
record3(bot.rowId, { state: "connecting" });
|
|
127978
128047
|
enqueueForRow(bot.rowId, async () => {
|
|
127979
128048
|
try {
|
|
127980
128049
|
await ready;
|
|
127981
128050
|
if (closed || adapter === void 0) return;
|
|
127982
|
-
const connection = await adapter.connect(bot,
|
|
128051
|
+
const connection = await adapter.connect(bot, {
|
|
128052
|
+
...inboundHandlersFor(bot),
|
|
128053
|
+
onConnectionState: (status) => {
|
|
128054
|
+
if (closed) return;
|
|
128055
|
+
if (status.state === "connected") {
|
|
128056
|
+
record3(bot.rowId, status);
|
|
128057
|
+
return;
|
|
128058
|
+
}
|
|
128059
|
+
record3(bot.rowId, {
|
|
128060
|
+
state: "failed",
|
|
128061
|
+
...status.reason === void 0 ? {} : { reason: status.reason },
|
|
128062
|
+
...status.error === void 0 ? {} : { error: redactor.redact(describeError(status.error)) },
|
|
128063
|
+
...status.hint === void 0 ? {} : { hint: status.hint }
|
|
128064
|
+
});
|
|
128065
|
+
}
|
|
128066
|
+
});
|
|
127983
128067
|
if (closed) connection.close();
|
|
127984
128068
|
else closeConnection = () => connection.close();
|
|
127985
128069
|
} catch (error) {
|
|
128070
|
+
const detail = redactor.redact(describeError(error));
|
|
128071
|
+
if (!closed) record3(bot.rowId, { state: "failed", error: detail });
|
|
127986
128072
|
host.log.warn("chat could not start an inbound connection", {
|
|
127987
128073
|
bot: bot.displayName,
|
|
127988
128074
|
platform: bot.platform,
|
|
127989
|
-
error:
|
|
128075
|
+
error: detail
|
|
127990
128076
|
});
|
|
127991
128077
|
}
|
|
127992
128078
|
});
|
|
@@ -128001,19 +128087,25 @@ var startConnections = (core, inboundHandlersFor) => {
|
|
|
128001
128087
|
const reconcile = () => {
|
|
128002
128088
|
const bots = disposed ? [] : core.bots();
|
|
128003
128089
|
const wanted = /* @__PURE__ */ new Map();
|
|
128004
|
-
const credentials3 = /* @__PURE__ */ new
|
|
128090
|
+
const credentials3 = /* @__PURE__ */ new Map();
|
|
128091
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
128005
128092
|
for (const bot of bots) {
|
|
128006
128093
|
const adapter = adapterFor(bot.platform);
|
|
128007
128094
|
if (adapter === void 0) continue;
|
|
128008
128095
|
const fingerprint = `${bot.platform}:${adapter.columns.map((column) => bot.values[column.key] ?? "").join(" ")}`;
|
|
128009
|
-
|
|
128096
|
+
const duplicateOf = credentials3.get(fingerprint);
|
|
128097
|
+
if (duplicateOf !== void 0) {
|
|
128098
|
+
duplicates.set(bot.rowId, duplicateOf);
|
|
128099
|
+
if (statuses.get(bot.rowId)?.duplicateOf !== duplicateOf) {
|
|
128100
|
+
record3(bot.rowId, { state: "duplicate", duplicateOf });
|
|
128101
|
+
}
|
|
128010
128102
|
host.log.warn("chat did not connect a bot that repeats another bot's credentials", {
|
|
128011
128103
|
bot: bot.displayName,
|
|
128012
128104
|
platform: bot.platform
|
|
128013
128105
|
});
|
|
128014
128106
|
continue;
|
|
128015
128107
|
}
|
|
128016
|
-
credentials3.
|
|
128108
|
+
credentials3.set(fingerprint, bot.rowId);
|
|
128017
128109
|
wanted.set(bot.rowId, { bot, key: connectionKey(adapter, bot) });
|
|
128018
128110
|
}
|
|
128019
128111
|
for (const [rowId, connection] of live) {
|
|
@@ -128021,6 +128113,9 @@ var startConnections = (core, inboundHandlersFor) => {
|
|
|
128021
128113
|
connection.close();
|
|
128022
128114
|
live.delete(rowId);
|
|
128023
128115
|
}
|
|
128116
|
+
for (const rowId of statuses.keys()) {
|
|
128117
|
+
if (!wanted.has(rowId) && !duplicates.has(rowId)) remove(rowId);
|
|
128118
|
+
}
|
|
128024
128119
|
for (const [rowId, { bot, key }] of wanted) {
|
|
128025
128120
|
if (!live.has(rowId)) live.set(rowId, open(bot, key));
|
|
128026
128121
|
}
|
|
@@ -128029,8 +128124,18 @@ var startConnections = (core, inboundHandlersFor) => {
|
|
|
128029
128124
|
host.onDispose(() => {
|
|
128030
128125
|
disposed = true;
|
|
128031
128126
|
reconcile();
|
|
128127
|
+
listeners.clear();
|
|
128032
128128
|
});
|
|
128033
|
-
return {
|
|
128129
|
+
return {
|
|
128130
|
+
reconcile,
|
|
128131
|
+
subscribe: (listener) => {
|
|
128132
|
+
if (!disposed) listeners.add(listener);
|
|
128133
|
+
listener(Object.fromEntries(statuses));
|
|
128134
|
+
return () => {
|
|
128135
|
+
listeners.delete(listener);
|
|
128136
|
+
};
|
|
128137
|
+
}
|
|
128138
|
+
};
|
|
128034
128139
|
};
|
|
128035
128140
|
|
|
128036
128141
|
// src/deliveryHttp.ts
|
|
@@ -128279,6 +128384,7 @@ ${token}` : void 0;
|
|
|
128279
128384
|
};
|
|
128280
128385
|
|
|
128281
128386
|
// src/core.ts
|
|
128387
|
+
var OUTBOUND_QUEUE_LIMIT = 100;
|
|
128282
128388
|
var makeImCore = (input) => {
|
|
128283
128389
|
const { host, t, adapters } = input;
|
|
128284
128390
|
const adapterFor = (platform) => adapters.find((adapter) => adapter.platform === platform);
|
|
@@ -128313,10 +128419,21 @@ var makeImCore = (input) => {
|
|
|
128313
128419
|
const bindChat = (chatKey, threadId) => {
|
|
128314
128420
|
commit("chat-updated", { chatKey, threadId });
|
|
128315
128421
|
};
|
|
128316
|
-
const outbound = makeKeyedQueue(
|
|
128317
|
-
|
|
128318
|
-
|
|
128319
|
-
|
|
128422
|
+
const outbound = makeKeyedQueue(
|
|
128423
|
+
(error) => {
|
|
128424
|
+
host.log.warn("chat could not deliver queued work", { error: describeError(error) });
|
|
128425
|
+
},
|
|
128426
|
+
{
|
|
128427
|
+
limit: OUTBOUND_QUEUE_LIMIT,
|
|
128428
|
+
onFull: (chatKey, limit) => {
|
|
128429
|
+
host.log.warn("chat queue is full; refused a conclusion until restart", {
|
|
128430
|
+
chatKey,
|
|
128431
|
+
limit
|
|
128432
|
+
});
|
|
128433
|
+
}
|
|
128434
|
+
}
|
|
128435
|
+
);
|
|
128436
|
+
const postImages = async (binding, attachments, onFailure) => {
|
|
128320
128437
|
const adapter = adapterFor(binding.platform);
|
|
128321
128438
|
if (adapter?.sendImage === void 0) return;
|
|
128322
128439
|
for (const attachment of attachments) {
|
|
@@ -128333,19 +128450,22 @@ var makeImCore = (input) => {
|
|
|
128333
128450
|
name: attachment.name,
|
|
128334
128451
|
error: describeError(error)
|
|
128335
128452
|
});
|
|
128453
|
+
await onFailure?.(error);
|
|
128336
128454
|
}
|
|
128337
128455
|
}
|
|
128338
128456
|
};
|
|
128339
|
-
const deliver = async (binding, text4, attachments = []) => {
|
|
128340
|
-
|
|
128457
|
+
const deliver = async (binding, text4, attachments = [], options = {}) => {
|
|
128458
|
+
const { retry, onFailure } = options;
|
|
128459
|
+
await postImages(binding, attachments, onFailure);
|
|
128341
128460
|
if (text4.trim() === "") return true;
|
|
128342
128461
|
const adapter = adapterFor(binding.platform);
|
|
128343
128462
|
if (adapter === void 0) return false;
|
|
128344
128463
|
try {
|
|
128345
|
-
await adapter.sendText(binding, text4);
|
|
128464
|
+
await adapter.sendText(binding, text4, { retry });
|
|
128346
128465
|
return true;
|
|
128347
128466
|
} catch (error) {
|
|
128348
128467
|
host.log.warn("chat could not deliver", { error: describeError(error) });
|
|
128468
|
+
await onFailure?.(error);
|
|
128349
128469
|
return false;
|
|
128350
128470
|
}
|
|
128351
128471
|
};
|
|
@@ -128377,6 +128497,92 @@ var makeImCore = (input) => {
|
|
|
128377
128497
|
// src/conclusionDelivery.ts
|
|
128378
128498
|
import { threadOrNull as threadOrNull3 } from "@ycodium-ai/plugin-api";
|
|
128379
128499
|
|
|
128500
|
+
// src/abortableSleep.ts
|
|
128501
|
+
var abortableSleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
128502
|
+
if (signal?.aborted === true) {
|
|
128503
|
+
reject(new Error("aborted"));
|
|
128504
|
+
return;
|
|
128505
|
+
}
|
|
128506
|
+
const onAbort = () => {
|
|
128507
|
+
clearTimeout(timer);
|
|
128508
|
+
reject(new Error("aborted"));
|
|
128509
|
+
};
|
|
128510
|
+
const timer = setTimeout(() => {
|
|
128511
|
+
signal?.removeEventListener("abort", onAbort);
|
|
128512
|
+
resolve();
|
|
128513
|
+
}, ms);
|
|
128514
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
128515
|
+
});
|
|
128516
|
+
|
|
128517
|
+
// src/deliveryFailure.ts
|
|
128518
|
+
import * as NodeCrypto2 from "node:crypto";
|
|
128519
|
+
|
|
128520
|
+
// src/diagnostics.ts
|
|
128521
|
+
var PREFIX = {
|
|
128522
|
+
conn: "IM-CONN",
|
|
128523
|
+
msg: "IM-MSG",
|
|
128524
|
+
setup: "IM-SETUP"
|
|
128525
|
+
};
|
|
128526
|
+
var shortSalt = () => {
|
|
128527
|
+
const bytes = new Uint8Array(2);
|
|
128528
|
+
crypto.getRandomValues(bytes);
|
|
128529
|
+
return Array.from(bytes, (b) => b.toString(16).toUpperCase().padStart(2, "0")).join("");
|
|
128530
|
+
};
|
|
128531
|
+
var stableDiagnosticRef = (kind, digest) => `${PREFIX[kind]}-${digest.slice(0, 16).toUpperCase()}`;
|
|
128532
|
+
var diagnosticRef = (kind, nowMs = Date.now()) => {
|
|
128533
|
+
const stamp = nowMs.toString(36).toUpperCase();
|
|
128534
|
+
return `${PREFIX[kind]}-${stamp}-${shortSalt()}`;
|
|
128535
|
+
};
|
|
128536
|
+
var formatDiagnosticCopy = (report) => [
|
|
128537
|
+
`ok=${report.ok ? "yes" : "no"}`,
|
|
128538
|
+
`platform=${report.platform}`,
|
|
128539
|
+
`bot=${report.botName}`,
|
|
128540
|
+
`row=${report.rowId}`,
|
|
128541
|
+
`stage=${report.stage}`,
|
|
128542
|
+
`at=${report.at}`,
|
|
128543
|
+
`detail=${report.detail}`
|
|
128544
|
+
].join("\n");
|
|
128545
|
+
|
|
128546
|
+
// src/deliveryFailure.ts
|
|
128547
|
+
var deliveryFailure = (core, binding, threadId, turnId) => async (error) => {
|
|
128548
|
+
const rejection = core.adapterFor(binding.platform)?.describeDeliveryRejection?.(error, binding);
|
|
128549
|
+
if (rejection === void 0) return;
|
|
128550
|
+
const { recipients } = rejection;
|
|
128551
|
+
const digest = NodeCrypto2.createHash("sha256").update(JSON.stringify([threadId, turnId, binding.platform, binding.rowId, recipients])).digest("hex");
|
|
128552
|
+
const id = `im.delivery-failed:${digest}`;
|
|
128553
|
+
const reference2 = stableDiagnosticRef("msg", digest);
|
|
128554
|
+
const payload = {
|
|
128555
|
+
platform: binding.platform,
|
|
128556
|
+
recipients,
|
|
128557
|
+
hint: rejection.hint,
|
|
128558
|
+
providerCode: rejection.providerCode,
|
|
128559
|
+
reference: reference2,
|
|
128560
|
+
sourceTurnId: turnId
|
|
128561
|
+
};
|
|
128562
|
+
core.host.log.warn("chat recipient rejected delivery", { threadId, ...payload });
|
|
128563
|
+
if (core.state.opened[threadId] === void 0) return;
|
|
128564
|
+
try {
|
|
128565
|
+
await core.host.threads.externalMessages.append({
|
|
128566
|
+
requestId: id,
|
|
128567
|
+
threadId,
|
|
128568
|
+
messages: [],
|
|
128569
|
+
activities: [
|
|
128570
|
+
{
|
|
128571
|
+
id,
|
|
128572
|
+
tone: "error",
|
|
128573
|
+
kind: "im.delivery-failed",
|
|
128574
|
+
summary: rejection.summary,
|
|
128575
|
+
payload,
|
|
128576
|
+
turnId: null,
|
|
128577
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
128578
|
+
}
|
|
128579
|
+
]
|
|
128580
|
+
});
|
|
128581
|
+
} catch {
|
|
128582
|
+
core.host.log.warn("chat could not append delivery failure notice", { threadId, reference: reference2 });
|
|
128583
|
+
}
|
|
128584
|
+
};
|
|
128585
|
+
|
|
128380
128586
|
// src/threadMessages.ts
|
|
128381
128587
|
import {
|
|
128382
128588
|
isThreadNotFound,
|
|
@@ -128428,20 +128634,30 @@ async function messagesAfterLastUser(threads, threadId) {
|
|
|
128428
128634
|
}
|
|
128429
128635
|
|
|
128430
128636
|
// src/conclusionDelivery.ts
|
|
128637
|
+
var ALWAYS_OWED = () => true;
|
|
128431
128638
|
var makeConclusionDelivery = (core, anchors) => {
|
|
128432
128639
|
let disposed = false;
|
|
128640
|
+
const stopped = new AbortController();
|
|
128433
128641
|
core.host.onDispose(() => {
|
|
128434
128642
|
disposed = true;
|
|
128643
|
+
stopped.abort();
|
|
128435
128644
|
});
|
|
128436
128645
|
const marked = (text4, recovered) => recovered ? `${core.t("reply.conclusionRecovered")}
|
|
128437
128646
|
${text4}` : text4;
|
|
128647
|
+
const sleep3 = (ms) => abortableSleep(ms, stopped.signal).catch(() => void 0);
|
|
128648
|
+
const retryFor = (threadId, owed = ALWAYS_OWED) => ({
|
|
128649
|
+
sleep: sleep3,
|
|
128650
|
+
shouldContinue: async () => !disposed && owed() && await threadOrNull3(core.host.threads, threadId) !== null
|
|
128651
|
+
});
|
|
128438
128652
|
return {
|
|
128653
|
+
retryFor,
|
|
128439
128654
|
prepareConclusion: async (threadId, turnId = null) => {
|
|
128440
128655
|
const thread = await threadOrNull3(core.host.threads, threadId);
|
|
128441
128656
|
const final = thread === null ? void 0 : await latestMessage(
|
|
128442
128657
|
core.host.threads,
|
|
128443
128658
|
threadId,
|
|
128444
|
-
|
|
128659
|
+
// 给了轮次就只取这一轮的正文:排队等着的结论不能拿到下一轮的话。没记轮次的老消息照旧认。
|
|
128660
|
+
(message) => message.role === "assistant" && message.text.trim() !== "" && (turnId === null || message.turnId === null || message.turnId === turnId)
|
|
128445
128661
|
);
|
|
128446
128662
|
const attachments = final === void 0 ? [] : await attachmentsOf(core.host.threads, threadId, final);
|
|
128447
128663
|
return async (binding, options) => {
|
|
@@ -128451,12 +128667,22 @@ ${text4}` : text4;
|
|
|
128451
128667
|
|
|
128452
128668
|
${final.text}`, options.recovered);
|
|
128453
128669
|
const anchored = await anchors.anchored(binding, threadId, turnId ?? final.turnId);
|
|
128454
|
-
return !disposed && core.deliver(anchored, text4, attachments
|
|
128670
|
+
return !disposed && core.deliver(anchored, text4, attachments, {
|
|
128671
|
+
retry: retryFor(threadId, options.owed),
|
|
128672
|
+
onFailure: deliveryFailure(core, binding, threadId, turnId ?? final.turnId)
|
|
128673
|
+
});
|
|
128455
128674
|
};
|
|
128456
128675
|
},
|
|
128457
|
-
|
|
128676
|
+
/**
|
|
128677
|
+
* 发一段已经写好的结论文字(失败通知、卡片定稿失败时的文字兜底):锚点、停用检查、重发与
|
|
128678
|
+
* 拒收提醒都在这里,调用方只管写文字。
|
|
128679
|
+
*/
|
|
128680
|
+
sendText: async (binding, threadId, notice, recovered, turnId = null, owed = ALWAYS_OWED) => {
|
|
128458
128681
|
const anchored = await anchors.anchored(binding, threadId, turnId);
|
|
128459
|
-
return !disposed && core.deliver(anchored, marked(notice, recovered)
|
|
128682
|
+
return !disposed && core.deliver(anchored, marked(notice, recovered), [], {
|
|
128683
|
+
retry: retryFor(threadId, owed),
|
|
128684
|
+
onFailure: deliveryFailure(core, binding, threadId, turnId)
|
|
128685
|
+
});
|
|
128460
128686
|
}
|
|
128461
128687
|
};
|
|
128462
128688
|
};
|
|
@@ -130583,29 +130809,6 @@ var sleep = async (deps) => {
|
|
|
130583
130809
|
}
|
|
130584
130810
|
};
|
|
130585
130811
|
|
|
130586
|
-
// src/redact.ts
|
|
130587
|
-
var DETAIL_MAX_CHARS = 200;
|
|
130588
|
-
var MASK = "***";
|
|
130589
|
-
var TOKEN_LIKE = /[A-Za-z0-9_=-]{24,}/g;
|
|
130590
|
-
var MIN_SECRET_LENGTH = 6;
|
|
130591
|
-
var makeRedactor = () => {
|
|
130592
|
-
const secrets = /* @__PURE__ */ new Set();
|
|
130593
|
-
const redact = (text4) => {
|
|
130594
|
-
let out = text4;
|
|
130595
|
-
for (const secret of [...secrets].sort((a, b) => b.length - a.length)) {
|
|
130596
|
-
out = out.split(secret).join(MASK);
|
|
130597
|
-
}
|
|
130598
|
-
return out.replace(TOKEN_LIKE, MASK);
|
|
130599
|
-
};
|
|
130600
|
-
return {
|
|
130601
|
-
register: (secret) => {
|
|
130602
|
-
if (typeof secret === "string" && secret.length >= MIN_SECRET_LENGTH) secrets.add(secret);
|
|
130603
|
-
},
|
|
130604
|
-
redact,
|
|
130605
|
-
detail: (text4) => redact(text4).slice(0, DETAIL_MAX_CHARS)
|
|
130606
|
-
};
|
|
130607
|
-
};
|
|
130608
|
-
|
|
130609
130812
|
// src/lark/setup/cookieJar.ts
|
|
130610
130813
|
var MAX_REDIRECT_HOPS = 10;
|
|
130611
130814
|
var parseSetCookie = (responseUrl, header) => {
|
|
@@ -131323,21 +131526,7 @@ var buildChecklist = () => ({
|
|
|
131323
131526
|
});
|
|
131324
131527
|
var makeRealClock = () => ({
|
|
131325
131528
|
now: () => Date.now(),
|
|
131326
|
-
sleep:
|
|
131327
|
-
if (signal?.aborted === true) {
|
|
131328
|
-
reject(new Error("aborted"));
|
|
131329
|
-
return;
|
|
131330
|
-
}
|
|
131331
|
-
const onAbort = () => {
|
|
131332
|
-
clearTimeout(timer);
|
|
131333
|
-
reject(new Error("aborted"));
|
|
131334
|
-
};
|
|
131335
|
-
const timer = setTimeout(() => {
|
|
131336
|
-
signal?.removeEventListener("abort", onAbort);
|
|
131337
|
-
resolve();
|
|
131338
|
-
}, ms);
|
|
131339
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
131340
|
-
})
|
|
131529
|
+
sleep: abortableSleep
|
|
131341
131530
|
});
|
|
131342
131531
|
var saveAndConclude = async (ctx, updateSettings, result) => {
|
|
131343
131532
|
try {
|
|
@@ -131429,6 +131618,9 @@ var registerLarkSetup = (ctx, options = {}) => {
|
|
|
131429
131618
|
return runner;
|
|
131430
131619
|
};
|
|
131431
131620
|
|
|
131621
|
+
// src/larkApi.ts
|
|
131622
|
+
import { parseRetryAfterMs } from "@ycodium-ai/plugin-api";
|
|
131623
|
+
|
|
131432
131624
|
// src/larkPost.ts
|
|
131433
131625
|
var styledText = (text4, style) => {
|
|
131434
131626
|
let out = text4;
|
|
@@ -131608,6 +131800,33 @@ var parseLarkReply = (message) => {
|
|
|
131608
131800
|
}
|
|
131609
131801
|
};
|
|
131610
131802
|
|
|
131803
|
+
// src/sendRetry.ts
|
|
131804
|
+
var NO_RETRY = { retry: false };
|
|
131805
|
+
var SEND_RETRY_DELAYS_MS = [1e3, 4e3, 15e3];
|
|
131806
|
+
var MAX_WAIT_MS = 6e4;
|
|
131807
|
+
var SendStoppedError = class extends Error {
|
|
131808
|
+
constructor(cause) {
|
|
131809
|
+
super("send stopped before retrying", { cause });
|
|
131810
|
+
this.name = "SendStoppedError";
|
|
131811
|
+
}
|
|
131812
|
+
};
|
|
131813
|
+
var sendWithRetry = async (request, verdictOf, retry) => {
|
|
131814
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
131815
|
+
try {
|
|
131816
|
+
return await request();
|
|
131817
|
+
} catch (error) {
|
|
131818
|
+
const delayMs = SEND_RETRY_DELAYS_MS[attempt];
|
|
131819
|
+
if (retry === void 0 || delayMs === void 0) throw error;
|
|
131820
|
+
const verdict = verdictOf(error);
|
|
131821
|
+
if (!verdict.retry) throw error;
|
|
131822
|
+
const waitMs = verdict.afterMs ?? delayMs;
|
|
131823
|
+
if (waitMs > MAX_WAIT_MS) throw error;
|
|
131824
|
+
await retry.sleep(waitMs);
|
|
131825
|
+
if (!await retry.shouldContinue()) throw new SendStoppedError(error);
|
|
131826
|
+
}
|
|
131827
|
+
}
|
|
131828
|
+
};
|
|
131829
|
+
|
|
131611
131830
|
// src/splitMessage.ts
|
|
131612
131831
|
var splitMessage = (text4, limit) => {
|
|
131613
131832
|
if (text4.length <= limit) return [text4];
|
|
@@ -131640,19 +131859,39 @@ var LARK_TEXT_MAX_CHARS = 3500;
|
|
|
131640
131859
|
var LarkApiError = class extends Error {
|
|
131641
131860
|
operation;
|
|
131642
131861
|
code;
|
|
131643
|
-
|
|
131862
|
+
status;
|
|
131863
|
+
retryAfterMs;
|
|
131864
|
+
constructor(operation, code2, message, http = {}) {
|
|
131644
131865
|
super(`lark ${operation} failed (code ${String(code2 ?? "?")}): ${message}`);
|
|
131645
131866
|
this.name = "LarkApiError";
|
|
131646
131867
|
this.operation = operation;
|
|
131647
131868
|
this.code = code2;
|
|
131869
|
+
this.status = http.status;
|
|
131870
|
+
this.retryAfterMs = http.retryAfterMs;
|
|
131648
131871
|
}
|
|
131649
131872
|
};
|
|
131650
|
-
var isLarkPermissionError = (error) => error instanceof LarkApiError && (error.code === 99991672 || error.code === 99991679 ||
|
|
131873
|
+
var isLarkPermissionError = (error) => error instanceof LarkApiError && (error.code === 99991672 || error.code === 99991679 || error.status === 401 || error.status === 403);
|
|
131874
|
+
var LARK_RATE_LIMITED = 99991400;
|
|
131875
|
+
var isReplyRejected = (error) => error instanceof LarkApiError && error.status === void 0 && error.code !== LARK_RATE_LIMITED;
|
|
131876
|
+
var larkSendVerdict = (error) => {
|
|
131877
|
+
if (!(error instanceof LarkApiError)) return NO_RETRY;
|
|
131878
|
+
if (error.status === 429 || error.code === LARK_RATE_LIMITED) {
|
|
131879
|
+
return { retry: true, afterMs: error.retryAfterMs };
|
|
131880
|
+
}
|
|
131881
|
+
if (error.status !== void 0 && error.status >= 500) {
|
|
131882
|
+
return { retry: true, afterMs: error.retryAfterMs };
|
|
131883
|
+
}
|
|
131884
|
+
return NO_RETRY;
|
|
131885
|
+
};
|
|
131651
131886
|
var readEnvelope = async (operation, response) => {
|
|
131652
131887
|
if (!response.ok) {
|
|
131653
131888
|
await response.body?.cancel().catch(() => void 0);
|
|
131654
|
-
throw
|
|
131655
|
-
status: response.status
|
|
131889
|
+
throw new LarkApiError(operation, void 0, `HTTP ${String(response.status)}`, {
|
|
131890
|
+
status: response.status,
|
|
131891
|
+
retryAfterMs: parseRetryAfterMs(
|
|
131892
|
+
response.headers.get("retry-after") ?? response.headers.get("x-ogw-ratelimit-reset"),
|
|
131893
|
+
Date.now()
|
|
131894
|
+
) ?? void 0
|
|
131656
131895
|
});
|
|
131657
131896
|
}
|
|
131658
131897
|
const body = await response.json();
|
|
@@ -131679,35 +131918,37 @@ var postMessage = async (input) => {
|
|
|
131679
131918
|
authorization: `Bearer ${input.token}`,
|
|
131680
131919
|
"content-type": "application/json; charset=utf-8"
|
|
131681
131920
|
};
|
|
131682
|
-
const message = {
|
|
131683
|
-
|
|
131921
|
+
const message = {
|
|
131922
|
+
msg_type: input.msgType,
|
|
131923
|
+
content: JSON.stringify(input.content),
|
|
131924
|
+
...input.retry === void 0 ? {} : { uuid: crypto.randomUUID() }
|
|
131925
|
+
};
|
|
131926
|
+
const post = (url, body) => sendWithRetry(
|
|
131927
|
+
async () => (await readEnvelope(
|
|
131928
|
+
input.operation,
|
|
131929
|
+
await input.http(url, { method: "POST", headers, body: JSON.stringify(body) })
|
|
131930
|
+
)).data,
|
|
131931
|
+
larkSendVerdict,
|
|
131932
|
+
input.retry
|
|
131933
|
+
);
|
|
131684
131934
|
if (input.reply !== void 0) {
|
|
131685
131935
|
try {
|
|
131686
|
-
const
|
|
131936
|
+
const sent2 = await post(
|
|
131687
131937
|
`${LARK_BASE}/im/v1/messages/${encodeURIComponent(input.reply.messageId)}/reply`,
|
|
131688
|
-
{
|
|
131689
|
-
method: "POST",
|
|
131690
|
-
headers,
|
|
131691
|
-
body: JSON.stringify({
|
|
131692
|
-
...message,
|
|
131693
|
-
...input.reply.inThread ? { reply_in_thread: true } : {}
|
|
131694
|
-
})
|
|
131695
|
-
}
|
|
131938
|
+
{ ...message, ...input.reply.inThread ? { reply_in_thread: true } : {} }
|
|
131696
131939
|
);
|
|
131697
|
-
|
|
131698
|
-
|
|
131699
|
-
return sent?.message_id ?? null;
|
|
131940
|
+
if (input.reply.inThread) input.onThreadReply?.(sent2?.thread_id || void 0);
|
|
131941
|
+
return sent2?.message_id ?? null;
|
|
131700
131942
|
} catch (error) {
|
|
131701
|
-
if (!(error
|
|
131943
|
+
if (!isReplyRejected(error)) throw error;
|
|
131702
131944
|
}
|
|
131703
131945
|
}
|
|
131704
131946
|
const idType = input.receiveIdType ?? "chat_id";
|
|
131705
|
-
const
|
|
131706
|
-
|
|
131707
|
-
|
|
131708
|
-
body: JSON.stringify({ receive_id: input.chatId, ...message })
|
|
131947
|
+
const sent = await post(`${LARK_BASE}/im/v1/messages?receive_id_type=${idType}`, {
|
|
131948
|
+
receive_id: input.chatId,
|
|
131949
|
+
...message
|
|
131709
131950
|
});
|
|
131710
|
-
return
|
|
131951
|
+
return sent?.message_id ?? null;
|
|
131711
131952
|
};
|
|
131712
131953
|
var readMessage = async (input) => {
|
|
131713
131954
|
const response = await input.http(
|
|
@@ -137310,7 +137551,7 @@ var UNSUPPORTED_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
|
137310
137551
|
"share_chat",
|
|
137311
137552
|
"share_user",
|
|
137312
137553
|
"system",
|
|
137313
|
-
"
|
|
137554
|
+
"merge_forward",
|
|
137314
137555
|
"interactive"
|
|
137315
137556
|
]);
|
|
137316
137557
|
var botIdsOf = (mentions, appId) => {
|
|
@@ -137482,6 +137723,7 @@ var cardActionOperator = (event) => {
|
|
|
137482
137723
|
}
|
|
137483
137724
|
return null;
|
|
137484
137725
|
};
|
|
137726
|
+
var isLarkAppId = (appId) => /^cli_[0-9a-fA-F]{16}$/u.test(appId);
|
|
137485
137727
|
var startLarkInbound = (input) => {
|
|
137486
137728
|
const dispatcher = new import_node_sdk.EventDispatcher({}).register({
|
|
137487
137729
|
"im.message.receive_v1": (event) => {
|
|
@@ -137523,20 +137765,42 @@ var startLarkInbound = (input) => {
|
|
|
137523
137765
|
return notice === null ? {} : { toast: { type: "info", content: notice } };
|
|
137524
137766
|
}
|
|
137525
137767
|
});
|
|
137768
|
+
if (!isLarkAppId(input.appId)) {
|
|
137769
|
+
input.onConnectionState?.({ state: "failed", reason: "invalid-app-id" });
|
|
137770
|
+
return { close: () => void 0 };
|
|
137771
|
+
}
|
|
137772
|
+
let closed = false;
|
|
137773
|
+
const connected = () => {
|
|
137774
|
+
if (!closed) input.onConnectionState?.({ state: "connected" });
|
|
137775
|
+
};
|
|
137776
|
+
const failed = (error) => {
|
|
137777
|
+
if (!closed) {
|
|
137778
|
+
input.onConnectionState?.({ state: "failed", reason: "disconnected", error });
|
|
137779
|
+
}
|
|
137780
|
+
};
|
|
137526
137781
|
const client = new import_node_sdk.WSClient({
|
|
137527
137782
|
appId: input.appId,
|
|
137528
137783
|
appSecret: input.appSecret,
|
|
137529
137784
|
...input.domain === void 0 ? {} : { domain: input.domain },
|
|
137530
137785
|
autoReconnect: true,
|
|
137531
|
-
|
|
137786
|
+
onReady: connected,
|
|
137787
|
+
onReconnected: connected,
|
|
137788
|
+
onReconnecting: () => failed(),
|
|
137789
|
+
onError: (cause) => {
|
|
137790
|
+
if (closed) return;
|
|
137791
|
+
failed(cause);
|
|
137792
|
+
input.onError(cause.message);
|
|
137793
|
+
}
|
|
137532
137794
|
});
|
|
137533
|
-
void client.start({ eventDispatcher: dispatcher });
|
|
137534
|
-
return {
|
|
137795
|
+
void client.start({ eventDispatcher: dispatcher }).catch(failed);
|
|
137796
|
+
return {
|
|
137797
|
+
close: () => {
|
|
137798
|
+
closed = true;
|
|
137799
|
+
client.close({ force: true });
|
|
137800
|
+
}
|
|
137801
|
+
};
|
|
137535
137802
|
};
|
|
137536
137803
|
|
|
137537
|
-
// src/replyReference.ts
|
|
137538
|
-
import * as NodeCrypto2 from "node:crypto";
|
|
137539
|
-
|
|
137540
137804
|
// src/deadline.ts
|
|
137541
137805
|
var withDeadline2 = async (timeoutMs, load) => {
|
|
137542
137806
|
const signal = AbortSignal.timeout(timeoutMs);
|
|
@@ -137554,6 +137818,7 @@ var withDeadline2 = async (timeoutMs, load) => {
|
|
|
137554
137818
|
};
|
|
137555
137819
|
|
|
137556
137820
|
// src/replyReference.ts
|
|
137821
|
+
import * as NodeCrypto3 from "node:crypto";
|
|
137557
137822
|
var CONTENT_MAX = 8e3;
|
|
137558
137823
|
var ATTACHMENTS_MAX = 20;
|
|
137559
137824
|
var AUTHOR_MAX = 256;
|
|
@@ -137626,15 +137891,16 @@ var formatReplyReference = (reference2) => {
|
|
|
137626
137891
|
...lines.map((line) => `> ${line}`)
|
|
137627
137892
|
].join("\n");
|
|
137628
137893
|
};
|
|
137629
|
-
var textWithInboundContext = (message, rowId, t) => {
|
|
137630
|
-
const
|
|
137631
|
-
|
|
137632
|
-
|
|
137633
|
-
|
|
137894
|
+
var textWithInboundContext = (message, rowId, t, topicRoot) => {
|
|
137895
|
+
const text4 = [
|
|
137896
|
+
formatReplyReference(topicRoot),
|
|
137897
|
+
formatReplyReference(message.replyTo),
|
|
137898
|
+
message.text
|
|
137899
|
+
].filter((part) => part !== null).join("\n\n");
|
|
137634
137900
|
if (message.chatKind !== "group" || message.senderId === null) return text4;
|
|
137635
137901
|
let name = cleanString(message.senderName, AUTHOR_MAX).value;
|
|
137636
137902
|
if (!name) {
|
|
137637
|
-
const code2 =
|
|
137903
|
+
const code2 = NodeCrypto3.createHash("sha256").update(JSON.stringify([rowId, message.senderId])).digest("hex").slice(0, 4);
|
|
137638
137904
|
name = t("source.member", { code: code2 });
|
|
137639
137905
|
}
|
|
137640
137906
|
const chat = cleanString(message.chatTitle, AUTHOR_MAX).value;
|
|
@@ -137687,6 +137953,26 @@ var makeLookup = (rowId, load) => {
|
|
|
137687
137953
|
};
|
|
137688
137954
|
var makeLarkMessageContext = (deps) => {
|
|
137689
137955
|
let contactDenied = false;
|
|
137956
|
+
const deliveredRoots = makeBoundedSeen(CACHE_LIMIT);
|
|
137957
|
+
const loadReference = (messageId) => loadReplyReference(async (signal) => {
|
|
137958
|
+
const token = await deps.tenantToken();
|
|
137959
|
+
signal.throwIfAborted();
|
|
137960
|
+
return fetchMessageReference({ http: deps.http, token, messageId, signal });
|
|
137961
|
+
});
|
|
137962
|
+
const topicRootForSession = (message) => {
|
|
137963
|
+
const topic = message.topic;
|
|
137964
|
+
if (topic === void 0 || topic.rootGiven === false) return void 0;
|
|
137965
|
+
return async (recipientId) => {
|
|
137966
|
+
const key = JSON.stringify([message.chatId, topic.rootMessageId, recipientId]);
|
|
137967
|
+
if (deliveredRoots.has(key)) return void 0;
|
|
137968
|
+
return {
|
|
137969
|
+
reference: topic.rootMessageId === message.messageId ? void 0 : await loadReference(topic.rootMessageId),
|
|
137970
|
+
confirmConsumed: () => {
|
|
137971
|
+
deliveredRoots.claim(key);
|
|
137972
|
+
}
|
|
137973
|
+
};
|
|
137974
|
+
};
|
|
137975
|
+
};
|
|
137690
137976
|
const userName = makeLookup(deps.rowId, async (openId, signal) => {
|
|
137691
137977
|
try {
|
|
137692
137978
|
const token = await deps.tenantToken();
|
|
@@ -137713,7 +137999,7 @@ var makeLarkMessageContext = (deps) => {
|
|
|
137713
137999
|
});
|
|
137714
138000
|
return name instanceof Promise || chat instanceof Promise ? Promise.all([name, chat]).then(([senderName, info]) => fields(senderName, info)) : fields(name, chat);
|
|
137715
138001
|
};
|
|
137716
|
-
return { chatInfo, forMessage };
|
|
138002
|
+
return { chatInfo, forMessage, loadReference, topicRootForSession };
|
|
137717
138003
|
};
|
|
137718
138004
|
|
|
137719
138005
|
// src/larkAdapter.ts
|
|
@@ -137755,6 +138041,7 @@ var larkConfigIssues = (binding) => {
|
|
|
137755
138041
|
const { appId, appSecret } = credentials(binding);
|
|
137756
138042
|
const issues = [];
|
|
137757
138043
|
if (appId === "") issues.push({ column: "larkAppId", code: "required" });
|
|
138044
|
+
else if (!isLarkAppId(appId)) issues.push({ column: "larkAppId", code: "format" });
|
|
137758
138045
|
if (appSecret === "") issues.push({ column: "larkAppSecret", code: "required" });
|
|
137759
138046
|
return issues;
|
|
137760
138047
|
};
|
|
@@ -137842,7 +138129,7 @@ var makeLarkAdapter = (deps) => {
|
|
|
137842
138129
|
return rootMessageId === void 0 ? void 0 : groupId;
|
|
137843
138130
|
},
|
|
137844
138131
|
validate: larkConfigIssues,
|
|
137845
|
-
isConfigured: (binding) => larkConfigIssues(binding).
|
|
138132
|
+
isConfigured: (binding) => larkConfigIssues(binding).every((issue) => issue.code !== "required"),
|
|
137846
138133
|
connect: (binding, handlers) => {
|
|
137847
138134
|
const { appId, appSecret } = credentials(binding);
|
|
137848
138135
|
const port = {
|
|
@@ -137871,6 +138158,7 @@ var makeLarkAdapter = (deps) => {
|
|
|
137871
138158
|
topicOnMention: topicOnMentionOf(binding),
|
|
137872
138159
|
isSoloGroup: soloGroupFor(context),
|
|
137873
138160
|
onError: handlers.onError,
|
|
138161
|
+
...handlers.onConnectionState === void 0 ? {} : { onConnectionState: handlers.onConnectionState },
|
|
137874
138162
|
onCardAction: handlers.onButton,
|
|
137875
138163
|
onPanelClick: (click, operatorOpenId) => handlers.onPanelClick?.({
|
|
137876
138164
|
chatId: click.chatId,
|
|
@@ -137883,14 +138171,7 @@ var makeLarkAdapter = (deps) => {
|
|
|
137883
138171
|
const { topic } = message;
|
|
137884
138172
|
const source = context.forMessage(message);
|
|
137885
138173
|
const parentMessageId = message.parentMessageId;
|
|
137886
|
-
const reference2 = parentMessageId === void 0 ? null :
|
|
137887
|
-
async (signal) => fetchMessageReference({
|
|
137888
|
-
http: deps.http,
|
|
137889
|
-
token: await tenantToken(binding),
|
|
137890
|
-
messageId: parentMessageId,
|
|
137891
|
-
signal
|
|
137892
|
-
})
|
|
137893
|
-
);
|
|
138174
|
+
const reference2 = parentMessageId === void 0 ? null : context.loadReference(parentMessageId);
|
|
137894
138175
|
const deliver = (names, replyTo) => handlers.onMessage({
|
|
137895
138176
|
messageId: message.messageId,
|
|
137896
138177
|
// 已经开出来的话题就是它自己那个聊天;将要开出来的(主窗口里 @ 机器人)先算群的,
|
|
@@ -137906,6 +138187,7 @@ var makeLarkAdapter = (deps) => {
|
|
|
137906
138187
|
senderId: message.senderOpenId,
|
|
137907
138188
|
...names,
|
|
137908
138189
|
text: message.text,
|
|
138190
|
+
topicRootForSession: context.topicRootForSession(message),
|
|
137909
138191
|
...replyTo === void 0 ? {} : { replyTo },
|
|
137910
138192
|
chatKind: message.chatType === "p2p" ? "private" : "group",
|
|
137911
138193
|
replyInThread: message.inThread,
|
|
@@ -137960,7 +138242,8 @@ var makeLarkAdapter = (deps) => {
|
|
|
137960
138242
|
const messageId = await sendChatText({
|
|
137961
138243
|
...target2,
|
|
137962
138244
|
receiveIdType,
|
|
137963
|
-
text: chunk
|
|
138245
|
+
text: chunk,
|
|
138246
|
+
retry: options?.retry
|
|
137964
138247
|
});
|
|
137965
138248
|
deps.log.info("lark delivered a message", { messageId, bot: binding.displayName });
|
|
137966
138249
|
}
|
|
@@ -137974,6 +138257,9 @@ var makeLarkAdapter = (deps) => {
|
|
|
137974
138257
|
detail: "missing app id or secret in saved config"
|
|
137975
138258
|
};
|
|
137976
138259
|
}
|
|
138260
|
+
if (!isLarkAppId(appId)) {
|
|
138261
|
+
return { stage: "credentials", ok: false, detail: "malformed app id in saved config" };
|
|
138262
|
+
}
|
|
137977
138263
|
try {
|
|
137978
138264
|
const { expiresInSeconds } = await fetchTenantToken({ http: deps.http, appId, appSecret });
|
|
137979
138265
|
return {
|
|
@@ -138285,7 +138571,7 @@ var en_default = {
|
|
|
138285
138571
|
},
|
|
138286
138572
|
wecomAppCallbackBaseUrl: {
|
|
138287
138573
|
label: "Public callback base URL (optional)",
|
|
138288
|
-
description: "When set,
|
|
138574
|
+
description: "The public address that forwards to this machine's callback port. When set, the full callback URL to paste into WeCom \u201CReceive messages \u2192 API receive\u201D appears below; otherwise only the path does.",
|
|
138289
138575
|
placeholder: "https://im.example.com or http://IP:30987"
|
|
138290
138576
|
},
|
|
138291
138577
|
wecomAppApiBaseUrl: {
|
|
@@ -138295,9 +138581,14 @@ var en_default = {
|
|
|
138295
138581
|
},
|
|
138296
138582
|
wecomAppListenPort: {
|
|
138297
138583
|
label: "Local callback port (optional)",
|
|
138298
|
-
description: "Defaults to 30987 on 127.0.0.1
|
|
138584
|
+
description: "Defaults to 30987. Self-built apps listening on the same address share one port; rows with different listen addresses (say 0.0.0.0 and 127.0.0.1) need different ports, or the second one fails to listen.",
|
|
138299
138585
|
placeholder: "30987"
|
|
138300
138586
|
},
|
|
138587
|
+
wecomAppListenHost: {
|
|
138588
|
+
label: "Local listen address (optional)",
|
|
138589
|
+
description: "Defaults to 127.0.0.1: only this machine can reach the callback port, so put a reverse proxy or tunnel in front of it. 0.0.0.0 listens on every network interface, which opens the callback port to the network; only use it behind a firewall you control.",
|
|
138590
|
+
placeholder: "127.0.0.1"
|
|
138591
|
+
},
|
|
138301
138592
|
wechatBotToken: {
|
|
138302
138593
|
label: "WeChat bot token",
|
|
138303
138594
|
description: "bot_token from QR binding. Live iLink login is gated by proposal 0069; filling this in does not connect yet."
|
|
@@ -138308,6 +138599,7 @@ var en_default = {
|
|
|
138308
138599
|
}
|
|
138309
138600
|
},
|
|
138310
138601
|
reply: {
|
|
138602
|
+
wecomDeliveryFailed: "This reply didn't reach {{recipient}} in WeCom: they are outside this app's visible range. Add them to the app's visible range in the WeCom admin console, then ask the agent to send it again.",
|
|
138311
138603
|
conclusionRecovered: "(Finished while restarting; delivered now)",
|
|
138312
138604
|
notAllowed: "You are not on this bot's allow list, so this tap had no effect.",
|
|
138313
138605
|
noDefaultModel: 'Project "{{title}}" has no agent selected yet, so a thread cannot be started. Send /model to pick one, or set a default in the project settings, then message again.',
|
|
@@ -138331,7 +138623,8 @@ var en_default = {
|
|
|
138331
138623
|
unsupportedType: "I can't process {{type}} messages yet.",
|
|
138332
138624
|
unsupportedFolder: "Folders can't be downloaded. Zip it and send the archive instead.",
|
|
138333
138625
|
sendingFile: "Sending {{name}}:",
|
|
138334
|
-
notAllowedYet: `You are not on the allow list yet. Your user id is {{id}}. Add it under Settings \u2192 Plugins \u2192 Chat, in this bot's "Allowed people" box
|
|
138626
|
+
notAllowedYet: `You are not on the allow list yet. Your user id is {{id}}. Add it under Settings \u2192 Plugins \u2192 Chat, in this bot's "Allowed people" box.`,
|
|
138627
|
+
received: "Got it, working on it."
|
|
138335
138628
|
},
|
|
138336
138629
|
approval: {
|
|
138337
138630
|
allow: "Allow",
|
|
@@ -138662,13 +138955,16 @@ var en_default = {
|
|
|
138662
138955
|
description: "Verify platform credentials still work; does not open a session or call a model.",
|
|
138663
138956
|
running: "Checking {{rowId}}\u2026",
|
|
138664
138957
|
done: "Connection OK",
|
|
138665
|
-
failed: "Connection failed
|
|
138958
|
+
failed: "Connection failed",
|
|
138666
138959
|
notSaved: "Save this row first (credentials are read from saved config only).",
|
|
138667
138960
|
hint: {
|
|
138668
|
-
badToken: "This does not look like a bot token. Copy it again from BotFather: digits, a colon, then the key
|
|
138669
|
-
unauthorized: "Telegram does not accept this token. It may have been revoked; get the current one from BotFather
|
|
138670
|
-
notBot: "This token does not belong to a bot. Use the token BotFather gave you
|
|
138671
|
-
webhookActive: "This bot has a webhook set by another service, so it cannot receive messages here. Remove the webhook there, then check again
|
|
138961
|
+
badToken: "This does not look like a bot token. Copy it again from BotFather: digits, a colon, then the key.",
|
|
138962
|
+
unauthorized: "Telegram does not accept this token. It may have been revoked; get the current one from BotFather.",
|
|
138963
|
+
notBot: "This token does not belong to a bot. Use the token BotFather gave you.",
|
|
138964
|
+
webhookActive: "This bot has a webhook set by another service, so it cannot receive messages here. Remove the webhook there, then check again.",
|
|
138965
|
+
wecomTrustedIp: "Add this machine's outbound public IP to the app's trusted IP list in the WeCom admin console.",
|
|
138966
|
+
wecomInvalidUser: "Check that the recipient, department or tag exists and is in this app's visible range.",
|
|
138967
|
+
wecomInvalidAgent: "Check the AgentId against this self-built application in the WeCom admin console."
|
|
138672
138968
|
}
|
|
138673
138969
|
},
|
|
138674
138970
|
copyDiagnostics: {
|
|
@@ -138676,24 +138972,24 @@ var en_default = {
|
|
|
138676
138972
|
description: "Run a connection probe and produce copy-paste diagnostics (no secrets).",
|
|
138677
138973
|
running: "Building diagnostics for {{rowId}}\u2026",
|
|
138678
138974
|
done: "Diagnostics ready \u2014 see details below",
|
|
138679
|
-
failed: "Diagnostics failed
|
|
138975
|
+
failed: "Diagnostics failed",
|
|
138680
138976
|
notSaved: "Save this row first before copying diagnostics."
|
|
138681
138977
|
},
|
|
138682
138978
|
diagnostic: {
|
|
138683
|
-
ref: "
|
|
138979
|
+
ref: "Reference: {{ref}}\n{{detail}}"
|
|
138684
138980
|
},
|
|
138685
138981
|
larkRepair: {
|
|
138686
138982
|
label: "Repair scopes",
|
|
138687
|
-
description: "
|
|
138983
|
+
description: "Check whether the saved credentials can mint a token; scopes, event subscriptions and publishing are not checked automatically.",
|
|
138688
138984
|
step: {
|
|
138689
|
-
scopes: "
|
|
138690
|
-
events: "
|
|
138691
|
-
publish: "
|
|
138985
|
+
scopes: "Scopes \u2014 not checked",
|
|
138986
|
+
events: "Event subscriptions \u2014 not checked",
|
|
138987
|
+
publish: "Publishing \u2014 not checked",
|
|
138692
138988
|
verify: "Verify the app can still mint a tenant token"
|
|
138693
138989
|
},
|
|
138694
|
-
done: "
|
|
138695
|
-
hint: "
|
|
138696
|
-
failed: "Could not
|
|
138990
|
+
done: "Only token issuance was verified. Scopes, event subscriptions and publishing were not checked automatically; review them on the Feishu open platform.",
|
|
138991
|
+
hint: "Reference: {{ref}}\n{{detail}}\nReview scopes, event subscriptions and publishing on the Feishu open platform; none were checked automatically.",
|
|
138992
|
+
failed: "Could not mint a token with the saved credentials. Scopes, event subscriptions and publishing were not checked automatically; review them on the Feishu open platform.",
|
|
138697
138993
|
notLark: "This row is not a saved Lark bot."
|
|
138698
138994
|
}
|
|
138699
138995
|
},
|
|
@@ -138732,7 +139028,23 @@ var en_default = {
|
|
|
138732
139028
|
removeFailed: "Couldn't delete this bot.",
|
|
138733
139029
|
status: {
|
|
138734
139030
|
ready: "Ready",
|
|
138735
|
-
incomplete: "Incomplete"
|
|
139031
|
+
incomplete: "Incomplete",
|
|
139032
|
+
connecting: "Connecting",
|
|
139033
|
+
connected: "Connected",
|
|
139034
|
+
notConnected: "Not connected"
|
|
139035
|
+
},
|
|
139036
|
+
connection: {
|
|
139037
|
+
failed: "The last connection attempt failed.",
|
|
139038
|
+
details: "Details: {{error}}",
|
|
139039
|
+
reason: {
|
|
139040
|
+
"not-available": "This platform can't be connected yet.",
|
|
139041
|
+
"invalid-app-id": "The App ID isn't in the right format.",
|
|
139042
|
+
disconnected: "The connection to the platform is down.",
|
|
139043
|
+
"subscription-failed": "The platform didn't confirm the subscription.",
|
|
139044
|
+
"token-unavailable": "Couldn't get an access token.",
|
|
139045
|
+
"credentials-rejected": "The platform rejected the credentials."
|
|
139046
|
+
},
|
|
139047
|
+
duplicate: "Uses the same credentials as \u201C{{name}}\u201D. Only that row connects."
|
|
138736
139048
|
},
|
|
138737
139049
|
secret: {
|
|
138738
139050
|
saved: "Saved. Leave blank to keep it.",
|
|
@@ -138744,7 +139056,8 @@ var en_default = {
|
|
|
138744
139056
|
format: "This format isn't right."
|
|
138745
139057
|
},
|
|
138746
139058
|
publicField: {
|
|
138747
|
-
callbackUrl: "Callback URL"
|
|
139059
|
+
callbackUrl: "Callback URL",
|
|
139060
|
+
callbackPath: "Callback path"
|
|
138748
139061
|
},
|
|
138749
139062
|
action: {
|
|
138750
139063
|
running: "Working\u2026",
|
|
@@ -138770,6 +139083,11 @@ var en_default = {
|
|
|
138770
139083
|
untitled: "New target",
|
|
138771
139084
|
removeConfirm: "Delete this target",
|
|
138772
139085
|
removeFailed: "Couldn't delete this target."
|
|
139086
|
+
},
|
|
139087
|
+
publicFieldHint: {
|
|
139088
|
+
callbackNeedsKeys: "Fill in Token and EncodingAESKey and save; the callback URL is derived from them and appears here.",
|
|
139089
|
+
callbackPathNeedsBase: "Put the public address that forwards to this machine in front of this path, or fill in the public callback base URL above to get the full URL.",
|
|
139090
|
+
callbackFollowsKeys: "This URL changes when Token or EncodingAESKey changes. Paste it into WeCom again after changing them."
|
|
138773
139091
|
}
|
|
138774
139092
|
},
|
|
138775
139093
|
team: {
|
|
@@ -138955,7 +139273,7 @@ var zh_CN_default = {
|
|
|
138955
139273
|
},
|
|
138956
139274
|
wecomAppCallbackBaseUrl: {
|
|
138957
139275
|
label: "\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF08\u53EF\u9009\uFF09",
|
|
138958
|
-
description: "\
|
|
139276
|
+
description: "\u8F6C\u53D1\u5230\u672C\u673A\u56DE\u8C03\u7AEF\u53E3\u7684\u516C\u7F51\u5730\u5740\u3002\u586B\u4E86\u4E0B\u9762\u5C31\u7ED9\u51FA\u5B8C\u6574\u56DE\u8C03\u5730\u5740\uFF0C\u8D34\u8FDB\u4F01\u4E1A\u5FAE\u4FE1\u300C\u63A5\u6536\u6D88\u606F \u2192 \u8BBE\u7F6E API \u63A5\u6536\u300D\uFF1B\u4E0D\u586B\u53EA\u7ED9\u8DEF\u5F84\u3002",
|
|
138959
139277
|
placeholder: "https://im.example.com \u6216 http://IP:30987"
|
|
138960
139278
|
},
|
|
138961
139279
|
wecomAppApiBaseUrl: {
|
|
@@ -138965,9 +139283,14 @@ var zh_CN_default = {
|
|
|
138965
139283
|
},
|
|
138966
139284
|
wecomAppListenPort: {
|
|
138967
139285
|
label: "\u672C\u673A\u56DE\u8C03\u7AEF\u53E3\uFF08\u53EF\u9009\uFF09",
|
|
138968
|
-
description: "\u9ED8\u8BA4 30987\
|
|
139286
|
+
description: "\u9ED8\u8BA4 30987\u3002\u76D1\u542C\u5730\u5740\u76F8\u540C\u7684\u81EA\u5EFA\u5E94\u7528\u5171\u7528\u4E00\u4E2A\u7AEF\u53E3\uFF1B\u76D1\u542C\u5730\u5740\u4E0D\u540C\u7684\u4E24\u884C\uFF08\u6BD4\u5982 0.0.0.0 \u548C 127.0.0.1\uFF09\u8981\u7528\u4E0D\u540C\u7AEF\u53E3\uFF0C\u5426\u5219\u540E\u4E00\u4E2A\u76D1\u542C\u4E0D\u8D77\u6765\u3002",
|
|
138969
139287
|
placeholder: "30987"
|
|
138970
139288
|
},
|
|
139289
|
+
wecomAppListenHost: {
|
|
139290
|
+
label: "\u672C\u673A\u76D1\u542C\u5730\u5740\uFF08\u53EF\u9009\uFF09",
|
|
139291
|
+
description: "\u9ED8\u8BA4 127.0.0.1\uFF1A\u53EA\u6709\u672C\u673A\u8FDE\u5F97\u4E0A\u56DE\u8C03\u7AEF\u53E3\uFF0C\u9700\u8981\u5728\u524D\u9762\u653E\u53CD\u4EE3\u6216\u96A7\u9053\u3002\u586B 0.0.0.0 \u4F1A\u5728\u6240\u6709\u7F51\u5361\u4E0A\u76D1\u542C\uFF0C\u7B49\u4E8E\u628A\u56DE\u8C03\u7AEF\u53E3\u5BF9\u5916\u5F00\u653E\uFF0C\u8981\u81EA\u5DF1\u7528\u9632\u706B\u5899\u63A7\u597D\u3002",
|
|
139292
|
+
placeholder: "127.0.0.1"
|
|
139293
|
+
},
|
|
138971
139294
|
wechatBotToken: {
|
|
138972
139295
|
label: "\u5FAE\u4FE1\u673A\u5668\u4EBA\u4EE4\u724C",
|
|
138973
139296
|
description: "\u626B\u7801\u7ED1\u5B9A\u540E\u5F97\u5230\u7684 bot_token\u3002\u771F\u767B\u5F55\u5C1A\u672A\u5F00\u653E\uFF1A\u586B\u4E86\u4E5F\u4E0D\u4F1A\u8FDE\u4E0A iLink\uFF0C\u89C1\u63D0\u6848 0069 \u5B89\u5168\u8BC4\u5BA1\u3002"
|
|
@@ -138978,6 +139301,7 @@ var zh_CN_default = {
|
|
|
138978
139301
|
}
|
|
138979
139302
|
},
|
|
138980
139303
|
reply: {
|
|
139304
|
+
wecomDeliveryFailed: "\u8FD9\u6761\u56DE\u590D\u6CA1\u9001\u5230\u4F01\u4E1A\u5FAE\u4FE1\u91CC\u7684 {{recipient}}\uFF1A\u5BF9\u65B9\u4E0D\u5728\u8FD9\u4E2A\u5E94\u7528\u7684\u53EF\u89C1\u8303\u56F4\u3002\u5230\u4F01\u4E1A\u5FAE\u4FE1\u7BA1\u7406\u540E\u53F0\u628A\u4ED6\u4EEC\u52A0\u8FDB\u5E94\u7528\u7684\u53EF\u89C1\u8303\u56F4\uFF0C\u518D\u8BA9 agent \u91CD\u53D1\u4E00\u6B21\u3002",
|
|
138981
139305
|
conclusionRecovered: "\uFF08\u91CD\u542F\u671F\u95F4\u5B8C\u6210\uFF0C\u73B0\u5728\u8865\u53D1\uFF09",
|
|
138982
139306
|
notAllowed: "\u4F60\u4E0D\u5728\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u5141\u8BB8\u540D\u5355\u91CC\uFF0C\u8FD9\u6B21\u70B9\u51FB\u6CA1\u6709\u751F\u6548\u3002",
|
|
138983
139307
|
noDefaultModel: "\u9879\u76EE\u300C{{title}}\u300D\u8FD8\u6CA1\u9009 agent\uFF0C\u5F00\u4E0D\u4E86\u4F1A\u8BDD\u3002\u53D1 /model \u9009\u4E00\u4E2A\uFF0C\u6216\u8005\u5230\u9879\u76EE\u8BBE\u7F6E\u91CC\u8BBE\u4E2A\u9ED8\u8BA4\uFF0C\u518D\u53D1\u4E00\u6B21\u6D88\u606F\u3002",
|
|
@@ -139001,7 +139325,8 @@ var zh_CN_default = {
|
|
|
139001
139325
|
unsupportedType: "\u6211\u8FD8\u4E0D\u80FD\u5904\u7406 {{type}} \u7C7B\u578B\u7684\u6D88\u606F\u3002",
|
|
139002
139326
|
unsupportedFolder: "\u6587\u4EF6\u5939\u6CA1\u6CD5\u4E0B\u8F7D\uFF0C\u8BF7\u6253\u5305\u6210\u538B\u7F29\u6587\u4EF6\u518D\u53D1\u3002",
|
|
139003
139327
|
sendingFile: "\u6B63\u5728\u53D1\u9001 {{name}}\uFF1A",
|
|
139004
|
-
notAllowedYet: "\u4F60\u8FD8\u4E0D\u5728\u5141\u8BB8\u540D\u5355\u91CC\uFF0C\u4F60\u7684\u7528\u6237 id \u662F {{id}}\uFF0C\u8BF7\u628A\u5B83\u586B\u8FDB \u8BBE\u7F6E \u2192 \u63D2\u4EF6 \u2192 \u804A\u5929 \u2192 \u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u300C\u5141\u8BB8\u7684\u4EBA\u300D\u3002"
|
|
139328
|
+
notAllowedYet: "\u4F60\u8FD8\u4E0D\u5728\u5141\u8BB8\u540D\u5355\u91CC\uFF0C\u4F60\u7684\u7528\u6237 id \u662F {{id}}\uFF0C\u8BF7\u628A\u5B83\u586B\u8FDB \u8BBE\u7F6E \u2192 \u63D2\u4EF6 \u2192 \u804A\u5929 \u2192 \u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u300C\u5141\u8BB8\u7684\u4EBA\u300D\u3002",
|
|
139329
|
+
received: "\u6536\u5230\uFF0C\u5728\u5904\u7406\u3002"
|
|
139005
139330
|
},
|
|
139006
139331
|
approval: {
|
|
139007
139332
|
allow: "\u5141\u8BB8",
|
|
@@ -139332,13 +139657,16 @@ var zh_CN_default = {
|
|
|
139332
139657
|
description: "\u9A8C\u8BC1\u5E73\u53F0\u51ED\u636E\u662F\u5426\u4ECD\u53EF\u7528\uFF1B\u4E0D\u4F1A\u5F00\u4F1A\u8BDD\uFF0C\u4E5F\u4E0D\u4F1A\u8C03\u6A21\u578B\u3002",
|
|
139333
139658
|
running: "\u6B63\u5728\u68C0\u67E5 {{rowId}} \u2026",
|
|
139334
139659
|
done: "\u8FDE\u63A5\u6B63\u5E38",
|
|
139335
|
-
failed: "\u8FDE\u63A5\u5931\u8D25
|
|
139660
|
+
failed: "\u8FDE\u63A5\u5931\u8D25",
|
|
139336
139661
|
notSaved: "\u8BF7\u5148\u4FDD\u5B58\u8FD9\u4E00\u884C\u518D\u68C0\u67E5\u8FDE\u63A5\uFF08\u51ED\u636E\u53EA\u4ECE\u5DF2\u4FDD\u5B58\u914D\u7F6E\u8BFB\u53D6\uFF09\u3002",
|
|
139337
139662
|
hint: {
|
|
139338
|
-
badToken: "\u8FD9\u4E0D\u50CF\u673A\u5668\u4EBA\u7684 token\u3002\u5230 BotFather \u91CD\u65B0\u590D\u5236\u4E00\u4EFD\uFF1A\u6570\u5B57\u3001\u5192\u53F7\uFF0C\u540E\u9762\u662F\u5BC6\u94A5\
|
|
139339
|
-
unauthorized: "Telegram \u4E0D\u8BA4\u8FD9\u4E2A token\uFF0C\u53EF\u80FD\u5DF2\u7ECF\u4F5C\u5E9F\u3002\u5230 BotFather \u53D6\u73B0\u5728\u7684\u90A3\u4E00\u4EFD\
|
|
139340
|
-
notBot: "\u8FD9\u4E2A token \u4E0D\u662F\u673A\u5668\u4EBA\u7684\u3002\u8BF7\u7528 BotFather \u7ED9\u7684\u90A3\u4E00\u4EFD\
|
|
139341
|
-
webhookActive: "\u8FD9\u4E2A\u673A\u5668\u4EBA\u88AB\u522B\u7684\u670D\u52A1\u8BBE\u4E86 webhook\uFF0C\u5728\u8FD9\u91CC\u6536\u4E0D\u5230\u6D88\u606F\u3002\u5148\u5230\u90A3\u8FB9\u64A4\u6389 webhook\uFF0C\u518D\u68C0\u67E5\u4E00\u6B21\
|
|
139663
|
+
badToken: "\u8FD9\u4E0D\u50CF\u673A\u5668\u4EBA\u7684 token\u3002\u5230 BotFather \u91CD\u65B0\u590D\u5236\u4E00\u4EFD\uFF1A\u6570\u5B57\u3001\u5192\u53F7\uFF0C\u540E\u9762\u662F\u5BC6\u94A5\u3002",
|
|
139664
|
+
unauthorized: "Telegram \u4E0D\u8BA4\u8FD9\u4E2A token\uFF0C\u53EF\u80FD\u5DF2\u7ECF\u4F5C\u5E9F\u3002\u5230 BotFather \u53D6\u73B0\u5728\u7684\u90A3\u4E00\u4EFD\u3002",
|
|
139665
|
+
notBot: "\u8FD9\u4E2A token \u4E0D\u662F\u673A\u5668\u4EBA\u7684\u3002\u8BF7\u7528 BotFather \u7ED9\u7684\u90A3\u4E00\u4EFD\u3002",
|
|
139666
|
+
webhookActive: "\u8FD9\u4E2A\u673A\u5668\u4EBA\u88AB\u522B\u7684\u670D\u52A1\u8BBE\u4E86 webhook\uFF0C\u5728\u8FD9\u91CC\u6536\u4E0D\u5230\u6D88\u606F\u3002\u5148\u5230\u90A3\u8FB9\u64A4\u6389 webhook\uFF0C\u518D\u68C0\u67E5\u4E00\u6B21\u3002",
|
|
139667
|
+
wecomTrustedIp: "\u628A\u8FD9\u53F0\u673A\u5668\u7684\u51FA\u7AD9\u516C\u7F51 IP \u52A0\u8FDB\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u8FD9\u4E2A\u5E94\u7528\u7684\u4F01\u4E1A\u53EF\u4FE1 IP\u3002",
|
|
139668
|
+
wecomInvalidUser: "\u786E\u8BA4\u6536\u4EF6\u4EBA\u3001\u90E8\u95E8\u6216\u6807\u7B7E\u5B58\u5728\uFF0C\u5E76\u5728\u8FD9\u4E2A\u81EA\u5EFA\u5E94\u7528\u7684\u53EF\u89C1\u8303\u56F4\u5185\u3002",
|
|
139669
|
+
wecomInvalidAgent: "\u6838\u5BF9\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u8FD9\u4E2A\u81EA\u5EFA\u5E94\u7528\u7684 AgentId\u3002"
|
|
139342
139670
|
}
|
|
139343
139671
|
},
|
|
139344
139672
|
copyDiagnostics: {
|
|
@@ -139346,24 +139674,24 @@ var zh_CN_default = {
|
|
|
139346
139674
|
description: "\u8DD1\u4E00\u6B21\u8FDE\u63A5\u63A2\u6D4B\uFF0C\u751F\u6210\u53EF\u590D\u5236\u7684\u8BCA\u65AD\u6587\u672C\uFF08\u4E0D\u542B\u5BC6\u94A5\uFF09\u3002",
|
|
139347
139675
|
running: "\u6B63\u5728\u751F\u6210\u8BCA\u65AD {{rowId}} \u2026",
|
|
139348
139676
|
done: "\u8BCA\u65AD\u5DF2\u751F\u6210\uFF0C\u89C1\u4E0B\u65B9\u8BE6\u60C5",
|
|
139349
|
-
failed: "\u8BCA\u65AD\u5931\u8D25
|
|
139677
|
+
failed: "\u8BCA\u65AD\u5931\u8D25",
|
|
139350
139678
|
notSaved: "\u8BF7\u5148\u4FDD\u5B58\u8FD9\u4E00\u884C\u518D\u590D\u5236\u8BCA\u65AD\u3002"
|
|
139351
139679
|
},
|
|
139352
139680
|
diagnostic: {
|
|
139353
|
-
ref: "\u53C2\u8003\u53F7
|
|
139681
|
+
ref: "\u53C2\u8003\u53F7\uFF1A{{ref}}\n{{detail}}"
|
|
139354
139682
|
},
|
|
139355
139683
|
larkRepair: {
|
|
139356
139684
|
label: "\u8865\u5168\u6743\u9650",
|
|
139357
|
-
description: "\
|
|
139685
|
+
description: "\u68C0\u67E5\u5DF2\u4FDD\u5B58\u7684\u51ED\u636E\u80FD\u5426\u6362\u53D6 token\uFF1B\u6743\u9650\u3001\u4E8B\u4EF6\u8BA2\u9605\u548C\u53D1\u5E03\u4E0D\u4F1A\u81EA\u52A8\u68C0\u67E5\u3002",
|
|
139358
139686
|
step: {
|
|
139359
|
-
scopes: "\
|
|
139360
|
-
events: "\
|
|
139361
|
-
publish: "\
|
|
139687
|
+
scopes: "\u6743\u9650\uFF1A\u672A\u68C0\u67E5",
|
|
139688
|
+
events: "\u4E8B\u4EF6\u8BA2\u9605\uFF1A\u672A\u68C0\u67E5",
|
|
139689
|
+
publish: "\u53D1\u5E03\uFF1A\u672A\u68C0\u67E5",
|
|
139362
139690
|
verify: "\u9A8C\u8BC1\u5E94\u7528\u4ECD\u53EF\u6362\u53D6 tenant token"
|
|
139363
139691
|
},
|
|
139364
|
-
done: "\u51ED\u636E\
|
|
139365
|
-
hint: "\u53C2\u8003\u53F7
|
|
139366
|
-
failed: "\
|
|
139692
|
+
done: "\u4EC5\u6838\u5B9E\u4E86\u51ED\u636E\u4ECD\u80FD\u6362\u53D6 token\uFF1B\u6743\u9650\u3001\u4E8B\u4EF6\u8BA2\u9605\u548C\u53D1\u5E03\u6CA1\u6709\u81EA\u52A8\u68C0\u67E5\uFF0C\u8BF7\u5230\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u6838\u5BF9\u3002",
|
|
139693
|
+
hint: "\u53C2\u8003\u53F7\uFF1A{{ref}}\n{{detail}}\n\u8BF7\u5230\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u6838\u5BF9\u6743\u9650\u3001\u4E8B\u4EF6\u8BA2\u9605\u548C\u53D1\u5E03\uFF1B\u8FD9\u4E09\u9879\u5747\u672A\u81EA\u52A8\u68C0\u67E5\u3002",
|
|
139694
|
+
failed: "\u5DF2\u4FDD\u5B58\u7684\u51ED\u636E\u672A\u80FD\u6362\u53D6 token\uFF1B\u6743\u9650\u3001\u4E8B\u4EF6\u8BA2\u9605\u548C\u53D1\u5E03\u6CA1\u6709\u81EA\u52A8\u68C0\u67E5\uFF0C\u8BF7\u5230\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u6838\u5BF9\u3002",
|
|
139367
139695
|
notLark: "\u8FD9\u4E00\u884C\u4E0D\u662F\u5DF2\u4FDD\u5B58\u7684\u98DE\u4E66\u673A\u5668\u4EBA\u3002"
|
|
139368
139696
|
}
|
|
139369
139697
|
},
|
|
@@ -139401,8 +139729,24 @@ var zh_CN_default = {
|
|
|
139401
139729
|
copyFailed: "\u6CA1\u590D\u5236\u4E0A\u3002",
|
|
139402
139730
|
removeFailed: "\u6CA1\u80FD\u5220\u6389\u8FD9\u4E2A\u673A\u5668\u4EBA\u3002",
|
|
139403
139731
|
status: {
|
|
139404
|
-
ready: "\
|
|
139405
|
-
incomplete: "\
|
|
139732
|
+
ready: "\u5C31\u7EEA",
|
|
139733
|
+
incomplete: "\u5F85\u8865\u5168",
|
|
139734
|
+
connecting: "\u8FDE\u63A5\u4E2D",
|
|
139735
|
+
connected: "\u5DF2\u8FDE\u63A5",
|
|
139736
|
+
notConnected: "\u672A\u8FDE\u63A5"
|
|
139737
|
+
},
|
|
139738
|
+
connection: {
|
|
139739
|
+
failed: "\u4E0A\u6B21\u8FDE\u63A5\u6CA1\u6709\u6210\u529F\u3002",
|
|
139740
|
+
details: "\u8BE6\u60C5\uFF1A{{error}}",
|
|
139741
|
+
reason: {
|
|
139742
|
+
"not-available": "\u8FD9\u4E2A\u5E73\u53F0\u8FD8\u4E0D\u80FD\u8FDE\u63A5\u3002",
|
|
139743
|
+
"invalid-app-id": "App ID \u683C\u5F0F\u4E0D\u6B63\u786E\u3002",
|
|
139744
|
+
disconnected: "\u548C\u5E73\u53F0\u7684\u8FDE\u63A5\u65AD\u4E86\u3002",
|
|
139745
|
+
"subscription-failed": "\u5E73\u53F0\u6CA1\u6709\u786E\u8BA4\u8BA2\u9605\u3002",
|
|
139746
|
+
"token-unavailable": "\u6CA1\u80FD\u6362\u5230\u8BBF\u95EE\u4EE4\u724C\u3002",
|
|
139747
|
+
"credentials-rejected": "\u5E73\u53F0\u62D2\u7EDD\u4E86\u51ED\u636E\u3002"
|
|
139748
|
+
},
|
|
139749
|
+
duplicate: "\u548C\u300C{{name}}\u300D\u7528\u7684\u662F\u540C\u4E00\u4EFD\u51ED\u636E\uFF0C\u53EA\u8FDE\u90A3\u4E00\u884C\u3002"
|
|
139406
139750
|
},
|
|
139407
139751
|
secret: {
|
|
139408
139752
|
saved: "\u5DF2\u7ECF\u5B58\u8FC7\uFF0C\u7559\u7A7A\u5C31\u4FDD\u6301\u539F\u503C\u3002",
|
|
@@ -139414,7 +139758,8 @@ var zh_CN_default = {
|
|
|
139414
139758
|
format: "\u8FD9\u4E2A\u683C\u5F0F\u4E0D\u5BF9\u3002"
|
|
139415
139759
|
},
|
|
139416
139760
|
publicField: {
|
|
139417
|
-
callbackUrl: "\u56DE\u8C03\u5730\u5740"
|
|
139761
|
+
callbackUrl: "\u56DE\u8C03\u5730\u5740",
|
|
139762
|
+
callbackPath: "\u56DE\u8C03\u8DEF\u5F84"
|
|
139418
139763
|
},
|
|
139419
139764
|
action: {
|
|
139420
139765
|
running: "\u6B63\u5728\u5904\u7406\u2026",
|
|
@@ -139440,6 +139785,11 @@ var zh_CN_default = {
|
|
|
139440
139785
|
untitled: "\u65B0\u76EE\u6807",
|
|
139441
139786
|
removeConfirm: "\u5220\u9664\u8FD9\u4E2A\u76EE\u6807",
|
|
139442
139787
|
removeFailed: "\u8FD9\u4E2A\u76EE\u6807\u6CA1\u5220\u6389\u3002"
|
|
139788
|
+
},
|
|
139789
|
+
publicFieldHint: {
|
|
139790
|
+
callbackNeedsKeys: "\u586B\u597D Token \u548C EncodingAESKey \u5E76\u4FDD\u5B58\u540E\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u56DE\u8C03\u5730\u5740\uFF08\u5730\u5740\u7531\u5B83\u4FE9\u7B97\u51FA\uFF09\u3002",
|
|
139791
|
+
callbackPathNeedsBase: "\u628A\u8F6C\u53D1\u5230\u672C\u673A\u7684\u516C\u7F51\u5730\u5740\u62FC\u5728\u8FD9\u6BB5\u8DEF\u5F84\u524D\u9762\uFF0C\u6216\u5728\u4E0A\u9762\u586B\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF0C\u8FD9\u91CC\u5C31\u7ED9\u51FA\u5B8C\u6574\u5730\u5740\u3002",
|
|
139792
|
+
callbackFollowsKeys: "\u6539\u4E86 Token \u6216 EncodingAESKey\uFF0C\u8FD9\u4E2A\u5730\u5740\u4F1A\u53D8\uFF0C\u8981\u91CD\u65B0\u8D34\u8FDB\u4F01\u4E1A\u5FAE\u4FE1\u3002"
|
|
139443
139793
|
}
|
|
139444
139794
|
},
|
|
139445
139795
|
team: {
|
|
@@ -139577,6 +139927,16 @@ var makeModelPlan = (core, deps) => {
|
|
|
139577
139927
|
// src/notifications.ts
|
|
139578
139928
|
import { readThreadFailed, threadOrNull as threadOrNull5 } from "@ycodium-ai/plugin-api";
|
|
139579
139929
|
|
|
139930
|
+
// src/conclusionOutbox.ts
|
|
139931
|
+
var enqueueConclusion = (core, ledger, binding, debt, send) => core.outbound(
|
|
139932
|
+
chatKeyOf(binding),
|
|
139933
|
+
async () => {
|
|
139934
|
+
if (debt === void 0) await send();
|
|
139935
|
+
else await ledger.deliver(debt, send);
|
|
139936
|
+
},
|
|
139937
|
+
{ droppable: debt !== void 0 }
|
|
139938
|
+
);
|
|
139939
|
+
|
|
139580
139940
|
// src/conclusionRecovery.ts
|
|
139581
139941
|
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
139582
139942
|
var recoverConclusions = async (core, ledger, delivery, failures) => {
|
|
@@ -139584,6 +139944,12 @@ var recoverConclusions = async (core, ledger, delivery, failures) => {
|
|
|
139584
139944
|
core.host.onDispose(() => {
|
|
139585
139945
|
disposed = true;
|
|
139586
139946
|
});
|
|
139947
|
+
const couldNotRecover = (debt, error) => {
|
|
139948
|
+
core.host.log.warn("chat could not recover a conclusion", {
|
|
139949
|
+
...debt,
|
|
139950
|
+
error: describeError(error)
|
|
139951
|
+
});
|
|
139952
|
+
};
|
|
139587
139953
|
await core.ready;
|
|
139588
139954
|
for (const debt of Object.values(conclusionDebtsOf(core.state))) {
|
|
139589
139955
|
if (disposed) return;
|
|
@@ -139610,24 +139976,27 @@ var recoverConclusions = async (core, ledger, delivery, failures) => {
|
|
|
139610
139976
|
}
|
|
139611
139977
|
const binding = core.bindingForChatKey(debt.chatKey);
|
|
139612
139978
|
if (binding === void 0) continue;
|
|
139613
|
-
|
|
139614
|
-
|
|
139615
|
-
|
|
139616
|
-
|
|
139617
|
-
|
|
139618
|
-
|
|
139619
|
-
|
|
139620
|
-
|
|
139621
|
-
|
|
139979
|
+
enqueueConclusion(core, ledger, binding, debt, async (owed) => {
|
|
139980
|
+
try {
|
|
139981
|
+
if (latest.state === "error") {
|
|
139982
|
+
return delivery.sendText(
|
|
139983
|
+
binding,
|
|
139984
|
+
debt.threadId,
|
|
139985
|
+
failures.forFailure(debt.threadId, execution.session?.lastError),
|
|
139986
|
+
true,
|
|
139987
|
+
latest.turnId,
|
|
139988
|
+
owed
|
|
139989
|
+
);
|
|
139990
|
+
}
|
|
139991
|
+
const send = await delivery.prepareConclusion(debt.threadId, latest.turnId);
|
|
139992
|
+
return send(binding, { recovered: true, streaming: false, owed });
|
|
139993
|
+
} catch (error) {
|
|
139994
|
+
couldNotRecover(debt, error);
|
|
139995
|
+
return false;
|
|
139622
139996
|
}
|
|
139623
|
-
const send = await delivery.prepareConclusion(debt.threadId, latest.turnId);
|
|
139624
|
-
return send(binding, { recovered: true, streaming: false });
|
|
139625
139997
|
});
|
|
139626
139998
|
} catch (error) {
|
|
139627
|
-
|
|
139628
|
-
...debt,
|
|
139629
|
-
error: describeError(error)
|
|
139630
|
-
});
|
|
139999
|
+
couldNotRecover(debt, error);
|
|
139631
140000
|
}
|
|
139632
140001
|
}
|
|
139633
140002
|
};
|
|
@@ -139650,7 +140019,7 @@ var outcomeOfSession = (status) => {
|
|
|
139650
140019
|
var THREAD_PROJECT_CACHE_LIMIT = 256;
|
|
139651
140020
|
var makeNotifications = (core, deps) => {
|
|
139652
140021
|
const { host, adapterFor, bindingForChatKey, ready } = core;
|
|
139653
|
-
const {
|
|
140022
|
+
const { takeWorking } = deps;
|
|
139654
140023
|
const { turnCards } = deps.replyCards;
|
|
139655
140024
|
const { failures, conclusions, delivery } = deps;
|
|
139656
140025
|
void recoverConclusions(core, conclusions, delivery, failures);
|
|
@@ -139673,6 +140042,11 @@ var makeNotifications = (core, deps) => {
|
|
|
139673
140042
|
});
|
|
139674
140043
|
const streamsTo = (binding, threadId) => adapterFor(binding.platform)?.turnCards !== void 0 && owns(binding, threadId);
|
|
139675
140044
|
const owns = (binding, threadId) => chatOfThread(core.state, threadId) === chatKeyOf(binding);
|
|
140045
|
+
const later = (binding, work) => {
|
|
140046
|
+
core.outbound(chatKeyOf(binding), async () => {
|
|
140047
|
+
await work();
|
|
140048
|
+
});
|
|
140049
|
+
};
|
|
139676
140050
|
const threadsWithSomethingToReport = /* @__PURE__ */ new Set();
|
|
139677
140051
|
host.reactor({
|
|
139678
140052
|
name: "im.assistant-messages",
|
|
@@ -139695,32 +140069,38 @@ var makeNotifications = (core, deps) => {
|
|
|
139695
140069
|
const said = threadsWithSomethingToReport.delete(threadId);
|
|
139696
140070
|
await ready;
|
|
139697
140071
|
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
139698
|
-
const
|
|
139699
|
-
(debt2) => debt2.threadId === threadId
|
|
139700
|
-
);
|
|
139701
|
-
const { debt, handled, execution } = said || owes ? await conclusions.forTurn(threadId) : { debt: void 0, handled: false, execution: null };
|
|
140072
|
+
const { debt, handled, execution } = await conclusions.forTurn(threadId);
|
|
139702
140073
|
if (debt !== void 0) {
|
|
139703
140074
|
const binding = bindingForChatKey(debt.chatKey);
|
|
139704
140075
|
if (binding !== void 0 && !streamsTo(binding, threadId) && execution?.session?.activeTurnId == null && execution?.latestTurn?.state !== "running" && execution?.latestTurn?.state !== "error" && payload.session?.status !== "error") {
|
|
139705
|
-
|
|
139706
|
-
|
|
139707
|
-
|
|
139708
|
-
|
|
139709
|
-
);
|
|
139710
|
-
return send(binding, { recovered: false, streaming: false });
|
|
140076
|
+
const turnId = execution?.latestTurn?.turnId ?? null;
|
|
140077
|
+
enqueueConclusion(core, conclusions, binding, debt, async (owed) => {
|
|
140078
|
+
const send = await delivery.prepareConclusion(threadId, turnId);
|
|
140079
|
+
return send(binding, { recovered: false, streaming: false, owed });
|
|
139711
140080
|
});
|
|
139712
140081
|
}
|
|
139713
140082
|
} else if (said && !handled) {
|
|
139714
140083
|
const send = await delivery.prepareConclusion(threadId);
|
|
139715
140084
|
for (const binding of targets) {
|
|
139716
|
-
|
|
139717
|
-
|
|
139718
|
-
|
|
139719
|
-
|
|
140085
|
+
const streaming = streamsTo(binding, threadId);
|
|
140086
|
+
enqueueConclusion(
|
|
140087
|
+
core,
|
|
140088
|
+
conclusions,
|
|
140089
|
+
binding,
|
|
140090
|
+
void 0,
|
|
140091
|
+
() => send(binding, { recovered: false, streaming })
|
|
140092
|
+
);
|
|
139720
140093
|
}
|
|
139721
140094
|
}
|
|
139722
140095
|
const outcome = outcomeOfSession(payload.session?.status);
|
|
139723
|
-
for (const binding of targets)
|
|
140096
|
+
for (const binding of targets) {
|
|
140097
|
+
const withdraw = takeWorking(binding, threadId, outcome);
|
|
140098
|
+
turnCards.afterTurn(
|
|
140099
|
+
threadId,
|
|
140100
|
+
() => later(binding, withdraw),
|
|
140101
|
+
execution?.latestTurn?.turnId ?? null
|
|
140102
|
+
);
|
|
140103
|
+
}
|
|
139724
140104
|
}
|
|
139725
140105
|
});
|
|
139726
140106
|
host.events.on("thread.failed", async (event) => {
|
|
@@ -139729,7 +140109,7 @@ var makeNotifications = (core, deps) => {
|
|
|
139729
140109
|
threadsWithSomethingToReport.delete(threadId);
|
|
139730
140110
|
await ready;
|
|
139731
140111
|
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
139732
|
-
const { debt, handled } = await conclusions.forTurn(threadId);
|
|
140112
|
+
const { debt, handled, execution } = await conclusions.forTurn(threadId);
|
|
139733
140113
|
const debtBinding = debt === void 0 ? void 0 : bindingForChatKey(debt.chatKey);
|
|
139734
140114
|
const recipients = debt !== void 0 ? debtBinding === void 0 ? [] : [debtBinding] : targets;
|
|
139735
140115
|
const textTargets = handled ? [] : recipients.filter(
|
|
@@ -139739,16 +140119,20 @@ var makeNotifications = (core, deps) => {
|
|
|
139739
140119
|
const notice = textTargets.length > 0 || drawingTurn !== null ? failures.forFailure(threadId, readThreadFailed(event)?.detail) : null;
|
|
139740
140120
|
if (notice !== null && drawingTurn !== null)
|
|
139741
140121
|
failures.holdForCard(threadId, drawingTurn, notice);
|
|
139742
|
-
for (const binding of targets) {
|
|
139743
|
-
await clearWorking(binding, threadId, "failed");
|
|
139744
|
-
}
|
|
139745
140122
|
if (notice !== null) {
|
|
139746
140123
|
for (const binding of textTargets) {
|
|
139747
|
-
const send = () => delivery.
|
|
139748
|
-
|
|
139749
|
-
else await send();
|
|
140124
|
+
const send = (owed) => delivery.sendText(binding, threadId, notice, false, null, owed);
|
|
140125
|
+
enqueueConclusion(core, conclusions, binding, debt, send);
|
|
139750
140126
|
}
|
|
139751
140127
|
}
|
|
140128
|
+
for (const binding of targets) {
|
|
140129
|
+
const withdraw = takeWorking(binding, threadId, "failed");
|
|
140130
|
+
turnCards.afterTurn(
|
|
140131
|
+
threadId,
|
|
140132
|
+
() => later(binding, withdraw),
|
|
140133
|
+
execution?.latestTurn?.turnId ?? null
|
|
140134
|
+
);
|
|
140135
|
+
}
|
|
139752
140136
|
});
|
|
139753
140137
|
const rememberThreadProject = (threadId, projectId) => {
|
|
139754
140138
|
projectByThread.set(threadId, projectId);
|
|
@@ -140309,32 +140693,6 @@ var makeProjectRows = (core) => {
|
|
|
140309
140693
|
return { projectRowsFor, listedProjectsByChat };
|
|
140310
140694
|
};
|
|
140311
140695
|
|
|
140312
|
-
// src/diagnostics.ts
|
|
140313
|
-
var PREFIX = {
|
|
140314
|
-
conn: "IM-CONN",
|
|
140315
|
-
msg: "IM-MSG",
|
|
140316
|
-
setup: "IM-SETUP"
|
|
140317
|
-
};
|
|
140318
|
-
var shortSalt = () => {
|
|
140319
|
-
const bytes = new Uint8Array(2);
|
|
140320
|
-
crypto.getRandomValues(bytes);
|
|
140321
|
-
return Array.from(bytes, (b) => b.toString(16).toUpperCase().padStart(2, "0")).join("");
|
|
140322
|
-
};
|
|
140323
|
-
var diagnosticRef = (kind, nowMs = Date.now()) => {
|
|
140324
|
-
const stamp = nowMs.toString(36).toUpperCase();
|
|
140325
|
-
return `${PREFIX[kind]}-${stamp}-${shortSalt()}`;
|
|
140326
|
-
};
|
|
140327
|
-
var formatDiagnosticCopy = (report) => [
|
|
140328
|
-
`ref=${report.ref}`,
|
|
140329
|
-
`ok=${report.ok ? "yes" : "no"}`,
|
|
140330
|
-
`platform=${report.platform}`,
|
|
140331
|
-
`bot=${report.botName}`,
|
|
140332
|
-
`row=${report.rowId}`,
|
|
140333
|
-
`stage=${report.stage}`,
|
|
140334
|
-
`at=${report.at}`,
|
|
140335
|
-
`detail=${report.detail}`
|
|
140336
|
-
].join("\n");
|
|
140337
|
-
|
|
140338
140696
|
// src/failureNotices.ts
|
|
140339
140697
|
var makeFailureNotices = (core) => {
|
|
140340
140698
|
const heldForCard = /* @__PURE__ */ new Map();
|
|
@@ -140426,20 +140784,12 @@ var trailingReply = (messages) => {
|
|
|
140426
140784
|
var ROTATE = "rotate";
|
|
140427
140785
|
var isDrawing = (live) => live.card !== null || live.reopen;
|
|
140428
140786
|
var RECENT_ENDED_LIMIT = 256;
|
|
140787
|
+
var turnKey = (threadId, turnId) => JSON.stringify([threadId, turnId]);
|
|
140429
140788
|
var makeTurnCards = (deps) => {
|
|
140430
140789
|
const slots = /* @__PURE__ */ new Map();
|
|
140431
|
-
const recentEnded =
|
|
140790
|
+
const recentEnded = makeBoundedSeen(RECENT_ENDED_LIMIT);
|
|
140432
140791
|
const erroredThreads = /* @__PURE__ */ new Set();
|
|
140433
140792
|
let disposed = false;
|
|
140434
|
-
const rememberEnded = (threadId, turnId) => {
|
|
140435
|
-
if (turnId === null) return;
|
|
140436
|
-
recentEnded.delete(threadId);
|
|
140437
|
-
recentEnded.set(threadId, turnId);
|
|
140438
|
-
if (recentEnded.size > RECENT_ENDED_LIMIT) {
|
|
140439
|
-
const oldest = recentEnded.keys().next().value;
|
|
140440
|
-
if (oldest !== void 0) recentEnded.delete(oldest);
|
|
140441
|
-
}
|
|
140442
|
-
};
|
|
140443
140793
|
const readTexts = async (live, progress) => {
|
|
140444
140794
|
const texts = /* @__PURE__ */ new Map();
|
|
140445
140795
|
for (const segment of progress.segments) {
|
|
@@ -140491,29 +140841,28 @@ var makeTurnCards = (deps) => {
|
|
|
140491
140841
|
const turnId = progress.turnId ?? live?.turnId ?? null;
|
|
140492
140842
|
const target2 = live?.target ?? deps.resolveTarget(threadId, turnId);
|
|
140493
140843
|
if (target2 === null) return;
|
|
140494
|
-
rememberEnded(threadId, turnId);
|
|
140495
140844
|
if (end.status === "error") erroredThreads.add(threadId);
|
|
140496
140845
|
const title = live?.title ?? await deps.titleOf(threadId);
|
|
140497
140846
|
const view = await finalView(title, progress, live, end);
|
|
140498
|
-
|
|
140499
|
-
|
|
140500
|
-
|
|
140501
|
-
|
|
140502
|
-
|
|
140503
|
-
|
|
140504
|
-
|
|
140505
|
-
|
|
140506
|
-
|
|
140507
|
-
|
|
140508
|
-
|
|
140509
|
-
|
|
140510
|
-
|
|
140511
|
-
|
|
140847
|
+
const card = live?.card ?? null;
|
|
140848
|
+
const finished = card !== null && await card.finish(view);
|
|
140849
|
+
if (card !== null) deps.onClosed(card.cardId);
|
|
140850
|
+
const send = async () => finished || card === null && await openCard(target2, view) !== null;
|
|
140851
|
+
const sent = deps.finalize === void 0 ? await send() : await deps.finalize(threadId, turnId, target2.chatKey, send);
|
|
140852
|
+
if (!sent) await deps.fallback(threadId, turnId, target2.chatKey, view);
|
|
140853
|
+
if (turnId !== null) recentEnded.claim(turnKey(threadId, turnId));
|
|
140854
|
+
const callbacks = slot.afterTurn.get(turnId) ?? [];
|
|
140855
|
+
slot.afterTurn.delete(turnId);
|
|
140856
|
+
if (turnId !== null) {
|
|
140857
|
+
callbacks.push(...slot.afterTurn.get(null) ?? []);
|
|
140858
|
+
slot.afterTurn.delete(null);
|
|
140859
|
+
}
|
|
140860
|
+
for (const after of callbacks) after();
|
|
140512
140861
|
};
|
|
140513
140862
|
const handle = async (slot, threadId, item) => {
|
|
140514
140863
|
await deps.ready;
|
|
140515
140864
|
if (disposed) return;
|
|
140516
|
-
if (item.turnId !== null && recentEnded.
|
|
140865
|
+
if (item.turnId !== null && recentEnded.has(turnKey(threadId, item.turnId))) return;
|
|
140517
140866
|
let live = slot.live;
|
|
140518
140867
|
if (live !== null) {
|
|
140519
140868
|
const sameTurn = item.turnId === null || live.turnId === null || live.turnId === item.turnId;
|
|
@@ -140597,7 +140946,11 @@ var makeTurnCards = (deps) => {
|
|
|
140597
140946
|
}
|
|
140598
140947
|
} finally {
|
|
140599
140948
|
slot.running = false;
|
|
140600
|
-
if (slot.live === null && slot.queue.length === 0)
|
|
140949
|
+
if (slot.live === null && slot.queue.length === 0) {
|
|
140950
|
+
slots.delete(threadId);
|
|
140951
|
+
for (const callbacks of slot.afterTurn.values()) for (const after of callbacks) after();
|
|
140952
|
+
slot.afterTurn.clear();
|
|
140953
|
+
}
|
|
140601
140954
|
}
|
|
140602
140955
|
};
|
|
140603
140956
|
return {
|
|
@@ -140606,7 +140959,7 @@ var makeTurnCards = (deps) => {
|
|
|
140606
140959
|
if (disposed) return;
|
|
140607
140960
|
let slot = slots.get(threadId);
|
|
140608
140961
|
if (slot === void 0) {
|
|
140609
|
-
slot = { queue: [], running: false, live: null };
|
|
140962
|
+
slot = { queue: [], running: false, live: null, afterTurn: /* @__PURE__ */ new Map() };
|
|
140610
140963
|
slots.set(threadId, slot);
|
|
140611
140964
|
}
|
|
140612
140965
|
const last = slot.queue.at(-1);
|
|
@@ -140620,6 +140973,18 @@ var makeTurnCards = (deps) => {
|
|
|
140620
140973
|
void pump(threadId, slot);
|
|
140621
140974
|
}
|
|
140622
140975
|
},
|
|
140976
|
+
/** 撤回执只等所属轮次收尾;没有轮次 id 时仍等当前线程槽,不能在出站队列里等自己。 */
|
|
140977
|
+
afterTurn: (threadId, work, turnId = null) => {
|
|
140978
|
+
if (disposed) return;
|
|
140979
|
+
const slot = slots.get(threadId);
|
|
140980
|
+
if (slot === void 0 || turnId !== null && recentEnded.has(turnKey(threadId, turnId)))
|
|
140981
|
+
work();
|
|
140982
|
+
else {
|
|
140983
|
+
const callbacks = slot.afterTurn.get(turnId) ?? [];
|
|
140984
|
+
callbacks.push(work);
|
|
140985
|
+
slot.afterTurn.set(turnId, callbacks);
|
|
140986
|
+
}
|
|
140987
|
+
},
|
|
140623
140988
|
/**
|
|
140624
140989
|
* 审批或提问答完了:封存这条会话开着的卡,下一拍另开一张。立刻返回;没有在画的卡、或
|
|
140625
140990
|
* 平台不换卡,就什么都不做。
|
|
@@ -140646,7 +141011,10 @@ var makeTurnCards = (deps) => {
|
|
|
140646
141011
|
/** 插件停用:放下所有在画的卡,不再发任何更新。卡会停在最后一拍,重启时被标「已中断」。 */
|
|
140647
141012
|
dispose: () => {
|
|
140648
141013
|
disposed = true;
|
|
140649
|
-
for (const slot of slots.values())
|
|
141014
|
+
for (const slot of slots.values()) {
|
|
141015
|
+
slot.live?.card?.abandon();
|
|
141016
|
+
slot.afterTurn.clear();
|
|
141017
|
+
}
|
|
140650
141018
|
slots.clear();
|
|
140651
141019
|
}
|
|
140652
141020
|
};
|
|
@@ -140654,7 +141022,7 @@ var makeTurnCards = (deps) => {
|
|
|
140654
141022
|
|
|
140655
141023
|
// src/replyCards.ts
|
|
140656
141024
|
var makeReplyCards = (core, failures, anchors, conclusions, delivery) => {
|
|
140657
|
-
const { host, adapterFor, commit,
|
|
141025
|
+
const { host, adapterFor, commit, bindingForChatKey, bindingOfThread, ready } = core;
|
|
140658
141026
|
const stopRequested = /* @__PURE__ */ new Set();
|
|
140659
141027
|
const turnCards = makeTurnCards({
|
|
140660
141028
|
ready,
|
|
@@ -140713,22 +141081,28 @@ var makeReplyCards = (core, failures, anchors, conclusions, delivery) => {
|
|
|
140713
141081
|
onClosed: (cardId) => commit("turn-card-closed", { cardId }),
|
|
140714
141082
|
finalize: async (threadId, turnId, chatKey, send) => {
|
|
140715
141083
|
const { debt, handled } = await conclusions.forTurn(threadId, turnId);
|
|
140716
|
-
if (handled) return;
|
|
140717
|
-
if (debt === void 0)
|
|
140718
|
-
|
|
140719
|
-
return;
|
|
140720
|
-
}
|
|
140721
|
-
if (!await conclusions.deliver(debt, send)) return;
|
|
141084
|
+
if (handled) return true;
|
|
141085
|
+
if (debt === void 0) return send();
|
|
141086
|
+
if (!await conclusions.deliver(debt, send)) return false;
|
|
140722
141087
|
const binding = bindingForChatKey(chatKey);
|
|
140723
|
-
if (binding === void 0) return;
|
|
141088
|
+
if (binding === void 0) return true;
|
|
140724
141089
|
const sendConclusion = await delivery.prepareConclusion(threadId, turnId);
|
|
140725
141090
|
await sendConclusion(binding, { recovered: false, streaming: true });
|
|
141091
|
+
return true;
|
|
140726
141092
|
},
|
|
140727
141093
|
fallback: async (threadId, turnId, chatKey, view) => {
|
|
141094
|
+
const { debt, handled } = await conclusions.forTurn(threadId, turnId);
|
|
141095
|
+
if (handled) return;
|
|
140728
141096
|
const binding = bindingForChatKey(chatKey);
|
|
140729
|
-
if (binding === void 0) return
|
|
141097
|
+
if (binding === void 0) return;
|
|
140730
141098
|
const text4 = [view.body, view.errorText ?? ""].filter((part) => part !== "").join("\n\n");
|
|
140731
|
-
|
|
141099
|
+
enqueueConclusion(
|
|
141100
|
+
core,
|
|
141101
|
+
conclusions,
|
|
141102
|
+
binding,
|
|
141103
|
+
debt,
|
|
141104
|
+
(owed) => delivery.sendText(binding, threadId, text4, false, turnId, owed)
|
|
141105
|
+
);
|
|
140732
141106
|
},
|
|
140733
141107
|
schedule: (run, delayMs) => {
|
|
140734
141108
|
const timer = setTimeout(run, delayMs);
|
|
@@ -141098,7 +141472,7 @@ var makeSessions = (core) => {
|
|
|
141098
141472
|
};
|
|
141099
141473
|
|
|
141100
141474
|
// src/teamGoals.ts
|
|
141101
|
-
import * as
|
|
141475
|
+
import * as NodeCrypto4 from "node:crypto";
|
|
141102
141476
|
var isRecord2 = (value2) => typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
141103
141477
|
var teamGoalRequestId = (binding, messageId) => {
|
|
141104
141478
|
const identity = JSON.stringify([
|
|
@@ -141108,7 +141482,7 @@ var teamGoalRequestId = (binding, messageId) => {
|
|
|
141108
141482
|
binding.chatId,
|
|
141109
141483
|
messageId
|
|
141110
141484
|
]);
|
|
141111
|
-
return
|
|
141485
|
+
return NodeCrypto4.createHash("sha256").update(identity).digest("hex");
|
|
141112
141486
|
};
|
|
141113
141487
|
var makeTeamGoals = (core) => {
|
|
141114
141488
|
const { host, t, deliver, commit } = core;
|
|
@@ -141129,14 +141503,16 @@ var makeTeamGoals = (core) => {
|
|
|
141129
141503
|
};
|
|
141130
141504
|
const startTeamGoal = async (binding, message) => {
|
|
141131
141505
|
try {
|
|
141506
|
+
const requestId = teamGoalRequestId(binding, message.messageId);
|
|
141507
|
+
const topicRoot = await message.topicRootForSession?.(requestId);
|
|
141132
141508
|
const result = await host.plugins.invoke({
|
|
141133
141509
|
pluginId: "team",
|
|
141134
141510
|
command: "startGoal",
|
|
141135
141511
|
payload: {
|
|
141136
141512
|
projectId: binding.projectId,
|
|
141137
|
-
goal: textWithInboundContext(message, binding.rowId, t),
|
|
141513
|
+
goal: textWithInboundContext(message, binding.rowId, t, topicRoot?.reference),
|
|
141138
141514
|
titleSeed: message.text,
|
|
141139
|
-
requestId
|
|
141515
|
+
requestId
|
|
141140
141516
|
}
|
|
141141
141517
|
});
|
|
141142
141518
|
if (isRecord2(result) && result._tag === "TeamGoalRejection") {
|
|
@@ -141151,6 +141527,7 @@ var makeTeamGoals = (core) => {
|
|
|
141151
141527
|
if (!isRecord2(result) || typeof result.leadThreadId !== "string" || result.leadThreadId === "" || result.leadName !== null && typeof result.leadName !== "string") {
|
|
141152
141528
|
throw new Error("team startGoal returned an invalid result");
|
|
141153
141529
|
}
|
|
141530
|
+
topicRoot?.confirmConsumed();
|
|
141154
141531
|
commit("team-goal-started", { chatKey: chatKeyOf(binding), threadId: result.leadThreadId });
|
|
141155
141532
|
await deliver(
|
|
141156
141533
|
binding,
|
|
@@ -141206,6 +141583,10 @@ var TelegramApiError = class extends Error {
|
|
|
141206
141583
|
this.retryAfterSeconds = retryAfterSeconds;
|
|
141207
141584
|
}
|
|
141208
141585
|
};
|
|
141586
|
+
var telegramSendVerdict = (error) => error instanceof TelegramApiError && (error.code === 429 || error.code === 503 && error.retryAfterSeconds !== void 0) ? {
|
|
141587
|
+
retry: true,
|
|
141588
|
+
afterMs: error.retryAfterSeconds === void 0 ? void 0 : error.retryAfterSeconds * 1e3
|
|
141589
|
+
} : NO_RETRY;
|
|
141209
141590
|
var isNotModified = (error) => error instanceof TelegramApiError && error.code === 400 && error.message.toLowerCase().includes("message is not modified");
|
|
141210
141591
|
var PHOTO_NAME = "photo.jpg";
|
|
141211
141592
|
var PHOTO_MIME = "image/jpeg";
|
|
@@ -141412,9 +141793,13 @@ var makeTelegramApi = (input) => {
|
|
|
141412
141793
|
},
|
|
141413
141794
|
POLL_CALL_TIMEOUT_MS
|
|
141414
141795
|
),
|
|
141415
|
-
sendMessage: async (chatId, text4) => {
|
|
141796
|
+
sendMessage: async (chatId, text4, retry) => {
|
|
141416
141797
|
for (const chunk of splitForTelegram(text4)) {
|
|
141417
|
-
await
|
|
141798
|
+
await sendWithRetry(
|
|
141799
|
+
() => call("sendMessage", { ...target(chatId), text: chunk }),
|
|
141800
|
+
telegramSendVerdict,
|
|
141801
|
+
retry
|
|
141802
|
+
);
|
|
141418
141803
|
}
|
|
141419
141804
|
},
|
|
141420
141805
|
/**
|
|
@@ -141852,6 +142237,7 @@ var makeTelegramAdapter = (deps) => {
|
|
|
141852
142237
|
const poll = async () => {
|
|
141853
142238
|
for (; ; ) {
|
|
141854
142239
|
if (!running) return;
|
|
142240
|
+
let checkingConnection = true;
|
|
141855
142241
|
try {
|
|
141856
142242
|
const api = await apiFor(binding);
|
|
141857
142243
|
liveApi = api;
|
|
@@ -141860,6 +142246,7 @@ var makeTelegramAdapter = (deps) => {
|
|
|
141860
142246
|
const own = await api.getMe();
|
|
141861
142247
|
botUsername = own.username ?? null;
|
|
141862
142248
|
botId = own.id;
|
|
142249
|
+
if (running) handlers.onConnectionState?.({ state: "connected" });
|
|
141863
142250
|
}
|
|
141864
142251
|
if (!running) return;
|
|
141865
142252
|
if (!menuSent) {
|
|
@@ -141874,6 +142261,8 @@ var makeTelegramAdapter = (deps) => {
|
|
|
141874
142261
|
acknowledged = offset;
|
|
141875
142262
|
const updates = await api.getUpdates(offset);
|
|
141876
142263
|
if (!running) return;
|
|
142264
|
+
handlers.onConnectionState?.({ state: "connected" });
|
|
142265
|
+
checkingConnection = false;
|
|
141877
142266
|
backoff = BACKOFF_START_MS;
|
|
141878
142267
|
for (const update of updates) {
|
|
141879
142268
|
if (!running) break;
|
|
@@ -141958,6 +142347,7 @@ var makeTelegramAdapter = (deps) => {
|
|
|
141958
142347
|
}
|
|
141959
142348
|
} catch (error) {
|
|
141960
142349
|
if (!running) return;
|
|
142350
|
+
if (checkingConnection) handlers.onConnectionState?.({ state: "failed", error });
|
|
141961
142351
|
handlers.onError(error instanceof Error ? error.message : String(error));
|
|
141962
142352
|
await Promise.race([(deps.sleep ?? defaultSleep)(backoff), stopped]);
|
|
141963
142353
|
backoff = Math.min(backoff * 2, BACKOFF_MAX_MS);
|
|
@@ -141975,9 +142365,9 @@ var makeTelegramAdapter = (deps) => {
|
|
|
141975
142365
|
}
|
|
141976
142366
|
};
|
|
141977
142367
|
},
|
|
141978
|
-
sendText: async (binding, text4) => {
|
|
142368
|
+
sendText: async (binding, text4, options) => {
|
|
141979
142369
|
const api = await apiFor(binding);
|
|
141980
|
-
await api.sendMessage(binding.chatId, text4);
|
|
142370
|
+
await api.sendMessage(binding.chatId, text4, options?.retry);
|
|
141981
142371
|
},
|
|
141982
142372
|
checkConnection: async (bot) => {
|
|
141983
142373
|
const token = tokenOf(bot);
|
|
@@ -142236,6 +142626,7 @@ var makeTurns = (core, deps) => {
|
|
|
142236
142626
|
const text4 = message.text;
|
|
142237
142627
|
const threadId = await ensureThread(binding, text4 || message.resources[0]?.name || "Chat");
|
|
142238
142628
|
if (threadId === null) return null;
|
|
142629
|
+
const topicRoot = await message.topicRootForSession?.(threadId);
|
|
142239
142630
|
const carried = waitingFor(chatKey, threadId);
|
|
142240
142631
|
pendingByChat.delete(chatKey);
|
|
142241
142632
|
const own = await collectResources(
|
|
@@ -142273,7 +142664,10 @@ var makeTurns = (core, deps) => {
|
|
|
142273
142664
|
message: {
|
|
142274
142665
|
messageId: userMessageId,
|
|
142275
142666
|
role: "user",
|
|
142276
|
-
text: [
|
|
142667
|
+
text: [
|
|
142668
|
+
textWithInboundContext(message, binding.rowId, t, topicRoot?.reference),
|
|
142669
|
+
...notes
|
|
142670
|
+
].join("\n"),
|
|
142277
142671
|
attachments: attachments.map(
|
|
142278
142672
|
(attachment) => attachment.type === "image" ? { ...attachment, type: "image" } : { ...attachment, type: "file" }
|
|
142279
142673
|
)
|
|
@@ -142283,6 +142677,7 @@ var makeTurns = (core, deps) => {
|
|
|
142283
142677
|
interactionMode: interactionModeOf(chatKey),
|
|
142284
142678
|
...intentAction !== void 0 ? { intentAction } : {}
|
|
142285
142679
|
});
|
|
142680
|
+
topicRoot?.confirmConsumed();
|
|
142286
142681
|
if (intentAction?.kind !== "steer") {
|
|
142287
142682
|
deps.conclusions.owe({
|
|
142288
142683
|
chatKey,
|
|
@@ -142411,8 +142806,15 @@ var ROW_ACTION_ITEM_SCHEMA = makeFlowItemSchema({
|
|
|
142411
142806
|
doneRequired: ["messageKey", "fills"]
|
|
142412
142807
|
});
|
|
142413
142808
|
var botOf = (config2, adapters, rowId) => {
|
|
142414
|
-
const
|
|
142415
|
-
|
|
142809
|
+
const table2 = config2[BOTS_FIELD];
|
|
142810
|
+
if (typeof table2 !== "object" || table2 === null || Array.isArray(table2) || !Object.hasOwn(table2, rowId))
|
|
142811
|
+
return void 0;
|
|
142812
|
+
const row = table2[rowId];
|
|
142813
|
+
if (typeof row !== "object" || row === null || Array.isArray(row)) return void 0;
|
|
142814
|
+
const raw = row;
|
|
142815
|
+
const platform = platformOf(raw);
|
|
142816
|
+
const adapter = adapters.find((candidate) => candidate.platform === platform);
|
|
142817
|
+
return { ...readBotView(rowId, raw, adapter ?? { label: platform }), platform };
|
|
142416
142818
|
};
|
|
142417
142819
|
var reportOf = (bot, stage, ok, detail, hint) => ({
|
|
142418
142820
|
ref: diagnosticRef("conn"),
|
|
@@ -142428,12 +142830,9 @@ var reportOf = (bot, stage, ok, detail, hint) => ({
|
|
|
142428
142830
|
var probe = async (adapters, bot) => {
|
|
142429
142831
|
const adapter = adapters.find((candidate) => candidate.platform === bot.platform);
|
|
142430
142832
|
if (adapter?.checkConnection === void 0) {
|
|
142431
|
-
return reportOf(bot, "platform", false, `unsupported platform ${bot.platform}
|
|
142432
|
-
}
|
|
142433
|
-
const redactor = makeRedactor();
|
|
142434
|
-
for (const column of adapter.columns) {
|
|
142435
|
-
if (column.kind === "password") redactor.register(bot.values[column.key]);
|
|
142833
|
+
return reportOf(bot, "platform", false, `unsupported platform ${bot.platform}`, "notAvailable");
|
|
142436
142834
|
}
|
|
142835
|
+
const redactor = botRedactor(adapter.columns, bot.values);
|
|
142437
142836
|
try {
|
|
142438
142837
|
const result = await adapter.checkConnection(bot);
|
|
142439
142838
|
return reportOf(
|
|
@@ -142458,10 +142857,15 @@ var emitReport = (emit, report, action) => {
|
|
|
142458
142857
|
});
|
|
142459
142858
|
return;
|
|
142460
142859
|
}
|
|
142860
|
+
const suggested = report.hint !== void 0 && action.keyPrefix === "rowAction.checkConnection";
|
|
142461
142861
|
emit({
|
|
142462
142862
|
kind: "failed",
|
|
142463
|
-
reasonKey: report.hint !== void 0
|
|
142464
|
-
|
|
142863
|
+
reasonKey: suggested && report.hint !== void 0 ? connectionHintKey(report.hint) : `${action.keyPrefix}.failed`,
|
|
142864
|
+
// 参考号由界面写在细节第一行(「参考号:…」),结论句里不带。
|
|
142865
|
+
params: {
|
|
142866
|
+
ref: report.ref,
|
|
142867
|
+
...suggested && report.hint !== void 0 ? { hint: report.hint } : {}
|
|
142868
|
+
},
|
|
142465
142869
|
detail
|
|
142466
142870
|
});
|
|
142467
142871
|
};
|
|
@@ -142513,9 +142917,9 @@ var registerSettingsRowActions = (ctx, adapters) => {
|
|
|
142513
142917
|
send({
|
|
142514
142918
|
kind: "steps",
|
|
142515
142919
|
steps: [
|
|
142516
|
-
{ id: "scopes", labelKey: "rowAction.larkRepair.step.scopes", state: "
|
|
142517
|
-
{ id: "events", labelKey: "rowAction.larkRepair.step.events", state: "
|
|
142518
|
-
{ id: "publish", labelKey: "rowAction.larkRepair.step.publish", state: "
|
|
142920
|
+
{ id: "scopes", labelKey: "rowAction.larkRepair.step.scopes", state: "skipped" },
|
|
142921
|
+
{ id: "events", labelKey: "rowAction.larkRepair.step.events", state: "skipped" },
|
|
142922
|
+
{ id: "publish", labelKey: "rowAction.larkRepair.step.publish", state: "skipped" },
|
|
142519
142923
|
{ id: "verify", labelKey: "rowAction.larkRepair.step.verify", state: "running" }
|
|
142520
142924
|
]
|
|
142521
142925
|
});
|
|
@@ -142532,9 +142936,9 @@ var registerSettingsRowActions = (ctx, adapters) => {
|
|
|
142532
142936
|
send({
|
|
142533
142937
|
kind: "steps",
|
|
142534
142938
|
steps: [
|
|
142535
|
-
{ id: "scopes", labelKey: "rowAction.larkRepair.step.scopes", state: "
|
|
142536
|
-
{ id: "events", labelKey: "rowAction.larkRepair.step.events", state: "
|
|
142537
|
-
{ id: "publish", labelKey: "rowAction.larkRepair.step.publish", state: "
|
|
142939
|
+
{ id: "scopes", labelKey: "rowAction.larkRepair.step.scopes", state: "skipped" },
|
|
142940
|
+
{ id: "events", labelKey: "rowAction.larkRepair.step.events", state: "skipped" },
|
|
142941
|
+
{ id: "publish", labelKey: "rowAction.larkRepair.step.publish", state: "skipped" },
|
|
142538
142942
|
{
|
|
142539
142943
|
id: "verify",
|
|
142540
142944
|
labelKey: "rowAction.larkRepair.step.verify",
|
|
@@ -142550,7 +142954,7 @@ var registerSettingsRowActions = (ctx, adapters) => {
|
|
|
142550
142954
|
warnings: [
|
|
142551
142955
|
{
|
|
142552
142956
|
key: "rowAction.larkRepair.hint",
|
|
142553
|
-
params: { ref, detail: formatDiagnosticCopy(
|
|
142957
|
+
params: { ref, detail: formatDiagnosticCopy(report) }
|
|
142554
142958
|
}
|
|
142555
142959
|
]
|
|
142556
142960
|
});
|
|
@@ -142560,7 +142964,7 @@ var registerSettingsRowActions = (ctx, adapters) => {
|
|
|
142560
142964
|
kind: "failed",
|
|
142561
142965
|
reasonKey: "rowAction.larkRepair.failed",
|
|
142562
142966
|
params: { ref },
|
|
142563
|
-
detail: formatDiagnosticCopy(
|
|
142967
|
+
detail: formatDiagnosticCopy(report)
|
|
142564
142968
|
});
|
|
142565
142969
|
}
|
|
142566
142970
|
});
|
|
@@ -142760,8 +143164,29 @@ var generalWriteOptions = (payload, next) => {
|
|
|
142760
143164
|
}
|
|
142761
143165
|
return void 0;
|
|
142762
143166
|
};
|
|
142763
|
-
var
|
|
142764
|
-
|
|
143167
|
+
var registerSettingsCommands = (ctx, adapters, updateSettings, connections) => {
|
|
143168
|
+
const viewAfterWrite = async () => buildSettingsView(await ctx.settings.read(), adapters);
|
|
143169
|
+
ctx.stream({
|
|
143170
|
+
name: SETTINGS_CONNECTIONS_COMMAND,
|
|
143171
|
+
description: "Read bot connection states as an initial snapshot and subsequent changes.",
|
|
143172
|
+
scope: "read",
|
|
143173
|
+
payloadSchema: EMPTY_PAYLOAD,
|
|
143174
|
+
buffer: { latest: 1 },
|
|
143175
|
+
handle: async (_payload, emit, signal) => {
|
|
143176
|
+
if (signal.aborted) return;
|
|
143177
|
+
const unsubscribe = connections.subscribe((snapshot) => {
|
|
143178
|
+
if (!signal.aborted) emit(snapshot);
|
|
143179
|
+
});
|
|
143180
|
+
try {
|
|
143181
|
+
await new Promise((resolve) => {
|
|
143182
|
+
if (signal.aborted) resolve();
|
|
143183
|
+
else signal.addEventListener("abort", () => resolve(), { once: true });
|
|
143184
|
+
});
|
|
143185
|
+
} finally {
|
|
143186
|
+
unsubscribe();
|
|
143187
|
+
}
|
|
143188
|
+
}
|
|
143189
|
+
});
|
|
142765
143190
|
ctx.command({
|
|
142766
143191
|
name: SETTINGS_VIEW_COMMAND,
|
|
142767
143192
|
description: "Read the chat-bridge settings view, bot columns, and this machine's proxies.",
|
|
@@ -142788,7 +143213,7 @@ var registerSettingsCommands = (ctx, adapters, updateSettings) => {
|
|
|
142788
143213
|
return { result, write: { config: next, options: { secrets, clearSecrets } } };
|
|
142789
143214
|
});
|
|
142790
143215
|
if (!edited.ok) return edited;
|
|
142791
|
-
return { ok: true, rowId: edited.rowId, view: await viewAfterWrite(
|
|
143216
|
+
return { ok: true, rowId: edited.rowId, view: await viewAfterWrite() };
|
|
142792
143217
|
};
|
|
142793
143218
|
const removeRow2 = async (remove) => {
|
|
142794
143219
|
const removed = await updateSettings((config2) => {
|
|
@@ -142796,7 +143221,7 @@ var registerSettingsCommands = (ctx, adapters, updateSettings) => {
|
|
|
142796
143221
|
return next === null ? { result: false } : { result: true, write: { config: next } };
|
|
142797
143222
|
});
|
|
142798
143223
|
if (!removed) return { ok: false, code: "unknown-row" };
|
|
142799
|
-
return { ok: true, view: await viewAfterWrite(
|
|
143224
|
+
return { ok: true, view: await viewAfterWrite() };
|
|
142800
143225
|
};
|
|
142801
143226
|
ctx.command({
|
|
142802
143227
|
name: SETTINGS_SAVE_BOT_COMMAND,
|
|
@@ -142847,7 +143272,7 @@ var registerSettingsCommands = (ctx, adapters, updateSettings) => {
|
|
|
142847
143272
|
write: options === void 0 ? { config: next } : { config: next, options }
|
|
142848
143273
|
};
|
|
142849
143274
|
});
|
|
142850
|
-
return { ok: true, view: await viewAfterWrite(
|
|
143275
|
+
return { ok: true, view: await viewAfterWrite() };
|
|
142851
143276
|
}
|
|
142852
143277
|
});
|
|
142853
143278
|
};
|
|
@@ -142875,12 +143300,13 @@ var makeWechatAdapter = (deps) => {
|
|
|
142875
143300
|
columns: COLUMNS3,
|
|
142876
143301
|
validate: wechatConfigIssues,
|
|
142877
143302
|
isConfigured: (bot) => wechatConfigIssues(bot).length === 0,
|
|
142878
|
-
connect: (bot,
|
|
143303
|
+
connect: (bot, handlers) => {
|
|
142879
143304
|
deps.log.warn("wechat iLink connect is stubbed pending security-review gate (YCO-236)", {
|
|
142880
143305
|
bot: bot.displayName,
|
|
142881
143306
|
hasToken: tokenOf2(bot) !== "",
|
|
142882
143307
|
textLimit: WECHAT_TEXT_MAX_CHARS
|
|
142883
143308
|
});
|
|
143309
|
+
handlers.onConnectionState?.({ state: "failed", reason: "not-available" });
|
|
142884
143310
|
return { close: () => void 0 };
|
|
142885
143311
|
},
|
|
142886
143312
|
sendText: async (binding, _text) => {
|
|
@@ -142903,7 +143329,7 @@ var makeWechatAdapter = (deps) => {
|
|
|
142903
143329
|
};
|
|
142904
143330
|
|
|
142905
143331
|
// src/wecomUpload.ts
|
|
142906
|
-
import * as
|
|
143332
|
+
import * as NodeCrypto5 from "node:crypto";
|
|
142907
143333
|
var WECOM_CHUNK_BYTES = 512 * 1024;
|
|
142908
143334
|
var WECOM_MAX_CHUNKS = 100;
|
|
142909
143335
|
var WECOM_MIN_UPLOAD_BYTES = 5;
|
|
@@ -142936,7 +143362,7 @@ var uploadWecomMedia = async (input) => {
|
|
|
142936
143362
|
filename: clampName(input.filename),
|
|
142937
143363
|
total_size: bytes.byteLength,
|
|
142938
143364
|
total_chunks: totalChunks,
|
|
142939
|
-
md5:
|
|
143365
|
+
md5: NodeCrypto5.createHash("md5").update(bytes).digest("hex")
|
|
142940
143366
|
});
|
|
142941
143367
|
const uploadId = init.upload_id;
|
|
142942
143368
|
if (typeof uploadId !== "string" || uploadId === "") {
|
|
@@ -143023,7 +143449,7 @@ var wecomReplyReference = (quote) => {
|
|
|
143023
143449
|
};
|
|
143024
143450
|
|
|
143025
143451
|
// src/wecomApi.ts
|
|
143026
|
-
var DEFAULT_WECOM_ENDPOINT = "wss://openws.work.weixin.qq.com
|
|
143452
|
+
var DEFAULT_WECOM_ENDPOINT = "wss://openws.work.weixin.qq.com";
|
|
143027
143453
|
var PING_INTERVAL_MS = 3e4;
|
|
143028
143454
|
var MAX_MISSED_PONGS = 2;
|
|
143029
143455
|
var SUBSCRIBE_TIMEOUT_MS = 1e4;
|
|
@@ -143160,9 +143586,10 @@ var runWecomClient = (input) => {
|
|
|
143160
143586
|
const message = parseWecomMessage(frame, input.botId);
|
|
143161
143587
|
if (message !== null) input.handlers.onMessage(message);
|
|
143162
143588
|
};
|
|
143163
|
-
const finish = () => {
|
|
143589
|
+
const finish = (error = new Error("WeCom connection closed"), reason = "disconnected") => {
|
|
143164
143590
|
if (finished) return;
|
|
143165
143591
|
finished = true;
|
|
143592
|
+
if (!closed) input.handlers.onConnectionState?.({ state: "failed", error, reason });
|
|
143166
143593
|
clearInterval(heartbeat);
|
|
143167
143594
|
openStreams.clear();
|
|
143168
143595
|
void input.socket.close().catch(() => void 0);
|
|
@@ -143180,6 +143607,7 @@ var runWecomClient = (input) => {
|
|
|
143180
143607
|
if (!closed) {
|
|
143181
143608
|
input.handlers.onError(error instanceof Error ? error.message : String(error));
|
|
143182
143609
|
}
|
|
143610
|
+
finish(error);
|
|
143183
143611
|
}
|
|
143184
143612
|
finish();
|
|
143185
143613
|
};
|
|
@@ -143187,7 +143615,7 @@ var runWecomClient = (input) => {
|
|
|
143187
143615
|
if (finished) return;
|
|
143188
143616
|
if (missedPong >= MAX_MISSED_PONGS) {
|
|
143189
143617
|
input.handlers.onError("socket hang up: missed pong");
|
|
143190
|
-
finish();
|
|
143618
|
+
finish(new Error("socket hang up: missed pong"));
|
|
143191
143619
|
return;
|
|
143192
143620
|
}
|
|
143193
143621
|
missedPong += 1;
|
|
@@ -143208,10 +143636,13 @@ var runWecomClient = (input) => {
|
|
|
143208
143636
|
settleAck(subscribeId, error instanceof Error ? error : new Error(String(error)));
|
|
143209
143637
|
});
|
|
143210
143638
|
const ready = subscribed.then(
|
|
143211
|
-
() =>
|
|
143639
|
+
() => {
|
|
143640
|
+
if (!finished && !closed) input.handlers.onConnectionState?.({ state: "connected" });
|
|
143641
|
+
return !finished && !closed;
|
|
143642
|
+
},
|
|
143212
143643
|
(error) => {
|
|
143213
143644
|
if (!closed) input.handlers.onError(error instanceof Error ? error.message : String(error));
|
|
143214
|
-
finish();
|
|
143645
|
+
finish(error, "subscription-failed");
|
|
143215
143646
|
return false;
|
|
143216
143647
|
}
|
|
143217
143648
|
);
|
|
@@ -143346,7 +143777,7 @@ var runWecomClient = (input) => {
|
|
|
143346
143777
|
};
|
|
143347
143778
|
|
|
143348
143779
|
// src/wecomMedia.ts
|
|
143349
|
-
import * as
|
|
143780
|
+
import * as NodeCrypto6 from "node:crypto";
|
|
143350
143781
|
|
|
143351
143782
|
// src/wecomPadding.ts
|
|
143352
143783
|
var PADDING_BLOCK = 32;
|
|
@@ -143377,7 +143808,7 @@ var decryptWecomMedia = (cipher, aesKey) => {
|
|
|
143377
143808
|
if (cipher.byteLength === 0 || cipher.byteLength % AES_BLOCK !== 0) {
|
|
143378
143809
|
throw new WecomDecryptError("the ciphertext is not a whole number of blocks");
|
|
143379
143810
|
}
|
|
143380
|
-
const decipher =
|
|
143811
|
+
const decipher = NodeCrypto6.createDecipheriv("aes-256-cbc", key, key.subarray(0, IV_BYTES));
|
|
143381
143812
|
decipher.setAutoPadding(false);
|
|
143382
143813
|
const plain = Buffer.concat([decipher.update(cipher), decipher.final()]);
|
|
143383
143814
|
const unpadded = stripPadding(plain);
|
|
@@ -143520,6 +143951,9 @@ ${kept}`;
|
|
|
143520
143951
|
botSecret,
|
|
143521
143952
|
handlers: {
|
|
143522
143953
|
onError: handlers.onError,
|
|
143954
|
+
onConnectionState: (state) => {
|
|
143955
|
+
if (!stopped) handlers.onConnectionState?.(state);
|
|
143956
|
+
},
|
|
143523
143957
|
onMessage: (message) => {
|
|
143524
143958
|
if (message.chatType !== "single") return;
|
|
143525
143959
|
client.rememberRequest(message.chatId, message.requestId);
|
|
@@ -143561,6 +143995,8 @@ ${kept}`;
|
|
|
143561
143995
|
try {
|
|
143562
143996
|
if (await runOnce()) backoff = BACKOFF_START_MS2;
|
|
143563
143997
|
} catch (error) {
|
|
143998
|
+
if (stopped) return;
|
|
143999
|
+
handlers.onConnectionState?.({ state: "failed", error, reason: "disconnected" });
|
|
143564
144000
|
handlers.onError(error instanceof Error ? error.message : String(error));
|
|
143565
144001
|
}
|
|
143566
144002
|
if (stopped) return;
|
|
@@ -143578,6 +144014,7 @@ ${kept}`;
|
|
|
143578
144014
|
}
|
|
143579
144015
|
};
|
|
143580
144016
|
},
|
|
144017
|
+
// 不看 `options.retry`:长连接的回执没有核实过的限流码,也没有幂等键,失败一律说不清发没发出去。
|
|
143581
144018
|
sendText: async (binding, text4) => {
|
|
143582
144019
|
const client = clients.get(binding.rowId);
|
|
143583
144020
|
if (client === void 0) {
|
|
@@ -143594,12 +144031,36 @@ ${kept}`;
|
|
|
143594
144031
|
detail: "missing bot id or secret in saved config"
|
|
143595
144032
|
};
|
|
143596
144033
|
}
|
|
144034
|
+
let stage = "websocket";
|
|
143597
144035
|
try {
|
|
143598
144036
|
const socket = await deps.connectSocket(endpoint);
|
|
143599
|
-
|
|
143600
|
-
|
|
144037
|
+
stage = "aibot_subscribe";
|
|
144038
|
+
let detail = "WeCom connection closed before subscribe ack";
|
|
144039
|
+
let closing;
|
|
144040
|
+
const client = runWecomClient({
|
|
144041
|
+
socket: {
|
|
144042
|
+
send: (data) => socket.send(data),
|
|
144043
|
+
messages: socket.messages,
|
|
144044
|
+
close: () => closing ??= socket.close()
|
|
144045
|
+
},
|
|
144046
|
+
botId,
|
|
144047
|
+
botSecret,
|
|
144048
|
+
handlers: {
|
|
144049
|
+
onMessage: () => void 0,
|
|
144050
|
+
onError: (error) => {
|
|
144051
|
+
detail = error;
|
|
144052
|
+
}
|
|
144053
|
+
}
|
|
144054
|
+
});
|
|
144055
|
+
try {
|
|
144056
|
+
const ok = await client.ready;
|
|
144057
|
+
return { stage, ok, detail: ok ? `subscription confirmed (${endpoint})` : detail };
|
|
144058
|
+
} finally {
|
|
144059
|
+
client.close();
|
|
144060
|
+
await closing;
|
|
144061
|
+
}
|
|
143601
144062
|
} catch (error) {
|
|
143602
|
-
return { stage
|
|
144063
|
+
return { stage, ok: false, detail: describeError(error) };
|
|
143603
144064
|
}
|
|
143604
144065
|
},
|
|
143605
144066
|
askApproval: async (binding, request) => {
|
|
@@ -143656,18 +144117,25 @@ ${kept}`;
|
|
|
143656
144117
|
// src/wecomAppApi.ts
|
|
143657
144118
|
var WECOM_APP_DEFAULT_API_BASE = "https://qyapi.weixin.qq.com";
|
|
143658
144119
|
var WECOM_APP_TEXT_MAX_BYTES = 2048;
|
|
144120
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
144121
|
+
var MEDIA_TIMEOUT_MS = 6e4;
|
|
143659
144122
|
var WecomAppApiError = class extends Error {
|
|
143660
144123
|
code;
|
|
143661
144124
|
providerCode;
|
|
143662
144125
|
hint;
|
|
144126
|
+
invalidUsers;
|
|
143663
144127
|
constructor(code2, message, extras) {
|
|
143664
144128
|
super(message);
|
|
143665
144129
|
this.name = "WecomAppApiError";
|
|
143666
144130
|
this.code = code2;
|
|
143667
144131
|
this.providerCode = extras?.providerCode;
|
|
143668
144132
|
this.hint = extras?.hint;
|
|
144133
|
+
this.invalidUsers = extras?.invalidUsers ?? [];
|
|
143669
144134
|
}
|
|
143670
144135
|
};
|
|
144136
|
+
var TOKEN_INVALID_CODES = /* @__PURE__ */ new Set(["40014", "42001"]);
|
|
144137
|
+
var RATE_LIMITED_CODES = /* @__PURE__ */ new Set(["45009", "45033"]);
|
|
144138
|
+
var wecomAppSendVerdict = (error) => error instanceof WecomAppApiError && error.providerCode !== void 0 && (RATE_LIMITED_CODES.has(error.providerCode) || TOKEN_INVALID_CODES.has(error.providerCode)) ? { retry: true } : NO_RETRY;
|
|
143671
144139
|
var cleanString2 = (value2) => {
|
|
143672
144140
|
if (typeof value2 !== "string") return null;
|
|
143673
144141
|
const trimmed = value2.trim();
|
|
@@ -143703,6 +144171,7 @@ var splitUtf8ByBytes = (text4, maxBytes = WECOM_APP_TEXT_MAX_BYTES) => {
|
|
|
143703
144171
|
if (current.length > 0) chunks.push(current);
|
|
143704
144172
|
return chunks;
|
|
143705
144173
|
};
|
|
144174
|
+
var parseInvalidUsers = (value2) => typeof value2 === "string" ? value2.split("|").map((user) => user.trim()).filter(Boolean) : [];
|
|
143706
144175
|
var WecomAppApi = class {
|
|
143707
144176
|
corpId;
|
|
143708
144177
|
corpSecret;
|
|
@@ -143754,9 +144223,13 @@ var WecomAppApi = class {
|
|
|
143754
144223
|
async sendText(input) {
|
|
143755
144224
|
const chunks = splitUtf8ByBytes(input.content);
|
|
143756
144225
|
for (const chunk of chunks) {
|
|
143757
|
-
await
|
|
143758
|
-
|
|
143759
|
-
|
|
144226
|
+
await sendWithRetry(
|
|
144227
|
+
() => this.#send(
|
|
144228
|
+
{ touser: input.userId, msgtype: "text", text: { content: chunk } },
|
|
144229
|
+
input.signal
|
|
144230
|
+
),
|
|
144231
|
+
wecomAppSendVerdict,
|
|
144232
|
+
input.retry
|
|
143760
144233
|
);
|
|
143761
144234
|
}
|
|
143762
144235
|
}
|
|
@@ -143783,12 +144256,16 @@ var WecomAppApi = class {
|
|
|
143783
144256
|
new Blob([new Uint8Array(input.bytes)], { type: input.mimeType }),
|
|
143784
144257
|
input.name
|
|
143785
144258
|
);
|
|
143786
|
-
const payload = await this.#requestJson(
|
|
143787
|
-
|
|
143788
|
-
|
|
143789
|
-
|
|
143790
|
-
|
|
143791
|
-
|
|
144259
|
+
const payload = await this.#requestJson(
|
|
144260
|
+
url,
|
|
144261
|
+
{
|
|
144262
|
+
method: "POST",
|
|
144263
|
+
// 不设 content-type:multipart 的 boundary 要让 fetch 自己写。
|
|
144264
|
+
body: form,
|
|
144265
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
144266
|
+
},
|
|
144267
|
+
MEDIA_TIMEOUT_MS
|
|
144268
|
+
);
|
|
143792
144269
|
const mediaId = payload["media_id"];
|
|
143793
144270
|
if (typeof mediaId === "string" && mediaId !== "") return mediaId;
|
|
143794
144271
|
throw this.#apiError(Number(payload["errcode"] ?? -1), payload["errmsg"]);
|
|
@@ -143802,10 +144279,17 @@ var WecomAppApi = class {
|
|
|
143802
144279
|
const url = new URL("/cgi-bin/media/get", this.apiBaseUrl);
|
|
143803
144280
|
url.searchParams.set("access_token", token);
|
|
143804
144281
|
url.searchParams.set("media_id", input.mediaId);
|
|
143805
|
-
|
|
143806
|
-
|
|
143807
|
-
|
|
143808
|
-
|
|
144282
|
+
return this.#withRequest(
|
|
144283
|
+
url,
|
|
144284
|
+
{
|
|
144285
|
+
method: "GET",
|
|
144286
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
144287
|
+
},
|
|
144288
|
+
MEDIA_TIMEOUT_MS,
|
|
144289
|
+
(response) => this.#readMedia(response, input.maxBytes)
|
|
144290
|
+
);
|
|
144291
|
+
}
|
|
144292
|
+
async #readMedia(response, maxBytes) {
|
|
143809
144293
|
const contentType = response.headers.get("content-type") ?? "";
|
|
143810
144294
|
if (contentType.includes("application/json") || contentType.includes("text/plain")) {
|
|
143811
144295
|
let payload = {};
|
|
@@ -143825,7 +144309,7 @@ var WecomAppApi = class {
|
|
|
143825
144309
|
`WeCom media/get failed (HTTP ${String(response.status)}).`
|
|
143826
144310
|
);
|
|
143827
144311
|
}
|
|
143828
|
-
const bytes = await readBodyLimited(response,
|
|
144312
|
+
const bytes = await readBodyLimited(response, maxBytes);
|
|
143829
144313
|
const name = filenameFromContentDisposition(response.headers.get("content-disposition"));
|
|
143830
144314
|
const mimeType = contentType.split(";")[0]?.trim();
|
|
143831
144315
|
return {
|
|
@@ -143844,63 +144328,85 @@ var WecomAppApi = class {
|
|
|
143844
144328
|
body: JSON.stringify({ ...message, agentid: Number.parseInt(this.agentId, 10) }),
|
|
143845
144329
|
...signal === void 0 ? {} : { signal }
|
|
143846
144330
|
});
|
|
143847
|
-
const errcode = Number(payload["errcode"] ?? 0);
|
|
143848
|
-
if (errcode !== 0) throw this.#apiError(errcode, payload["errmsg"]);
|
|
143849
144331
|
const invalid = payload["invaliduser"];
|
|
143850
144332
|
if (typeof invalid === "string" && invalid.trim() !== "") {
|
|
143851
144333
|
throw new WecomAppApiError("invalid-user", `WeCom did not deliver to: ${invalid.trim()}.`, {
|
|
143852
144334
|
providerCode: "81013",
|
|
143853
|
-
hint: "
|
|
144335
|
+
hint: "wecomInvalidUser",
|
|
144336
|
+
invalidUsers: parseInvalidUsers(invalid)
|
|
143854
144337
|
});
|
|
143855
144338
|
}
|
|
143856
144339
|
}
|
|
143857
|
-
#apiError(errcode, errmsg) {
|
|
144340
|
+
#apiError(errcode, errmsg, invalidUsers) {
|
|
143858
144341
|
const code2 = String(errcode);
|
|
143859
144342
|
const message = typeof errmsg === "string" && errmsg !== "" ? `WeCom API failed (${code2}): ${errmsg}` : `WeCom API failed (${code2}).`;
|
|
143860
|
-
if (
|
|
144343
|
+
if (TOKEN_INVALID_CODES.has(code2)) this.invalidateToken();
|
|
143861
144344
|
if (errcode === 60020) {
|
|
143862
144345
|
return new WecomAppApiError("trusted-ip", "WeCom rejected the outbound IP (errcode 60020).", {
|
|
143863
144346
|
providerCode: code2,
|
|
143864
|
-
hint: "
|
|
144347
|
+
hint: "wecomTrustedIp"
|
|
143865
144348
|
});
|
|
143866
144349
|
}
|
|
143867
144350
|
if (errcode === 81013) {
|
|
143868
144351
|
return new WecomAppApiError("invalid-user", message, {
|
|
143869
144352
|
providerCode: code2,
|
|
143870
|
-
hint: "
|
|
144353
|
+
hint: "wecomInvalidUser",
|
|
144354
|
+
invalidUsers: parseInvalidUsers(invalidUsers)
|
|
143871
144355
|
});
|
|
143872
144356
|
}
|
|
143873
144357
|
if (errcode === 40056) {
|
|
143874
144358
|
return new WecomAppApiError("invalid-agent", message, {
|
|
143875
144359
|
providerCode: code2,
|
|
143876
|
-
hint: "
|
|
144360
|
+
hint: "wecomInvalidAgent"
|
|
143877
144361
|
});
|
|
143878
144362
|
}
|
|
143879
144363
|
return new WecomAppApiError("api-failed", message, { providerCode: code2 });
|
|
143880
144364
|
}
|
|
143881
|
-
async #
|
|
143882
|
-
const
|
|
143883
|
-
|
|
144365
|
+
async #withRequest(url, init, timeoutMs, read) {
|
|
144366
|
+
const deadline = new AbortController();
|
|
144367
|
+
const signal = AbortSignal.any([deadline.signal, ...init.signal ? [init.signal] : []]);
|
|
144368
|
+
const timeout = new WecomAppApiError(
|
|
144369
|
+
"timeout",
|
|
144370
|
+
`WeCom ${url.pathname} timed out after ${timeoutMs}ms.`
|
|
144371
|
+
);
|
|
144372
|
+
const timer = setTimeout(() => deadline.abort(timeout), timeoutMs);
|
|
143884
144373
|
try {
|
|
143885
|
-
|
|
143886
|
-
} catch {
|
|
143887
|
-
throw
|
|
143888
|
-
|
|
143889
|
-
|
|
143890
|
-
);
|
|
143891
|
-
}
|
|
143892
|
-
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
143893
|
-
throw new WecomAppApiError("bad-response", "WeCom returned a non-object JSON body.");
|
|
144374
|
+
return await read(await this.#fetch(url, { ...init, signal }));
|
|
144375
|
+
} catch (error) {
|
|
144376
|
+
if (signal.aborted) throw signal.reason;
|
|
144377
|
+
throw error;
|
|
144378
|
+
} finally {
|
|
144379
|
+
clearTimeout(timer);
|
|
143894
144380
|
}
|
|
143895
|
-
|
|
144381
|
+
}
|
|
144382
|
+
async #requestJson(url, init, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
144383
|
+
return this.#withRequest(url, init, timeoutMs, async (response) => {
|
|
144384
|
+
let payload;
|
|
144385
|
+
try {
|
|
144386
|
+
payload = await response.json();
|
|
144387
|
+
} catch {
|
|
144388
|
+
throw new WecomAppApiError(
|
|
144389
|
+
"bad-response",
|
|
144390
|
+
`WeCom returned non-JSON (HTTP ${String(response.status)}).`
|
|
144391
|
+
);
|
|
144392
|
+
}
|
|
144393
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
144394
|
+
throw new WecomAppApiError("bad-response", "WeCom returned a non-object JSON body.");
|
|
144395
|
+
}
|
|
144396
|
+
const result = payload;
|
|
144397
|
+
const errcode = Number(result["errcode"] ?? 0);
|
|
144398
|
+
if (errcode !== 0) throw this.#apiError(errcode, result["errmsg"], result["invaliduser"]);
|
|
144399
|
+
return result;
|
|
144400
|
+
});
|
|
143896
144401
|
}
|
|
143897
144402
|
};
|
|
143898
144403
|
|
|
143899
144404
|
// src/wecomAppCallback.ts
|
|
143900
144405
|
import * as NodeHttp2 from "node:http";
|
|
144406
|
+
import * as NodeNet from "node:net";
|
|
143901
144407
|
|
|
143902
144408
|
// src/wecomAppCrypto.ts
|
|
143903
|
-
import * as
|
|
144409
|
+
import * as NodeCrypto7 from "node:crypto";
|
|
143904
144410
|
var AES_KEY_BYTES = 32;
|
|
143905
144411
|
var RANDOM_BYTES = 16;
|
|
143906
144412
|
var WecomAppCryptoError = class extends Error {
|
|
@@ -143923,13 +144429,13 @@ var timingSafeEqualString2 = (a, b) => {
|
|
|
143923
144429
|
const left = Buffer.from(a);
|
|
143924
144430
|
const right = Buffer.from(b);
|
|
143925
144431
|
if (left.length === 0 || left.length !== right.length) return false;
|
|
143926
|
-
return
|
|
144432
|
+
return NodeCrypto7.timingSafeEqual(left, right);
|
|
143927
144433
|
};
|
|
143928
|
-
var computeSignature = (token, timestamp, nonce, encrypt) =>
|
|
144434
|
+
var computeSignature = (token, timestamp, nonce, encrypt) => NodeCrypto7.createHash("sha1").update([token, timestamp, nonce, encrypt].sort().join("")).digest("hex");
|
|
143929
144435
|
var verifySignature = (token, timestamp, nonce, encrypt, signature) => timingSafeEqualString2(computeSignature(token, timestamp, nonce, encrypt), signature);
|
|
143930
144436
|
var decrypt = (encodingAESKey, encryptText, expectReceiveId) => {
|
|
143931
144437
|
const { key, iv } = parseEncodingAESKey(encodingAESKey);
|
|
143932
|
-
const decipher =
|
|
144438
|
+
const decipher = NodeCrypto7.createDecipheriv("aes-256-cbc", key, iv);
|
|
143933
144439
|
decipher.setAutoPadding(false);
|
|
143934
144440
|
let deciphered;
|
|
143935
144441
|
try {
|
|
@@ -143988,7 +144494,7 @@ var createWecomAppCrypto = (input) => {
|
|
|
143988
144494
|
decrypt: (encryptText) => decrypt(encodingAESKey, encryptText, corpId).message
|
|
143989
144495
|
};
|
|
143990
144496
|
};
|
|
143991
|
-
var deriveCallbackPathSecret = (token, encodingAESKey) =>
|
|
144497
|
+
var deriveCallbackPathSecret = (token, encodingAESKey) => NodeCrypto7.createHash("sha256").update(`${token.trim()}:${encodingAESKey.trim()}`).digest("hex").slice(0, 24);
|
|
143992
144498
|
|
|
143993
144499
|
// src/wecomAppParse.ts
|
|
143994
144500
|
var isRecord4 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
@@ -144060,6 +144566,10 @@ var parseWecomAppPlainMessage = (raw) => {
|
|
|
144060
144566
|
|
|
144061
144567
|
// src/wecomAppCallback.ts
|
|
144062
144568
|
var WECOM_APP_DEFAULT_CALLBACK_HOST = "127.0.0.1";
|
|
144569
|
+
var parseListenHost = (raw) => {
|
|
144570
|
+
if (raw === "") return WECOM_APP_DEFAULT_CALLBACK_HOST;
|
|
144571
|
+
return NodeNet.isIPv4(raw) ? raw : null;
|
|
144572
|
+
};
|
|
144063
144573
|
var WECOM_APP_DEFAULT_CALLBACK_PORT = 30987;
|
|
144064
144574
|
var WECOM_APP_CALLBACK_PATH_PREFIX = "/wecom-app-callback";
|
|
144065
144575
|
var MAX_BODY_BYTES2 = 1 * 1024 * 1024;
|
|
@@ -144318,7 +144828,8 @@ var wecomAppCredentials = (bot) => ({
|
|
|
144318
144828
|
encodingAESKey: value(bot, "wecomAppEncodingAESKey"),
|
|
144319
144829
|
callbackBaseUrl: value(bot, "wecomAppCallbackBaseUrl").replace(/\/+$/u, ""),
|
|
144320
144830
|
apiBaseUrl: value(bot, "wecomAppApiBaseUrl"),
|
|
144321
|
-
listenPortRaw: value(bot, "wecomAppListenPort")
|
|
144831
|
+
listenPortRaw: value(bot, "wecomAppListenPort"),
|
|
144832
|
+
listenHostRaw: value(bot, "wecomAppListenHost")
|
|
144322
144833
|
});
|
|
144323
144834
|
var validCorpId = (id) => /^[A-Za-z][A-Za-z0-9_-]{2,127}$/u.test(id);
|
|
144324
144835
|
var validAgentId = (id) => /^\d{1,32}$/u.test(id) && Number(id) > 0;
|
|
@@ -144361,14 +144872,18 @@ var validateWecomAppBot = (bot) => {
|
|
|
144361
144872
|
if (parseListenPort(c.listenPortRaw) === null) {
|
|
144362
144873
|
issues.push({ column: "wecomAppListenPort", code: "format" });
|
|
144363
144874
|
}
|
|
144875
|
+
if (parseListenHost(c.listenHostRaw) === null) {
|
|
144876
|
+
issues.push({ column: "wecomAppListenHost", code: "format" });
|
|
144877
|
+
}
|
|
144364
144878
|
return issues;
|
|
144365
144879
|
};
|
|
144366
144880
|
var readWecomAppConnectConfig = (bot) => {
|
|
144367
144881
|
const issues = validateWecomAppBot(bot);
|
|
144368
144882
|
const credentials3 = wecomAppCredentials(bot);
|
|
144369
144883
|
const listenPort = parseListenPort(credentials3.listenPortRaw);
|
|
144370
|
-
|
|
144371
|
-
return { ok:
|
|
144884
|
+
const listenHost = parseListenHost(credentials3.listenHostRaw);
|
|
144885
|
+
if (issues.length > 0 || listenPort === null || listenHost === null) return { ok: false, issues };
|
|
144886
|
+
return { ok: true, credentials: credentials3, listenHost, listenPort };
|
|
144372
144887
|
};
|
|
144373
144888
|
|
|
144374
144889
|
// src/wecomAppAdapter.ts
|
|
@@ -144413,24 +144928,36 @@ var COLUMNS5 = [
|
|
|
144413
144928
|
labelKey: "column.wecomAppListenPort.label",
|
|
144414
144929
|
descriptionKey: "column.wecomAppListenPort.description",
|
|
144415
144930
|
placeholderKey: "column.wecomAppListenPort.placeholder"
|
|
144931
|
+
},
|
|
144932
|
+
{
|
|
144933
|
+
key: "wecomAppListenHost",
|
|
144934
|
+
kind: "text",
|
|
144935
|
+
labelKey: "column.wecomAppListenHost.label",
|
|
144936
|
+
descriptionKey: "column.wecomAppListenHost.description",
|
|
144937
|
+
placeholderKey: "column.wecomAppListenHost.placeholder"
|
|
144416
144938
|
}
|
|
144417
144939
|
];
|
|
144418
144940
|
var WECOM_APP_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
144419
144941
|
var WECOM_APP_FILE_BYTES = 20 * 1024 * 1024;
|
|
144420
144942
|
var WECOM_APP_MIN_BYTES = 5;
|
|
144421
144943
|
var WECOM_APP_IMAGE_TYPES = /* @__PURE__ */ new Set(["image/jpeg", "image/png"]);
|
|
144944
|
+
var CREDENTIAL_ERROR_CODES = /* @__PURE__ */ new Set(["40001", "40013", "40014", "40056", "42001", "60020"]);
|
|
144422
144945
|
var joinCallbackUrl = (baseOrOrigin, path) => `${baseOrOrigin}${path}`;
|
|
144423
144946
|
var wecomAppPublicFields = (bot) => {
|
|
144424
144947
|
const c = wecomAppCredentials(bot);
|
|
144425
|
-
if (c.
|
|
144948
|
+
if (c.token === "" || c.encodingAESKey === "") {
|
|
144949
|
+
return [{ key: "callbackUrl", value: "", hint: "callbackNeedsKeys" }];
|
|
144950
|
+
}
|
|
144951
|
+
const path = callbackRoutePath(bot.rowId, c.token, c.encodingAESKey);
|
|
144952
|
+
if (c.callbackBaseUrl === "") {
|
|
144953
|
+
return [{ key: "callbackPath", value: path, copyable: true, hint: "callbackPathNeedsBase" }];
|
|
144954
|
+
}
|
|
144426
144955
|
return [
|
|
144427
144956
|
{
|
|
144428
144957
|
key: "callbackUrl",
|
|
144429
|
-
value: joinCallbackUrl(
|
|
144430
|
-
|
|
144431
|
-
|
|
144432
|
-
),
|
|
144433
|
-
copyable: true
|
|
144958
|
+
value: joinCallbackUrl(c.callbackBaseUrl, path),
|
|
144959
|
+
copyable: true,
|
|
144960
|
+
hint: "callbackFollowsKeys"
|
|
144434
144961
|
}
|
|
144435
144962
|
];
|
|
144436
144963
|
};
|
|
@@ -144440,6 +144967,8 @@ var OUTBOUND_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
144440
144967
|
"wecomAppSecret",
|
|
144441
144968
|
"wecomAppApiBaseUrl"
|
|
144442
144969
|
]);
|
|
144970
|
+
var PROBE_BACKOFF_START_MS = 1e3;
|
|
144971
|
+
var PROBE_BACKOFF_MAX_MS = 6e4;
|
|
144443
144972
|
var makeWecomAppAdapter = (deps) => {
|
|
144444
144973
|
const apis = /* @__PURE__ */ new Map();
|
|
144445
144974
|
const newApi = (c) => new WecomAppApi({
|
|
@@ -144450,17 +144979,30 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144450
144979
|
fetch: deps.fetch
|
|
144451
144980
|
});
|
|
144452
144981
|
const callbackHub = makeWecomAppCallbackHub();
|
|
144453
|
-
const
|
|
144982
|
+
const connectionFor = (binding) => {
|
|
144454
144983
|
const api = apis.get(binding.rowId);
|
|
144455
144984
|
if (api === void 0) {
|
|
144456
144985
|
throw new ImNotConnectedError(`wecom-app bot '${binding.displayName}' is not connected.`);
|
|
144457
144986
|
}
|
|
144458
144987
|
return api;
|
|
144459
144988
|
};
|
|
144989
|
+
const deliver = async (binding, send) => {
|
|
144990
|
+
const connection = connectionFor(binding);
|
|
144991
|
+
try {
|
|
144992
|
+
await send(connection.api);
|
|
144993
|
+
connection.report({ state: "connected" });
|
|
144994
|
+
} catch (error) {
|
|
144995
|
+
if (error instanceof WecomAppApiError && error.providerCode !== void 0 && CREDENTIAL_ERROR_CODES.has(error.providerCode)) {
|
|
144996
|
+
connection.report({ state: "failed", error, reason: "credentials-rejected" });
|
|
144997
|
+
}
|
|
144998
|
+
throw error;
|
|
144999
|
+
}
|
|
145000
|
+
};
|
|
144460
145001
|
const sendMedia = async (binding, mediaType, file) => {
|
|
144461
|
-
|
|
144462
|
-
|
|
144463
|
-
|
|
145002
|
+
await deliver(binding, async (api) => {
|
|
145003
|
+
const mediaId = await api.uploadMedia({ mediaType, ...file });
|
|
145004
|
+
await api.sendMedia({ userId: binding.chatId, mediaType, mediaId });
|
|
145005
|
+
});
|
|
144464
145006
|
deps.log.info(`wecom-app delivered ${mediaType === "image" ? "an image" : "a file"}`, {
|
|
144465
145007
|
name: file.name
|
|
144466
145008
|
});
|
|
@@ -144511,6 +145053,19 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144511
145053
|
(issue) => issue.code !== "required" && issue.column !== "wecomAppEncodingAESKey"
|
|
144512
145054
|
),
|
|
144513
145055
|
publicFields: wecomAppPublicFields,
|
|
145056
|
+
// 收件人不在应用可见范围(invaliduser / 81013):说清是谁、为什么、怎么办。
|
|
145057
|
+
describeDeliveryRejection: (error, binding) => {
|
|
145058
|
+
if (!(error instanceof WecomAppApiError) || error.code !== "invalid-user") return void 0;
|
|
145059
|
+
const recipients = [
|
|
145060
|
+
...new Set(error.invalidUsers.length > 0 ? error.invalidUsers : [binding.chatId])
|
|
145061
|
+
].sort();
|
|
145062
|
+
return {
|
|
145063
|
+
recipients,
|
|
145064
|
+
summary: deps.translate("reply.wecomDeliveryFailed", { recipient: recipients.join(", ") }),
|
|
145065
|
+
hint: error.hint,
|
|
145066
|
+
providerCode: error.providerCode
|
|
145067
|
+
};
|
|
145068
|
+
},
|
|
144514
145069
|
/**
|
|
144515
145070
|
* 自建应用是回调式渠道:入站由企微推到我们的 listener,没有可探的长连接;能探的是出站
|
|
144516
145071
|
* 凭据——和真实发送同一条路,向 gettoken 换一次 access_token。
|
|
@@ -144541,7 +145096,12 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144541
145096
|
detail: "access_token ok (callback reachability is not probed)"
|
|
144542
145097
|
};
|
|
144543
145098
|
} catch (error) {
|
|
144544
|
-
return {
|
|
145099
|
+
return {
|
|
145100
|
+
stage: "gettoken",
|
|
145101
|
+
ok: false,
|
|
145102
|
+
detail: describeError(error),
|
|
145103
|
+
...error instanceof WecomAppApiError && error.hint !== void 0 ? { hint: error.hint } : {}
|
|
145104
|
+
};
|
|
144545
145105
|
}
|
|
144546
145106
|
},
|
|
144547
145107
|
connect: async (bot, handlers) => {
|
|
@@ -144552,10 +145112,17 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144552
145112
|
);
|
|
144553
145113
|
}
|
|
144554
145114
|
const c = config2.credentials;
|
|
144555
|
-
const lease = await callbackHub.acquire({ port: config2.listenPort });
|
|
145115
|
+
const lease = await callbackHub.acquire({ host: config2.listenHost, port: config2.listenPort });
|
|
144556
145116
|
const server = lease.server;
|
|
144557
145117
|
const api = newApi(c);
|
|
144558
|
-
|
|
145118
|
+
let closed = false;
|
|
145119
|
+
const report = (state) => {
|
|
145120
|
+
if (closed) return;
|
|
145121
|
+
handlers.onConnectionState?.(
|
|
145122
|
+
state.state === "failed" && state.error instanceof WecomAppApiError && state.error.hint !== void 0 ? { ...state, hint: state.error.hint } : state
|
|
145123
|
+
);
|
|
145124
|
+
};
|
|
145125
|
+
apis.set(bot.rowId, { api, report });
|
|
144559
145126
|
let path;
|
|
144560
145127
|
try {
|
|
144561
145128
|
path = server.register({
|
|
@@ -144571,7 +145138,7 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144571
145138
|
await lease.release();
|
|
144572
145139
|
throw error;
|
|
144573
145140
|
}
|
|
144574
|
-
deps.log.info("wecom-app
|
|
145141
|
+
deps.log.info("wecom-app callback listening", {
|
|
144575
145142
|
bot: bot.displayName,
|
|
144576
145143
|
callbackPath: path,
|
|
144577
145144
|
callbackUrl: joinCallbackUrl(
|
|
@@ -144580,8 +145147,26 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144580
145147
|
),
|
|
144581
145148
|
listen: `${server.host}:${String(server.port)}`
|
|
144582
145149
|
});
|
|
145150
|
+
const probe2 = new AbortController();
|
|
145151
|
+
void (async () => {
|
|
145152
|
+
let backoff = PROBE_BACKOFF_START_MS;
|
|
145153
|
+
while (!probe2.signal.aborted) {
|
|
145154
|
+
try {
|
|
145155
|
+
await api.getAccessToken(probe2.signal);
|
|
145156
|
+
report({ state: "connected" });
|
|
145157
|
+
return;
|
|
145158
|
+
} catch (error) {
|
|
145159
|
+
if (probe2.signal.aborted) return;
|
|
145160
|
+
report({ state: "failed", error, reason: "token-unavailable" });
|
|
145161
|
+
await (deps.sleep ?? abortableSleep)(backoff, probe2.signal).catch(() => void 0);
|
|
145162
|
+
backoff = Math.min(backoff * 2, PROBE_BACKOFF_MAX_MS);
|
|
145163
|
+
}
|
|
145164
|
+
}
|
|
145165
|
+
})();
|
|
144583
145166
|
return {
|
|
144584
145167
|
close: () => {
|
|
145168
|
+
closed = true;
|
|
145169
|
+
probe2.abort();
|
|
144585
145170
|
server.unregister(bot.rowId);
|
|
144586
145171
|
apis.delete(bot.rowId);
|
|
144587
145172
|
void lease.release().catch((error) => {
|
|
@@ -144597,7 +145182,19 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144597
145182
|
if (options?.targetKind === "group") {
|
|
144598
145183
|
throw new Error("wecom-app can only deliver to a user; group targets are not supported.");
|
|
144599
145184
|
}
|
|
144600
|
-
await
|
|
145185
|
+
await deliver(
|
|
145186
|
+
binding,
|
|
145187
|
+
(api) => api.sendText({ userId: binding.chatId, content: text4, retry: options?.retry })
|
|
145188
|
+
);
|
|
145189
|
+
},
|
|
145190
|
+
// D376:企业微信自建应用没有表情回执也没有流式,开工时先回一句文字,结论照常另发。没有要撤的
|
|
145191
|
+
// 东西,回 null;发不出去由核心记一条 warn,不拦这一轮。
|
|
145192
|
+
acknowledge: async (binding) => {
|
|
145193
|
+
await deliver(
|
|
145194
|
+
binding,
|
|
145195
|
+
(api) => api.sendText({ userId: binding.chatId, content: deps.translate("reply.received") })
|
|
145196
|
+
);
|
|
145197
|
+
return null;
|
|
144601
145198
|
},
|
|
144602
145199
|
sendImage: (binding, image2) => sendMedia(binding, "image", image2),
|
|
144603
145200
|
sendFile: (binding, file) => sendMedia(binding, "file", file),
|
|
@@ -144607,11 +145204,16 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144607
145204
|
minBytes: WECOM_APP_MIN_BYTES
|
|
144608
145205
|
},
|
|
144609
145206
|
imageMimeTypes: WECOM_APP_IMAGE_TYPES,
|
|
144610
|
-
fetchResource: (binding, input) =>
|
|
145207
|
+
fetchResource: (binding, input) => connectionFor(binding).api.downloadMedia({
|
|
145208
|
+
mediaId: input.resource.key,
|
|
145209
|
+
maxBytes: input.maxBytes
|
|
145210
|
+
}),
|
|
144611
145211
|
askApproval: async (binding, request) => {
|
|
144612
|
-
|
|
144613
|
-
|
|
144614
|
-
|
|
145212
|
+
if (!apis.has(binding.rowId)) return null;
|
|
145213
|
+
await deliver(
|
|
145214
|
+
binding,
|
|
145215
|
+
(api) => api.sendText({ userId: binding.chatId, content: numberedApprovalText(request) })
|
|
145216
|
+
);
|
|
144615
145217
|
return null;
|
|
144616
145218
|
},
|
|
144617
145219
|
answerByText: (_binding, text4, options) => answerByNumber(text4, options)
|
|
@@ -144621,7 +145223,7 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
144621
145223
|
// src/index.ts
|
|
144622
145224
|
var imPlugin = definePlugin({
|
|
144623
145225
|
id: "im",
|
|
144624
|
-
apiVersion:
|
|
145226
|
+
apiVersion: 18,
|
|
144625
145227
|
activate: async (ctx) => {
|
|
144626
145228
|
const { t, setLanguage } = makeLiveTranslate(
|
|
144627
145229
|
parseReplyLanguage(ctx.config[REPLY_LANGUAGE_FIELD])
|
|
@@ -144682,7 +145284,6 @@ var imPlugin = definePlugin({
|
|
|
144682
145284
|
const updateSettings = makeSettingsUpdater(ctx.settings);
|
|
144683
145285
|
registerLarkSetup(ctx, { updateSettings });
|
|
144684
145286
|
registerSettingsRowActions(ctx, adapters);
|
|
144685
|
-
registerSettingsCommands(ctx, adapters, updateSettings);
|
|
144686
145287
|
const core = makeImCore({
|
|
144687
145288
|
host: {
|
|
144688
145289
|
log: ctx.log,
|
|
@@ -144717,7 +145318,7 @@ var imPlugin = definePlugin({
|
|
|
144717
145318
|
);
|
|
144718
145319
|
const teams = makeTeamGoals(core);
|
|
144719
145320
|
const notifications = makeNotifications(core, {
|
|
144720
|
-
|
|
145321
|
+
takeWorking: acknowledgements.takeWorking,
|
|
144721
145322
|
replyCards,
|
|
144722
145323
|
failures,
|
|
144723
145324
|
conclusions,
|
|
@@ -144793,6 +145394,7 @@ var imPlugin = definePlugin({
|
|
|
144793
145394
|
]
|
|
144794
145395
|
});
|
|
144795
145396
|
const connections = startConnections(core, inbound.inboundHandlersFor);
|
|
145397
|
+
registerSettingsCommands(ctx, adapters, updateSettings, connections);
|
|
144796
145398
|
const { bots, connecting } = connections.reconcile();
|
|
144797
145399
|
const deliveryHttp = makeDeliveryHttp({
|
|
144798
145400
|
// 每次请求按此刻的设置找目标:投递目标表改了不用重开监听。
|