opencode-feishu-plugin 0.1.1 → 0.1.3
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/README.en.md +74 -5
- package/README.md +135 -241
- package/dist/index.js +1980 -481
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8870,11 +8870,11 @@ var require_mime_types = __commonJS({
|
|
|
8870
8870
|
}
|
|
8871
8871
|
return false;
|
|
8872
8872
|
}
|
|
8873
|
-
function contentType(
|
|
8874
|
-
if (!
|
|
8873
|
+
function contentType(str6) {
|
|
8874
|
+
if (!str6 || typeof str6 !== "string") {
|
|
8875
8875
|
return false;
|
|
8876
8876
|
}
|
|
8877
|
-
var mime =
|
|
8877
|
+
var mime = str6.indexOf("/") === -1 ? exports.lookup(str6) : str6;
|
|
8878
8878
|
if (!mime) {
|
|
8879
8879
|
return false;
|
|
8880
8880
|
}
|
|
@@ -9413,14 +9413,14 @@ var require_implementation = __commonJS({
|
|
|
9413
9413
|
return arr;
|
|
9414
9414
|
};
|
|
9415
9415
|
var joiny = function(arr, joiner) {
|
|
9416
|
-
var
|
|
9416
|
+
var str6 = "";
|
|
9417
9417
|
for (var i = 0; i < arr.length; i += 1) {
|
|
9418
|
-
|
|
9418
|
+
str6 += arr[i];
|
|
9419
9419
|
if (i + 1 < arr.length) {
|
|
9420
|
-
|
|
9420
|
+
str6 += joiner;
|
|
9421
9421
|
}
|
|
9422
9422
|
}
|
|
9423
|
-
return
|
|
9423
|
+
return str6;
|
|
9424
9424
|
};
|
|
9425
9425
|
module.exports = function bind6(that) {
|
|
9426
9426
|
var target = this;
|
|
@@ -9978,8 +9978,8 @@ var require_form_data = __commonJS({
|
|
|
9978
9978
|
var setToStringTag = require_es_set_tostringtag();
|
|
9979
9979
|
var hasOwn = require_hasown();
|
|
9980
9980
|
var populate = require_populate();
|
|
9981
|
-
function escapeHeaderParam(
|
|
9982
|
-
return String(
|
|
9981
|
+
function escapeHeaderParam(str6) {
|
|
9982
|
+
return String(str6).replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/"/g, "%22");
|
|
9983
9983
|
}
|
|
9984
9984
|
function FormData4(options2) {
|
|
9985
9985
|
if (!(this instanceof FormData4)) {
|
|
@@ -10303,13 +10303,13 @@ var require_ms = __commonJS({
|
|
|
10303
10303
|
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
10304
10304
|
);
|
|
10305
10305
|
};
|
|
10306
|
-
function parse(
|
|
10307
|
-
|
|
10308
|
-
if (
|
|
10306
|
+
function parse(str6) {
|
|
10307
|
+
str6 = String(str6);
|
|
10308
|
+
if (str6.length > 100) {
|
|
10309
10309
|
return;
|
|
10310
10310
|
}
|
|
10311
10311
|
var match8 = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
10312
|
-
|
|
10312
|
+
str6
|
|
10313
10313
|
);
|
|
10314
10314
|
if (!match8) {
|
|
10315
10315
|
return;
|
|
@@ -10910,7 +10910,7 @@ var require_node = __commonJS({
|
|
|
10910
10910
|
var { formatters } = module.exports;
|
|
10911
10911
|
formatters.o = function(v) {
|
|
10912
10912
|
this.inspectOpts.colors = this.useColors;
|
|
10913
|
-
return util4.inspect(v, this.inspectOpts).split("\n").map((
|
|
10913
|
+
return util4.inspect(v, this.inspectOpts).split("\n").map((str6) => str6.trim()).join(" ");
|
|
10914
10914
|
};
|
|
10915
10915
|
formatters.O = function(v) {
|
|
10916
10916
|
this.inspectOpts.colors = this.useColors;
|
|
@@ -11952,20 +11952,20 @@ var require_object_inspect = __commonJS({
|
|
|
11952
11952
|
var gPO = (typeof Reflect === "function" ? Reflect.getPrototypeOf : Object.getPrototypeOf) || ([].__proto__ === Array.prototype ? function(O) {
|
|
11953
11953
|
return O.__proto__;
|
|
11954
11954
|
} : null);
|
|
11955
|
-
function addNumericSeparator(num,
|
|
11956
|
-
if (num === Infinity || num === -Infinity || num !== num || num && num > -1e3 && num < 1e3 || $test.call(/e/,
|
|
11957
|
-
return
|
|
11955
|
+
function addNumericSeparator(num, str6) {
|
|
11956
|
+
if (num === Infinity || num === -Infinity || num !== num || num && num > -1e3 && num < 1e3 || $test.call(/e/, str6)) {
|
|
11957
|
+
return str6;
|
|
11958
11958
|
}
|
|
11959
11959
|
var sepRegex = /[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;
|
|
11960
11960
|
if (typeof num === "number") {
|
|
11961
11961
|
var int = num < 0 ? -$floor(-num) : $floor(num);
|
|
11962
11962
|
if (int !== num) {
|
|
11963
11963
|
var intStr = String(int);
|
|
11964
|
-
var dec = $slice.call(
|
|
11964
|
+
var dec = $slice.call(str6, intStr.length + 1);
|
|
11965
11965
|
return $replace.call(intStr, sepRegex, "$&_") + "." + $replace.call($replace.call(dec, /([0-9]{3})/g, "$&_"), /_$/, "");
|
|
11966
11966
|
}
|
|
11967
11967
|
}
|
|
11968
|
-
return $replace.call(
|
|
11968
|
+
return $replace.call(str6, sepRegex, "$&_");
|
|
11969
11969
|
}
|
|
11970
11970
|
var utilInspect = require_util_inspect();
|
|
11971
11971
|
var inspectCustom = utilInspect.custom;
|
|
@@ -12015,8 +12015,8 @@ var require_object_inspect = __commonJS({
|
|
|
12015
12015
|
if (obj === 0) {
|
|
12016
12016
|
return Infinity / obj > 0 ? "0" : "-0";
|
|
12017
12017
|
}
|
|
12018
|
-
var
|
|
12019
|
-
return numericSeparator ? addNumericSeparator(obj,
|
|
12018
|
+
var str6 = String(obj);
|
|
12019
|
+
return numericSeparator ? addNumericSeparator(obj, str6) : str6;
|
|
12020
12020
|
}
|
|
12021
12021
|
if (typeof obj === "bigint") {
|
|
12022
12022
|
var bigIntStr = String(obj) + "n";
|
|
@@ -12336,15 +12336,15 @@ var require_object_inspect = __commonJS({
|
|
|
12336
12336
|
}
|
|
12337
12337
|
return typeof x.nodeName === "string" && typeof x.getAttribute === "function";
|
|
12338
12338
|
}
|
|
12339
|
-
function inspectString(
|
|
12340
|
-
if (
|
|
12341
|
-
var remaining =
|
|
12339
|
+
function inspectString(str6, opts) {
|
|
12340
|
+
if (str6.length > opts.maxStringLength) {
|
|
12341
|
+
var remaining = str6.length - opts.maxStringLength;
|
|
12342
12342
|
var trailer = "... " + remaining + " more character" + (remaining > 1 ? "s" : "");
|
|
12343
|
-
return inspectString($slice.call(
|
|
12343
|
+
return inspectString($slice.call(str6, 0, opts.maxStringLength), opts) + trailer;
|
|
12344
12344
|
}
|
|
12345
12345
|
var quoteRE = quoteREs[opts.quoteStyle || "single"];
|
|
12346
12346
|
quoteRE.lastIndex = 0;
|
|
12347
|
-
var s = $replace.call($replace.call(
|
|
12347
|
+
var s = $replace.call($replace.call(str6, quoteRE, "\\$1"), /[\x00-\x1f]/g, lowbyte);
|
|
12348
12348
|
return wrapQuotes(s, "single", opts);
|
|
12349
12349
|
}
|
|
12350
12350
|
function lowbyte(c) {
|
|
@@ -12361,8 +12361,8 @@ var require_object_inspect = __commonJS({
|
|
|
12361
12361
|
}
|
|
12362
12362
|
return "\\x" + (n < 16 ? "0" : "") + $toUpperCase.call(n.toString(16));
|
|
12363
12363
|
}
|
|
12364
|
-
function markBoxed(
|
|
12365
|
-
return "Object(" +
|
|
12364
|
+
function markBoxed(str6) {
|
|
12365
|
+
return "Object(" + str6 + ")";
|
|
12366
12366
|
}
|
|
12367
12367
|
function weakCollectionOf(type) {
|
|
12368
12368
|
return type + " { ? }";
|
|
@@ -12912,8 +12912,8 @@ var require_utils = __commonJS({
|
|
|
12912
12912
|
return acc;
|
|
12913
12913
|
}, target);
|
|
12914
12914
|
};
|
|
12915
|
-
var decode3 = function(
|
|
12916
|
-
var strWithoutPlus =
|
|
12915
|
+
var decode3 = function(str6, defaultDecoder, charset) {
|
|
12916
|
+
var strWithoutPlus = str6.replace(/\+/g, " ");
|
|
12917
12917
|
if (charset === "iso-8859-1") {
|
|
12918
12918
|
return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape);
|
|
12919
12919
|
}
|
|
@@ -12924,15 +12924,15 @@ var require_utils = __commonJS({
|
|
|
12924
12924
|
}
|
|
12925
12925
|
};
|
|
12926
12926
|
var limit = 1024;
|
|
12927
|
-
var encode4 = function encode5(
|
|
12928
|
-
if (
|
|
12929
|
-
return
|
|
12927
|
+
var encode4 = function encode5(str6, defaultEncoder, charset, kind, format5) {
|
|
12928
|
+
if (str6.length === 0) {
|
|
12929
|
+
return str6;
|
|
12930
12930
|
}
|
|
12931
|
-
var string3 =
|
|
12932
|
-
if (typeof
|
|
12933
|
-
string3 = Symbol.prototype.toString.call(
|
|
12934
|
-
} else if (typeof
|
|
12935
|
-
string3 = String(
|
|
12931
|
+
var string3 = str6;
|
|
12932
|
+
if (typeof str6 === "symbol") {
|
|
12933
|
+
string3 = Symbol.prototype.toString.call(str6);
|
|
12934
|
+
} else if (typeof str6 !== "string") {
|
|
12935
|
+
string3 = String(str6);
|
|
12936
12936
|
}
|
|
12937
12937
|
if (charset === "iso-8859-1") {
|
|
12938
12938
|
return escape(string3).replace(/%u[0-9a-f]{4}/gi, function($0) {
|
|
@@ -13380,8 +13380,8 @@ var require_parse = __commonJS({
|
|
|
13380
13380
|
strictNullHandling: false,
|
|
13381
13381
|
throwOnLimitExceeded: false
|
|
13382
13382
|
};
|
|
13383
|
-
var interpretNumericEntities = function(
|
|
13384
|
-
return
|
|
13383
|
+
var interpretNumericEntities = function(str6) {
|
|
13384
|
+
return str6.replace(/&#(\d+);/g, function($0, numberStr) {
|
|
13385
13385
|
return String.fromCharCode(parseInt(numberStr, 10));
|
|
13386
13386
|
});
|
|
13387
13387
|
};
|
|
@@ -13407,9 +13407,9 @@ var require_parse = __commonJS({
|
|
|
13407
13407
|
};
|
|
13408
13408
|
var isoSentinel = "utf8=%26%2310003%3B";
|
|
13409
13409
|
var charsetSentinel = "utf8=%E2%9C%93";
|
|
13410
|
-
var parseValues = function parseQueryStringValues(
|
|
13410
|
+
var parseValues = function parseQueryStringValues(str6, options2) {
|
|
13411
13411
|
var obj = { __proto__: null };
|
|
13412
|
-
var cleanStr = options2.ignoreQueryPrefix ?
|
|
13412
|
+
var cleanStr = options2.ignoreQueryPrefix ? str6.replace(/^\?/, "") : str6;
|
|
13413
13413
|
cleanStr = cleanStr.replace(/%5B/gi, "[").replace(/%5D/gi, "]");
|
|
13414
13414
|
var limit = options2.parameterLimit === Infinity ? void 0 : options2.parameterLimit;
|
|
13415
13415
|
var parts = cleanStr.split(
|
|
@@ -13656,17 +13656,17 @@ var require_parse = __commonJS({
|
|
|
13656
13656
|
throwOnLimitExceeded: typeof opts.throwOnLimitExceeded === "boolean" ? opts.throwOnLimitExceeded : false
|
|
13657
13657
|
};
|
|
13658
13658
|
};
|
|
13659
|
-
module.exports = function(
|
|
13659
|
+
module.exports = function(str6, opts) {
|
|
13660
13660
|
var options2 = normalizeParseOptions(opts);
|
|
13661
|
-
if (
|
|
13661
|
+
if (str6 === "" || str6 === null || typeof str6 === "undefined") {
|
|
13662
13662
|
return options2.plainObjects ? { __proto__: null } : {};
|
|
13663
13663
|
}
|
|
13664
|
-
var tempObj = typeof
|
|
13664
|
+
var tempObj = typeof str6 === "string" ? parseValues(str6, options2) : str6;
|
|
13665
13665
|
var obj = options2.plainObjects ? { __proto__: null } : {};
|
|
13666
13666
|
var keys4 = Object.keys(tempObj);
|
|
13667
13667
|
for (var i = 0; i < keys4.length; ++i) {
|
|
13668
13668
|
var key = keys4[i];
|
|
13669
|
-
var newObj = parseKeys(key, tempObj[key], options2, typeof
|
|
13669
|
+
var newObj = parseKeys(key, tempObj[key], options2, typeof str6 === "string");
|
|
13670
13670
|
obj = utils.merge(obj, newObj, options2);
|
|
13671
13671
|
}
|
|
13672
13672
|
if (options2.allowSparse === true) {
|
|
@@ -19964,27 +19964,27 @@ var require_umd = __commonJS({
|
|
|
19964
19964
|
}
|
|
19965
19965
|
Long.fromBits = fromBits;
|
|
19966
19966
|
var pow_dbl = Math.pow;
|
|
19967
|
-
function fromString2(
|
|
19968
|
-
if (
|
|
19967
|
+
function fromString2(str6, unsigned, radix) {
|
|
19968
|
+
if (str6.length === 0) throw Error("empty string");
|
|
19969
19969
|
if (typeof unsigned === "number") {
|
|
19970
19970
|
radix = unsigned;
|
|
19971
19971
|
unsigned = false;
|
|
19972
19972
|
} else {
|
|
19973
19973
|
unsigned = !!unsigned;
|
|
19974
19974
|
}
|
|
19975
|
-
if (
|
|
19975
|
+
if (str6 === "NaN" || str6 === "Infinity" || str6 === "+Infinity" || str6 === "-Infinity")
|
|
19976
19976
|
return unsigned ? UZERO : ZERO;
|
|
19977
19977
|
radix = radix || 10;
|
|
19978
19978
|
if (radix < 2 || 36 < radix) throw RangeError("radix");
|
|
19979
19979
|
var p;
|
|
19980
|
-
if ((p =
|
|
19980
|
+
if ((p = str6.indexOf("-")) > 0) throw Error("interior hyphen");
|
|
19981
19981
|
else if (p === 0) {
|
|
19982
|
-
return fromString2(
|
|
19982
|
+
return fromString2(str6.substring(1), unsigned, radix).neg();
|
|
19983
19983
|
}
|
|
19984
19984
|
var radixToPower = fromNumber(pow_dbl(radix, 8));
|
|
19985
19985
|
var result3 = ZERO;
|
|
19986
|
-
for (var i = 0; i <
|
|
19987
|
-
var size6 = Math.min(8,
|
|
19986
|
+
for (var i = 0; i < str6.length; i += 8) {
|
|
19987
|
+
var size6 = Math.min(8, str6.length - i), value3 = parseInt(str6.substring(i, i + size6), radix);
|
|
19988
19988
|
if (size6 < 8) {
|
|
19989
19989
|
var power = fromNumber(pow_dbl(radix, size6));
|
|
19990
19990
|
result3 = result3.mul(power).add(fromNumber(value3));
|
|
@@ -20632,8 +20632,8 @@ var require_minimal = __commonJS({
|
|
|
20632
20632
|
writable: true
|
|
20633
20633
|
});
|
|
20634
20634
|
};
|
|
20635
|
-
util4.lcFirst = function lcFirst(
|
|
20636
|
-
return
|
|
20635
|
+
util4.lcFirst = function lcFirst(str6) {
|
|
20636
|
+
return str6.charAt(0).toLowerCase() + str6.substring(1);
|
|
20637
20637
|
};
|
|
20638
20638
|
function newError(name) {
|
|
20639
20639
|
function CustomError(message, properties) {
|
|
@@ -21436,8 +21436,8 @@ var toSafeFlatObject = (thing) => {
|
|
|
21436
21436
|
return result3;
|
|
21437
21437
|
};
|
|
21438
21438
|
var kindOf = /* @__PURE__ */ ((cache) => (thing) => {
|
|
21439
|
-
const
|
|
21440
|
-
return cache[
|
|
21439
|
+
const str6 = toString.call(thing);
|
|
21440
|
+
return cache[str6] || (cache[str6] = str6.slice(8, -1).toLowerCase());
|
|
21441
21441
|
})(/* @__PURE__ */ Object.create(null));
|
|
21442
21442
|
var kindOfTest = (type) => {
|
|
21443
21443
|
type = type.toLowerCase();
|
|
@@ -21520,8 +21520,8 @@ var [isReadableStream, isRequest, isResponse, isHeaders] = [
|
|
|
21520
21520
|
"Response",
|
|
21521
21521
|
"Headers"
|
|
21522
21522
|
].map(kindOfTest);
|
|
21523
|
-
var trim = (
|
|
21524
|
-
return
|
|
21523
|
+
var trim = (str6) => {
|
|
21524
|
+
return str6.trim ? str6.trim() : str6.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
|
|
21525
21525
|
};
|
|
21526
21526
|
function forEach(obj, fn3, { allOwnKeys = false } = {}) {
|
|
21527
21527
|
if (obj === null || typeof obj === "undefined") {
|
|
@@ -21678,13 +21678,13 @@ var toFlatObject = (sourceObj, destObj, filter9, propFilter) => {
|
|
|
21678
21678
|
} while (sourceObj && (!filter9 || filter9(sourceObj, destObj)) && sourceObj !== Object.prototype);
|
|
21679
21679
|
return destObj;
|
|
21680
21680
|
};
|
|
21681
|
-
var endsWith = (
|
|
21682
|
-
|
|
21683
|
-
if (position === void 0 || position >
|
|
21684
|
-
position =
|
|
21681
|
+
var endsWith = (str6, searchString, position) => {
|
|
21682
|
+
str6 = String(str6);
|
|
21683
|
+
if (position === void 0 || position > str6.length) {
|
|
21684
|
+
position = str6.length;
|
|
21685
21685
|
}
|
|
21686
21686
|
position -= searchString.length;
|
|
21687
|
-
const lastIndex =
|
|
21687
|
+
const lastIndex = str6.indexOf(searchString, position);
|
|
21688
21688
|
return lastIndex !== -1 && lastIndex === position;
|
|
21689
21689
|
};
|
|
21690
21690
|
var toArray = (thing) => {
|
|
@@ -21712,17 +21712,17 @@ var forEachEntry = (obj, fn3) => {
|
|
|
21712
21712
|
fn3.call(obj, pair[0], pair[1]);
|
|
21713
21713
|
}
|
|
21714
21714
|
};
|
|
21715
|
-
var matchAll = (regExp,
|
|
21715
|
+
var matchAll = (regExp, str6) => {
|
|
21716
21716
|
let matches;
|
|
21717
21717
|
const arr = [];
|
|
21718
|
-
while ((matches = regExp.exec(
|
|
21718
|
+
while ((matches = regExp.exec(str6)) !== null) {
|
|
21719
21719
|
arr.push(matches);
|
|
21720
21720
|
}
|
|
21721
21721
|
return arr;
|
|
21722
21722
|
};
|
|
21723
21723
|
var isHTMLForm = kindOfTest("HTMLFormElement");
|
|
21724
|
-
var toCamelCase = (
|
|
21725
|
-
return
|
|
21724
|
+
var toCamelCase = (str6) => {
|
|
21725
|
+
return str6.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, function replacer(m, p1, p2) {
|
|
21726
21726
|
return p1.toUpperCase() + p2;
|
|
21727
21727
|
});
|
|
21728
21728
|
};
|
|
@@ -21949,24 +21949,24 @@ var parseHeaders_default = (rawHeaders) => {
|
|
|
21949
21949
|
};
|
|
21950
21950
|
|
|
21951
21951
|
// node_modules/axios/lib/helpers/sanitizeHeaderValue.js
|
|
21952
|
-
function trimSPorHTAB(
|
|
21952
|
+
function trimSPorHTAB(str6) {
|
|
21953
21953
|
let start2 = 0;
|
|
21954
|
-
let end =
|
|
21954
|
+
let end = str6.length;
|
|
21955
21955
|
while (start2 < end) {
|
|
21956
|
-
const code =
|
|
21956
|
+
const code = str6.charCodeAt(start2);
|
|
21957
21957
|
if (code !== 9 && code !== 32) {
|
|
21958
21958
|
break;
|
|
21959
21959
|
}
|
|
21960
21960
|
start2 += 1;
|
|
21961
21961
|
}
|
|
21962
21962
|
while (end > start2) {
|
|
21963
|
-
const code =
|
|
21963
|
+
const code = str6.charCodeAt(end - 1);
|
|
21964
21964
|
if (code !== 9 && code !== 32) {
|
|
21965
21965
|
break;
|
|
21966
21966
|
}
|
|
21967
21967
|
end -= 1;
|
|
21968
21968
|
}
|
|
21969
|
-
return start2 === 0 && end ===
|
|
21969
|
+
return start2 === 0 && end === str6.length ? str6 : str6.slice(start2, end);
|
|
21970
21970
|
}
|
|
21971
21971
|
var INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+", "g");
|
|
21972
21972
|
var INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+", "g");
|
|
@@ -21997,11 +21997,11 @@ function normalizeValue(value3) {
|
|
|
21997
21997
|
}
|
|
21998
21998
|
return utils_default.isArray(value3) ? value3.map(normalizeValue) : sanitizeHeaderValue(String(value3));
|
|
21999
21999
|
}
|
|
22000
|
-
function parseTokens(
|
|
22000
|
+
function parseTokens(str6) {
|
|
22001
22001
|
const tokens = /* @__PURE__ */ Object.create(null);
|
|
22002
22002
|
const tokensRE = /([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;
|
|
22003
22003
|
let match8;
|
|
22004
|
-
while (match8 = tokensRE.exec(
|
|
22004
|
+
while (match8 = tokensRE.exec(str6)) {
|
|
22005
22005
|
tokens[match8[1]] = match8[2];
|
|
22006
22006
|
}
|
|
22007
22007
|
return tokens;
|
|
@@ -22049,12 +22049,12 @@ function decodeQuotedString(value3) {
|
|
|
22049
22049
|
}
|
|
22050
22050
|
function parseParameters(value3) {
|
|
22051
22051
|
const parameters = /* @__PURE__ */ Object.create(null);
|
|
22052
|
-
const
|
|
22052
|
+
const str6 = String(value3);
|
|
22053
22053
|
let start2 = 0;
|
|
22054
22054
|
let quoted = false;
|
|
22055
22055
|
let escaped = false;
|
|
22056
22056
|
function parseParameter2(end) {
|
|
22057
|
-
const part = trimOWS(
|
|
22057
|
+
const part = trimOWS(str6.slice(start2, end));
|
|
22058
22058
|
const equals4 = part.indexOf("=");
|
|
22059
22059
|
if (equals4 < 1) {
|
|
22060
22060
|
return;
|
|
@@ -22070,8 +22070,8 @@ function parseParameters(value3) {
|
|
|
22070
22070
|
const parameterValue = trimOWS(part.slice(equals4 + 1));
|
|
22071
22071
|
parameters[normalizedName] = decodeQuotedString(parameterValue);
|
|
22072
22072
|
}
|
|
22073
|
-
for (let i = 0; i <
|
|
22074
|
-
const code =
|
|
22073
|
+
for (let i = 0; i < str6.length; i++) {
|
|
22074
|
+
const code = str6.charCodeAt(i);
|
|
22075
22075
|
if (quoted) {
|
|
22076
22076
|
if (escaped) {
|
|
22077
22077
|
escaped = false;
|
|
@@ -22087,10 +22087,10 @@ function parseParameters(value3) {
|
|
|
22087
22087
|
start2 = i + 1;
|
|
22088
22088
|
}
|
|
22089
22089
|
}
|
|
22090
|
-
parseParameter2(
|
|
22090
|
+
parseParameter2(str6.length);
|
|
22091
22091
|
return parameters;
|
|
22092
22092
|
}
|
|
22093
|
-
var isValidHeaderName = (
|
|
22093
|
+
var isValidHeaderName = (str6) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str6.trim());
|
|
22094
22094
|
function matchHeaderValue(context3, value3, header, filter9, isHeaderNameFilter) {
|
|
22095
22095
|
if (utils_default.isFunction(filter9)) {
|
|
22096
22096
|
return filter9.call(this, value3, header);
|
|
@@ -22107,8 +22107,8 @@ function matchHeaderValue(context3, value3, header, filter9, isHeaderNameFilter)
|
|
|
22107
22107
|
}
|
|
22108
22108
|
}
|
|
22109
22109
|
function formatHeader(header) {
|
|
22110
|
-
return header.trim().toLowerCase().replace(/([a-z\d])(\w*)/g, (w, char,
|
|
22111
|
-
return char.toUpperCase() +
|
|
22110
|
+
return header.trim().toLowerCase().replace(/([a-z\d])(\w*)/g, (w, char, str6) => {
|
|
22111
|
+
return char.toUpperCase() + str6;
|
|
22112
22112
|
});
|
|
22113
22113
|
}
|
|
22114
22114
|
function buildAccessors(obj, header) {
|
|
@@ -22643,7 +22643,7 @@ function toFormData(obj, formData, options2) {
|
|
|
22643
22643
|
var toFormData_default = toFormData;
|
|
22644
22644
|
|
|
22645
22645
|
// node_modules/axios/lib/helpers/AxiosURLSearchParams.js
|
|
22646
|
-
function encode(
|
|
22646
|
+
function encode(str6) {
|
|
22647
22647
|
const charMap = {
|
|
22648
22648
|
"!": "%21",
|
|
22649
22649
|
"'": "%27",
|
|
@@ -22652,7 +22652,7 @@ function encode(str5) {
|
|
|
22652
22652
|
"~": "%7E",
|
|
22653
22653
|
"%20": "+"
|
|
22654
22654
|
};
|
|
22655
|
-
return encodeURIComponent(
|
|
22655
|
+
return encodeURIComponent(str6).replace(/[!'()~]|%20/g, function replacer(match8) {
|
|
22656
22656
|
return charMap[match8];
|
|
22657
22657
|
});
|
|
22658
22658
|
}
|
|
@@ -22860,14 +22860,14 @@ var ALPHABET = {
|
|
|
22860
22860
|
ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT
|
|
22861
22861
|
};
|
|
22862
22862
|
var generateString = (size6 = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {
|
|
22863
|
-
let
|
|
22863
|
+
let str6 = "";
|
|
22864
22864
|
const { length: length2 } = alphabet;
|
|
22865
22865
|
const randomValues = new Uint32Array(size6);
|
|
22866
22866
|
crypto3.randomFillSync(randomValues);
|
|
22867
22867
|
for (let i = 0; i < size6; i++) {
|
|
22868
|
-
|
|
22868
|
+
str6 += alphabet[randomValues[i] % length2];
|
|
22869
22869
|
}
|
|
22870
|
-
return
|
|
22870
|
+
return str6;
|
|
22871
22871
|
};
|
|
22872
22872
|
var node_default = {
|
|
22873
22873
|
isNode: true,
|
|
@@ -24153,7 +24153,7 @@ var asyncDecorator = (fn3, scheduler = utils_default.asap) => (...args2) => sche
|
|
|
24153
24153
|
|
|
24154
24154
|
// node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js
|
|
24155
24155
|
var isHexDigit = (charCode) => charCode >= 48 && charCode <= 57 || charCode >= 65 && charCode <= 70 || charCode >= 97 && charCode <= 102;
|
|
24156
|
-
var isPercentEncodedByte = (
|
|
24156
|
+
var isPercentEncodedByte = (str6, i, len) => i + 2 < len && isHexDigit(str6.charCodeAt(i + 1)) && isHexDigit(str6.charCodeAt(i + 2));
|
|
24157
24157
|
var hexValue = (charCode) => charCode <= 57 ? charCode - 48 : (charCode & 223) - 55;
|
|
24158
24158
|
var isBase64Char = (charCode) => charCode >= 65 && charCode <= 90 || // A-Z
|
|
24159
24159
|
charCode >= 97 && charCode <= 122 || // a-z
|
|
@@ -25469,7 +25469,7 @@ function mergeConfig(config1, config2) {
|
|
|
25469
25469
|
}
|
|
25470
25470
|
|
|
25471
25471
|
// node_modules/axios/lib/helpers/resolveConfig.js
|
|
25472
|
-
var encodeUTF8 = (
|
|
25472
|
+
var encodeUTF8 = (str6) => encodeURIComponent(str6).replace(
|
|
25473
25473
|
/%([0-9A-F]{2})/gi,
|
|
25474
25474
|
(_, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
25475
25475
|
);
|
|
@@ -25840,7 +25840,7 @@ var DEFAULT_REQUEST_OPTIONS = {
|
|
|
25840
25840
|
window: null
|
|
25841
25841
|
};
|
|
25842
25842
|
var { isFunction: isFunction2 } = utils_default;
|
|
25843
|
-
var encodeUTF82 = (
|
|
25843
|
+
var encodeUTF82 = (str6) => encodeURIComponent(str6).replace(
|
|
25844
25844
|
/%([0-9A-F]{2})/gi,
|
|
25845
25845
|
(_, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
25846
25846
|
);
|
|
@@ -25890,7 +25890,7 @@ var factory = (env) => {
|
|
|
25890
25890
|
return false;
|
|
25891
25891
|
}
|
|
25892
25892
|
const isReadableStreamSupported = isFetchSupported && isFunction2(ReadableStream2);
|
|
25893
|
-
const encodeText = isFetchSupported && (typeof TextEncoder2 === "function" ? /* @__PURE__ */ ((encoder2) => (
|
|
25893
|
+
const encodeText = isFetchSupported && (typeof TextEncoder2 === "function" ? /* @__PURE__ */ ((encoder2) => (str6) => encoder2.encode(str6))(new TextEncoder2()) : async (str6) => new Uint8Array(await new Request3(str6).arrayBuffer()));
|
|
25894
25894
|
const supportsRequestStream = isRequestSupported && isReadableStreamSupported && test(() => {
|
|
25895
25895
|
let duplexAccessed = false;
|
|
25896
25896
|
const request3 = new Request3(platform_default.origin, {
|
|
@@ -122259,10 +122259,10 @@ var number = (n) => {
|
|
|
122259
122259
|
}
|
|
122260
122260
|
return optimize(h);
|
|
122261
122261
|
};
|
|
122262
|
-
var string = (
|
|
122263
|
-
let h = 5381, i =
|
|
122262
|
+
var string = (str6) => {
|
|
122263
|
+
let h = 5381, i = str6.length;
|
|
122264
122264
|
while (i) {
|
|
122265
|
-
h = h * 33 ^
|
|
122265
|
+
h = h * 33 ^ str6.charCodeAt(--i);
|
|
122266
122266
|
}
|
|
122267
122267
|
return optimize(h);
|
|
122268
122268
|
};
|
|
@@ -124566,8 +124566,8 @@ var EncodingError = class extends (/* @__PURE__ */ TaggedError2("EncodingError")
|
|
|
124566
124566
|
[EncodingErrorTypeId] = EncodingErrorTypeId;
|
|
124567
124567
|
};
|
|
124568
124568
|
var encodeBase64 = (input) => typeof input === "string" ? base64EncodeUint8Array(encoder.encode(input)) : base64EncodeUint8Array(input);
|
|
124569
|
-
var decodeBase64 = (
|
|
124570
|
-
const stripped = stripCrlf(
|
|
124569
|
+
var decodeBase64 = (str6) => {
|
|
124570
|
+
const stripped = stripCrlf(str6);
|
|
124571
124571
|
const length2 = stripped.length;
|
|
124572
124572
|
if (length2 % 4 !== 0) {
|
|
124573
124573
|
return fail2(new EncodingError({
|
|
@@ -124605,10 +124605,10 @@ var decodeBase64 = (str5) => {
|
|
|
124605
124605
|
}));
|
|
124606
124606
|
}
|
|
124607
124607
|
};
|
|
124608
|
-
var decodeBase64String = (
|
|
124608
|
+
var decodeBase64String = (str6) => map2(decodeBase64(str6), (_) => decoder.decode(_));
|
|
124609
124609
|
var encodeBase64Url = (input) => typeof input === "string" ? base64UrlEncodeUint8Array(encoder.encode(input)) : base64UrlEncodeUint8Array(input);
|
|
124610
|
-
var decodeBase64Url = (
|
|
124611
|
-
const stripped = stripCrlf(
|
|
124610
|
+
var decodeBase64Url = (str6) => {
|
|
124611
|
+
const stripped = stripCrlf(str6);
|
|
124612
124612
|
const length2 = stripped.length;
|
|
124613
124613
|
if (length2 % 4 === 1) {
|
|
124614
124614
|
return fail2(new EncodingError({
|
|
@@ -124630,7 +124630,7 @@ var decodeBase64Url = (str5) => {
|
|
|
124630
124630
|
sanitized = sanitized.replace(/-/g, "+").replace(/_/g, "/");
|
|
124631
124631
|
return decodeBase64(sanitized);
|
|
124632
124632
|
};
|
|
124633
|
-
var decodeBase64UrlString = (
|
|
124633
|
+
var decodeBase64UrlString = (str6) => map2(decodeBase64Url(str6), (_) => decoder.decode(_));
|
|
124634
124634
|
var encodeHex = (input) => typeof input === "string" ? hexEncodeUint8Array(encoder.encode(input)) : hexEncodeUint8Array(input);
|
|
124635
124635
|
var randomHex = (length2) => {
|
|
124636
124636
|
let result3 = "";
|
|
@@ -124640,13 +124640,13 @@ var randomHex = (length2) => {
|
|
|
124640
124640
|
}
|
|
124641
124641
|
return result3;
|
|
124642
124642
|
};
|
|
124643
|
-
var decodeHex = (
|
|
124644
|
-
const bytes = new TextEncoder().encode(
|
|
124643
|
+
var decodeHex = (str6) => {
|
|
124644
|
+
const bytes = new TextEncoder().encode(str6);
|
|
124645
124645
|
if (bytes.length % 2 !== 0) {
|
|
124646
124646
|
return fail2(new EncodingError({
|
|
124647
124647
|
module: "Hex",
|
|
124648
124648
|
kind: "Decode",
|
|
124649
|
-
input:
|
|
124649
|
+
input: str6,
|
|
124650
124650
|
message: `Length must be a multiple of 2, but is ${bytes.length}`
|
|
124651
124651
|
}));
|
|
124652
124652
|
}
|
|
@@ -124663,15 +124663,15 @@ var decodeHex = (str5) => {
|
|
|
124663
124663
|
return fail2(new EncodingError({
|
|
124664
124664
|
module: "Hex",
|
|
124665
124665
|
kind: "Decode",
|
|
124666
|
-
input:
|
|
124666
|
+
input: str6,
|
|
124667
124667
|
message: e instanceof Error ? e.message : "Invalid input"
|
|
124668
124668
|
}));
|
|
124669
124669
|
}
|
|
124670
124670
|
};
|
|
124671
|
-
var decodeHexString = (
|
|
124671
|
+
var decodeHexString = (str6) => map2(decodeHex(str6), (_) => decoder.decode(_));
|
|
124672
124672
|
var encoder = /* @__PURE__ */ new TextEncoder();
|
|
124673
124673
|
var decoder = /* @__PURE__ */ new TextDecoder();
|
|
124674
|
-
var stripCrlf = (
|
|
124674
|
+
var stripCrlf = (str6) => str6.replace(/[\n\r]/g, "");
|
|
124675
124675
|
var base64EncodeUint8Array = (bytes) => {
|
|
124676
124676
|
const length2 = bytes.length;
|
|
124677
124677
|
let result3 = "";
|
|
@@ -128500,11 +128500,11 @@ var uncapitalize = (self2) => {
|
|
|
128500
128500
|
var trim2 = (self2) => self2.trim();
|
|
128501
128501
|
var snakeToCamel = (self2) => {
|
|
128502
128502
|
if (self2.length === 0) return self2;
|
|
128503
|
-
let
|
|
128503
|
+
let str6 = self2[0];
|
|
128504
128504
|
for (let i = 1; i < self2.length; i++) {
|
|
128505
|
-
|
|
128505
|
+
str6 += self2[i] === "_" ? self2[++i].toUpperCase() : self2[i];
|
|
128506
128506
|
}
|
|
128507
|
-
return
|
|
128507
|
+
return str6;
|
|
128508
128508
|
};
|
|
128509
128509
|
var camelToSnake = (self2) => self2.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
128510
128510
|
|
|
@@ -144016,6 +144016,14 @@ function resolveConfig2(raw, env = process.env, deps = {}) {
|
|
|
144016
144016
|
const recentDirsLimit = clamp4(asNumber(merged.recentDirsLimit, 5), 1, 20);
|
|
144017
144017
|
const recentModelsLimit = clamp4(asNumber(merged.recentModelsLimit, 5), 1, 20);
|
|
144018
144018
|
const sessionPageSize = clamp4(asNumber(merged.sessionPageSize, 8), 5, 20);
|
|
144019
|
+
const sessionAllowButton = asBoolean(merged.sessionAllowButton, true);
|
|
144020
|
+
const resumeSummary = asBoolean(merged.resumeSummary, true);
|
|
144021
|
+
const resumeSummaryTimeoutMs = clamp4(asNumber(merged.resumeSummaryTimeoutMs, 15e3), 3e3, 6e4);
|
|
144022
|
+
const resumeCompactTimeoutMs = clamp4(asNumber(merged.resumeCompactTimeoutMs, 12e4), 3e4, 3e5);
|
|
144023
|
+
const topicStatus = asBoolean(merged.topicStatus, true);
|
|
144024
|
+
const topicStatusInTitle = asBoolean(merged.topicStatusInTitle, false);
|
|
144025
|
+
const topicStatusThrottleMs = clamp4(asNumber(merged.topicStatusThrottleMs, 1e3), 500, 1e4);
|
|
144026
|
+
const cardMaxTables = clamp4(asNumber(merged.cardMaxTables, 4), 1, 5);
|
|
144019
144027
|
const domain = merged.domain === "lark" ? "lark" : "feishu";
|
|
144020
144028
|
const logFile = resolveLogFile(merged.logFile, env, deps);
|
|
144021
144029
|
const gatewayLocation = asString(merged.gatewayLocation).trim() || void 0;
|
|
@@ -144055,7 +144063,15 @@ function resolveConfig2(raw, env = process.env, deps = {}) {
|
|
|
144055
144063
|
allowedRoots,
|
|
144056
144064
|
recentDirsLimit,
|
|
144057
144065
|
recentModelsLimit,
|
|
144058
|
-
sessionPageSize
|
|
144066
|
+
sessionPageSize,
|
|
144067
|
+
sessionAllowButton,
|
|
144068
|
+
resumeSummary,
|
|
144069
|
+
resumeSummaryTimeoutMs,
|
|
144070
|
+
resumeCompactTimeoutMs,
|
|
144071
|
+
topicStatus,
|
|
144072
|
+
topicStatusInTitle,
|
|
144073
|
+
topicStatusThrottleMs,
|
|
144074
|
+
cardMaxTables
|
|
144059
144075
|
};
|
|
144060
144076
|
}
|
|
144061
144077
|
function loadConfigFile(env, deps, warnings) {
|
|
@@ -144433,6 +144449,37 @@ function verifyApproval(token, secret, options2 = {}) {
|
|
|
144433
144449
|
return { ok: true, claims };
|
|
144434
144450
|
}
|
|
144435
144451
|
var STOP_PURPOSE = "stop";
|
|
144452
|
+
var ALLOW_SESSION_PURPOSE = "allow_session";
|
|
144453
|
+
function signAllowSession(input, secret, options2 = {}) {
|
|
144454
|
+
const now3 = input.now ?? Date.now();
|
|
144455
|
+
const claims = {
|
|
144456
|
+
p: ALLOW_SESSION_PURPOSE,
|
|
144457
|
+
r: input.requestID,
|
|
144458
|
+
s: input.sessionID,
|
|
144459
|
+
a: input.action,
|
|
144460
|
+
e: now3 + input.ttlMs,
|
|
144461
|
+
n: options2.nonce ?? randomBytes(9).toString("hex")
|
|
144462
|
+
};
|
|
144463
|
+
const body = b64url(JSON.stringify(claims));
|
|
144464
|
+
return `${body}.${hmac(body, secret)}`;
|
|
144465
|
+
}
|
|
144466
|
+
function verifyAllowSession(token, secret, options2 = {}) {
|
|
144467
|
+
const opened = openSigned(token, secret);
|
|
144468
|
+
if (!opened.ok) return opened;
|
|
144469
|
+
const claims = opened.payload;
|
|
144470
|
+
if (claims?.p !== ALLOW_SESSION_PURPOSE || typeof claims?.r !== "string" || typeof claims?.s !== "string" || typeof claims?.a !== "string" || typeof claims?.e !== "number" || typeof claims?.n !== "string") {
|
|
144471
|
+
return { ok: false, reason: "bad-claims" };
|
|
144472
|
+
}
|
|
144473
|
+
const now3 = options2.now ?? Date.now();
|
|
144474
|
+
if (claims.e <= now3) return { ok: false, reason: "expired" };
|
|
144475
|
+
if (options2.expectSessionID && claims.s !== options2.expectSessionID) {
|
|
144476
|
+
return { ok: false, reason: "session-mismatch" };
|
|
144477
|
+
}
|
|
144478
|
+
if (options2.expectAction && claims.a !== options2.expectAction) {
|
|
144479
|
+
return { ok: false, reason: "action-mismatch" };
|
|
144480
|
+
}
|
|
144481
|
+
return { ok: true, claims };
|
|
144482
|
+
}
|
|
144436
144483
|
function signStop(input, secret, options2 = {}) {
|
|
144437
144484
|
const now3 = input.now ?? Date.now();
|
|
144438
144485
|
const claims = {
|
|
@@ -144705,6 +144752,155 @@ function safeArgs(args2) {
|
|
|
144705
144752
|
}).join(" ").slice(0, 500);
|
|
144706
144753
|
}
|
|
144707
144754
|
|
|
144755
|
+
// src/feishu/card-limits.ts
|
|
144756
|
+
var DEFAULT_CARD_MAX_TABLES = 4;
|
|
144757
|
+
var CARD_MAX_TABLES_MIN = 1;
|
|
144758
|
+
var CARD_MAX_TABLES_MAX = 5;
|
|
144759
|
+
var DEFAULT_CARD_MAX_ELEMENTS = 200;
|
|
144760
|
+
function clampMaxTables(value3) {
|
|
144761
|
+
const n = typeof value3 === "number" && Number.isFinite(value3) ? Math.floor(value3) : DEFAULT_CARD_MAX_TABLES;
|
|
144762
|
+
return Math.min(CARD_MAX_TABLES_MAX, Math.max(CARD_MAX_TABLES_MIN, n));
|
|
144763
|
+
}
|
|
144764
|
+
function createCardMarkdownBudget(max6 = DEFAULT_CARD_MAX_TABLES) {
|
|
144765
|
+
const clamped = clampMaxTables(max6);
|
|
144766
|
+
return { max: clamped, remaining: clamped, tables: 0, degraded: 0 };
|
|
144767
|
+
}
|
|
144768
|
+
function findMarkdownTables(text) {
|
|
144769
|
+
if (!text || !text.includes("|")) return [];
|
|
144770
|
+
const lines = text.split("\n");
|
|
144771
|
+
const fence = computeFenceMask(lines);
|
|
144772
|
+
const spans = [];
|
|
144773
|
+
let i = 0;
|
|
144774
|
+
while (i < lines.length) {
|
|
144775
|
+
const line = lines[i];
|
|
144776
|
+
if (fence[i] || !isSeparatorRow(line)) {
|
|
144777
|
+
i += 1;
|
|
144778
|
+
continue;
|
|
144779
|
+
}
|
|
144780
|
+
if (i === 0 || fence[i - 1]) {
|
|
144781
|
+
i += 1;
|
|
144782
|
+
continue;
|
|
144783
|
+
}
|
|
144784
|
+
const header = lines[i - 1];
|
|
144785
|
+
if (header.trim() === "" || !header.includes("|") || isSeparatorRow(header)) {
|
|
144786
|
+
i += 1;
|
|
144787
|
+
continue;
|
|
144788
|
+
}
|
|
144789
|
+
let end = i;
|
|
144790
|
+
let j = i + 1;
|
|
144791
|
+
while (j < lines.length && !fence[j]) {
|
|
144792
|
+
const body = lines[j];
|
|
144793
|
+
if (body.trim() === "" || !body.includes("|") || isSeparatorRow(body)) break;
|
|
144794
|
+
end = j;
|
|
144795
|
+
j += 1;
|
|
144796
|
+
}
|
|
144797
|
+
spans.push({ start: i - 1, end });
|
|
144798
|
+
i = end + 1;
|
|
144799
|
+
}
|
|
144800
|
+
return spans;
|
|
144801
|
+
}
|
|
144802
|
+
function degradeExtraTables(text, max6 = DEFAULT_CARD_MAX_TABLES) {
|
|
144803
|
+
const keep = Math.max(0, Math.floor(max6));
|
|
144804
|
+
const spans = findMarkdownTables(text);
|
|
144805
|
+
if (spans.length <= keep) return { text, degraded: 0 };
|
|
144806
|
+
const extras = spans.slice(keep);
|
|
144807
|
+
const starts = new Set(extras.map((s) => s.start));
|
|
144808
|
+
const ends = new Set(extras.map((s) => s.end));
|
|
144809
|
+
const fence = text.includes("```") ? "~~~" : "```";
|
|
144810
|
+
const lines = text.split("\n");
|
|
144811
|
+
const out = [];
|
|
144812
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
144813
|
+
if (starts.has(i)) out.push(fence);
|
|
144814
|
+
out.push(lines[i]);
|
|
144815
|
+
if (ends.has(i)) out.push(fence);
|
|
144816
|
+
}
|
|
144817
|
+
return { text: out.join("\n"), degraded: extras.length };
|
|
144818
|
+
}
|
|
144819
|
+
function toCardMarkdown(text, budget) {
|
|
144820
|
+
const spans = findMarkdownTables(text);
|
|
144821
|
+
if (spans.length === 0) return text;
|
|
144822
|
+
budget.tables += spans.length;
|
|
144823
|
+
const keep = Math.max(0, Math.min(spans.length, budget.remaining));
|
|
144824
|
+
budget.remaining -= keep;
|
|
144825
|
+
if (keep === spans.length) return text;
|
|
144826
|
+
budget.degraded += spans.length - keep;
|
|
144827
|
+
return degradeExtraTables(text, keep).text;
|
|
144828
|
+
}
|
|
144829
|
+
function enforceCardLimits(card, options2 = {}) {
|
|
144830
|
+
const maxTables = clampMaxTables(options2.maxTables);
|
|
144831
|
+
const maxElements = typeof options2.maxElements === "number" && Number.isFinite(options2.maxElements) ? Math.max(1, Math.floor(options2.maxElements)) : DEFAULT_CARD_MAX_ELEMENTS;
|
|
144832
|
+
const clone2 = deepClone(card);
|
|
144833
|
+
const budget = createCardMarkdownBudget(maxTables);
|
|
144834
|
+
visitMarkdown(clone2, (content) => toCardMarkdown(content, budget));
|
|
144835
|
+
let elements = countElements(clone2);
|
|
144836
|
+
let dropped = 0;
|
|
144837
|
+
if (elements > maxElements) {
|
|
144838
|
+
const body = clone2.body;
|
|
144839
|
+
if (body && Array.isArray(body.elements)) {
|
|
144840
|
+
while (elements > maxElements && body.elements.length > 1) {
|
|
144841
|
+
body.elements.shift();
|
|
144842
|
+
dropped += 1;
|
|
144843
|
+
elements = countElements(clone2);
|
|
144844
|
+
}
|
|
144845
|
+
}
|
|
144846
|
+
}
|
|
144847
|
+
return {
|
|
144848
|
+
card: clone2,
|
|
144849
|
+
report: { tables: budget.tables, degradedTables: budget.degraded, elements, droppedElements: dropped }
|
|
144850
|
+
};
|
|
144851
|
+
}
|
|
144852
|
+
function visitMarkdown(node, fn3) {
|
|
144853
|
+
if (!node || typeof node !== "object") return;
|
|
144854
|
+
if (Array.isArray(node)) {
|
|
144855
|
+
for (const item of node) visitMarkdown(item, fn3);
|
|
144856
|
+
return;
|
|
144857
|
+
}
|
|
144858
|
+
const rec = node;
|
|
144859
|
+
if (rec.tag === "markdown" && typeof rec.content === "string") {
|
|
144860
|
+
rec.content = fn3(rec.content);
|
|
144861
|
+
}
|
|
144862
|
+
for (const value3 of Object.values(rec)) visitMarkdown(value3, fn3);
|
|
144863
|
+
}
|
|
144864
|
+
function countElements(node) {
|
|
144865
|
+
if (!node || typeof node !== "object") return 0;
|
|
144866
|
+
if (Array.isArray(node)) {
|
|
144867
|
+
let total3 = 0;
|
|
144868
|
+
for (const item of node) total3 += countElements(item);
|
|
144869
|
+
return total3;
|
|
144870
|
+
}
|
|
144871
|
+
const rec = node;
|
|
144872
|
+
let total2 = typeof rec.tag === "string" ? 1 : 0;
|
|
144873
|
+
for (const value3 of Object.values(rec)) total2 += countElements(value3);
|
|
144874
|
+
return total2;
|
|
144875
|
+
}
|
|
144876
|
+
function computeFenceMask(lines) {
|
|
144877
|
+
const mask3 = [];
|
|
144878
|
+
let fenceChar;
|
|
144879
|
+
for (const line of lines) {
|
|
144880
|
+
const match8 = /^\s{0,3}(`{3,}|~{3,})/.exec(line);
|
|
144881
|
+
const marker = match8?.[1];
|
|
144882
|
+
const char = marker?.[0];
|
|
144883
|
+
if (char && (!fenceChar || fenceChar === char)) {
|
|
144884
|
+
fenceChar = fenceChar ? void 0 : char;
|
|
144885
|
+
mask3.push(true);
|
|
144886
|
+
continue;
|
|
144887
|
+
}
|
|
144888
|
+
mask3.push(fenceChar !== void 0);
|
|
144889
|
+
}
|
|
144890
|
+
return mask3;
|
|
144891
|
+
}
|
|
144892
|
+
function isSeparatorRow(line) {
|
|
144893
|
+
const trimmed = line.trim();
|
|
144894
|
+
if (!trimmed.includes("|")) return false;
|
|
144895
|
+
const inner = trimmed.replace(/^\|/, "").replace(/\|$/, "");
|
|
144896
|
+
const cells = inner.split("|").map((c) => c.trim());
|
|
144897
|
+
if (cells.length < 1) return false;
|
|
144898
|
+
return cells.every((c) => /^:?-+:?$/.test(c));
|
|
144899
|
+
}
|
|
144900
|
+
function deepClone(value3) {
|
|
144901
|
+
return JSON.parse(JSON.stringify(value3));
|
|
144902
|
+
}
|
|
144903
|
+
|
|
144708
144904
|
// src/feishu/sender.ts
|
|
144709
144905
|
function describeLarkError(err2) {
|
|
144710
144906
|
const base2 = errorMessage(err2);
|
|
@@ -144721,7 +144917,20 @@ function describeLarkError(err2) {
|
|
|
144721
144917
|
if (typeof data === "string" && data.length > 0) return `${base2} [${data.slice(0, 300)}]`;
|
|
144722
144918
|
return base2;
|
|
144723
144919
|
}
|
|
144724
|
-
function createFeishuSender(client, log2) {
|
|
144920
|
+
function createFeishuSender(client, log2, options2 = {}) {
|
|
144921
|
+
const guard = (card, tag2) => {
|
|
144922
|
+
const { card: guarded, report } = enforceCardLimits(card, { maxTables: options2.cardMaxTables });
|
|
144923
|
+
if (report.degradedTables > 0 || report.droppedElements > 0) {
|
|
144924
|
+
log2.warn("\u5361\u7247\u5185\u5BB9\u8D85\u9650\uFF0C\u5DF2\u964D\u7EA7\uFF08\u53D1\u9001\u5C42\u515C\u5E95\uFF09", {
|
|
144925
|
+
where: tag2,
|
|
144926
|
+
tables: report.tables,
|
|
144927
|
+
degradedTables: report.degradedTables,
|
|
144928
|
+
elements: report.elements,
|
|
144929
|
+
droppedElements: report.droppedElements
|
|
144930
|
+
});
|
|
144931
|
+
}
|
|
144932
|
+
return guarded;
|
|
144933
|
+
};
|
|
144725
144934
|
return {
|
|
144726
144935
|
async sendCard(chatId, card) {
|
|
144727
144936
|
if (!chatId) return { ok: false, error: "missing chatId" };
|
|
@@ -144731,7 +144940,7 @@ function createFeishuSender(client, log2) {
|
|
|
144731
144940
|
data: {
|
|
144732
144941
|
receive_id: chatId,
|
|
144733
144942
|
msg_type: "interactive",
|
|
144734
|
-
content: JSON.stringify(card)
|
|
144943
|
+
content: JSON.stringify(guard(card, "create"))
|
|
144735
144944
|
}
|
|
144736
144945
|
});
|
|
144737
144946
|
if (res?.code && res.code !== 0) {
|
|
@@ -144752,7 +144961,7 @@ function createFeishuSender(client, log2) {
|
|
|
144752
144961
|
path: { message_id: messageId },
|
|
144753
144962
|
data: {
|
|
144754
144963
|
msg_type: "interactive",
|
|
144755
|
-
content: JSON.stringify(card),
|
|
144964
|
+
content: JSON.stringify(guard(card, "reply")),
|
|
144756
144965
|
...opts?.replyInThread ? { reply_in_thread: true } : {}
|
|
144757
144966
|
}
|
|
144758
144967
|
});
|
|
@@ -144778,7 +144987,7 @@ function createFeishuSender(client, log2) {
|
|
|
144778
144987
|
try {
|
|
144779
144988
|
const res = await client.im.message.patch({
|
|
144780
144989
|
path: { message_id: messageId },
|
|
144781
|
-
data: { content: JSON.stringify(card) }
|
|
144990
|
+
data: { content: JSON.stringify(guard(card, "patch")) }
|
|
144782
144991
|
});
|
|
144783
144992
|
if (res?.code && res.code !== 0) {
|
|
144784
144993
|
log2.warn("\u66F4\u65B0\u5361\u7247\u5931\u8D25", { messageId, code: res.code, msg: res.msg });
|
|
@@ -145070,6 +145279,18 @@ var SessionMap = class {
|
|
|
145070
145279
|
async link(chatId, sessionID, openId) {
|
|
145071
145280
|
await this.addSession(chatId, sessionID, "", openId);
|
|
145072
145281
|
}
|
|
145282
|
+
/**
|
|
145283
|
+
* 写入 / 清除该会话的**话题根卡基础内容**(工作状态刷新用,见 `types.SessionRootCardBase`)。
|
|
145284
|
+
* 会话不存在返回 false(不凭空造卡)。
|
|
145285
|
+
*/
|
|
145286
|
+
async setRootCard(sessionID, base2) {
|
|
145287
|
+
return this.setSessionMeta(sessionID, { rootCard: base2 });
|
|
145288
|
+
}
|
|
145289
|
+
/** 读取该会话的话题根卡基础内容(无则 undefined,状态刷新将跳过)。 */
|
|
145290
|
+
async getRootCard(sessionID) {
|
|
145291
|
+
const link2 = await this.resolveBySession(sessionID);
|
|
145292
|
+
return link2?.rootCard;
|
|
145293
|
+
}
|
|
145073
145294
|
remember(sessionID, link2) {
|
|
145074
145295
|
this.sessionToChat.set(sessionID, link2);
|
|
145075
145296
|
}
|
|
@@ -145152,7 +145373,9 @@ function serializeSession(link2) {
|
|
|
145152
145373
|
...link2.perm ? { perm: link2.perm } : {},
|
|
145153
145374
|
...link2.gateMode ? { gateMode: link2.gateMode } : {},
|
|
145154
145375
|
...link2.dir ? { dir: link2.dir } : {},
|
|
145155
|
-
...link2.model ? { model: link2.model } : {}
|
|
145376
|
+
...link2.model ? { model: link2.model } : {},
|
|
145377
|
+
...link2.allowActions && link2.allowActions.length > 0 ? { allowActions: [...link2.allowActions] } : {},
|
|
145378
|
+
...link2.rootCard ? { rootCard: link2.rootCard } : {}
|
|
145156
145379
|
};
|
|
145157
145380
|
}
|
|
145158
145381
|
function parseSessionLink(value3) {
|
|
@@ -145165,6 +145388,8 @@ function parseSessionLink(value3) {
|
|
|
145165
145388
|
const gateMode = value3.gateMode === "off" || value3.gateMode === "gate" ? value3.gateMode : void 0;
|
|
145166
145389
|
const dir = str2(value3.dir);
|
|
145167
145390
|
const model = parseModelRef(value3.model);
|
|
145391
|
+
const allowActions = parseStringArray(value3.allowActions);
|
|
145392
|
+
const rootCard = parseRootCard(value3.rootCard);
|
|
145168
145393
|
return {
|
|
145169
145394
|
chatId,
|
|
145170
145395
|
openId,
|
|
@@ -145172,9 +145397,55 @@ function parseSessionLink(value3) {
|
|
|
145172
145397
|
...perm ? { perm } : {},
|
|
145173
145398
|
...gateMode ? { gateMode } : {},
|
|
145174
145399
|
...dir ? { dir } : {},
|
|
145175
|
-
...model ? { model } : {}
|
|
145400
|
+
...model ? { model } : {},
|
|
145401
|
+
...allowActions.length > 0 ? { allowActions } : {},
|
|
145402
|
+
...rootCard ? { rootCard } : {}
|
|
145176
145403
|
};
|
|
145177
145404
|
}
|
|
145405
|
+
function parseRootCard(value3) {
|
|
145406
|
+
if (!isRecord3(value3)) return void 0;
|
|
145407
|
+
const style = value3.style === "created" || value3.style === "resumed" ? value3.style : void 0;
|
|
145408
|
+
const sessionID = str2(value3.sessionID);
|
|
145409
|
+
if (!style || !sessionID) return void 0;
|
|
145410
|
+
const title = str2(value3.title);
|
|
145411
|
+
const dir = str2(value3.dir);
|
|
145412
|
+
const model = str2(value3.model);
|
|
145413
|
+
const perm = str2(value3.perm);
|
|
145414
|
+
const summary = str2(value3.summary);
|
|
145415
|
+
const summaryLabel = str2(value3.summaryLabel);
|
|
145416
|
+
const compactError = str2(value3.compactError);
|
|
145417
|
+
const note2 = str2(value3.note);
|
|
145418
|
+
const updatedAt = typeof value3.updatedAt === "number" && Number.isFinite(value3.updatedAt) ? value3.updatedAt : void 0;
|
|
145419
|
+
return {
|
|
145420
|
+
style,
|
|
145421
|
+
sessionID,
|
|
145422
|
+
title,
|
|
145423
|
+
...dir ? { dir } : {},
|
|
145424
|
+
...model ? { model } : {},
|
|
145425
|
+
...perm ? { perm } : {},
|
|
145426
|
+
...updatedAt ? { updatedAt } : {},
|
|
145427
|
+
...summary ? { summary } : {},
|
|
145428
|
+
...summaryLabel ? { summaryLabel } : {},
|
|
145429
|
+
...value3.summaryPending === true ? { summaryPending: true } : {},
|
|
145430
|
+
...value3.compactPending === true ? { compactPending: true } : {},
|
|
145431
|
+
...compactError ? { compactError } : {},
|
|
145432
|
+
...value3.compactButton === true ? { compactButton: true } : {},
|
|
145433
|
+
...note2 ? { note: note2 } : {}
|
|
145434
|
+
};
|
|
145435
|
+
}
|
|
145436
|
+
function parseStringArray(value3) {
|
|
145437
|
+
if (!Array.isArray(value3)) return [];
|
|
145438
|
+
const out = [];
|
|
145439
|
+
const seen = /* @__PURE__ */ new Set();
|
|
145440
|
+
for (const item of value3) {
|
|
145441
|
+
if (typeof item !== "string") continue;
|
|
145442
|
+
const trimmed = item.trim();
|
|
145443
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
145444
|
+
seen.add(trimmed);
|
|
145445
|
+
out.push(trimmed);
|
|
145446
|
+
}
|
|
145447
|
+
return out;
|
|
145448
|
+
}
|
|
145178
145449
|
function isPreset(value3) {
|
|
145179
145450
|
return value3 === "readonly" || value3 === "edit" || value3 === "askHigh" || value3 === "trust";
|
|
145180
145451
|
}
|
|
@@ -145501,6 +145772,20 @@ function buildApprovalCard(input) {
|
|
|
145501
145772
|
lines.push("\u2139\uFE0F \u672C\u8BF7\u6C42\u672A\u643A\u5E26\u4FDD\u5B58\u9879\uFF0C\u300C\u59CB\u7EC8\u5141\u8BB8\u300D\u7B49\u4EF7\u4E8E\u300C\u5141\u8BB8\u4E00\u6B21\u300D\u3002");
|
|
145502
145773
|
}
|
|
145503
145774
|
const alwaysLabel = input.canPersistAlways ? "\u{1F513} \u59CB\u7EC8\u5141\u8BB8" : "\u{1F513} \u59CB\u7EC8\u5141\u8BB8\uFF08\u540C\u4E00\u6B21\uFF09";
|
|
145775
|
+
const buttons = [
|
|
145776
|
+
button("\u2705 \u5141\u8BB8\u4E00\u6B21", "primary", { t: input.token, d: "once" }),
|
|
145777
|
+
button(alwaysLabel, "default", { t: input.token, d: "always" })
|
|
145778
|
+
];
|
|
145779
|
+
if (input.allowSessionToken) {
|
|
145780
|
+
buttons.push(
|
|
145781
|
+
button("\u2705 \u672C\u4F1A\u8BDD\u5185\u5141\u8BB8\u8BE5\u5DE5\u5177", "default", {
|
|
145782
|
+
cmd: "allow_session",
|
|
145783
|
+
a: input.action,
|
|
145784
|
+
t: input.allowSessionToken
|
|
145785
|
+
})
|
|
145786
|
+
);
|
|
145787
|
+
}
|
|
145788
|
+
buttons.push(button("\u274C \u62D2\u7EDD", "danger", { t: input.token, d: "reject" }));
|
|
145504
145789
|
return {
|
|
145505
145790
|
schema: "2.0",
|
|
145506
145791
|
config: { update_multi: true },
|
|
@@ -145511,9 +145796,35 @@ function buildApprovalCard(input) {
|
|
|
145511
145796
|
body: {
|
|
145512
145797
|
elements: [
|
|
145513
145798
|
{ tag: "markdown", content: truncateCardContent(lines.join("\n")) },
|
|
145514
|
-
|
|
145515
|
-
|
|
145516
|
-
|
|
145799
|
+
...buttons
|
|
145800
|
+
]
|
|
145801
|
+
}
|
|
145802
|
+
};
|
|
145803
|
+
}
|
|
145804
|
+
function buildSessionAllowResolvedCard(input, outcome) {
|
|
145805
|
+
const when3 = new Date(outcome.at).toISOString();
|
|
145806
|
+
return {
|
|
145807
|
+
schema: "2.0",
|
|
145808
|
+
config: { update_multi: true },
|
|
145809
|
+
header: {
|
|
145810
|
+
title: { tag: "plain_text", content: `\u2705 \u5DF2\u5141\u8BB8\u672C\u4F1A\u8BDD\u5185 ${outcome.action}` },
|
|
145811
|
+
template: "green"
|
|
145812
|
+
},
|
|
145813
|
+
body: {
|
|
145814
|
+
elements: [
|
|
145815
|
+
{
|
|
145816
|
+
tag: "markdown",
|
|
145817
|
+
content: truncateCardContent(
|
|
145818
|
+
[
|
|
145819
|
+
`**\u64CD\u4F5C**\uFF1A\`${escapeInline(input.action)}\``,
|
|
145820
|
+
"",
|
|
145821
|
+
"\u672C\u4F1A\u8BDD\u5185\u540E\u7EED\u8C03\u7528\u8BE5\u5DE5\u5177\u5C06**\u4E0D\u518D\u8BE2\u95EE**\uFF08\u5176\u5B83\u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\uFF09\u3002",
|
|
145822
|
+
"",
|
|
145823
|
+
`**\u5904\u7406\u4EBA**\uFF1A\`${escapeInline(mask2(outcome.operatorOpenId))}\``,
|
|
145824
|
+
`**\u65F6\u95F4**\uFF1A${when3}`
|
|
145825
|
+
].join("\n")
|
|
145826
|
+
)
|
|
145827
|
+
}
|
|
145517
145828
|
]
|
|
145518
145829
|
}
|
|
145519
145830
|
};
|
|
@@ -145620,7 +145931,7 @@ var HEADER_SUMMARY_MAX = 80;
|
|
|
145620
145931
|
var TOOL_INPUT_MAX = 600;
|
|
145621
145932
|
var OUTPUT_FIRST_LINE_MAX = 200;
|
|
145622
145933
|
var TEXT_ELEMENT_MAX = 8 * 1024;
|
|
145623
|
-
function renderRunCard(state, stopValue) {
|
|
145934
|
+
function renderRunCard(state, stopValue, options2 = {}) {
|
|
145624
145935
|
const elements = [];
|
|
145625
145936
|
for (const group of groupBlocks(state.blocks)) {
|
|
145626
145937
|
if (group.kind === "text") {
|
|
@@ -145655,7 +145966,11 @@ function renderRunCard(state, stopValue) {
|
|
|
145655
145966
|
},
|
|
145656
145967
|
body: { elements }
|
|
145657
145968
|
};
|
|
145658
|
-
|
|
145969
|
+
const { card: guarded, report } = enforceCardLimits(card, { maxTables: options2.maxTables });
|
|
145970
|
+
if (options2.onLimit && (report.degradedTables > 0 || report.droppedElements > 0)) {
|
|
145971
|
+
options2.onLimit(report);
|
|
145972
|
+
}
|
|
145973
|
+
return enforceSize(guarded);
|
|
145659
145974
|
}
|
|
145660
145975
|
function groupBlocks(blocks) {
|
|
145661
145976
|
const groups = [];
|
|
@@ -145858,7 +146173,18 @@ function createRunController(deps) {
|
|
|
145858
146173
|
}
|
|
145859
146174
|
return runs;
|
|
145860
146175
|
};
|
|
145861
|
-
const renderCard = (sessionID, state) => renderRunCard(state, deps.buildStopValue?.(sessionID)
|
|
146176
|
+
const renderCard = (sessionID, state) => renderRunCard(state, deps.buildStopValue?.(sessionID), {
|
|
146177
|
+
maxTables: deps.cardMaxTables,
|
|
146178
|
+
onLimit: (report) => {
|
|
146179
|
+
deps.log.warn("\u8FD0\u884C\u5361\u5185\u5BB9\u8D85\u9650\uFF0C\u5DF2\u964D\u7EA7", {
|
|
146180
|
+
sessionID,
|
|
146181
|
+
tables: report.tables,
|
|
146182
|
+
degradedTables: report.degradedTables,
|
|
146183
|
+
elements: report.elements,
|
|
146184
|
+
droppedElements: report.droppedElements
|
|
146185
|
+
});
|
|
146186
|
+
}
|
|
146187
|
+
});
|
|
145862
146188
|
const patch = async (card) => {
|
|
145863
146189
|
if (disposed) return;
|
|
145864
146190
|
const res = await deps.sender.patchCard(card.messageId, renderCard(card.sessionID, card.state));
|
|
@@ -146280,8 +146606,8 @@ function buildFormCard(form, answers, opts = {}) {
|
|
|
146280
146606
|
});
|
|
146281
146607
|
const hints = [];
|
|
146282
146608
|
if (opts.notice) hints.push(opts.notice);
|
|
146283
|
-
if (missing2.length > 0 && visible.length > 1) hints.push(`\u8FD8\u9700\u56DE\u7B54\uFF1A${missing2.join("\u3001")}`);
|
|
146284
|
-
else if (missing2.length > 0) hints.push("\
|
|
146609
|
+
if (missing2.length > 0 && visible.length > 1) hints.push(`\u8FD8\u9700\u56DE\u7B54\uFF1A${missing2.join("\u3001")}\uFF08\u53EF\u76F4\u63A5\u53D1\u6587\u5B57\u56DE\u7B54\uFF09`);
|
|
146610
|
+
else if (missing2.length > 0) hints.push("\u53EF\u76F4\u63A5\u53D1\u6587\u5B57\u56DE\u7B54\uFF0C\u6216\u70B9\u4E0A\u65B9\u9009\u9879\u3002");
|
|
146285
146611
|
if (hints.length > 0) elements.push({ tag: "markdown", content: truncateCardContent(hints.join("\n\n")) });
|
|
146286
146612
|
const header = headerFor(form);
|
|
146287
146613
|
return {
|
|
@@ -146345,20 +146671,29 @@ var FormRelay = class {
|
|
|
146345
146671
|
this.deps.log.warn("\u8868\u5355\u5361\u53D1\u9001\u5931\u8D25", { formID: form.id, error: res.error ?? "unknown" });
|
|
146346
146672
|
return;
|
|
146347
146673
|
}
|
|
146348
|
-
|
|
146674
|
+
const firstVisible = form.fields.find((f) => f.hidden !== true);
|
|
146675
|
+
const pending = {
|
|
146349
146676
|
form,
|
|
146350
146677
|
sessionID: form.sessionID,
|
|
146351
146678
|
chatId: link2.chatId,
|
|
146352
146679
|
messageId: res.messageId,
|
|
146353
146680
|
...link2.dir ? { directory: link2.dir } : {},
|
|
146354
146681
|
answers: {},
|
|
146355
|
-
settled: false
|
|
146356
|
-
|
|
146682
|
+
settled: false,
|
|
146683
|
+
// 自动进入「等待文字回答」状态:用户直接发文字即可作为答案,
|
|
146684
|
+
// 无需先点「直接回复答案」按钮。第一个可见字段作为默认答案字段。
|
|
146685
|
+
...firstVisible ? { awaitingField: firstVisible.key } : {}
|
|
146686
|
+
};
|
|
146687
|
+
this.forms.set(form.id, pending);
|
|
146688
|
+
if (firstVisible) {
|
|
146689
|
+
this.awaiting.set(form.sessionID, form.id);
|
|
146690
|
+
}
|
|
146357
146691
|
this.deps.log.info("\u8868\u5355\u5361\u5DF2\u53D1\u9001", {
|
|
146358
146692
|
formID: form.id,
|
|
146359
146693
|
sessionID: form.sessionID,
|
|
146360
146694
|
fieldCount: form.fields.length,
|
|
146361
|
-
isQuestion: form.metadata?.kind === "question"
|
|
146695
|
+
isQuestion: form.metadata?.kind === "question",
|
|
146696
|
+
awaitingField: firstVisible?.key
|
|
146362
146697
|
});
|
|
146363
146698
|
}
|
|
146364
146699
|
/**
|
|
@@ -146388,8 +146723,13 @@ var FormRelay = class {
|
|
|
146388
146723
|
if (parsed.v === void 0) return TOAST("error", "\u65E0\u6CD5\u8BC6\u522B\u7684\u64CD\u4F5C");
|
|
146389
146724
|
const value3 = field?.type === "multiselect" && !Array.isArray(parsed.v) ? [String(parsed.v)] : parsed.v;
|
|
146390
146725
|
pending.answers[parsed.k] = value3;
|
|
146391
|
-
pending.
|
|
146392
|
-
|
|
146726
|
+
const nextField = pending.form.fields.find((f) => f.hidden !== true && pending.answers[f.key] === void 0);
|
|
146727
|
+
pending.awaitingField = nextField?.key;
|
|
146728
|
+
if (pending.awaitingField) {
|
|
146729
|
+
this.awaiting.set(pending.sessionID, pending.form.id);
|
|
146730
|
+
} else {
|
|
146731
|
+
this.awaiting.delete(pending.sessionID);
|
|
146732
|
+
}
|
|
146393
146733
|
if (isComplete(pending.form, pending.answers)) {
|
|
146394
146734
|
pending.settled = true;
|
|
146395
146735
|
void this.submit(pending);
|
|
@@ -146685,11 +147025,616 @@ function topicTitle(text, max6 = 20) {
|
|
|
146685
147025
|
|
|
146686
147026
|
// src/feishu/routing.ts
|
|
146687
147027
|
function decideRoute(facts) {
|
|
146688
|
-
if (!facts.hasThread) return { kind: "main-hint" };
|
|
146689
147028
|
if (facts.threadKnown) return { kind: "use-session", source: "thread" };
|
|
146690
147029
|
if (facts.rootKnown) return { kind: "use-session", source: "root" };
|
|
147030
|
+
if (!facts.hasThread) return { kind: "main-hint" };
|
|
146691
147031
|
return { kind: "create-in-thread" };
|
|
146692
147032
|
}
|
|
147033
|
+
|
|
147034
|
+
// src/feishu/session-list.ts
|
|
147035
|
+
function normalizeSessionList(raw) {
|
|
147036
|
+
const array3 = extractArray(raw);
|
|
147037
|
+
if (!array3) return void 0;
|
|
147038
|
+
const out = [];
|
|
147039
|
+
const seen = /* @__PURE__ */ new Set();
|
|
147040
|
+
for (const item of array3) {
|
|
147041
|
+
const entry = normalizeSessionInfo(item);
|
|
147042
|
+
if (!entry || seen.has(entry.sessionID)) continue;
|
|
147043
|
+
seen.add(entry.sessionID);
|
|
147044
|
+
out.push(entry);
|
|
147045
|
+
}
|
|
147046
|
+
return sortByUpdatedDesc(out);
|
|
147047
|
+
}
|
|
147048
|
+
function normalizeSessionInfo(raw) {
|
|
147049
|
+
if (!isRecord5(raw)) return void 0;
|
|
147050
|
+
const sessionID = str3(raw.id) || str3(raw.sessionID);
|
|
147051
|
+
if (!sessionID) return void 0;
|
|
147052
|
+
const title = str3(raw.title) || str3(raw.slug);
|
|
147053
|
+
const updatedAt = extractUpdatedAt(raw);
|
|
147054
|
+
const directory = extractDirectory(raw);
|
|
147055
|
+
return {
|
|
147056
|
+
sessionID,
|
|
147057
|
+
title,
|
|
147058
|
+
updatedAt,
|
|
147059
|
+
...directory ? { directory } : {}
|
|
147060
|
+
};
|
|
147061
|
+
}
|
|
147062
|
+
function extractSessionTitle(raw) {
|
|
147063
|
+
const title = normalizeSessionInfo(raw)?.title.trim();
|
|
147064
|
+
return title ? title : void 0;
|
|
147065
|
+
}
|
|
147066
|
+
function extractSessionPermissions(raw) {
|
|
147067
|
+
if (!isRecord5(raw) || !Array.isArray(raw.permissions)) return void 0;
|
|
147068
|
+
const out = [];
|
|
147069
|
+
for (const item of raw.permissions) {
|
|
147070
|
+
if (!isRecord5(item)) continue;
|
|
147071
|
+
const action = str3(item.action);
|
|
147072
|
+
const resource = str3(item.resource);
|
|
147073
|
+
const effect2 = item.effect;
|
|
147074
|
+
if (!action || !resource) continue;
|
|
147075
|
+
if (effect2 !== "allow" && effect2 !== "ask" && effect2 !== "deny") continue;
|
|
147076
|
+
out.push({ action, resource, effect: effect2 });
|
|
147077
|
+
}
|
|
147078
|
+
return out;
|
|
147079
|
+
}
|
|
147080
|
+
function toMillis2(value3) {
|
|
147081
|
+
if (typeof value3 === "number") {
|
|
147082
|
+
return Number.isFinite(value3) && value3 > 0 ? value3 : 0;
|
|
147083
|
+
}
|
|
147084
|
+
if (typeof value3 === "string") {
|
|
147085
|
+
const trimmed = value3.trim();
|
|
147086
|
+
if (!trimmed) return 0;
|
|
147087
|
+
if (/^\d+$/.test(trimmed)) {
|
|
147088
|
+
const parsed2 = Number.parseInt(trimmed, 10);
|
|
147089
|
+
return Number.isFinite(parsed2) && parsed2 > 0 ? parsed2 : 0;
|
|
147090
|
+
}
|
|
147091
|
+
const parsed = Date.parse(trimmed);
|
|
147092
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
147093
|
+
}
|
|
147094
|
+
if (value3 instanceof Date) {
|
|
147095
|
+
const ms = value3.getTime();
|
|
147096
|
+
return Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
147097
|
+
}
|
|
147098
|
+
if (isRecord5(value3)) {
|
|
147099
|
+
for (const key of ["epochMillis", "epochMilliseconds", "millis", "value"]) {
|
|
147100
|
+
const ms = toMillis2(value3[key]);
|
|
147101
|
+
if (ms > 0) return ms;
|
|
147102
|
+
}
|
|
147103
|
+
}
|
|
147104
|
+
return 0;
|
|
147105
|
+
}
|
|
147106
|
+
function sortByUpdatedDesc(entries3) {
|
|
147107
|
+
return [...entries3].sort(
|
|
147108
|
+
(a, b) => b.updatedAt - a.updatedAt || a.sessionID.localeCompare(b.sessionID)
|
|
147109
|
+
);
|
|
147110
|
+
}
|
|
147111
|
+
function fallbackEntries(entries3) {
|
|
147112
|
+
return sortByUpdatedDesc(
|
|
147113
|
+
entries3.map((entry) => ({
|
|
147114
|
+
sessionID: entry.sessionID,
|
|
147115
|
+
title: entry.title,
|
|
147116
|
+
updatedAt: Number.isFinite(entry.updatedAt) && entry.updatedAt > 0 ? entry.updatedAt : 0
|
|
147117
|
+
}))
|
|
147118
|
+
);
|
|
147119
|
+
}
|
|
147120
|
+
function relativeTime(fromMs, nowMs) {
|
|
147121
|
+
if (!Number.isFinite(fromMs) || fromMs <= 0) return "\u65F6\u95F4\u672A\u77E5";
|
|
147122
|
+
const diff = nowMs - fromMs;
|
|
147123
|
+
if (diff < 6e4) return "\u521A\u521A";
|
|
147124
|
+
const minutes2 = Math.floor(diff / 6e4);
|
|
147125
|
+
if (minutes2 < 60) return `${minutes2} \u5206\u949F\u524D`;
|
|
147126
|
+
const hours2 = Math.floor(minutes2 / 60);
|
|
147127
|
+
if (hours2 < 24) return `${hours2} \u5C0F\u65F6\u524D`;
|
|
147128
|
+
const days2 = Math.floor(hours2 / 24);
|
|
147129
|
+
if (days2 < 30) return `${days2} \u5929\u524D`;
|
|
147130
|
+
const date = new Date(fromMs);
|
|
147131
|
+
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
147132
|
+
}
|
|
147133
|
+
function directoryTail(dir) {
|
|
147134
|
+
const trimmed = dir.trim().replace(/\/+$/, "");
|
|
147135
|
+
if (!trimmed) return "";
|
|
147136
|
+
const parts = trimmed.split("/");
|
|
147137
|
+
return parts[parts.length - 1] || trimmed;
|
|
147138
|
+
}
|
|
147139
|
+
function extractArray(raw) {
|
|
147140
|
+
if (Array.isArray(raw)) return raw;
|
|
147141
|
+
if (isRecord5(raw)) {
|
|
147142
|
+
for (const key of ["data", "sessions", "items"]) {
|
|
147143
|
+
if (Array.isArray(raw[key])) return raw[key];
|
|
147144
|
+
}
|
|
147145
|
+
}
|
|
147146
|
+
return void 0;
|
|
147147
|
+
}
|
|
147148
|
+
function extractUpdatedAt(raw) {
|
|
147149
|
+
const time = isRecord5(raw.time) ? raw.time : void 0;
|
|
147150
|
+
const candidates = [
|
|
147151
|
+
time?.updated,
|
|
147152
|
+
raw.updatedAt,
|
|
147153
|
+
raw.updated,
|
|
147154
|
+
time?.created,
|
|
147155
|
+
raw.createdAt,
|
|
147156
|
+
raw.created
|
|
147157
|
+
];
|
|
147158
|
+
for (const candidate of candidates) {
|
|
147159
|
+
const ms = toMillis2(candidate);
|
|
147160
|
+
if (ms > 0) return ms;
|
|
147161
|
+
}
|
|
147162
|
+
return 0;
|
|
147163
|
+
}
|
|
147164
|
+
function extractDirectory(raw) {
|
|
147165
|
+
if (isRecord5(raw.location)) {
|
|
147166
|
+
const directory = str3(raw.location.directory);
|
|
147167
|
+
if (directory) return directory;
|
|
147168
|
+
}
|
|
147169
|
+
return str3(raw.directory) || (typeof raw.location === "string" ? raw.location : "");
|
|
147170
|
+
}
|
|
147171
|
+
function pad2(value3) {
|
|
147172
|
+
return value3 < 10 ? `0${value3}` : String(value3);
|
|
147173
|
+
}
|
|
147174
|
+
function isRecord5(value3) {
|
|
147175
|
+
return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
147176
|
+
}
|
|
147177
|
+
function str3(value3) {
|
|
147178
|
+
return typeof value3 === "string" ? value3 : "";
|
|
147179
|
+
}
|
|
147180
|
+
|
|
147181
|
+
// src/session/topic-status.ts
|
|
147182
|
+
var STATUS_META = {
|
|
147183
|
+
review: { emoji: "\u{1F7E1}", color: "orange", label: "\u5F85\u5BA1\u6838" },
|
|
147184
|
+
running: { emoji: "\u{1F9E0}", color: "blue", label: "\u8FD0\u884C\u4E2D" },
|
|
147185
|
+
pending: { emoji: "\u23F3", color: "grey", label: "\u5F85\u56DE\u590D" },
|
|
147186
|
+
failed: { emoji: "\u{1F534}", color: "red", label: "\u5931\u8D25" },
|
|
147187
|
+
interrupted: { emoji: "\u23F9", color: "grey", label: "\u5DF2\u4E2D\u65AD" },
|
|
147188
|
+
done: { emoji: "\u2705", color: "green", label: "\u5B8C\u6210" }
|
|
147189
|
+
};
|
|
147190
|
+
function topicStatusMeta(kind) {
|
|
147191
|
+
return STATUS_META[kind];
|
|
147192
|
+
}
|
|
147193
|
+
function computeTopicStatus(input) {
|
|
147194
|
+
if (input.permissionPending > 0) {
|
|
147195
|
+
return { kind: "review", ...input.reviewAction ? { reviewAction: input.reviewAction } : {} };
|
|
147196
|
+
}
|
|
147197
|
+
if (input.running) return { kind: "running" };
|
|
147198
|
+
if (input.queued > 0) return { kind: "pending", queued: input.queued };
|
|
147199
|
+
if (input.terminal === "failed") return { kind: "failed" };
|
|
147200
|
+
if (input.terminal === "interrupted") return { kind: "interrupted" };
|
|
147201
|
+
return { kind: "done" };
|
|
147202
|
+
}
|
|
147203
|
+
function formatClock(now3) {
|
|
147204
|
+
const d = new Date(now3);
|
|
147205
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
147206
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
147207
|
+
return `${hh}:${mm}`;
|
|
147208
|
+
}
|
|
147209
|
+
function topicStatusFooter(view, now3) {
|
|
147210
|
+
switch (view.kind) {
|
|
147211
|
+
case "review":
|
|
147212
|
+
return view.reviewAction ? `\u{1F7E1} \u5F85\u5BA1\u6838\uFF1A${view.reviewAction}` : "\u{1F7E1} \u5F85\u5BA1\u6838";
|
|
147213
|
+
case "running":
|
|
147214
|
+
return `\u{1F9E0} \u8FD0\u884C\u4E2D \xB7 ${formatClock(now3)}`;
|
|
147215
|
+
case "pending":
|
|
147216
|
+
return `\u23F3 \u5F85\u56DE\u590D\uFF08\u6392\u961F ${view.queued ?? 0}\uFF09`;
|
|
147217
|
+
case "failed":
|
|
147218
|
+
return "\u{1F534} \u5931\u8D25";
|
|
147219
|
+
case "interrupted":
|
|
147220
|
+
return "\u23F9 \u5DF2\u4E2D\u65AD";
|
|
147221
|
+
case "done":
|
|
147222
|
+
return "\u2705 \u5B8C\u6210";
|
|
147223
|
+
}
|
|
147224
|
+
}
|
|
147225
|
+
function topicStatusTitle(title, view, statusInTitle) {
|
|
147226
|
+
return `${topicStatusMeta(view.kind).emoji} ${title}`;
|
|
147227
|
+
}
|
|
147228
|
+
function newSessionStatusInput() {
|
|
147229
|
+
return { running: false, permissions: /* @__PURE__ */ new Set(), queued: /* @__PURE__ */ new Set() };
|
|
147230
|
+
}
|
|
147231
|
+
var HANDLED_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
147232
|
+
"session.execution.started",
|
|
147233
|
+
"session.execution.succeeded",
|
|
147234
|
+
"session.execution.failed",
|
|
147235
|
+
"session.execution.interrupted",
|
|
147236
|
+
"session.status",
|
|
147237
|
+
"session.idle",
|
|
147238
|
+
"permission.asked",
|
|
147239
|
+
"permission.replied",
|
|
147240
|
+
"session.inbox.enqueued",
|
|
147241
|
+
"session.inbox.delivered",
|
|
147242
|
+
"session.inbox.cancelled"
|
|
147243
|
+
]);
|
|
147244
|
+
var TopicStatusMachine = class {
|
|
147245
|
+
sessions = /* @__PURE__ */ new Map();
|
|
147246
|
+
lastKind = /* @__PURE__ */ new Map();
|
|
147247
|
+
permissionSeq = 0;
|
|
147248
|
+
/** 当前档位视图(未跟踪过的会话返回 undefined)。 */
|
|
147249
|
+
view(sessionID) {
|
|
147250
|
+
const input = this.sessions.get(sessionID);
|
|
147251
|
+
if (!input) return void 0;
|
|
147252
|
+
return this.computeView(input);
|
|
147253
|
+
}
|
|
147254
|
+
/** 消费一条事件;未识别/无会话 id 返回 undefined。 */
|
|
147255
|
+
reduce(sessionID, event) {
|
|
147256
|
+
if (!sessionID) return void 0;
|
|
147257
|
+
if (!HANDLED_EVENT_TYPES.has(event.type)) return void 0;
|
|
147258
|
+
const input = this.input(sessionID);
|
|
147259
|
+
const data = event.data ?? {};
|
|
147260
|
+
switch (event.type) {
|
|
147261
|
+
case "session.execution.started":
|
|
147262
|
+
input.running = true;
|
|
147263
|
+
input.terminal = void 0;
|
|
147264
|
+
break;
|
|
147265
|
+
case "session.execution.succeeded":
|
|
147266
|
+
input.running = false;
|
|
147267
|
+
input.terminal = "done";
|
|
147268
|
+
break;
|
|
147269
|
+
case "session.execution.failed":
|
|
147270
|
+
input.running = false;
|
|
147271
|
+
input.terminal = "failed";
|
|
147272
|
+
break;
|
|
147273
|
+
case "session.execution.interrupted":
|
|
147274
|
+
input.running = false;
|
|
147275
|
+
input.terminal = "interrupted";
|
|
147276
|
+
break;
|
|
147277
|
+
case "session.status": {
|
|
147278
|
+
const statusType = data.status?.type;
|
|
147279
|
+
if (statusType === "idle") {
|
|
147280
|
+
input.running = false;
|
|
147281
|
+
input.terminal = "done";
|
|
147282
|
+
} else if (statusType === "busy" || statusType === "retry") {
|
|
147283
|
+
input.running = true;
|
|
147284
|
+
input.terminal = void 0;
|
|
147285
|
+
} else {
|
|
147286
|
+
return void 0;
|
|
147287
|
+
}
|
|
147288
|
+
break;
|
|
147289
|
+
}
|
|
147290
|
+
case "session.idle":
|
|
147291
|
+
input.running = false;
|
|
147292
|
+
input.terminal = "done";
|
|
147293
|
+
break;
|
|
147294
|
+
case "permission.asked": {
|
|
147295
|
+
const id2 = str4(data.id) || `p${this.permissionSeq += 1}`;
|
|
147296
|
+
input.permissions.add(id2);
|
|
147297
|
+
const action = str4(data.action);
|
|
147298
|
+
if (action) input.reviewAction = action;
|
|
147299
|
+
break;
|
|
147300
|
+
}
|
|
147301
|
+
case "permission.replied": {
|
|
147302
|
+
const requestID = str4(data.requestID);
|
|
147303
|
+
if (requestID) input.permissions.delete(requestID);
|
|
147304
|
+
break;
|
|
147305
|
+
}
|
|
147306
|
+
case "session.inbox.enqueued": {
|
|
147307
|
+
const inboxID = str4(data.inboxID) || str4(data.item?.id);
|
|
147308
|
+
if (inboxID) input.queued.add(inboxID);
|
|
147309
|
+
break;
|
|
147310
|
+
}
|
|
147311
|
+
case "session.inbox.delivered":
|
|
147312
|
+
case "session.inbox.cancelled": {
|
|
147313
|
+
const inboxID = str4(data.inboxID);
|
|
147314
|
+
if (inboxID) input.queued.delete(inboxID);
|
|
147315
|
+
break;
|
|
147316
|
+
}
|
|
147317
|
+
default:
|
|
147318
|
+
return void 0;
|
|
147319
|
+
}
|
|
147320
|
+
return this.record(sessionID, input);
|
|
147321
|
+
}
|
|
147322
|
+
/** 运行卡终态等**非事件流**信号的显式入口(如 prompt 发送失败)。 */
|
|
147323
|
+
markTerminal(sessionID, kind) {
|
|
147324
|
+
if (!sessionID) return void 0;
|
|
147325
|
+
const input = this.input(sessionID);
|
|
147326
|
+
input.running = false;
|
|
147327
|
+
input.terminal = kind;
|
|
147328
|
+
return this.record(sessionID, input);
|
|
147329
|
+
}
|
|
147330
|
+
/** 清理某会话状态(卸载 / 测试用)。 */
|
|
147331
|
+
forget(sessionID) {
|
|
147332
|
+
this.sessions.delete(sessionID);
|
|
147333
|
+
this.lastKind.delete(sessionID);
|
|
147334
|
+
}
|
|
147335
|
+
clear() {
|
|
147336
|
+
this.sessions.clear();
|
|
147337
|
+
this.lastKind.clear();
|
|
147338
|
+
}
|
|
147339
|
+
input(sessionID) {
|
|
147340
|
+
let input = this.sessions.get(sessionID);
|
|
147341
|
+
if (!input) {
|
|
147342
|
+
input = newSessionStatusInput();
|
|
147343
|
+
this.sessions.set(sessionID, input);
|
|
147344
|
+
}
|
|
147345
|
+
return input;
|
|
147346
|
+
}
|
|
147347
|
+
computeView(input) {
|
|
147348
|
+
return computeTopicStatus({
|
|
147349
|
+
running: input.running,
|
|
147350
|
+
permissionPending: input.permissions.size,
|
|
147351
|
+
queued: input.queued.size,
|
|
147352
|
+
...input.terminal ? { terminal: input.terminal } : {},
|
|
147353
|
+
...input.reviewAction ? { reviewAction: input.reviewAction } : {}
|
|
147354
|
+
});
|
|
147355
|
+
}
|
|
147356
|
+
record(sessionID, input) {
|
|
147357
|
+
const view = this.computeView(input);
|
|
147358
|
+
const changed = this.lastKind.get(sessionID) !== view.kind;
|
|
147359
|
+
this.lastKind.set(sessionID, view.kind);
|
|
147360
|
+
return { view, changed };
|
|
147361
|
+
}
|
|
147362
|
+
};
|
|
147363
|
+
function str4(value3) {
|
|
147364
|
+
return typeof value3 === "string" ? value3 : "";
|
|
147365
|
+
}
|
|
147366
|
+
|
|
147367
|
+
// src/feishu/session-cards.ts
|
|
147368
|
+
function button2(text, type, value3) {
|
|
147369
|
+
return {
|
|
147370
|
+
tag: "button",
|
|
147371
|
+
text: { tag: "plain_text", content: text },
|
|
147372
|
+
type,
|
|
147373
|
+
behaviors: [{ type: "callback", value: value3 }]
|
|
147374
|
+
};
|
|
147375
|
+
}
|
|
147376
|
+
function sessionRowLine(row, now3) {
|
|
147377
|
+
const title = truncateTitle(row.title.trim() || "(\u672A\u547D\u540D)");
|
|
147378
|
+
const marks = [relativeTime(row.updatedAt, now3)];
|
|
147379
|
+
if (row.bound) marks.push("\u{1F4AC} \u5DF2\u7ED1\u8BDD\u9898");
|
|
147380
|
+
if (row.directory) marks.push(`\u{1F4CD} ${directoryTail(row.directory)}`);
|
|
147381
|
+
if (row.active) marks.push("\u2190 \u5F53\u524D");
|
|
147382
|
+
return `${row.index}. ${title}\uFF08\`${shortSessionId(row.sessionID)}\`\uFF09\xB7 ${marks.join(" \xB7 ")}`;
|
|
147383
|
+
}
|
|
147384
|
+
function buildSessionListCard(input) {
|
|
147385
|
+
const now3 = input.now ?? Date.now();
|
|
147386
|
+
const elements = [];
|
|
147387
|
+
if (input.rows.length === 0) {
|
|
147388
|
+
elements.push({
|
|
147389
|
+
tag: "markdown",
|
|
147390
|
+
content: truncateCardContent(
|
|
147391
|
+
"\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u3002\u70B9\u4E0B\u65B9\u300C\u2795 \u65B0\u5EFA\u4F1A\u8BDD\u300D\u521B\u5EFA\uFF0C\u6216\u76F4\u63A5\u5728\u8BDD\u9898\u91CC\u53D1\u6D88\u606F\u81EA\u52A8\u521B\u5EFA\u3002"
|
|
147392
|
+
)
|
|
147393
|
+
});
|
|
147394
|
+
} else {
|
|
147395
|
+
input.rows.forEach((row, i) => {
|
|
147396
|
+
if (i > 0) elements.push({ tag: "hr", margin: "2px 0px 2px 0px" });
|
|
147397
|
+
elements.push({
|
|
147398
|
+
tag: "column_set",
|
|
147399
|
+
flex_mode: "none",
|
|
147400
|
+
horizontal_spacing: "small",
|
|
147401
|
+
columns: [
|
|
147402
|
+
{
|
|
147403
|
+
tag: "column",
|
|
147404
|
+
width: "weighted",
|
|
147405
|
+
weight: 5,
|
|
147406
|
+
vertical_align: "center",
|
|
147407
|
+
elements: [{ tag: "markdown", content: truncateCardContent(sessionRowLine(row, now3)) }]
|
|
147408
|
+
},
|
|
147409
|
+
{
|
|
147410
|
+
tag: "column",
|
|
147411
|
+
width: "auto",
|
|
147412
|
+
vertical_align: "center",
|
|
147413
|
+
elements: [
|
|
147414
|
+
button2(row.bound ? "\u25B6\uFE0F \u518D\u5F00" : "\u25B6\uFE0F \u8FDB\u5165", row.active ? "primary" : "default", {
|
|
147415
|
+
cmd: "open",
|
|
147416
|
+
s: row.sessionID,
|
|
147417
|
+
c: input.chatId
|
|
147418
|
+
})
|
|
147419
|
+
]
|
|
147420
|
+
}
|
|
147421
|
+
]
|
|
147422
|
+
});
|
|
147423
|
+
});
|
|
147424
|
+
}
|
|
147425
|
+
if (input.page > 0) {
|
|
147426
|
+
elements.push(button2("\u2B05\uFE0F \u4E0A\u4E00\u9875", "default", { cmd: "list", p: input.page - 1, c: input.chatId }));
|
|
147427
|
+
}
|
|
147428
|
+
if (input.page + 1 < input.pageCount) {
|
|
147429
|
+
elements.push(button2("\u27A1\uFE0F \u4E0B\u4E00\u9875", "default", { cmd: "list", p: input.page + 1, c: input.chatId }));
|
|
147430
|
+
}
|
|
147431
|
+
elements.push(button2("\u2795 \u65B0\u5EFA\u4F1A\u8BDD", "default", { cmd: "new", c: input.chatId }));
|
|
147432
|
+
if (input.total > 0) {
|
|
147433
|
+
elements.push({
|
|
147434
|
+
tag: "markdown",
|
|
147435
|
+
content: `\u7B2C ${input.page + 1}/${input.pageCount} \u9875 \xB7 \u5171 ${input.total} \u4E2A\u4F1A\u8BDD`,
|
|
147436
|
+
text_size: "notation"
|
|
147437
|
+
});
|
|
147438
|
+
}
|
|
147439
|
+
const template2 = "blue";
|
|
147440
|
+
return guardCard({
|
|
147441
|
+
schema: "2.0",
|
|
147442
|
+
config: { update_multi: true },
|
|
147443
|
+
header: {
|
|
147444
|
+
title: { tag: "plain_text", content: input.title ?? "\u{1F9E9} OpenCode \u4F1A\u8BDD\uFF08\u5168\u90E8\uFF09" },
|
|
147445
|
+
template: template2
|
|
147446
|
+
},
|
|
147447
|
+
body: { elements }
|
|
147448
|
+
});
|
|
147449
|
+
}
|
|
147450
|
+
function parseSessionCardValue(raw) {
|
|
147451
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
147452
|
+
const record2 = raw;
|
|
147453
|
+
const chatId = typeof record2.c === "string" ? record2.c : "";
|
|
147454
|
+
if (record2.cmd === "new") return { cmd: "new", chatId };
|
|
147455
|
+
if (record2.cmd === "use" || record2.cmd === "open") {
|
|
147456
|
+
const sessionID = typeof record2.s === "string" ? record2.s : "";
|
|
147457
|
+
if (!sessionID) return void 0;
|
|
147458
|
+
return record2.cmd === "open" ? { cmd: "open", sessionID, chatId } : { cmd: "use", sessionID, chatId };
|
|
147459
|
+
}
|
|
147460
|
+
if (record2.cmd === "list") {
|
|
147461
|
+
const page = parsePage(record2.p);
|
|
147462
|
+
return { cmd: "list", page, chatId };
|
|
147463
|
+
}
|
|
147464
|
+
if (record2.cmd === "compact") {
|
|
147465
|
+
const sessionID = typeof record2.s === "string" ? record2.s : "";
|
|
147466
|
+
const token = typeof record2.t === "string" ? record2.t : "";
|
|
147467
|
+
if (!sessionID || !token) return void 0;
|
|
147468
|
+
return { cmd: "compact", sessionID, token };
|
|
147469
|
+
}
|
|
147470
|
+
return void 0;
|
|
147471
|
+
}
|
|
147472
|
+
function buildSessionRootCard(base2, status, options2 = {}) {
|
|
147473
|
+
const now3 = options2.now ?? Date.now();
|
|
147474
|
+
const elements = [];
|
|
147475
|
+
let headerTitle;
|
|
147476
|
+
if (base2.style === "created") {
|
|
147477
|
+
const title = base2.title.trim() || "(\u672A\u547D\u540D)";
|
|
147478
|
+
headerTitle = `\u2705 \u5DF2\u521B\u5EFA \xB7 ${title}`;
|
|
147479
|
+
elements.push({ tag: "markdown", content: truncateCardContent(renderCreatedBody(title, base2)) });
|
|
147480
|
+
} else {
|
|
147481
|
+
const title = truncateTitle(base2.title.trim() || "(\u672A\u547D\u540D)");
|
|
147482
|
+
headerTitle = `\u{1F504} ${title}`;
|
|
147483
|
+
elements.push({ tag: "markdown", content: truncateCardContent(renderResumedBody(title, base2, now3)) });
|
|
147484
|
+
if (base2.compactButton && options2.compactToken) {
|
|
147485
|
+
elements.push(
|
|
147486
|
+
button2("\u{1F5DC} \u538B\u7F29\u5E76\u603B\u7ED3", "default", {
|
|
147487
|
+
cmd: "compact",
|
|
147488
|
+
s: base2.sessionID,
|
|
147489
|
+
t: options2.compactToken
|
|
147490
|
+
})
|
|
147491
|
+
);
|
|
147492
|
+
}
|
|
147493
|
+
}
|
|
147494
|
+
if (status) {
|
|
147495
|
+
elements.push({ tag: "markdown", content: topicStatusFooter(status, now3), text_size: "notation" });
|
|
147496
|
+
}
|
|
147497
|
+
const template2 = status ? topicStatusMeta(status.kind).color : "green";
|
|
147498
|
+
const content = status && options2.statusInTitle ? topicStatusTitle(headerTitle, status) : headerTitle;
|
|
147499
|
+
return guardCard(
|
|
147500
|
+
{
|
|
147501
|
+
schema: "2.0",
|
|
147502
|
+
config: { update_multi: true },
|
|
147503
|
+
header: { title: { tag: "plain_text", content }, template: template2 },
|
|
147504
|
+
body: { elements }
|
|
147505
|
+
},
|
|
147506
|
+
options2
|
|
147507
|
+
);
|
|
147508
|
+
}
|
|
147509
|
+
function guardCard(card, options2 = {}) {
|
|
147510
|
+
const { card: guarded, report } = enforceCardLimits(card, { maxTables: options2.maxTables });
|
|
147511
|
+
if (options2.onLimit && (report.degradedTables > 0 || report.droppedElements > 0)) {
|
|
147512
|
+
options2.onLimit(report);
|
|
147513
|
+
}
|
|
147514
|
+
return guarded;
|
|
147515
|
+
}
|
|
147516
|
+
function renderResumedBody(title, base2, now3) {
|
|
147517
|
+
const lines = [`\u4F1A\u8BDD\u300C${title}\u300D\uFF1A\`${base2.sessionID}\``];
|
|
147518
|
+
const setup = [];
|
|
147519
|
+
if (base2.dir) setup.push(`- \u76EE\u5F55\uFF1A\`${base2.dir}\``);
|
|
147520
|
+
if (base2.model) setup.push(`- \u6A21\u578B\uFF1A${base2.model}`);
|
|
147521
|
+
if (base2.updatedAt && base2.updatedAt > 0) {
|
|
147522
|
+
setup.push(`- \u6700\u8FD1\u6D3B\u52A8\uFF1A${relativeTime(base2.updatedAt, now3)}`);
|
|
147523
|
+
}
|
|
147524
|
+
if (setup.length > 0) lines.push("", ...setup);
|
|
147525
|
+
lines.push("", "**\u56DE\u590D\u672C\u5361\u7247**\u5373\u53EF\u7EE7\u7EED\u8FD9\u4E2A\u5386\u53F2\u4F1A\u8BDD\uFF08\u98DE\u4E66\u56DE\u590D\u4F1A\u5728\u672C\u5361\u4E0B\u5F62\u6210\u8BDD\u9898\uFF09\u3002");
|
|
147526
|
+
if (base2.summary || base2.summaryPending || base2.compactPending || base2.compactError) {
|
|
147527
|
+
lines.push("", `**${base2.summaryLabel ?? "\u6458\u8981"}**\uFF1A`);
|
|
147528
|
+
if (base2.summaryPending) lines.push("\u23F3 \u6B63\u5728\u603B\u7ED3\u8BE5\u4F1A\u8BDD\u2026");
|
|
147529
|
+
if (base2.compactPending) lines.push("\u{1F5DC} \u6B63\u5728\u538B\u7F29\u4F1A\u8BDD\u2026\uFF08\u538B\u7F29\u4F1A\u4FEE\u6539\u4F1A\u8BDD\u5386\u53F2\uFF0C\u8BF7\u7A0D\u5019\uFF09");
|
|
147530
|
+
if (base2.summary) lines.push(base2.summary);
|
|
147531
|
+
if (base2.compactError) lines.push(base2.compactError);
|
|
147532
|
+
}
|
|
147533
|
+
lines.push(
|
|
147534
|
+
"",
|
|
147535
|
+
"\u8BDD\u9898\u5185\u53EF\u7528\uFF1A`/current` `/stop` `/model` `/perm` `/cd` `/help`\u3002",
|
|
147536
|
+
"\u4F1A\u8BDD\u7BA1\u7406\uFF08`/new` `/sessions` `/resume`\uFF09\u8BF7\u56DE\u5230\u4E3B\u804A\u5929\u6D41\u3002"
|
|
147537
|
+
);
|
|
147538
|
+
return lines.join("\n");
|
|
147539
|
+
}
|
|
147540
|
+
function renderCreatedBody(title, base2) {
|
|
147541
|
+
const lines = [`\u4F1A\u8BDD\u300C${title}\u300D\u5DF2\u521B\u5EFA\uFF1A\`${base2.sessionID}\``];
|
|
147542
|
+
const setup = [];
|
|
147543
|
+
if (base2.dir) setup.push(`- \u76EE\u5F55\uFF1A\`${base2.dir}\``);
|
|
147544
|
+
if (base2.model) setup.push(`- \u6A21\u578B\uFF1A${base2.model}`);
|
|
147545
|
+
if (base2.perm) setup.push(`- \u6743\u9650\uFF1A${base2.perm}`);
|
|
147546
|
+
if (setup.length > 0) lines.push("", ...setup);
|
|
147547
|
+
lines.push("", "\u70B9\u8FDB\u672C\u8BDD\u9898\u76F4\u63A5\u53D1\u6D88\u606F\u5373\u53EF\uFF0COpenCode \u5C31\u5728\u8FD9\u4E2A\u4F1A\u8BDD\u91CC\u5E72\u6D3B\u3002");
|
|
147548
|
+
if (base2.note) lines.push("", base2.note);
|
|
147549
|
+
return lines.join("\n");
|
|
147550
|
+
}
|
|
147551
|
+
function buildSessionOpenedCard(input) {
|
|
147552
|
+
const base2 = {
|
|
147553
|
+
style: "resumed",
|
|
147554
|
+
title: input.title,
|
|
147555
|
+
sessionID: input.sessionID,
|
|
147556
|
+
...input.dir ? { dir: input.dir } : {},
|
|
147557
|
+
...input.model ? { model: input.model } : {},
|
|
147558
|
+
...input.updatedAt ? { updatedAt: input.updatedAt } : {},
|
|
147559
|
+
...input.summary ? { summary: input.summary } : {},
|
|
147560
|
+
...input.summaryLabel ? { summaryLabel: input.summaryLabel } : {},
|
|
147561
|
+
...input.summaryPending ? { summaryPending: true } : {},
|
|
147562
|
+
...input.compactPending ? { compactPending: true } : {},
|
|
147563
|
+
...input.compactError ? { compactError: input.compactError } : {},
|
|
147564
|
+
...input.compactButton ? { compactButton: true } : {}
|
|
147565
|
+
};
|
|
147566
|
+
return buildSessionRootCard(base2, void 0, {
|
|
147567
|
+
now: input.now ?? Date.now(),
|
|
147568
|
+
...input.compactButton ? { compactToken: input.compactButton.token } : {},
|
|
147569
|
+
...input.maxTables !== void 0 ? { maxTables: input.maxTables } : {},
|
|
147570
|
+
...input.onLimit ? { onLimit: input.onLimit } : {}
|
|
147571
|
+
});
|
|
147572
|
+
}
|
|
147573
|
+
function buildResumeCompactPendingCard(title, sessionID, token, now3) {
|
|
147574
|
+
return buildSessionOpenedCard({
|
|
147575
|
+
title,
|
|
147576
|
+
sessionID,
|
|
147577
|
+
now: now3,
|
|
147578
|
+
compactPending: true,
|
|
147579
|
+
compactButton: { sessionID, token }
|
|
147580
|
+
});
|
|
147581
|
+
}
|
|
147582
|
+
function buildSessionMissingCard(sessionID, reason) {
|
|
147583
|
+
const lines = [
|
|
147584
|
+
`\u4F1A\u8BDD \`${sessionID}\` \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\uFF08\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u672C\u673A\u53EF\u89C1\u8303\u56F4\uFF09\u3002`,
|
|
147585
|
+
"",
|
|
147586
|
+
"\u53D1\u9001 `/sessions` \u91CD\u65B0\u83B7\u53D6\u5217\u8868\u3002"
|
|
147587
|
+
];
|
|
147588
|
+
if (reason) lines.splice(1, 0, "", `\u539F\u56E0\uFF1A${reason}`);
|
|
147589
|
+
return guardCard({
|
|
147590
|
+
schema: "2.0",
|
|
147591
|
+
config: { update_multi: true },
|
|
147592
|
+
header: { title: { tag: "plain_text", content: "\u26A0\uFE0F \u4F1A\u8BDD\u4E0D\u5B58\u5728" }, template: "orange" },
|
|
147593
|
+
body: { elements: [{ tag: "markdown", content: truncateCardContent(lines.join("\n")) }] }
|
|
147594
|
+
});
|
|
147595
|
+
}
|
|
147596
|
+
function buildSessionReadyCard(input) {
|
|
147597
|
+
const title = input.title.trim() || "(\u672A\u547D\u540D)";
|
|
147598
|
+
const lines = [`\u4F1A\u8BDD\u300C${title}\u300D\u5DF2\u521B\u5EFA\uFF1A\`${input.sessionID}\``];
|
|
147599
|
+
const setup = [];
|
|
147600
|
+
if (input.dir) setup.push(`- \u76EE\u5F55\uFF1A\`${input.dir}\``);
|
|
147601
|
+
if (input.model) setup.push(`- \u6A21\u578B\uFF1A${input.model}`);
|
|
147602
|
+
if (input.perm) setup.push(`- \u6743\u9650\uFF1A${input.perm}`);
|
|
147603
|
+
if (setup.length > 0) lines.push("", ...setup);
|
|
147604
|
+
lines.push(
|
|
147605
|
+
"",
|
|
147606
|
+
"**\u5728\u672C\u8BDD\u9898\u5185\u76F4\u63A5\u53D1\u6D88\u606F**\uFF0COpenCode \u5C31\u5728\u8FD9\u4E2A\u4F1A\u8BDD\u91CC\u5E72\u6D3B\u3002",
|
|
147607
|
+
"",
|
|
147608
|
+
"\u8BDD\u9898\u5185\u53EF\u7528\uFF1A`/current` `/stop` `/model` `/perm` `/cd` `/help`\u3002",
|
|
147609
|
+
"\u4F1A\u8BDD\u7BA1\u7406\uFF08`/new` `/sessions` `/use`\uFF09\u8BF7\u56DE\u5230\u4E3B\u804A\u5929\u6D41\u3002"
|
|
147610
|
+
);
|
|
147611
|
+
return guardCard({
|
|
147612
|
+
schema: "2.0",
|
|
147613
|
+
config: { update_multi: true },
|
|
147614
|
+
header: { title: { tag: "plain_text", content: "\u2705 \u4F1A\u8BDD\u5DF2\u5C31\u7EEA" }, template: "green" },
|
|
147615
|
+
body: {
|
|
147616
|
+
elements: [{ tag: "markdown", content: truncateCardContent(lines.join("\n")) }]
|
|
147617
|
+
}
|
|
147618
|
+
});
|
|
147619
|
+
}
|
|
147620
|
+
function buildSessionCreatedCard(input) {
|
|
147621
|
+
return buildSessionRootCard({
|
|
147622
|
+
style: "created",
|
|
147623
|
+
title: input.title,
|
|
147624
|
+
sessionID: input.sessionID,
|
|
147625
|
+
...input.dir ? { dir: input.dir } : {},
|
|
147626
|
+
...input.model ? { model: input.model } : {},
|
|
147627
|
+
...input.perm ? { perm: input.perm } : {},
|
|
147628
|
+
...input.note ? { note: input.note } : {}
|
|
147629
|
+
});
|
|
147630
|
+
}
|
|
147631
|
+
function truncateTitle(title, max6 = 30) {
|
|
147632
|
+
return title.length > max6 ? `${title.slice(0, max6)}\u2026` : title;
|
|
147633
|
+
}
|
|
147634
|
+
function parsePage(value3) {
|
|
147635
|
+
const parsed = typeof value3 === "number" ? value3 : typeof value3 === "string" ? Number.parseInt(value3, 10) : Number.NaN;
|
|
147636
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0;
|
|
147637
|
+
}
|
|
146693
147638
|
var SYSTEM_DIRS = [
|
|
146694
147639
|
"/etc",
|
|
146695
147640
|
"/usr",
|
|
@@ -146828,6 +147773,21 @@ function presetGateMode(preset) {
|
|
|
146828
147773
|
function presetAskActions(preset) {
|
|
146829
147774
|
return ASK_ACTIONS[preset] ?? [];
|
|
146830
147775
|
}
|
|
147776
|
+
function allowActionsForGrant(action) {
|
|
147777
|
+
return SHELL_ACTIONS.includes(action) ? [...SHELL_ACTIONS] : [action];
|
|
147778
|
+
}
|
|
147779
|
+
function appendAllowRules(base2, actions) {
|
|
147780
|
+
const granted = new Set(actions);
|
|
147781
|
+
const kept = base2.filter(
|
|
147782
|
+
(rule) => !(granted.has(rule.action) && rule.resource === "*" && rule.effect === "allow")
|
|
147783
|
+
);
|
|
147784
|
+
const appended = actions.map((action) => ({
|
|
147785
|
+
action,
|
|
147786
|
+
resource: "*",
|
|
147787
|
+
effect: "allow"
|
|
147788
|
+
}));
|
|
147789
|
+
return [...kept, ...appended];
|
|
147790
|
+
}
|
|
146831
147791
|
|
|
146832
147792
|
// src/feishu/wizard.ts
|
|
146833
147793
|
var WIZARD_KEY_PREFIX = "feishu:v2:setup:";
|
|
@@ -146941,14 +147901,14 @@ var WizardStore = class {
|
|
|
146941
147901
|
// src/feishu/recent.ts
|
|
146942
147902
|
var RECENT_DIRS_KEY = "feishu:v2:recent:dirs";
|
|
146943
147903
|
var RECENT_MODELS_KEY = "feishu:v2:recent:models";
|
|
146944
|
-
function
|
|
147904
|
+
function isRecord6(value3) {
|
|
146945
147905
|
return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
146946
147906
|
}
|
|
146947
147907
|
function modelKey(model) {
|
|
146948
147908
|
return `${model.providerID}/${model.id}`;
|
|
146949
147909
|
}
|
|
146950
147910
|
function parseModel2(value3) {
|
|
146951
|
-
if (!
|
|
147911
|
+
if (!isRecord6(value3)) return void 0;
|
|
146952
147912
|
const providerID = typeof value3.providerID === "string" ? value3.providerID : "";
|
|
146953
147913
|
const id2 = typeof value3.id === "string" ? value3.id : "";
|
|
146954
147914
|
if (!providerID || !id2) return void 0;
|
|
@@ -147003,32 +147963,32 @@ var RecentStore = class {
|
|
|
147003
147963
|
};
|
|
147004
147964
|
|
|
147005
147965
|
// src/feishu/models.ts
|
|
147006
|
-
function
|
|
147966
|
+
function isRecord7(value3) {
|
|
147007
147967
|
return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
147008
147968
|
}
|
|
147009
|
-
function
|
|
147969
|
+
function str5(value3) {
|
|
147010
147970
|
return typeof value3 === "string" ? value3 : "";
|
|
147011
147971
|
}
|
|
147012
147972
|
function normalizeModelList(raw) {
|
|
147013
|
-
const arr = Array.isArray(raw) ? raw :
|
|
147973
|
+
const arr = Array.isArray(raw) ? raw : isRecord7(raw) && Array.isArray(raw.data) ? raw.data : [];
|
|
147014
147974
|
const out = [];
|
|
147015
147975
|
const seen = /* @__PURE__ */ new Set();
|
|
147016
147976
|
for (const item of arr) {
|
|
147017
|
-
if (!
|
|
147977
|
+
if (!isRecord7(item)) continue;
|
|
147018
147978
|
if (item.enabled === false) continue;
|
|
147019
|
-
const providerID =
|
|
147020
|
-
const id2 =
|
|
147979
|
+
const providerID = str5(item.providerID);
|
|
147980
|
+
const id2 = str5(item.id) || str5(item.modelID);
|
|
147021
147981
|
if (!providerID || !id2) continue;
|
|
147022
147982
|
const key = `${providerID}/${id2}`;
|
|
147023
147983
|
if (seen.has(key)) continue;
|
|
147024
147984
|
seen.add(key);
|
|
147025
|
-
const time =
|
|
147985
|
+
const time = isRecord7(item.time) ? item.time : {};
|
|
147026
147986
|
const released = typeof time.released === "number" && Number.isFinite(time.released) ? time.released : void 0;
|
|
147027
|
-
const status =
|
|
147987
|
+
const status = str5(item.status) || void 0;
|
|
147028
147988
|
out.push({
|
|
147029
147989
|
providerID,
|
|
147030
147990
|
id: id2,
|
|
147031
|
-
name:
|
|
147991
|
+
name: str5(item.name) || id2,
|
|
147032
147992
|
...released !== void 0 ? { released } : {},
|
|
147033
147993
|
...status ? { status } : {}
|
|
147034
147994
|
});
|
|
@@ -147043,10 +148003,10 @@ function sameModel(a, b) {
|
|
|
147043
148003
|
return a.providerID === b.providerID && a.id === b.id;
|
|
147044
148004
|
}
|
|
147045
148005
|
function extractSessionModel(raw) {
|
|
147046
|
-
if (!
|
|
147047
|
-
const candidate =
|
|
147048
|
-
const providerID =
|
|
147049
|
-
const id2 =
|
|
148006
|
+
if (!isRecord7(raw)) return void 0;
|
|
148007
|
+
const candidate = isRecord7(raw.model) ? raw.model : raw;
|
|
148008
|
+
const providerID = str5(candidate.providerID);
|
|
148009
|
+
const id2 = str5(candidate.id);
|
|
147050
148010
|
if (!providerID || !id2) return void 0;
|
|
147051
148011
|
return { providerID, id: id2 };
|
|
147052
148012
|
}
|
|
@@ -147095,139 +148055,6 @@ function modelMatchErrorText(reason, candidates) {
|
|
|
147095
148055
|
}
|
|
147096
148056
|
}
|
|
147097
148057
|
|
|
147098
|
-
// src/feishu/session-list.ts
|
|
147099
|
-
function normalizeSessionList(raw) {
|
|
147100
|
-
const array3 = extractArray(raw);
|
|
147101
|
-
if (!array3) return void 0;
|
|
147102
|
-
const out = [];
|
|
147103
|
-
const seen = /* @__PURE__ */ new Set();
|
|
147104
|
-
for (const item of array3) {
|
|
147105
|
-
const entry = normalizeSessionInfo(item);
|
|
147106
|
-
if (!entry || seen.has(entry.sessionID)) continue;
|
|
147107
|
-
seen.add(entry.sessionID);
|
|
147108
|
-
out.push(entry);
|
|
147109
|
-
}
|
|
147110
|
-
return sortByUpdatedDesc(out);
|
|
147111
|
-
}
|
|
147112
|
-
function normalizeSessionInfo(raw) {
|
|
147113
|
-
if (!isRecord7(raw)) return void 0;
|
|
147114
|
-
const sessionID = str4(raw.id) || str4(raw.sessionID);
|
|
147115
|
-
if (!sessionID) return void 0;
|
|
147116
|
-
const title = str4(raw.title) || str4(raw.slug);
|
|
147117
|
-
const updatedAt = extractUpdatedAt(raw);
|
|
147118
|
-
const directory = extractDirectory(raw);
|
|
147119
|
-
return {
|
|
147120
|
-
sessionID,
|
|
147121
|
-
title,
|
|
147122
|
-
updatedAt,
|
|
147123
|
-
...directory ? { directory } : {}
|
|
147124
|
-
};
|
|
147125
|
-
}
|
|
147126
|
-
function extractSessionTitle(raw) {
|
|
147127
|
-
const title = normalizeSessionInfo(raw)?.title.trim();
|
|
147128
|
-
return title ? title : void 0;
|
|
147129
|
-
}
|
|
147130
|
-
function toMillis2(value3) {
|
|
147131
|
-
if (typeof value3 === "number") {
|
|
147132
|
-
return Number.isFinite(value3) && value3 > 0 ? value3 : 0;
|
|
147133
|
-
}
|
|
147134
|
-
if (typeof value3 === "string") {
|
|
147135
|
-
const trimmed = value3.trim();
|
|
147136
|
-
if (!trimmed) return 0;
|
|
147137
|
-
if (/^\d+$/.test(trimmed)) {
|
|
147138
|
-
const parsed2 = Number.parseInt(trimmed, 10);
|
|
147139
|
-
return Number.isFinite(parsed2) && parsed2 > 0 ? parsed2 : 0;
|
|
147140
|
-
}
|
|
147141
|
-
const parsed = Date.parse(trimmed);
|
|
147142
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
147143
|
-
}
|
|
147144
|
-
if (value3 instanceof Date) {
|
|
147145
|
-
const ms = value3.getTime();
|
|
147146
|
-
return Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
147147
|
-
}
|
|
147148
|
-
if (isRecord7(value3)) {
|
|
147149
|
-
for (const key of ["epochMillis", "epochMilliseconds", "millis", "value"]) {
|
|
147150
|
-
const ms = toMillis2(value3[key]);
|
|
147151
|
-
if (ms > 0) return ms;
|
|
147152
|
-
}
|
|
147153
|
-
}
|
|
147154
|
-
return 0;
|
|
147155
|
-
}
|
|
147156
|
-
function sortByUpdatedDesc(entries3) {
|
|
147157
|
-
return [...entries3].sort(
|
|
147158
|
-
(a, b) => b.updatedAt - a.updatedAt || a.sessionID.localeCompare(b.sessionID)
|
|
147159
|
-
);
|
|
147160
|
-
}
|
|
147161
|
-
function fallbackEntries(entries3) {
|
|
147162
|
-
return sortByUpdatedDesc(
|
|
147163
|
-
entries3.map((entry) => ({
|
|
147164
|
-
sessionID: entry.sessionID,
|
|
147165
|
-
title: entry.title,
|
|
147166
|
-
updatedAt: Number.isFinite(entry.updatedAt) && entry.updatedAt > 0 ? entry.updatedAt : 0
|
|
147167
|
-
}))
|
|
147168
|
-
);
|
|
147169
|
-
}
|
|
147170
|
-
function relativeTime(fromMs, nowMs) {
|
|
147171
|
-
if (!Number.isFinite(fromMs) || fromMs <= 0) return "\u65F6\u95F4\u672A\u77E5";
|
|
147172
|
-
const diff = nowMs - fromMs;
|
|
147173
|
-
if (diff < 6e4) return "\u521A\u521A";
|
|
147174
|
-
const minutes2 = Math.floor(diff / 6e4);
|
|
147175
|
-
if (minutes2 < 60) return `${minutes2} \u5206\u949F\u524D`;
|
|
147176
|
-
const hours2 = Math.floor(minutes2 / 60);
|
|
147177
|
-
if (hours2 < 24) return `${hours2} \u5C0F\u65F6\u524D`;
|
|
147178
|
-
const days2 = Math.floor(hours2 / 24);
|
|
147179
|
-
if (days2 < 30) return `${days2} \u5929\u524D`;
|
|
147180
|
-
const date = new Date(fromMs);
|
|
147181
|
-
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
147182
|
-
}
|
|
147183
|
-
function directoryTail(dir) {
|
|
147184
|
-
const trimmed = dir.trim().replace(/\/+$/, "");
|
|
147185
|
-
if (!trimmed) return "";
|
|
147186
|
-
const parts = trimmed.split("/");
|
|
147187
|
-
return parts[parts.length - 1] || trimmed;
|
|
147188
|
-
}
|
|
147189
|
-
function extractArray(raw) {
|
|
147190
|
-
if (Array.isArray(raw)) return raw;
|
|
147191
|
-
if (isRecord7(raw)) {
|
|
147192
|
-
for (const key of ["data", "sessions", "items"]) {
|
|
147193
|
-
if (Array.isArray(raw[key])) return raw[key];
|
|
147194
|
-
}
|
|
147195
|
-
}
|
|
147196
|
-
return void 0;
|
|
147197
|
-
}
|
|
147198
|
-
function extractUpdatedAt(raw) {
|
|
147199
|
-
const time = isRecord7(raw.time) ? raw.time : void 0;
|
|
147200
|
-
const candidates = [
|
|
147201
|
-
time?.updated,
|
|
147202
|
-
raw.updatedAt,
|
|
147203
|
-
raw.updated,
|
|
147204
|
-
time?.created,
|
|
147205
|
-
raw.createdAt,
|
|
147206
|
-
raw.created
|
|
147207
|
-
];
|
|
147208
|
-
for (const candidate of candidates) {
|
|
147209
|
-
const ms = toMillis2(candidate);
|
|
147210
|
-
if (ms > 0) return ms;
|
|
147211
|
-
}
|
|
147212
|
-
return 0;
|
|
147213
|
-
}
|
|
147214
|
-
function extractDirectory(raw) {
|
|
147215
|
-
if (isRecord7(raw.location)) {
|
|
147216
|
-
const directory = str4(raw.location.directory);
|
|
147217
|
-
if (directory) return directory;
|
|
147218
|
-
}
|
|
147219
|
-
return str4(raw.directory) || (typeof raw.location === "string" ? raw.location : "");
|
|
147220
|
-
}
|
|
147221
|
-
function pad2(value3) {
|
|
147222
|
-
return value3 < 10 ? `0${value3}` : String(value3);
|
|
147223
|
-
}
|
|
147224
|
-
function isRecord7(value3) {
|
|
147225
|
-
return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
147226
|
-
}
|
|
147227
|
-
function str4(value3) {
|
|
147228
|
-
return typeof value3 === "string" ? value3 : "";
|
|
147229
|
-
}
|
|
147230
|
-
|
|
147231
148058
|
// src/feishu/topic-guidance.ts
|
|
147232
148059
|
var TOPIC_GUIDANCE_MARKER = "opencode-feishu-topic-guidance";
|
|
147233
148060
|
function buildTopicGuidance(title) {
|
|
@@ -147274,8 +148101,14 @@ function decideEffect(action, config) {
|
|
|
147274
148101
|
}
|
|
147275
148102
|
return { effect: "ask", message: `opencode-feishu-v2: \u9700\u8981\u4EBA\u5DE5\u6279\u51C6 ${action}` };
|
|
147276
148103
|
}
|
|
147277
|
-
function decideEffectForSession(action, config, session) {
|
|
147278
|
-
if (!session)
|
|
148104
|
+
function decideEffectForSession(action, config, session, allowActions) {
|
|
148105
|
+
if (!session) {
|
|
148106
|
+
const base2 = decideEffect(action, config);
|
|
148107
|
+
if (base2.effect === "ask" && allowActions && allowActions.length > 0 && matchesAny(action, allowActions)) {
|
|
148108
|
+
return { effect: "allow" };
|
|
148109
|
+
}
|
|
148110
|
+
return base2;
|
|
148111
|
+
}
|
|
147279
148112
|
if (session.gateMode === "off") return {};
|
|
147280
148113
|
if (matchesAny(action, config.denyTools)) {
|
|
147281
148114
|
return { effect: "deny", message: `feishu policy: ${action} \u5DF2\u5728 denyTools` };
|
|
@@ -147283,6 +148116,9 @@ function decideEffectForSession(action, config, session) {
|
|
|
147283
148116
|
if (matchesAny(action, config.allowTools)) {
|
|
147284
148117
|
return { effect: "allow" };
|
|
147285
148118
|
}
|
|
148119
|
+
if (allowActions && allowActions.length > 0 && matchesAny(action, allowActions)) {
|
|
148120
|
+
return { effect: "allow" };
|
|
148121
|
+
}
|
|
147286
148122
|
if (session.askActions && matchesAny(action, session.askActions)) {
|
|
147287
148123
|
return { effect: "ask", message: `opencode-feishu-v2: \u4F1A\u8BDD\u9884\u8BBE\u9700\u4EBA\u5DE5\u6279\u51C6 ${action}` };
|
|
147288
148124
|
}
|
|
@@ -147297,6 +148133,15 @@ function parseApprovalValue(rawValue) {
|
|
|
147297
148133
|
if (d !== "once" && d !== "always" && d !== "reject") return void 0;
|
|
147298
148134
|
return { token, decision: d };
|
|
147299
148135
|
}
|
|
148136
|
+
function parseAllowSessionValue(rawValue) {
|
|
148137
|
+
if (typeof rawValue !== "object" || rawValue === null) return void 0;
|
|
148138
|
+
const record2 = rawValue;
|
|
148139
|
+
if (record2.cmd !== "allow_session") return void 0;
|
|
148140
|
+
const action = typeof record2.a === "string" ? record2.a : "";
|
|
148141
|
+
const token = typeof record2.t === "string" ? record2.t : "";
|
|
148142
|
+
if (!action || !token) return void 0;
|
|
148143
|
+
return { action, token };
|
|
148144
|
+
}
|
|
147300
148145
|
var ApprovalManager = class {
|
|
147301
148146
|
constructor(deps) {
|
|
147302
148147
|
this.deps = deps;
|
|
@@ -147324,6 +148169,11 @@ var ApprovalManager = class {
|
|
|
147324
148169
|
sessionID: request3.sessionID,
|
|
147325
148170
|
openId: link2.openId
|
|
147326
148171
|
});
|
|
148172
|
+
const allowSessionToken = this.deps.sessionAllowButton !== false && this.deps.signAllowSession ? this.deps.signAllowSession({
|
|
148173
|
+
requestID,
|
|
148174
|
+
sessionID: request3.sessionID,
|
|
148175
|
+
action: request3.action
|
|
148176
|
+
}) : void 0;
|
|
147327
148177
|
const input = {
|
|
147328
148178
|
requestID,
|
|
147329
148179
|
sessionID: request3.sessionID,
|
|
@@ -147332,6 +148182,7 @@ var ApprovalManager = class {
|
|
|
147332
148182
|
...request3.message ? { message: request3.message } : {},
|
|
147333
148183
|
canPersistAlways,
|
|
147334
148184
|
token,
|
|
148185
|
+
...allowSessionToken ? { allowSessionToken } : {},
|
|
147335
148186
|
maxResourcesShown: this.deps.config.maxResourcesShown
|
|
147336
148187
|
};
|
|
147337
148188
|
const result3 = link2.replyMessageId ? await this.deps.sender.replyCard(link2.replyMessageId, buildApprovalCard(input)) : await this.deps.sender.sendCard(link2.chatId, buildApprovalCard(input));
|
|
@@ -147371,6 +148222,8 @@ var ApprovalManager = class {
|
|
|
147371
148222
|
* 校验顺序:白名单 → 签名 → 绑定字段 → 防重放。
|
|
147372
148223
|
*/
|
|
147373
148224
|
handleCardAction(action) {
|
|
148225
|
+
const allowValue = parseAllowSessionValue(action.rawValue);
|
|
148226
|
+
if (allowValue) return this.handleAllowSession(action, allowValue);
|
|
147374
148227
|
const parsed = parseApprovalValue(action.rawValue);
|
|
147375
148228
|
if (!parsed) {
|
|
147376
148229
|
return toast2("error", "\u65E0\u6CD5\u8BC6\u522B\u7684\u64CD\u4F5C");
|
|
@@ -147407,6 +148260,89 @@ var ApprovalManager = class {
|
|
|
147407
148260
|
this.seenRequests.clear();
|
|
147408
148261
|
this.cards.clear();
|
|
147409
148262
|
}
|
|
148263
|
+
/**
|
|
148264
|
+
* 任务 A:「✅ 本会话内允许该工具」。
|
|
148265
|
+
*
|
|
148266
|
+
* 校验顺序严格按:**白名单 → 验签 → sessionID 匹配 → nonce 消费**。
|
|
148267
|
+
* 命中后:后台持久化 `allowActions` + 追加会话级 ruleset,并对当前挂起的请求回 `once`
|
|
148268
|
+
* (否则本次请求仍会卡住),最后把审批卡 patch 成「✅ 已允许本会话内 <action>」(无按钮)。
|
|
148269
|
+
* 重复点击 / 已生效只回 toast,不报错。
|
|
148270
|
+
*/
|
|
148271
|
+
handleAllowSession(action, value3) {
|
|
148272
|
+
if (!this.deps.isAllowed(action.operatorOpenId)) {
|
|
148273
|
+
this.deps.log.warn("\u62D2\u7EDD\u975E\u767D\u540D\u5355\u7528\u6237\u7684\u4F1A\u8BDD\u653E\u884C\u70B9\u51FB", {
|
|
148274
|
+
operator: action.operatorOpenId.slice(0, 8)
|
|
148275
|
+
});
|
|
148276
|
+
return toast2("error", "\u65E0\u5BA1\u6279\u6743\u9650");
|
|
148277
|
+
}
|
|
148278
|
+
if (!this.deps.verifyAllowSession || !this.deps.allowSession) {
|
|
148279
|
+
return toast2("error", "\u672C\u4F1A\u8BDD\u5185\u5141\u8BB8\u6682\u4E0D\u53EF\u7528");
|
|
148280
|
+
}
|
|
148281
|
+
const verified = this.deps.verifyAllowSession(value3.token, { action: value3.action });
|
|
148282
|
+
if (!verified.ok) {
|
|
148283
|
+
this.deps.log.warn("\u4F1A\u8BDD\u653E\u884C token \u6821\u9A8C\u5931\u8D25", { reason: verified.reason });
|
|
148284
|
+
return toast2("error", `\u5BA1\u6279\u51ED\u8BC1\u65E0\u6548\uFF08${verified.reason}\uFF09`);
|
|
148285
|
+
}
|
|
148286
|
+
const claims = verified.claims;
|
|
148287
|
+
const tracked = this.cards.get(claims.r);
|
|
148288
|
+
if (tracked && tracked.input.sessionID !== claims.s) {
|
|
148289
|
+
this.deps.log.warn("\u4F1A\u8BDD\u653E\u884C sessionID \u4E0D\u5339\u914D", {
|
|
148290
|
+
tokenSession: claims.s,
|
|
148291
|
+
cardSession: tracked.input.sessionID
|
|
148292
|
+
});
|
|
148293
|
+
return toast2("error", "\u4F1A\u8BDD\u4E0D\u5339\u914D");
|
|
148294
|
+
}
|
|
148295
|
+
const ttl = Math.max(1e3, claims.e - this.now());
|
|
148296
|
+
if (!this.deps.replay.consume(claims.n, ttl)) {
|
|
148297
|
+
return toast2("warning", "\u8BE5\u64CD\u4F5C\u5DF2\u5904\u7406\uFF0C\u8BF7\u52FF\u91CD\u590D\u70B9\u51FB");
|
|
148298
|
+
}
|
|
148299
|
+
const already = this.deps.hasSessionAllow?.({ sessionID: claims.s, action: claims.a }) ?? false;
|
|
148300
|
+
if (tracked) tracked.resolved = true;
|
|
148301
|
+
void this.applyAllowSession(claims, tracked, action).catch(
|
|
148302
|
+
(err2) => this.deps.log.error("\u4F1A\u8BDD\u653E\u884C\u5904\u7406\u5931\u8D25", {
|
|
148303
|
+
sessionID: claims.s,
|
|
148304
|
+
action: claims.a,
|
|
148305
|
+
error: errorMessage(err2)
|
|
148306
|
+
})
|
|
148307
|
+
);
|
|
148308
|
+
return already ? toast2("info", "\u8BE5\u5DE5\u5177\u5DF2\u5728\u672C\u4F1A\u8BDD\u5185\u5141\u8BB8") : toast2("success", `\u5DF2\u5141\u8BB8\u672C\u4F1A\u8BDD\u5185 ${claims.a}`);
|
|
148309
|
+
}
|
|
148310
|
+
async applyAllowSession(claims, tracked, action) {
|
|
148311
|
+
try {
|
|
148312
|
+
await this.deps.allowSession({ sessionID: claims.s, action: claims.a });
|
|
148313
|
+
} catch (err2) {
|
|
148314
|
+
this.deps.log.error("\u4F1A\u8BDD\u5185\u653E\u884C\u5199\u5165\u5931\u8D25", {
|
|
148315
|
+
sessionID: claims.s,
|
|
148316
|
+
action: claims.a,
|
|
148317
|
+
error: errorMessage(err2)
|
|
148318
|
+
});
|
|
148319
|
+
}
|
|
148320
|
+
const directory = tracked?.directory ?? (await this.deps.getLink(claims.s))?.dir;
|
|
148321
|
+
try {
|
|
148322
|
+
await this.deps.reply({
|
|
148323
|
+
sessionID: claims.s,
|
|
148324
|
+
requestID: claims.r,
|
|
148325
|
+
reply: "once",
|
|
148326
|
+
...directory ? { directory } : {}
|
|
148327
|
+
});
|
|
148328
|
+
} catch (err2) {
|
|
148329
|
+
this.deps.log.error("permission.reply \u5931\u8D25", {
|
|
148330
|
+
requestID: claims.r,
|
|
148331
|
+
error: errorMessage(err2)
|
|
148332
|
+
});
|
|
148333
|
+
}
|
|
148334
|
+
const messageId = tracked?.messageId;
|
|
148335
|
+
if (!messageId || !tracked) return;
|
|
148336
|
+
const card = buildSessionAllowResolvedCard(tracked.input, {
|
|
148337
|
+
action: claims.a,
|
|
148338
|
+
operatorOpenId: action.operatorOpenId,
|
|
148339
|
+
at: this.now()
|
|
148340
|
+
});
|
|
148341
|
+
const res = await this.deps.sender.patchCard(messageId, card);
|
|
148342
|
+
if (!res.ok) {
|
|
148343
|
+
this.deps.log.warn("\u4F1A\u8BDD\u653E\u884C\u7ED3\u679C\u5361\u7247\u66F4\u65B0\u5931\u8D25", { requestID: claims.r, error: res.error ?? "unknown" });
|
|
148344
|
+
}
|
|
148345
|
+
}
|
|
147410
148346
|
async applyReply(requestID, sessionID, reply, tracked, outcome, directory) {
|
|
147411
148347
|
try {
|
|
147412
148348
|
await this.deps.reply({ sessionID, requestID, reply, ...directory ? { directory } : {} });
|
|
@@ -147431,177 +148367,6 @@ var ApprovalManager = class {
|
|
|
147431
148367
|
function toast2(type, content) {
|
|
147432
148368
|
return { toast: { type, content } };
|
|
147433
148369
|
}
|
|
147434
|
-
|
|
147435
|
-
// src/feishu/session-cards.ts
|
|
147436
|
-
function button2(text, type, value3) {
|
|
147437
|
-
return {
|
|
147438
|
-
tag: "button",
|
|
147439
|
-
text: { tag: "plain_text", content: text },
|
|
147440
|
-
type,
|
|
147441
|
-
behaviors: [{ type: "callback", value: value3 }]
|
|
147442
|
-
};
|
|
147443
|
-
}
|
|
147444
|
-
function sessionRowLine(row, now3) {
|
|
147445
|
-
const title = truncateTitle(row.title.trim() || "(\u672A\u547D\u540D)");
|
|
147446
|
-
const marks = [relativeTime(row.updatedAt, now3)];
|
|
147447
|
-
if (row.bound) marks.push("\u{1F4AC} \u5DF2\u7ED1\u8BDD\u9898");
|
|
147448
|
-
if (row.directory) marks.push(`\u{1F4CD} ${directoryTail(row.directory)}`);
|
|
147449
|
-
if (row.active) marks.push("\u2190 \u5F53\u524D");
|
|
147450
|
-
return `${row.index}. ${title}\uFF08\`${shortSessionId(row.sessionID)}\`\uFF09\xB7 ${marks.join(" \xB7 ")}`;
|
|
147451
|
-
}
|
|
147452
|
-
function buildSessionListCard(input) {
|
|
147453
|
-
const now3 = input.now ?? Date.now();
|
|
147454
|
-
const elements = [];
|
|
147455
|
-
if (input.rows.length === 0) {
|
|
147456
|
-
elements.push({
|
|
147457
|
-
tag: "markdown",
|
|
147458
|
-
content: truncateCardContent(
|
|
147459
|
-
"\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u3002\u70B9\u4E0B\u65B9\u300C\u2795 \u65B0\u5EFA\u4F1A\u8BDD\u300D\u521B\u5EFA\uFF0C\u6216\u76F4\u63A5\u5728\u8BDD\u9898\u91CC\u53D1\u6D88\u606F\u81EA\u52A8\u521B\u5EFA\u3002"
|
|
147460
|
-
)
|
|
147461
|
-
});
|
|
147462
|
-
} else {
|
|
147463
|
-
const lines = input.rows.map((row) => sessionRowLine(row, now3)).join("\n");
|
|
147464
|
-
elements.push({ tag: "markdown", content: truncateCardContent(lines) });
|
|
147465
|
-
for (const row of input.rows) {
|
|
147466
|
-
elements.push(
|
|
147467
|
-
button2(row.bound ? "\u25B6\uFE0F \u518D\u5F00\u8BDD\u9898" : "\u25B6\uFE0F \u8FDB\u5165\u8BDD\u9898", row.active ? "primary" : "default", {
|
|
147468
|
-
cmd: "open",
|
|
147469
|
-
s: row.sessionID,
|
|
147470
|
-
c: input.chatId
|
|
147471
|
-
})
|
|
147472
|
-
);
|
|
147473
|
-
}
|
|
147474
|
-
}
|
|
147475
|
-
if (input.page > 0) {
|
|
147476
|
-
elements.push(button2("\u2B05\uFE0F \u4E0A\u4E00\u9875", "default", { cmd: "list", p: input.page - 1, c: input.chatId }));
|
|
147477
|
-
}
|
|
147478
|
-
if (input.page + 1 < input.pageCount) {
|
|
147479
|
-
elements.push(button2("\u27A1\uFE0F \u4E0B\u4E00\u9875", "default", { cmd: "list", p: input.page + 1, c: input.chatId }));
|
|
147480
|
-
}
|
|
147481
|
-
elements.push(button2("\u2795 \u65B0\u5EFA\u4F1A\u8BDD", "default", { cmd: "new", c: input.chatId }));
|
|
147482
|
-
if (input.total > 0) {
|
|
147483
|
-
elements.push({
|
|
147484
|
-
tag: "markdown",
|
|
147485
|
-
content: `\u7B2C ${input.page + 1}/${input.pageCount} \u9875 \xB7 \u5171 ${input.total} \u4E2A\u4F1A\u8BDD`,
|
|
147486
|
-
text_size: "notation"
|
|
147487
|
-
});
|
|
147488
|
-
}
|
|
147489
|
-
const template2 = "blue";
|
|
147490
|
-
return {
|
|
147491
|
-
schema: "2.0",
|
|
147492
|
-
config: { update_multi: true },
|
|
147493
|
-
header: {
|
|
147494
|
-
title: { tag: "plain_text", content: input.title ?? "\u{1F9E9} OpenCode \u4F1A\u8BDD\uFF08\u5168\u90E8\uFF09" },
|
|
147495
|
-
template: template2
|
|
147496
|
-
},
|
|
147497
|
-
body: { elements }
|
|
147498
|
-
};
|
|
147499
|
-
}
|
|
147500
|
-
function parseSessionCardValue(raw) {
|
|
147501
|
-
if (typeof raw !== "object" || raw === null) return void 0;
|
|
147502
|
-
const record2 = raw;
|
|
147503
|
-
const chatId = typeof record2.c === "string" ? record2.c : "";
|
|
147504
|
-
if (record2.cmd === "new") return { cmd: "new", chatId };
|
|
147505
|
-
if (record2.cmd === "use" || record2.cmd === "open") {
|
|
147506
|
-
const sessionID = typeof record2.s === "string" ? record2.s : "";
|
|
147507
|
-
if (!sessionID) return void 0;
|
|
147508
|
-
return record2.cmd === "open" ? { cmd: "open", sessionID, chatId } : { cmd: "use", sessionID, chatId };
|
|
147509
|
-
}
|
|
147510
|
-
if (record2.cmd === "list") {
|
|
147511
|
-
const page = parsePage(record2.p);
|
|
147512
|
-
return { cmd: "list", page, chatId };
|
|
147513
|
-
}
|
|
147514
|
-
return void 0;
|
|
147515
|
-
}
|
|
147516
|
-
function buildSessionOpenedCard(input) {
|
|
147517
|
-
const title = input.title.trim() || "(\u672A\u547D\u540D)";
|
|
147518
|
-
const lines = [`\u4F1A\u8BDD\u300C${title}\u300D\uFF1A\`${input.sessionID}\``];
|
|
147519
|
-
const setup = [];
|
|
147520
|
-
if (input.dir) setup.push(`- \u76EE\u5F55\uFF1A\`${input.dir}\``);
|
|
147521
|
-
if (input.updatedAt && input.updatedAt > 0) {
|
|
147522
|
-
setup.push(`- \u6700\u8FD1\u6D3B\u52A8\uFF1A${relativeTime(input.updatedAt, input.now ?? Date.now())}`);
|
|
147523
|
-
}
|
|
147524
|
-
if (setup.length > 0) lines.push("", ...setup);
|
|
147525
|
-
lines.push(
|
|
147526
|
-
"",
|
|
147527
|
-
"**\u5728\u672C\u8BDD\u9898\u5185\u76F4\u63A5\u53D1\u6D88\u606F**\uFF0COpenCode \u5C31\u63A5\u7740\u8FD9\u4E2A\u5386\u53F2\u4F1A\u8BDD\u7EE7\u7EED\u5E72\u6D3B\u3002",
|
|
147528
|
-
"",
|
|
147529
|
-
"\u8BDD\u9898\u5185\u53EF\u7528\uFF1A`/current` `/stop` `/model` `/perm` `/cd` `/help`\u3002",
|
|
147530
|
-
"\u4F1A\u8BDD\u7BA1\u7406\uFF08`/new` `/sessions` `/resume`\uFF09\u8BF7\u56DE\u5230\u4E3B\u804A\u5929\u6D41\u3002"
|
|
147531
|
-
);
|
|
147532
|
-
return {
|
|
147533
|
-
schema: "2.0",
|
|
147534
|
-
config: { update_multi: true },
|
|
147535
|
-
header: { title: { tag: "plain_text", content: `\u2705 \u5DF2\u8FDB\u5165\u4F1A\u8BDD \xB7 ${title}` }, template: "green" },
|
|
147536
|
-
body: {
|
|
147537
|
-
elements: [{ tag: "markdown", content: truncateCardContent(lines.join("\n")) }]
|
|
147538
|
-
}
|
|
147539
|
-
};
|
|
147540
|
-
}
|
|
147541
|
-
function buildSessionMissingCard(sessionID, reason) {
|
|
147542
|
-
const lines = [
|
|
147543
|
-
`\u4F1A\u8BDD \`${sessionID}\` \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\uFF08\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u672C\u673A\u53EF\u89C1\u8303\u56F4\uFF09\u3002`,
|
|
147544
|
-
"",
|
|
147545
|
-
"\u53D1\u9001 `/sessions` \u91CD\u65B0\u83B7\u53D6\u5217\u8868\u3002"
|
|
147546
|
-
];
|
|
147547
|
-
if (reason) lines.splice(1, 0, "", `\u539F\u56E0\uFF1A${reason}`);
|
|
147548
|
-
return {
|
|
147549
|
-
schema: "2.0",
|
|
147550
|
-
config: { update_multi: true },
|
|
147551
|
-
header: { title: { tag: "plain_text", content: "\u26A0\uFE0F \u4F1A\u8BDD\u4E0D\u5B58\u5728" }, template: "orange" },
|
|
147552
|
-
body: { elements: [{ tag: "markdown", content: truncateCardContent(lines.join("\n")) }] }
|
|
147553
|
-
};
|
|
147554
|
-
}
|
|
147555
|
-
function buildSessionReadyCard(input) {
|
|
147556
|
-
const title = input.title.trim() || "(\u672A\u547D\u540D)";
|
|
147557
|
-
const lines = [`\u4F1A\u8BDD\u300C${title}\u300D\u5DF2\u521B\u5EFA\uFF1A\`${input.sessionID}\``];
|
|
147558
|
-
const setup = [];
|
|
147559
|
-
if (input.dir) setup.push(`- \u76EE\u5F55\uFF1A\`${input.dir}\``);
|
|
147560
|
-
if (input.model) setup.push(`- \u6A21\u578B\uFF1A${input.model}`);
|
|
147561
|
-
if (input.perm) setup.push(`- \u6743\u9650\uFF1A${input.perm}`);
|
|
147562
|
-
if (setup.length > 0) lines.push("", ...setup);
|
|
147563
|
-
lines.push(
|
|
147564
|
-
"",
|
|
147565
|
-
"**\u5728\u672C\u8BDD\u9898\u5185\u76F4\u63A5\u53D1\u6D88\u606F**\uFF0COpenCode \u5C31\u5728\u8FD9\u4E2A\u4F1A\u8BDD\u91CC\u5E72\u6D3B\u3002",
|
|
147566
|
-
"",
|
|
147567
|
-
"\u8BDD\u9898\u5185\u53EF\u7528\uFF1A`/current` `/stop` `/model` `/perm` `/cd` `/help`\u3002",
|
|
147568
|
-
"\u4F1A\u8BDD\u7BA1\u7406\uFF08`/new` `/sessions` `/use`\uFF09\u8BF7\u56DE\u5230\u4E3B\u804A\u5929\u6D41\u3002"
|
|
147569
|
-
);
|
|
147570
|
-
return {
|
|
147571
|
-
schema: "2.0",
|
|
147572
|
-
config: { update_multi: true },
|
|
147573
|
-
header: { title: { tag: "plain_text", content: "\u2705 \u4F1A\u8BDD\u5DF2\u5C31\u7EEA" }, template: "green" },
|
|
147574
|
-
body: {
|
|
147575
|
-
elements: [{ tag: "markdown", content: truncateCardContent(lines.join("\n")) }]
|
|
147576
|
-
}
|
|
147577
|
-
};
|
|
147578
|
-
}
|
|
147579
|
-
function buildSessionCreatedCard(input) {
|
|
147580
|
-
const title = input.title.trim() || "(\u672A\u547D\u540D)";
|
|
147581
|
-
const lines = [`\u4F1A\u8BDD\u300C${title}\u300D\u5DF2\u521B\u5EFA\uFF1A\`${input.sessionID}\``];
|
|
147582
|
-
const setup = [];
|
|
147583
|
-
if (input.dir) setup.push(`- \u76EE\u5F55\uFF1A\`${input.dir}\``);
|
|
147584
|
-
if (input.model) setup.push(`- \u6A21\u578B\uFF1A${input.model}`);
|
|
147585
|
-
if (input.perm) setup.push(`- \u6743\u9650\uFF1A${input.perm}`);
|
|
147586
|
-
if (setup.length > 0) lines.push("", ...setup);
|
|
147587
|
-
lines.push("", "\u70B9\u8FDB\u672C\u8BDD\u9898\u76F4\u63A5\u53D1\u6D88\u606F\u5373\u53EF\uFF0COpenCode \u5C31\u5728\u8FD9\u4E2A\u4F1A\u8BDD\u91CC\u5E72\u6D3B\u3002");
|
|
147588
|
-
if (input.note) lines.push("", input.note);
|
|
147589
|
-
return {
|
|
147590
|
-
schema: "2.0",
|
|
147591
|
-
config: { update_multi: true },
|
|
147592
|
-
header: { title: { tag: "plain_text", content: `\u2705 \u5DF2\u521B\u5EFA \xB7 ${title}` }, template: "green" },
|
|
147593
|
-
body: {
|
|
147594
|
-
elements: [{ tag: "markdown", content: truncateCardContent(lines.join("\n")) }]
|
|
147595
|
-
}
|
|
147596
|
-
};
|
|
147597
|
-
}
|
|
147598
|
-
function truncateTitle(title, max6 = 30) {
|
|
147599
|
-
return title.length > max6 ? `${title.slice(0, max6)}\u2026` : title;
|
|
147600
|
-
}
|
|
147601
|
-
function parsePage(value3) {
|
|
147602
|
-
const parsed = typeof value3 === "number" ? value3 : typeof value3 === "string" ? Number.parseInt(value3, 10) : Number.NaN;
|
|
147603
|
-
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0;
|
|
147604
|
-
}
|
|
147605
148370
|
var SETUP_FORM_CMD = "setup.form";
|
|
147606
148371
|
var SETUP_FORM_NAME = "setup_form";
|
|
147607
148372
|
var SETUP_FORM_FIELDS = {
|
|
@@ -148545,6 +149310,14 @@ async function createSessionFromSetup(ctx, chatId, action, opts) {
|
|
|
148545
149310
|
} else {
|
|
148546
149311
|
ctx.deps.log.warn("\u4E00\u952E\u5F00\u8BDD\u9898\u540E\u672A\u8BFB\u5230 thread_id\uFF0C\u8BE5\u4F1A\u8BDD\u6682\u65E0\u6CD5\u81EA\u52A8\u8DEF\u7531", { messageId: res.messageId });
|
|
148547
149312
|
}
|
|
149313
|
+
await ctx.deps.sessionMap.setRootCard(created.id, {
|
|
149314
|
+
style: "created",
|
|
149315
|
+
sessionID: created.id,
|
|
149316
|
+
title,
|
|
149317
|
+
dir,
|
|
149318
|
+
...model ? { model: modelLabel(model) } : {},
|
|
149319
|
+
perm: presetLabel(perm)
|
|
149320
|
+
});
|
|
148548
149321
|
await ctx.patchCard(
|
|
148549
149322
|
action.messageId,
|
|
148550
149323
|
buildSessionCreatedCard({
|
|
@@ -148674,26 +149447,38 @@ async function enterSessionThread(ctx, input) {
|
|
|
148674
149447
|
return { ok: false, error: "missing anchor/chat" };
|
|
148675
149448
|
}
|
|
148676
149449
|
const info = input.info;
|
|
148677
|
-
const
|
|
149450
|
+
const link2 = await ctx.deps.sessionMap.resolveBySession(sessionID);
|
|
149451
|
+
const dir = info?.directory ?? link2?.dir;
|
|
149452
|
+
const showSummary = (ctx.deps.resumeSummary ?? true) && Boolean(ctx.deps.summarizeSession);
|
|
149453
|
+
const onLimit = (report) => {
|
|
149454
|
+
ctx.deps.log.warn("\u4F1A\u8BDD\u6062\u590D\u5361\u5185\u5BB9\u8D85\u9650\uFF0C\u5DF2\u964D\u7EA7", { sessionID, ...report });
|
|
149455
|
+
};
|
|
149456
|
+
const cardInput = {
|
|
148678
149457
|
title: info?.title ?? "",
|
|
148679
149458
|
sessionID,
|
|
148680
|
-
...
|
|
149459
|
+
...dir ? { dir } : {},
|
|
149460
|
+
...link2?.model ? { model: modelLabel(link2.model) } : {},
|
|
148681
149461
|
...info?.updatedAt ? { updatedAt: info.updatedAt } : {},
|
|
148682
|
-
now: ctx.now()
|
|
148683
|
-
|
|
148684
|
-
|
|
148685
|
-
|
|
149462
|
+
now: ctx.now(),
|
|
149463
|
+
...ctx.deps.cardMaxTables !== void 0 ? { maxTables: ctx.deps.cardMaxTables } : {},
|
|
149464
|
+
onLimit,
|
|
149465
|
+
...showSummary ? { summaryPending: true } : {},
|
|
149466
|
+
// 「🗜 压缩并总结」只在开关开启且运行时装配了签名时渲染。
|
|
149467
|
+
...showSummary && ctx.deps.signCompact ? { compactButton: { sessionID, token: ctx.deps.signCompact(sessionID) } } : {}
|
|
149468
|
+
};
|
|
149469
|
+
const card = buildSessionOpenedCard(cardInput);
|
|
149470
|
+
const res = await ctx.deps.sender.sendCard(chatId, card);
|
|
149471
|
+
ctx.deps.log.info("\u53D1\u9001\u4F1A\u8BDD\u6062\u590D\u5361", {
|
|
148686
149472
|
sessionID,
|
|
148687
149473
|
source: input.source,
|
|
148688
149474
|
anchorMessageId,
|
|
148689
|
-
|
|
148690
|
-
|
|
148691
|
-
|
|
148692
|
-
replyError: res.error
|
|
149475
|
+
sendOk: res.ok,
|
|
149476
|
+
cardMessageId: res.messageId,
|
|
149477
|
+
sendError: res.error
|
|
148693
149478
|
});
|
|
148694
149479
|
if (!res.ok || !res.messageId) {
|
|
148695
149480
|
const error = res.error ?? "unknown";
|
|
148696
|
-
ctx.deps.log.warn("\
|
|
149481
|
+
ctx.deps.log.warn("\u53D1\u9001\u6062\u590D\u5361\u5931\u8D25", { sessionID, anchorMessageId, error });
|
|
148697
149482
|
if (input.patchMessageId) {
|
|
148698
149483
|
await ctx.deps.sender.patchCard(
|
|
148699
149484
|
input.patchMessageId,
|
|
@@ -148702,16 +149487,54 @@ async function enterSessionThread(ctx, input) {
|
|
|
148702
149487
|
}
|
|
148703
149488
|
return { ok: false, error };
|
|
148704
149489
|
}
|
|
148705
|
-
const meta = res.threadId ? void 0 : await ctx.deps.sender.getMessageMeta(res.messageId);
|
|
148706
|
-
const threadId = res.threadId ?? meta?.threadId;
|
|
148707
|
-
if (!threadId) {
|
|
148708
|
-
ctx.deps.log.warn("\u8FDB\u5165\u8BDD\u9898\u540E\u672A\u8BFB\u5230 thread_id\uFF0C\u8BE5\u4F1A\u8BDD\u6682\u65E0\u6CD5\u81EA\u52A8\u8DEF\u7531", { messageId: res.messageId });
|
|
148709
|
-
return { ok: false, error: "\u672A\u62FF\u5230\u8BDD\u9898 ID" };
|
|
148710
|
-
}
|
|
148711
|
-
await ctx.deps.sessionMap.bindThread(threadId, sessionID, chatId, operatorOpenId, anchorMessageId);
|
|
148712
149490
|
await ctx.deps.sessionMap.bindRoot(res.messageId, sessionID);
|
|
148713
|
-
ctx.deps.log.info("
|
|
148714
|
-
|
|
149491
|
+
ctx.deps.log.info("resume card bound root to session", { sessionID, rootId: res.messageId });
|
|
149492
|
+
await ctx.deps.sessionMap.setRootCard(sessionID, {
|
|
149493
|
+
style: "resumed",
|
|
149494
|
+
sessionID,
|
|
149495
|
+
title: info?.title ?? "",
|
|
149496
|
+
...dir ? { dir } : {},
|
|
149497
|
+
...link2?.model ? { model: modelLabel(link2.model) } : {},
|
|
149498
|
+
...info?.updatedAt ? { updatedAt: info.updatedAt } : {},
|
|
149499
|
+
...showSummary ? { summaryPending: true, compactButton: Boolean(cardInput.compactButton) } : {}
|
|
149500
|
+
});
|
|
149501
|
+
if (showSummary) {
|
|
149502
|
+
void patchResumeSummary(ctx, sessionID, dir, res.messageId, cardInput);
|
|
149503
|
+
}
|
|
149504
|
+
return { ok: true, messageId: res.messageId };
|
|
149505
|
+
}
|
|
149506
|
+
var SUMMARY_LABEL = {
|
|
149507
|
+
reused: "\u4F1A\u8BDD\u6458\u8981",
|
|
149508
|
+
generated: "\u6458\u8981\uFF08\u5FEB\u6458\u8981\uFF09",
|
|
149509
|
+
compacted: "\u5DF2\u538B\u7F29 \xB7 \u4F1A\u8BDD\u6458\u8981"
|
|
149510
|
+
};
|
|
149511
|
+
async function patchResumeSummary(ctx, sessionID, dir, messageId, cardInput) {
|
|
149512
|
+
try {
|
|
149513
|
+
const outcome = await ctx.deps.summarizeSession({
|
|
149514
|
+
sessionID,
|
|
149515
|
+
...dir ? { directory: dir } : {},
|
|
149516
|
+
timeoutMs: ctx.deps.resumeSummaryTimeoutMs ?? 15e3
|
|
149517
|
+
});
|
|
149518
|
+
const summary = outcome.summary ?? "\uFF08\u6458\u8981\u751F\u6210\u5931\u8D25\uFF0C\u53EF\u76F4\u63A5\u53D1\u6D88\u606F\u7EE7\u7EED\uFF09";
|
|
149519
|
+
const summaryLabel = SUMMARY_LABEL[outcome.source] ?? "\u6458\u8981";
|
|
149520
|
+
const base2 = await ctx.deps.sessionMap.getRootCard(sessionID);
|
|
149521
|
+
if (base2) {
|
|
149522
|
+
await ctx.deps.sessionMap.setRootCard(sessionID, { ...base2, summaryPending: false, summary, summaryLabel });
|
|
149523
|
+
}
|
|
149524
|
+
const res = await ctx.deps.sender.patchCard(
|
|
149525
|
+
messageId,
|
|
149526
|
+
buildSessionOpenedCard({
|
|
149527
|
+
...cardInput,
|
|
149528
|
+
summaryPending: false,
|
|
149529
|
+
summary,
|
|
149530
|
+
summaryLabel
|
|
149531
|
+
})
|
|
149532
|
+
);
|
|
149533
|
+
if (!res.ok) ctx.deps.log.warn("\u6062\u590D\u5361\u6458\u8981\u66F4\u65B0\u5931\u8D25", { sessionID, error: res.error ?? "unknown" });
|
|
149534
|
+
ctx.deps.log.info("\u6062\u590D\u5361\u6458\u8981\u5DF2\u66F4\u65B0", { sessionID, source: outcome.source, hasSummary: Boolean(outcome.summary) });
|
|
149535
|
+
} catch (err2) {
|
|
149536
|
+
ctx.deps.log.warn("\u6062\u590D\u5361\u6458\u8981\u751F\u6210\u5F02\u5E38", { sessionID, error: errorMessage(err2) });
|
|
149537
|
+
}
|
|
148715
149538
|
}
|
|
148716
149539
|
async function handleOpenCardAction(ctx, action, value3) {
|
|
148717
149540
|
if (!ctx.threadRouting) {
|
|
@@ -148746,6 +149569,7 @@ async function patchMissingCard(ctx, messageId, sessionID) {
|
|
|
148746
149569
|
await ctx.deps.sender.patchCard(messageId, buildSessionMissingCard(sessionID));
|
|
148747
149570
|
}
|
|
148748
149571
|
async function applySessionCardAction(ctx, action, value3) {
|
|
149572
|
+
if (value3.cmd === "compact") return;
|
|
148749
149573
|
const chatId = action.chatId || value3.chatId;
|
|
148750
149574
|
if (!chatId) return;
|
|
148751
149575
|
if (value3.cmd === "new") {
|
|
@@ -149111,6 +149935,7 @@ function setupToast(value3) {
|
|
|
149111
149935
|
|
|
149112
149936
|
// src/runtime/event-router.ts
|
|
149113
149937
|
async function routeEvent(event, deps) {
|
|
149938
|
+
deps.onTopicStatus?.(event);
|
|
149114
149939
|
const touched = event.data?.sessionID;
|
|
149115
149940
|
if (typeof touched === "string") deps.touch(touched);
|
|
149116
149941
|
switch (event.type) {
|
|
@@ -149260,6 +150085,256 @@ function contentToText(content) {
|
|
|
149260
150085
|
return "";
|
|
149261
150086
|
}
|
|
149262
150087
|
|
|
150088
|
+
// src/session/resume-summary.ts
|
|
150089
|
+
var RESUME_SUMMARY_PROMPT = "\u7528\u4E0D\u8D85\u8FC7 5 \u6761\u8981\u70B9\u603B\u7ED3\u672C\u4F1A\u8BDD\uFF1A\u76EE\u6807\u3001\u5DF2\u5B8C\u6210\u3001\u5F53\u524D\u72B6\u6001/\u963B\u585E\u3001\u4E0B\u4E00\u6B65\u3002\u53EA\u8F93\u51FA\u8981\u70B9\uFF0C\u4E0D\u8981\u5C55\u5F00\u3002";
|
|
150090
|
+
var TRANSCRIPT_LIMIT = 6e3;
|
|
150091
|
+
var TRANSCRIPT_LINE_LIMIT = 600;
|
|
150092
|
+
var SummaryTimeoutError = class extends Error {
|
|
150093
|
+
constructor() {
|
|
150094
|
+
super("summary-timeout");
|
|
150095
|
+
this.name = "SummaryTimeoutError";
|
|
150096
|
+
}
|
|
150097
|
+
};
|
|
150098
|
+
function withTimeout(promise3, ms) {
|
|
150099
|
+
return new Promise((resolve3, reject) => {
|
|
150100
|
+
const timer = setTimeout(() => reject(new SummaryTimeoutError()), Math.max(1, ms));
|
|
150101
|
+
timer.unref?.();
|
|
150102
|
+
promise3.then(
|
|
150103
|
+
(value3) => {
|
|
150104
|
+
clearTimeout(timer);
|
|
150105
|
+
resolve3(value3);
|
|
150106
|
+
},
|
|
150107
|
+
(err2) => {
|
|
150108
|
+
clearTimeout(timer);
|
|
150109
|
+
reject(err2);
|
|
150110
|
+
}
|
|
150111
|
+
);
|
|
150112
|
+
});
|
|
150113
|
+
}
|
|
150114
|
+
function extractLatestSummary(raw) {
|
|
150115
|
+
const list = extractArray2(raw);
|
|
150116
|
+
if (!list) return void 0;
|
|
150117
|
+
for (let i = list.length - 1; i >= 0; i -= 1) {
|
|
150118
|
+
const item = list[i];
|
|
150119
|
+
if (!isRecord8(item)) continue;
|
|
150120
|
+
if (item.type !== "compaction") continue;
|
|
150121
|
+
if (item.status !== "completed") continue;
|
|
150122
|
+
const summary = typeof item.summary === "string" ? item.summary.trim() : "";
|
|
150123
|
+
if (summary) return summary;
|
|
150124
|
+
}
|
|
150125
|
+
return void 0;
|
|
150126
|
+
}
|
|
150127
|
+
function buildTranscript(raw, limit = TRANSCRIPT_LIMIT, lineLimit = TRANSCRIPT_LINE_LIMIT) {
|
|
150128
|
+
const list = extractArray2(raw);
|
|
150129
|
+
if (!list || list.length === 0) return void 0;
|
|
150130
|
+
const lines = [];
|
|
150131
|
+
for (const item of list) {
|
|
150132
|
+
if (!isRecord8(item)) continue;
|
|
150133
|
+
if (item.type === "user" && typeof item.text === "string") {
|
|
150134
|
+
const text = clip(item.text.trim(), lineLimit);
|
|
150135
|
+
if (text) lines.push(`\u7528\u6237\uFF1A${text}`);
|
|
150136
|
+
} else if (item.type === "assistant" && Array.isArray(item.content)) {
|
|
150137
|
+
const text = clip(
|
|
150138
|
+
item.content.filter((part) => isRecord8(part) && part.type === "text").map((part) => typeof part.text === "string" ? part.text.trim() : "").filter(Boolean).join("\n"),
|
|
150139
|
+
lineLimit
|
|
150140
|
+
);
|
|
150141
|
+
if (text) lines.push(`\u52A9\u624B\uFF1A${text}`);
|
|
150142
|
+
}
|
|
150143
|
+
}
|
|
150144
|
+
if (lines.length === 0) return void 0;
|
|
150145
|
+
const recent = [];
|
|
150146
|
+
let bytes = 0;
|
|
150147
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
150148
|
+
const line = lines[i];
|
|
150149
|
+
const size6 = Buffer.byteLength(line, "utf8");
|
|
150150
|
+
if (bytes + size6 > limit && recent.length > 0) break;
|
|
150151
|
+
recent.unshift(line);
|
|
150152
|
+
bytes += size6;
|
|
150153
|
+
}
|
|
150154
|
+
return recent.join("\n").slice(0, limit);
|
|
150155
|
+
}
|
|
150156
|
+
function buildSummaryPrompt(transcript) {
|
|
150157
|
+
return transcript ? `${RESUME_SUMMARY_PROMPT}
|
|
150158
|
+
|
|
150159
|
+
\u4F1A\u8BDD\u6700\u8FD1\u8BB0\u5F55\uFF1A
|
|
150160
|
+
${transcript}` : RESUME_SUMMARY_PROMPT;
|
|
150161
|
+
}
|
|
150162
|
+
async function summarizeSession(deps, input) {
|
|
150163
|
+
const timeoutMs = Math.max(1, Math.floor(input.timeoutMs));
|
|
150164
|
+
let messages;
|
|
150165
|
+
if (deps.readMessages) {
|
|
150166
|
+
try {
|
|
150167
|
+
messages = await withTimeout(deps.readMessages(input.sessionID, input.directory), timeoutMs);
|
|
150168
|
+
const reused = extractLatestSummary(messages);
|
|
150169
|
+
if (reused) return { summary: reused, source: "reused" };
|
|
150170
|
+
} catch (err2) {
|
|
150171
|
+
deps.log.debug("\u8BFB\u53D6\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25\uFF0C\u7EE7\u7EED\u5C1D\u8BD5\u5FEB\u6458\u8981", {
|
|
150172
|
+
sessionID: input.sessionID,
|
|
150173
|
+
error: errorMessage(err2)
|
|
150174
|
+
});
|
|
150175
|
+
}
|
|
150176
|
+
}
|
|
150177
|
+
if (!deps.generateText) return { source: "none" };
|
|
150178
|
+
try {
|
|
150179
|
+
const transcript = buildTranscript(messages);
|
|
150180
|
+
const raw = await withTimeout(
|
|
150181
|
+
deps.generateText(buildSummaryPrompt(transcript), input.directory),
|
|
150182
|
+
timeoutMs
|
|
150183
|
+
);
|
|
150184
|
+
const generated = extractGeneratedText(raw);
|
|
150185
|
+
if (generated) return { summary: generated, source: "generated" };
|
|
150186
|
+
return { source: "none", error: "empty-summary" };
|
|
150187
|
+
} catch (err2) {
|
|
150188
|
+
const error = errorMessage(err2);
|
|
150189
|
+
deps.log.warn("\u751F\u6210\u4F1A\u8BDD\u6458\u8981\u5931\u8D25", {
|
|
150190
|
+
sessionID: input.sessionID,
|
|
150191
|
+
timedOut: err2 instanceof SummaryTimeoutError,
|
|
150192
|
+
error
|
|
150193
|
+
});
|
|
150194
|
+
return { source: "none", error };
|
|
150195
|
+
}
|
|
150196
|
+
}
|
|
150197
|
+
function extractGeneratedText(raw) {
|
|
150198
|
+
if (typeof raw === "string") return raw.trim() || void 0;
|
|
150199
|
+
if (!isRecord8(raw)) return void 0;
|
|
150200
|
+
if (typeof raw.text === "string" && raw.text.trim()) return raw.text.trim();
|
|
150201
|
+
const data = raw.data;
|
|
150202
|
+
if (isRecord8(data) && typeof data.text === "string" && data.text.trim()) return data.text.trim();
|
|
150203
|
+
return void 0;
|
|
150204
|
+
}
|
|
150205
|
+
function clip(text, limit) {
|
|
150206
|
+
if (!text) return "";
|
|
150207
|
+
return text.length > limit ? text.slice(0, limit) : text;
|
|
150208
|
+
}
|
|
150209
|
+
function extractArray2(raw) {
|
|
150210
|
+
if (Array.isArray(raw)) return raw;
|
|
150211
|
+
if (isRecord8(raw)) {
|
|
150212
|
+
for (const key of ["data", "messages", "items"]) {
|
|
150213
|
+
if (Array.isArray(raw[key])) return raw[key];
|
|
150214
|
+
}
|
|
150215
|
+
}
|
|
150216
|
+
return void 0;
|
|
150217
|
+
}
|
|
150218
|
+
function isRecord8(value3) {
|
|
150219
|
+
return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
150220
|
+
}
|
|
150221
|
+
|
|
150222
|
+
// src/session/compact.ts
|
|
150223
|
+
var COMPACT_CMD = "compact";
|
|
150224
|
+
function parseCompactActionValue(raw) {
|
|
150225
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
150226
|
+
const record2 = raw;
|
|
150227
|
+
if (record2.cmd !== COMPACT_CMD) return void 0;
|
|
150228
|
+
const s = typeof record2.s === "string" ? record2.s : "";
|
|
150229
|
+
const t = typeof record2.t === "string" ? record2.t : "";
|
|
150230
|
+
if (!s || !t) return void 0;
|
|
150231
|
+
return { cmd: COMPACT_CMD, s, t };
|
|
150232
|
+
}
|
|
150233
|
+
var CompactController = class {
|
|
150234
|
+
constructor(deps) {
|
|
150235
|
+
this.deps = deps;
|
|
150236
|
+
this.now = deps.now ?? (() => Date.now());
|
|
150237
|
+
this.sleep = deps.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
|
|
150238
|
+
}
|
|
150239
|
+
deps;
|
|
150240
|
+
now;
|
|
150241
|
+
sleep;
|
|
150242
|
+
/**
|
|
150243
|
+
* 处理卡片点击:同步返回 toast(3 秒窗口),压缩 + 轮询在后台完成。
|
|
150244
|
+
* 校验顺序:白名单 → 验签 → 绑定 sessionID → 防重放。
|
|
150245
|
+
*/
|
|
150246
|
+
handleCardAction(action) {
|
|
150247
|
+
const parsed = parseCompactActionValue(action.rawValue);
|
|
150248
|
+
if (!parsed) return toast4("error", "\u65E0\u6CD5\u8BC6\u522B\u7684\u64CD\u4F5C");
|
|
150249
|
+
if (!this.deps.isAllowed(action.operatorOpenId)) {
|
|
150250
|
+
this.deps.log.warn("\u62D2\u7EDD\u975E\u767D\u540D\u5355\u7528\u6237\u7684\u538B\u7F29\u70B9\u51FB", { operator: action.operatorOpenId.slice(0, 8) });
|
|
150251
|
+
return toast4("error", "\u65E0\u64CD\u4F5C\u6743\u9650");
|
|
150252
|
+
}
|
|
150253
|
+
const verified = this.deps.verify(parsed.t, parsed.s);
|
|
150254
|
+
if (!verified.ok) {
|
|
150255
|
+
this.deps.log.warn("\u538B\u7F29 token \u6821\u9A8C\u5931\u8D25", { reason: verified.reason, sessionID: parsed.s });
|
|
150256
|
+
return toast4("error", `\u64CD\u4F5C\u51ED\u8BC1\u65E0\u6548\uFF08${verified.reason}\uFF09`);
|
|
150257
|
+
}
|
|
150258
|
+
const ttl = Math.max(1e3, verified.claims.e - this.now());
|
|
150259
|
+
if (!this.deps.replay.consume(verified.claims.n, ttl)) {
|
|
150260
|
+
return toast4("warning", "\u8BE5\u64CD\u4F5C\u5DF2\u5904\u7406\uFF0C\u8BF7\u52FF\u91CD\u590D\u70B9\u51FB");
|
|
150261
|
+
}
|
|
150262
|
+
const messageId = action.messageId;
|
|
150263
|
+
if (this.deps.patchPending && messageId) {
|
|
150264
|
+
void this.deps.patchPending(parsed.s, messageId, parsed.t).catch((err2) => this.deps.log.warn("\u538B\u7F29\u4E2D\u5361\u7247 patch \u5931\u8D25", { sessionID: parsed.s, error: errorMessage(err2) }));
|
|
150265
|
+
}
|
|
150266
|
+
void this.run(parsed.s, messageId).catch(
|
|
150267
|
+
(err2) => this.deps.log.warn("\u538B\u7F29\u4F1A\u8BDD\u5931\u8D25", { sessionID: parsed.s, error: errorMessage(err2) })
|
|
150268
|
+
);
|
|
150269
|
+
return toast4("success", "\u{1F5DC} \u6B63\u5728\u538B\u7F29\u4F1A\u8BDD\u2026");
|
|
150270
|
+
}
|
|
150271
|
+
/** 压缩 + 轮询到新摘要;失败/超时 patch 说明(best-effort)。 */
|
|
150272
|
+
async run(sessionID, messageId = "") {
|
|
150273
|
+
const baseline = this.baselineSummary(await this.readQuiet(sessionID));
|
|
150274
|
+
try {
|
|
150275
|
+
await this.deps.compact(sessionID);
|
|
150276
|
+
} catch (err2) {
|
|
150277
|
+
const error = errorMessage(err2);
|
|
150278
|
+
this.deps.log.warn("\u89E6\u53D1\u4F1A\u8BDD\u538B\u7F29\u5931\u8D25", { sessionID, error });
|
|
150279
|
+
await this.patchQuiet(sessionID, compactFailureText(error), "failed", messageId);
|
|
150280
|
+
return { error };
|
|
150281
|
+
}
|
|
150282
|
+
const result3 = await this.poll(sessionID, baseline);
|
|
150283
|
+
if (result3.summary) {
|
|
150284
|
+
await this.patchQuiet(sessionID, `\u5DF2\u538B\u7F29 \xB7 \u4F1A\u8BDD\u6458\u8981\uFF1A
|
|
150285
|
+
|
|
150286
|
+
${result3.summary}`, "completed", messageId);
|
|
150287
|
+
return result3;
|
|
150288
|
+
}
|
|
150289
|
+
await this.patchQuiet(sessionID, compactFailureText(result3.error ?? "timeout"), "failed", messageId);
|
|
150290
|
+
return result3;
|
|
150291
|
+
}
|
|
150292
|
+
/**
|
|
150293
|
+
* 轮询直到出现**新的** completed compaction 摘要。
|
|
150294
|
+
* `baseline` = 点击前的已有摘要,避免把旧摘要误当成新结果。
|
|
150295
|
+
*/
|
|
150296
|
+
async poll(sessionID, baseline) {
|
|
150297
|
+
const interval = Math.max(50, this.deps.pollIntervalMs ?? 2e3);
|
|
150298
|
+
const deadline = this.now() + Math.max(interval, this.deps.timeoutMs ?? 12e4);
|
|
150299
|
+
for (; ; ) {
|
|
150300
|
+
const summary = extractLatestSummary(await this.readQuiet(sessionID));
|
|
150301
|
+
if (summary && summary !== baseline) return { summary };
|
|
150302
|
+
if (this.now() >= deadline) return { error: "timeout" };
|
|
150303
|
+
await this.sleep(interval);
|
|
150304
|
+
}
|
|
150305
|
+
}
|
|
150306
|
+
/** 读一次当前已完成摘要(失败返回 undefined,不阻断)。 */
|
|
150307
|
+
baselineSummary(raw) {
|
|
150308
|
+
try {
|
|
150309
|
+
return extractLatestSummary(raw);
|
|
150310
|
+
} catch {
|
|
150311
|
+
return void 0;
|
|
150312
|
+
}
|
|
150313
|
+
}
|
|
150314
|
+
async readQuiet(sessionID) {
|
|
150315
|
+
try {
|
|
150316
|
+
return await this.deps.readMessages(sessionID);
|
|
150317
|
+
} catch (err2) {
|
|
150318
|
+
this.deps.log.debug("\u538B\u7F29\u8F6E\u8BE2\u8BFB\u53D6\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25", { sessionID, error: errorMessage(err2) });
|
|
150319
|
+
return void 0;
|
|
150320
|
+
}
|
|
150321
|
+
}
|
|
150322
|
+
async patchQuiet(sessionID, text, kind, messageId) {
|
|
150323
|
+
try {
|
|
150324
|
+
await this.deps.patch(sessionID, text, kind, messageId);
|
|
150325
|
+
} catch (err2) {
|
|
150326
|
+
this.deps.log.warn("\u538B\u7F29\u7ED3\u679C patch \u5931\u8D25", { sessionID, error: errorMessage(err2) });
|
|
150327
|
+
}
|
|
150328
|
+
}
|
|
150329
|
+
};
|
|
150330
|
+
function compactFailureText(error) {
|
|
150331
|
+
const reason = error === "timeout" ? "\u8D85\u65F6\uFF08\u538B\u7F29\u4ECD\u5728\u540E\u53F0\u8FDB\u884C\uFF09" : `\u5931\u8D25\uFF1A${error}`;
|
|
150332
|
+
return `\u26A0\uFE0F \u538B\u7F29\u4F1A\u8BDD${reason}\u3002\u53EF\u7EE7\u7EED\u5728\u672C\u8BDD\u9898/\u5361\u7247\u4E0B\u53D1\u6D88\u606F\uFF1B\u7A0D\u540E\u5982\u9700\u6458\u8981\u53EF\u518D\u70B9\u4E00\u6B21\u300C\u{1F5DC} \u538B\u7F29\u5E76\u603B\u7ED3\u300D\u3002`;
|
|
150333
|
+
}
|
|
150334
|
+
function toast4(type, content) {
|
|
150335
|
+
return { toast: { type, content } };
|
|
150336
|
+
}
|
|
150337
|
+
|
|
149263
150338
|
// src/runtime/card-action-router.ts
|
|
149264
150339
|
function routeCardAction(action, deps) {
|
|
149265
150340
|
const formResponse = deps.handleForm(action);
|
|
@@ -149268,6 +150343,9 @@ function routeCardAction(action, deps) {
|
|
|
149268
150343
|
if (parseStopActionValue(value3)) {
|
|
149269
150344
|
return deps.handleStop(action);
|
|
149270
150345
|
}
|
|
150346
|
+
if (parseCompactActionValue(value3)) {
|
|
150347
|
+
return deps.handleCompact(action);
|
|
150348
|
+
}
|
|
149271
150349
|
const hasForm = action.formValue !== void 0;
|
|
149272
150350
|
const routed = hasForm || isSetupFormAction(value3) || Boolean(parseSessionCardValue(value3)) || Boolean(parseSetupCardValue(value3));
|
|
149273
150351
|
deps.log.debug("\u5361\u7247\u56DE\u8C03\u8DEF\u7531", {
|
|
@@ -149282,6 +150360,237 @@ function routeCardAction(action, deps) {
|
|
|
149282
150360
|
return deps.handleApprovals(action);
|
|
149283
150361
|
}
|
|
149284
150362
|
|
|
150363
|
+
// src/runtime/topic-status.ts
|
|
150364
|
+
var MAX_CONSECUTIVE_FAILURES = 3;
|
|
150365
|
+
function createTopicStatusController(deps) {
|
|
150366
|
+
const log2 = deps.log;
|
|
150367
|
+
const now3 = deps.now ?? (() => Date.now());
|
|
150368
|
+
const throttleMs = Math.max(0, deps.throttleMs);
|
|
150369
|
+
const machine = new TopicStatusMachine();
|
|
150370
|
+
const throttlers = /* @__PURE__ */ new Map();
|
|
150371
|
+
const failures = /* @__PURE__ */ new Map();
|
|
150372
|
+
const disabled = /* @__PURE__ */ new Set();
|
|
150373
|
+
let disposed = false;
|
|
150374
|
+
const run2 = async (sessionID) => {
|
|
150375
|
+
if (disposed || !deps.enabled || disabled.has(sessionID)) return;
|
|
150376
|
+
const view = machine.view(sessionID);
|
|
150377
|
+
if (!view) return;
|
|
150378
|
+
let target;
|
|
150379
|
+
try {
|
|
150380
|
+
target = await deps.getRoot(sessionID);
|
|
150381
|
+
} catch (err2) {
|
|
150382
|
+
log2.warn("\u8BDD\u9898\u72B6\u6001\uFF1A\u8BFB\u53D6\u6839\u5361\u57FA\u7840\u5185\u5BB9\u5931\u8D25", { sessionID, error: errorMessage(err2) });
|
|
150383
|
+
return;
|
|
150384
|
+
}
|
|
150385
|
+
if (!target) {
|
|
150386
|
+
log2.debug("\u8BDD\u9898\u72B6\u6001\uFF1A\u65E0\u6839\u5361\u57FA\u7840\u5185\u5BB9\uFF0C\u8DF3\u8FC7\u5237\u65B0", { sessionID });
|
|
150387
|
+
return;
|
|
150388
|
+
}
|
|
150389
|
+
const card = buildSessionRootCard(target.base, view, {
|
|
150390
|
+
now: now3(),
|
|
150391
|
+
statusInTitle: deps.statusInTitle,
|
|
150392
|
+
...deps.compactToken ? { compactToken: deps.compactToken(sessionID) } : {}
|
|
150393
|
+
});
|
|
150394
|
+
let ok = false;
|
|
150395
|
+
let error;
|
|
150396
|
+
try {
|
|
150397
|
+
const res = await deps.patch(target.messageId, card);
|
|
150398
|
+
ok = res.ok;
|
|
150399
|
+
error = res.error;
|
|
150400
|
+
} catch (err2) {
|
|
150401
|
+
error = errorMessage(err2);
|
|
150402
|
+
}
|
|
150403
|
+
if (ok) {
|
|
150404
|
+
failures.delete(sessionID);
|
|
150405
|
+
return;
|
|
150406
|
+
}
|
|
150407
|
+
const count = (failures.get(sessionID) ?? 0) + 1;
|
|
150408
|
+
failures.set(sessionID, count);
|
|
150409
|
+
log2.warn("\u8BDD\u9898\u72B6\u6001\u6839\u5361\u5237\u65B0\u5931\u8D25", { sessionID, attempts: count, error: error ?? "unknown" });
|
|
150410
|
+
if (count >= MAX_CONSECUTIVE_FAILURES) {
|
|
150411
|
+
disabled.add(sessionID);
|
|
150412
|
+
log2.warn("\u8BDD\u9898\u72B6\u6001\uFF1A\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\uFF0C\u505C\u6B62\u8BE5\u4F1A\u8BDD\u540E\u7EED\u72B6\u6001\u5237\u65B0", {
|
|
150413
|
+
sessionID,
|
|
150414
|
+
attempts: count
|
|
150415
|
+
});
|
|
150416
|
+
}
|
|
150417
|
+
};
|
|
150418
|
+
const getThrottler = (sessionID) => {
|
|
150419
|
+
let throttler = throttlers.get(sessionID);
|
|
150420
|
+
if (!throttler) {
|
|
150421
|
+
throttler = createThrottler({
|
|
150422
|
+
intervalMs: throttleMs,
|
|
150423
|
+
now: now3,
|
|
150424
|
+
...deps.setTimer ? { setTimer: deps.setTimer } : {},
|
|
150425
|
+
...deps.clearTimer ? { clearTimer: deps.clearTimer } : {},
|
|
150426
|
+
onFire: () => {
|
|
150427
|
+
if (!disposed) void run2(sessionID);
|
|
150428
|
+
}
|
|
150429
|
+
});
|
|
150430
|
+
throttlers.set(sessionID, throttler);
|
|
150431
|
+
}
|
|
150432
|
+
return throttler;
|
|
150433
|
+
};
|
|
150434
|
+
const schedule2 = (sessionID) => {
|
|
150435
|
+
if (!deps.enabled || disposed || disabled.has(sessionID)) return;
|
|
150436
|
+
getThrottler(sessionID).schedule();
|
|
150437
|
+
};
|
|
150438
|
+
const sessionIDOf = (data) => {
|
|
150439
|
+
const value3 = data?.sessionID;
|
|
150440
|
+
return typeof value3 === "string" ? value3 : "";
|
|
150441
|
+
};
|
|
150442
|
+
return {
|
|
150443
|
+
onEvent(event) {
|
|
150444
|
+
if (!deps.enabled) return;
|
|
150445
|
+
const sessionID = sessionIDOf(event.data);
|
|
150446
|
+
if (!sessionID) return;
|
|
150447
|
+
const change = machine.reduce(sessionID, event);
|
|
150448
|
+
if (!change?.changed) return;
|
|
150449
|
+
schedule2(sessionID);
|
|
150450
|
+
},
|
|
150451
|
+
markTerminal(sessionID, kind) {
|
|
150452
|
+
if (!deps.enabled || !sessionID) return;
|
|
150453
|
+
const change = machine.markTerminal(sessionID, kind);
|
|
150454
|
+
if (!change?.changed) return;
|
|
150455
|
+
schedule2(sessionID);
|
|
150456
|
+
},
|
|
150457
|
+
statusOf(sessionID) {
|
|
150458
|
+
return machine.view(sessionID);
|
|
150459
|
+
},
|
|
150460
|
+
dispose() {
|
|
150461
|
+
disposed = true;
|
|
150462
|
+
for (const throttler of throttlers.values()) throttler.cancel();
|
|
150463
|
+
throttlers.clear();
|
|
150464
|
+
machine.clear();
|
|
150465
|
+
failures.clear();
|
|
150466
|
+
disabled.clear();
|
|
150467
|
+
}
|
|
150468
|
+
};
|
|
150469
|
+
}
|
|
150470
|
+
|
|
150471
|
+
// src/session/compact-http.ts
|
|
150472
|
+
function authHeaders2(service3) {
|
|
150473
|
+
if (!service3.password) return {};
|
|
150474
|
+
const token = Buffer.from(`opencode:${service3.password}`, "utf8").toString("base64");
|
|
150475
|
+
return { authorization: `Basic ${token}` };
|
|
150476
|
+
}
|
|
150477
|
+
async function fetchSessionMessagesHttp(sessionID, directory, deps) {
|
|
150478
|
+
const discover = deps.discover ?? (() => discoverLocalService());
|
|
150479
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
150480
|
+
const service3 = await discover();
|
|
150481
|
+
if (!service3) throw new Error("\u672A\u53D1\u73B0\u672C\u673A opencode \u670D\u52A1\u6CE8\u518C\uFF08service.json \u7F3A\u5931\u6216\u635F\u574F\uFF09");
|
|
150482
|
+
const path2 = `/api/session/${encodeURIComponent(sessionID)}/message?limit=200`;
|
|
150483
|
+
const headers = { ...authHeaders2(service3) };
|
|
150484
|
+
if (directory) headers["x-opencode-directory"] = encodeURIComponent(directory);
|
|
150485
|
+
const response2 = await doFetch(`${service3.url}${path2}`, {
|
|
150486
|
+
method: "GET",
|
|
150487
|
+
headers,
|
|
150488
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? 15e3)
|
|
150489
|
+
});
|
|
150490
|
+
if (!response2.ok) {
|
|
150491
|
+
const detail = await response2.text().catch(() => "");
|
|
150492
|
+
deps.log.debug("\u4F1A\u8BDD\u6D88\u606F HTTP \u8BFB\u53D6\u5931\u8D25", { status: response2.status, sessionID });
|
|
150493
|
+
throw new Error(
|
|
150494
|
+
`\u4F1A\u8BDD\u6D88\u606F\u8BFB\u53D6\u5931\u8D25 HTTP ${response2.status}${detail ? `: ${detail.slice(0, 200)}` : ""}`
|
|
150495
|
+
);
|
|
150496
|
+
}
|
|
150497
|
+
return response2.json();
|
|
150498
|
+
}
|
|
150499
|
+
async function compactSessionHttp(sessionID, directory, deps) {
|
|
150500
|
+
const discover = deps.discover ?? (() => discoverLocalService());
|
|
150501
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
150502
|
+
const service3 = await discover();
|
|
150503
|
+
if (!service3) throw new Error("\u672A\u53D1\u73B0\u672C\u673A opencode \u670D\u52A1\u6CE8\u518C\uFF08service.json \u7F3A\u5931\u6216\u635F\u574F\uFF09");
|
|
150504
|
+
const path2 = `/api/session/${encodeURIComponent(sessionID)}/compact`;
|
|
150505
|
+
const headers = {
|
|
150506
|
+
"content-type": "application/json",
|
|
150507
|
+
...authHeaders2(service3)
|
|
150508
|
+
};
|
|
150509
|
+
if (directory) headers["x-opencode-directory"] = encodeURIComponent(directory);
|
|
150510
|
+
const response2 = await doFetch(`${service3.url}${path2}`, {
|
|
150511
|
+
method: "POST",
|
|
150512
|
+
headers,
|
|
150513
|
+
body: JSON.stringify({}),
|
|
150514
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? 3e4)
|
|
150515
|
+
});
|
|
150516
|
+
if (!response2.ok) {
|
|
150517
|
+
const detail = await response2.text().catch(() => "");
|
|
150518
|
+
deps.log.debug("\u4F1A\u8BDD\u538B\u7F29 HTTP \u89E6\u53D1\u5931\u8D25", { status: response2.status, sessionID });
|
|
150519
|
+
throw new Error(
|
|
150520
|
+
`\u4F1A\u8BDD\u538B\u7F29\u89E6\u53D1\u5931\u8D25 HTTP ${response2.status}${detail ? `: ${detail.slice(0, 200)}` : ""}`
|
|
150521
|
+
);
|
|
150522
|
+
}
|
|
150523
|
+
}
|
|
150524
|
+
|
|
150525
|
+
// src/session/quick-generate.ts
|
|
150526
|
+
function sessionRoutingHeaders(sessionID, directory) {
|
|
150527
|
+
const headers = { "x-opencode-session": sessionID };
|
|
150528
|
+
if (directory) headers["x-opencode-directory"] = encodeURIComponent(directory);
|
|
150529
|
+
return headers;
|
|
150530
|
+
}
|
|
150531
|
+
function authHeaders3(service3) {
|
|
150532
|
+
if (!service3.password) return {};
|
|
150533
|
+
const token = Buffer.from(`opencode:${service3.password}`, "utf8").toString("base64");
|
|
150534
|
+
return { authorization: `Basic ${token}` };
|
|
150535
|
+
}
|
|
150536
|
+
async function quickGenerateWithSession(deps, input) {
|
|
150537
|
+
const headers = sessionRoutingHeaders(input.sessionID, input.directory);
|
|
150538
|
+
if (deps.generateText) {
|
|
150539
|
+
try {
|
|
150540
|
+
const result4 = await withAttemptTimeout(
|
|
150541
|
+
deps.generateText(input.prompt, { headers }),
|
|
150542
|
+
deps.attemptTimeoutMs ?? 8e3
|
|
150543
|
+
);
|
|
150544
|
+
if (result4 !== void 0 && result4 !== null) {
|
|
150545
|
+
deps.log.info("\u5FEB\u6458\u8981\u751F\u6210\u8D70\u751F\u6210 API", { sessionID: input.sessionID, route: "generate" });
|
|
150546
|
+
return { route: "generate", result: result4 };
|
|
150547
|
+
}
|
|
150548
|
+
deps.log.debug("\u751F\u6210 API \u8FD4\u56DE\u7A7A\u7ED3\u679C\uFF0C\u56DE\u9000\u672C\u673A HTTP \u751F\u6210", { sessionID: input.sessionID });
|
|
150549
|
+
} catch (err2) {
|
|
150550
|
+
deps.log.debug("\u751F\u6210 API \u5931\u8D25\uFF0C\u56DE\u9000\u672C\u673A HTTP \u751F\u6210", {
|
|
150551
|
+
sessionID: input.sessionID,
|
|
150552
|
+
error: errorMessage(err2)
|
|
150553
|
+
});
|
|
150554
|
+
}
|
|
150555
|
+
}
|
|
150556
|
+
const discover = deps.discover ?? (() => discoverLocalService());
|
|
150557
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
150558
|
+
const service3 = await discover();
|
|
150559
|
+
if (!service3) throw new Error("\u751F\u6210 API \u4E0E HTTP \u901A\u9053\u5747\u4E0D\u53EF\u7528\uFF08\u672A\u53D1\u73B0\u672C\u673A opencode \u670D\u52A1\u6CE8\u518C\uFF09");
|
|
150560
|
+
const response2 = await doFetch(`${service3.url}/api/experimental/generate`, {
|
|
150561
|
+
method: "POST",
|
|
150562
|
+
headers: { "content-type": "application/json", ...authHeaders3(service3), ...headers },
|
|
150563
|
+
body: JSON.stringify({ prompt: input.prompt }),
|
|
150564
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? 15e3)
|
|
150565
|
+
});
|
|
150566
|
+
if (!response2.ok) {
|
|
150567
|
+
const detail = await response2.text().catch(() => "");
|
|
150568
|
+
deps.log.debug("HTTP \u751F\u6210\u5931\u8D25", { status: response2.status, sessionID: input.sessionID });
|
|
150569
|
+
throw new Error(
|
|
150570
|
+
`HTTP \u751F\u6210\u5931\u8D25 HTTP ${response2.status}${detail ? `: ${detail.slice(0, 200)}` : ""}`
|
|
150571
|
+
);
|
|
150572
|
+
}
|
|
150573
|
+
const result3 = await response2.json();
|
|
150574
|
+
deps.log.info("\u5FEB\u6458\u8981\u751F\u6210\u8D70\u672C\u673A HTTP \u751F\u6210", { sessionID: input.sessionID, route: "http" });
|
|
150575
|
+
return { route: "http", result: result3 };
|
|
150576
|
+
}
|
|
150577
|
+
function withAttemptTimeout(promise3, ms) {
|
|
150578
|
+
return new Promise((resolve3, reject) => {
|
|
150579
|
+
const timer = setTimeout(() => reject(new Error("generate-attempt-timeout")), Math.max(1, ms));
|
|
150580
|
+
timer.unref?.();
|
|
150581
|
+
promise3.then(
|
|
150582
|
+
(value3) => {
|
|
150583
|
+
clearTimeout(timer);
|
|
150584
|
+
resolve3(value3);
|
|
150585
|
+
},
|
|
150586
|
+
(err2) => {
|
|
150587
|
+
clearTimeout(timer);
|
|
150588
|
+
reject(err2);
|
|
150589
|
+
}
|
|
150590
|
+
);
|
|
150591
|
+
});
|
|
150592
|
+
}
|
|
150593
|
+
|
|
149285
150594
|
// src/index.ts
|
|
149286
150595
|
var index_default = plugin_exports.define({
|
|
149287
150596
|
id: "feishu",
|
|
@@ -149344,7 +150653,7 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149344
150653
|
appSecret: config.appSecret,
|
|
149345
150654
|
domain: config.domain === "lark" ? Domain.Lark : Domain.Feishu
|
|
149346
150655
|
});
|
|
149347
|
-
const sender = createFeishuSender(client, log2);
|
|
150656
|
+
const sender = createFeishuSender(client, log2, { cardMaxTables: config.cardMaxTables });
|
|
149348
150657
|
await owner.load().catch((err2) => log2.warn("owner \u8BFB\u53D6\u5931\u8D25", { error: errorMessage(err2) }));
|
|
149349
150658
|
const dedup = new MessageDedup(storage, log2);
|
|
149350
150659
|
const executions = new ExecutionTracker();
|
|
@@ -149353,6 +150662,7 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149353
150662
|
log: log2,
|
|
149354
150663
|
enabled: config.stream,
|
|
149355
150664
|
throttleMs: config.streamThrottleMs,
|
|
150665
|
+
cardMaxTables: config.cardMaxTables,
|
|
149356
150666
|
// 每次 patch 重签强停 token(`stop` 在下方定义,闭包运行时才求值)。
|
|
149357
150667
|
buildStopValue: (sessionID) => stop.buildStopValue(sessionID)
|
|
149358
150668
|
});
|
|
@@ -149380,6 +150690,19 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149380
150690
|
isRunning: (sessionID) => executions.isRunning(sessionID) || runs.hasActive(sessionID),
|
|
149381
150691
|
interrupt: (sessionID, reason) => recovery.interrupt(sessionID, reason)
|
|
149382
150692
|
});
|
|
150693
|
+
const topicStatus = createTopicStatusController({
|
|
150694
|
+
log: log2,
|
|
150695
|
+
enabled: config.topicStatus,
|
|
150696
|
+
statusInTitle: config.topicStatusInTitle,
|
|
150697
|
+
throttleMs: config.topicStatusThrottleMs,
|
|
150698
|
+
getRoot: async (sessionID) => {
|
|
150699
|
+
const link2 = await sessionMap.resolveBySession(sessionID);
|
|
150700
|
+
if (!link2?.rootCard || !link2.replyMessageId) return void 0;
|
|
150701
|
+
return { base: link2.rootCard, messageId: link2.replyMessageId };
|
|
150702
|
+
},
|
|
150703
|
+
patch: (messageId, card) => sender.patchCard(messageId, card),
|
|
150704
|
+
...config.resumeSummary ? { compactToken: (sessionID) => signCompactToken(sessionID, config.signSecret) } : {}
|
|
150705
|
+
});
|
|
149383
150706
|
const formRelay = new FormRelay({
|
|
149384
150707
|
sender,
|
|
149385
150708
|
log: log2,
|
|
@@ -149473,12 +150796,79 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149473
150796
|
async function applyPermissionPreset(sessionID, preset) {
|
|
149474
150797
|
const permissions = presetToRuleset(preset);
|
|
149475
150798
|
await ctx.session.update({ sessionID, permissions });
|
|
149476
|
-
await sessionMap.setSessionMeta(sessionID, {
|
|
150799
|
+
await sessionMap.setSessionMeta(sessionID, {
|
|
150800
|
+
perm: preset,
|
|
150801
|
+
gateMode: presetGateMode(preset),
|
|
150802
|
+
allowActions: void 0
|
|
150803
|
+
});
|
|
149477
150804
|
}
|
|
149478
150805
|
async function moveSessionDir(sessionID, directory) {
|
|
149479
150806
|
await ctx.session.move({ sessionID, directory });
|
|
149480
150807
|
await sessionMap.setSessionMeta(sessionID, { dir: directory });
|
|
149481
150808
|
}
|
|
150809
|
+
async function grantSessionAllow(input) {
|
|
150810
|
+
const link2 = await sessionMap.resolveBySession(input.sessionID);
|
|
150811
|
+
const granted = allowActionsForGrant(input.action);
|
|
150812
|
+
const next = [...link2?.allowActions ?? []];
|
|
150813
|
+
for (const action of granted) if (!next.includes(action)) next.push(action);
|
|
150814
|
+
await sessionMap.setSessionMeta(input.sessionID, { allowActions: next });
|
|
150815
|
+
const serverRules = extractSessionPermissions(await getSessionInfoRaw(input.sessionID, link2?.dir));
|
|
150816
|
+
const base2 = serverRules ?? (link2?.perm ? presetToRuleset(link2.perm) : []);
|
|
150817
|
+
const permissions = appendAllowRules(base2, granted);
|
|
150818
|
+
try {
|
|
150819
|
+
const update2 = ctx.session.update;
|
|
150820
|
+
await update2(
|
|
150821
|
+
{ sessionID: input.sessionID, permissions },
|
|
150822
|
+
link2?.dir ? { headers: { "x-opencode-directory": link2.dir } } : void 0
|
|
150823
|
+
);
|
|
150824
|
+
} catch (err2) {
|
|
150825
|
+
log2.warn("\u4F1A\u8BDD\u7EA7\u6743\u9650\u89C4\u5219\u96C6\u66F4\u65B0\u5931\u8D25\uFF08allowActions \u4ECD\u751F\u6548\uFF09", {
|
|
150826
|
+
sessionID: input.sessionID,
|
|
150827
|
+
action: input.action,
|
|
150828
|
+
error: errorMessage(err2)
|
|
150829
|
+
});
|
|
150830
|
+
}
|
|
150831
|
+
log2.info("\u5DF2\u5728\u672C\u4F1A\u8BDD\u5185\u653E\u884C\u5DE5\u5177", { sessionID: input.sessionID, action: input.action, granted });
|
|
150832
|
+
}
|
|
150833
|
+
const compact2 = new CompactController({
|
|
150834
|
+
log: log2,
|
|
150835
|
+
isAllowed: (openId) => owner.isAllowed(openId),
|
|
150836
|
+
// 与强停同族校验:绑定 sessionID + 用途标签("compact") + TTL + nonce。
|
|
150837
|
+
verify: (token, sessionID) => verifyStop(token, config.signSecret, { expectSessionID: sessionID }),
|
|
150838
|
+
replay: new ReplayGuard(config.approvalTtlMs),
|
|
150839
|
+
compact: (sessionID) => compactSession(ctx, sessionID, sessionMap, log2),
|
|
150840
|
+
readMessages: (sessionID) => readSessionMessages(ctx, sessionID, void 0, log2),
|
|
150841
|
+
patchPending: (sessionID, messageId, token) => patchResumeCompactPendingCard(sessionID, messageId, token, sessionMap, sender, log2),
|
|
150842
|
+
patch: (sessionID, summary, kind, messageId) => patchResumeCompactCard(
|
|
150843
|
+
sessionID,
|
|
150844
|
+
summary,
|
|
150845
|
+
kind,
|
|
150846
|
+
messageId,
|
|
150847
|
+
sessionMap,
|
|
150848
|
+
sender,
|
|
150849
|
+
log2,
|
|
150850
|
+
(sid) => signCompactToken(sid, config.signSecret)
|
|
150851
|
+
),
|
|
150852
|
+
pollIntervalMs: 2e3,
|
|
150853
|
+
timeoutMs: config.resumeCompactTimeoutMs
|
|
150854
|
+
});
|
|
150855
|
+
async function summarizeSessionForResume(input) {
|
|
150856
|
+
const readMessages = async (sessionID, directory) => readSessionMessages(ctx, sessionID, directory, log2);
|
|
150857
|
+
const generateText = async (prompt, directory) => {
|
|
150858
|
+
const api = ctx.generate.text;
|
|
150859
|
+
const outcome = await quickGenerateWithSession(
|
|
150860
|
+
{
|
|
150861
|
+
log: log2,
|
|
150862
|
+
...typeof api === "function" ? {
|
|
150863
|
+
generateText: (p, requestOptions) => api({ prompt: p }, requestOptions)
|
|
150864
|
+
} : {}
|
|
150865
|
+
},
|
|
150866
|
+
{ prompt, sessionID: input.sessionID, ...directory ? { directory } : {} }
|
|
150867
|
+
);
|
|
150868
|
+
return outcome.result;
|
|
150869
|
+
};
|
|
150870
|
+
return summarizeSession({ log: log2, readMessages, generateText }, input);
|
|
150871
|
+
}
|
|
149482
150872
|
async function listAllSessionsRaw() {
|
|
149483
150873
|
const api = ctx.session.list;
|
|
149484
150874
|
if (typeof api !== "function") {
|
|
@@ -149549,7 +150939,13 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149549
150939
|
sessionPageSize: config.sessionPageSize,
|
|
149550
150940
|
threadRouting: config.threadRouting,
|
|
149551
150941
|
listAllSessions: listAllSessionsRaw,
|
|
149552
|
-
getSessionInfo: getSessionInfoRaw
|
|
150942
|
+
getSessionInfo: getSessionInfoRaw,
|
|
150943
|
+
resumeSummary: config.resumeSummary,
|
|
150944
|
+
resumeSummaryTimeoutMs: config.resumeSummaryTimeoutMs,
|
|
150945
|
+
resumeCompactTimeoutMs: config.resumeCompactTimeoutMs,
|
|
150946
|
+
cardMaxTables: config.cardMaxTables,
|
|
150947
|
+
summarizeSession: summarizeSessionForResume,
|
|
150948
|
+
signCompact: (sessionID) => signCompactToken(sessionID, config.signSecret)
|
|
149553
150949
|
});
|
|
149554
150950
|
const approvals = new ApprovalManager({
|
|
149555
150951
|
config,
|
|
@@ -149560,12 +150956,29 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149560
150956
|
sender,
|
|
149561
150957
|
getLink: (sessionID) => sessionMap.resolveBySession(sessionID),
|
|
149562
150958
|
isAllowed: (openId) => owner.isAllowed(openId),
|
|
149563
|
-
reply: (input) => replyPermission(ctx, input)
|
|
150959
|
+
reply: (input) => replyPermission(ctx, input),
|
|
150960
|
+
// 任务 A:审批卡「✅ 本会话内允许该工具」。
|
|
150961
|
+
sessionAllowButton: config.sessionAllowButton,
|
|
150962
|
+
signAllowSession: ({ requestID, sessionID, action }) => signAllowSession(
|
|
150963
|
+
{ requestID, sessionID, action, ttlMs: config.approvalTtlMs },
|
|
150964
|
+
config.signSecret
|
|
150965
|
+
),
|
|
150966
|
+
verifyAllowSession: (token, expect) => verifyAllowSession(token, config.signSecret, {
|
|
150967
|
+
...expect?.sessionID ? { expectSessionID: expect.sessionID } : {},
|
|
150968
|
+
...expect?.action ? { expectAction: expect.action } : {}
|
|
150969
|
+
}),
|
|
150970
|
+
allowSession: (input) => grantSessionAllow(input),
|
|
150971
|
+
hasSessionAllow: ({ sessionID, action }) => {
|
|
150972
|
+
const link2 = sessionMap.getLink(sessionID);
|
|
150973
|
+
const allowed = link2?.allowActions ?? [];
|
|
150974
|
+
return allowActionsForGrant(action).every((a) => allowed.includes(a));
|
|
150975
|
+
}
|
|
149564
150976
|
});
|
|
149565
150977
|
const evaluateRegistration = await ctx.permission.hook("evaluate", async (event) => {
|
|
149566
150978
|
const link2 = await sessionMap.resolveBySession(event.sessionID);
|
|
149567
150979
|
const sessionGate = link2 && link2.gateMode ? { gateMode: link2.gateMode, ...link2.perm ? { askActions: presetAskActions(link2.perm) } : {} } : void 0;
|
|
149568
|
-
const
|
|
150980
|
+
const allowActions = link2?.allowActions && link2.allowActions.length > 0 ? link2.allowActions : void 0;
|
|
150981
|
+
const decision = decideEffectForSession(event.action, config, sessionGate, allowActions);
|
|
149569
150982
|
if (decision.effect === void 0) return;
|
|
149570
150983
|
if (decision.effect === "ask" && !link2) {
|
|
149571
150984
|
log2.debug("\u8DF3\u8FC7 ask\uFF1A\u4F1A\u8BDD\u65E0\u98DE\u4E66\u6620\u5C04", { sessionID: event.sessionID, action: event.action });
|
|
@@ -149603,7 +151016,7 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149603
151016
|
}
|
|
149604
151017
|
const hasThread = Boolean(message.threadId);
|
|
149605
151018
|
let threadLink = hasThread ? await sessionMap.resolveByThread(message.threadId) : void 0;
|
|
149606
|
-
const rootLink =
|
|
151019
|
+
const rootLink = !threadLink && message.rootId ? await sessionMap.resolveByRoot(message.rootId) : void 0;
|
|
149607
151020
|
const decision = decideRoute({
|
|
149608
151021
|
hasThread,
|
|
149609
151022
|
threadKnown: Boolean(threadLink),
|
|
@@ -149619,7 +151032,10 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149619
151032
|
if (!sessionID) return;
|
|
149620
151033
|
const anchor2 = message.rootId ?? message.messageId;
|
|
149621
151034
|
if (decision.source === "root" || threadLink && !threadLink.anchorMessageId) {
|
|
149622
|
-
await
|
|
151035
|
+
const threadId = message.threadId ?? (rootLink ? (await sender.getMessageMeta(message.messageId))?.threadId : void 0);
|
|
151036
|
+
if (threadId) {
|
|
151037
|
+
await sessionMap.bindThread(threadId, sessionID, message.chatId, message.senderOpenId, anchor2);
|
|
151038
|
+
}
|
|
149623
151039
|
}
|
|
149624
151040
|
log2.debug("\u8BDD\u9898\u8DEF\u7531\u547D\u4E2D\u4F1A\u8BDD", { source: decision.source, sessionID, threadId: message.threadId });
|
|
149625
151041
|
if (formRelay.consumeText(sessionID, message.text)) {
|
|
@@ -149675,6 +151091,7 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149675
151091
|
} catch (err2) {
|
|
149676
151092
|
log2.warn("prompt \u53D1\u9001\u5931\u8D25", { sessionID, error: errorMessage(err2) });
|
|
149677
151093
|
runs.apply(sessionID, { type: "execution.failed", error: errorMessage(err2) });
|
|
151094
|
+
topicStatus.markTerminal(sessionID, "failed");
|
|
149678
151095
|
}
|
|
149679
151096
|
}
|
|
149680
151097
|
const gateway = startGateway({
|
|
@@ -149688,6 +151105,7 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149688
151105
|
log: log2,
|
|
149689
151106
|
handleForm: (a) => formRelay.handleCardAction(a),
|
|
149690
151107
|
handleStop: (a) => stop.handleCardAction(a),
|
|
151108
|
+
handleCompact: (a) => compact2.handleCardAction(a),
|
|
149691
151109
|
handleCommands: (a) => commands.handleCardAction(a),
|
|
149692
151110
|
handleApprovals: (a) => approvals.handleCardAction(a)
|
|
149693
151111
|
})
|
|
@@ -149713,7 +151131,8 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149713
151131
|
onFormCreated: (data) => formRelay.onCreated(data),
|
|
149714
151132
|
onFormReplied: (data) => formRelay.onReplied(data),
|
|
149715
151133
|
onFormCancelled: (data) => formRelay.onCancelled(data),
|
|
149716
|
-
notifyFailure: (sessionID, error) => notifyFailure(sessionID, error)
|
|
151134
|
+
notifyFailure: (sessionID, error) => notifyFailure(sessionID, error),
|
|
151135
|
+
onTopicStatus: (event) => topicStatus.onEvent(event)
|
|
149717
151136
|
};
|
|
149718
151137
|
async function handleEvent(event) {
|
|
149719
151138
|
await routeEvent(event, eventDeps);
|
|
@@ -149767,6 +151186,7 @@ async function start(ctx, config, log2, logSink) {
|
|
|
149767
151186
|
await subscription.catch(() => void 0);
|
|
149768
151187
|
runs.dispose();
|
|
149769
151188
|
executions.clear();
|
|
151189
|
+
topicStatus.dispose();
|
|
149770
151190
|
approvals.dispose();
|
|
149771
151191
|
formRelay.dispose();
|
|
149772
151192
|
await evaluateRegistration.dispose().catch((err2) => log2.warn("evaluate hook \u91CA\u653E\u5931\u8D25", { error: errorMessage(err2) }));
|
|
@@ -149869,6 +151289,85 @@ async function promptSession(ctx, sessionID, text, delivery) {
|
|
|
149869
151289
|
const api = ctx.session.prompt;
|
|
149870
151290
|
await api({ sessionID, text, delivery });
|
|
149871
151291
|
}
|
|
151292
|
+
async function readSessionMessages(ctx, sessionID, directory, log2) {
|
|
151293
|
+
const options2 = directory ? { headers: { "x-opencode-directory": directory } } : void 0;
|
|
151294
|
+
const session = ctx.session;
|
|
151295
|
+
const messageApi = ctx.message;
|
|
151296
|
+
const sessionMessageApi = session.message;
|
|
151297
|
+
for (const api of [sessionMessageApi, messageApi]) {
|
|
151298
|
+
if (typeof api?.list === "function") {
|
|
151299
|
+
try {
|
|
151300
|
+
const raw = await api.list({ sessionID, limit: 200 }, options2);
|
|
151301
|
+
if (raw !== void 0) return raw;
|
|
151302
|
+
} catch (err2) {
|
|
151303
|
+
log2.debug("session.message.list \u8BFB\u53D6\u5931\u8D25\uFF0C\u7EE7\u7EED\u56DE\u9000", { sessionID, error: errorMessage(err2) });
|
|
151304
|
+
}
|
|
151305
|
+
}
|
|
151306
|
+
}
|
|
151307
|
+
try {
|
|
151308
|
+
return await fetchSessionMessagesHttp(sessionID, directory, { log: log2 });
|
|
151309
|
+
} catch (err2) {
|
|
151310
|
+
log2.debug("HTTP \u8BFB\u53D6\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25\uFF0C\u56DE\u9000 session.context", { sessionID, error: errorMessage(err2) });
|
|
151311
|
+
}
|
|
151312
|
+
if (typeof session.context === "function") {
|
|
151313
|
+
return session.context({ sessionID }, options2);
|
|
151314
|
+
}
|
|
151315
|
+
return void 0;
|
|
151316
|
+
}
|
|
151317
|
+
async function compactSession(ctx, sessionID, sessionMap, log2) {
|
|
151318
|
+
const api = ctx.session.compact;
|
|
151319
|
+
const link2 = await sessionMap.resolveBySession(sessionID);
|
|
151320
|
+
const options2 = link2?.dir ? { headers: { "x-opencode-directory": link2.dir } } : void 0;
|
|
151321
|
+
if (typeof api === "function") {
|
|
151322
|
+
await api({ sessionID }, options2);
|
|
151323
|
+
return;
|
|
151324
|
+
}
|
|
151325
|
+
await compactSessionHttp(sessionID, link2?.dir, { log: log2 });
|
|
151326
|
+
}
|
|
151327
|
+
async function patchResumeCompactPendingCard(sessionID, messageId, token, sessionMap, sender, log2) {
|
|
151328
|
+
const link2 = await sessionMap.resolveBySession(sessionID);
|
|
151329
|
+
const entry = link2 ? await sessionMap.getSession(link2.chatId, sessionID) : void 0;
|
|
151330
|
+
const base2 = await sessionMap.getRootCard(sessionID);
|
|
151331
|
+
if (base2) await sessionMap.setRootCard(sessionID, { ...base2, compactPending: true, compactError: void 0 });
|
|
151332
|
+
const card = buildResumeCompactPendingCard(entry?.title ?? "", sessionID, token, Date.now());
|
|
151333
|
+
const res = await sender.patchCard(messageId, card);
|
|
151334
|
+
if (!res.ok) log2.warn("\u538B\u7F29\u4E2D\u5361\u7247\u66F4\u65B0\u5931\u8D25", { sessionID, error: res.error ?? "unknown" });
|
|
151335
|
+
}
|
|
151336
|
+
async function patchResumeCompactCard(sessionID, summary, kind, messageId, sessionMap, sender, log2, signCompact) {
|
|
151337
|
+
const link2 = await sessionMap.resolveBySession(sessionID);
|
|
151338
|
+
const entry = link2 ? await sessionMap.getSession(link2.chatId, sessionID) : void 0;
|
|
151339
|
+
const base2 = await sessionMap.getRootCard(sessionID);
|
|
151340
|
+
if (base2) {
|
|
151341
|
+
await sessionMap.setRootCard(
|
|
151342
|
+
sessionID,
|
|
151343
|
+
kind === "completed" ? { ...base2, compactPending: false, compactError: void 0, summary, summaryLabel: "\u5DF2\u538B\u7F29 \xB7 \u4F1A\u8BDD\u6458\u8981" } : { ...base2, compactPending: false, compactError: summary }
|
|
151344
|
+
);
|
|
151345
|
+
}
|
|
151346
|
+
const card = kind === "completed" ? buildSessionOpenedCard({
|
|
151347
|
+
title: entry?.title ?? "",
|
|
151348
|
+
sessionID,
|
|
151349
|
+
...link2?.dir ? { dir: link2.dir } : {},
|
|
151350
|
+
summary,
|
|
151351
|
+
summaryLabel: "\u5DF2\u538B\u7F29 \xB7 \u4F1A\u8BDD\u6458\u8981",
|
|
151352
|
+
compactButton: { sessionID, token: signCompact(sessionID) }
|
|
151353
|
+
}) : buildSessionOpenedCard({
|
|
151354
|
+
title: entry?.title ?? "",
|
|
151355
|
+
sessionID,
|
|
151356
|
+
...link2?.dir ? { dir: link2.dir } : {},
|
|
151357
|
+
compactError: summary,
|
|
151358
|
+
compactButton: { sessionID, token: signCompact(sessionID) }
|
|
151359
|
+
});
|
|
151360
|
+
const target = messageId || link2?.replyMessageId;
|
|
151361
|
+
if (!target) {
|
|
151362
|
+
log2.warn("\u538B\u7F29\u7ED3\u679C patch \u8DF3\u8FC7\uFF1A\u65E0\u5361\u7247\u6D88\u606F id", { sessionID });
|
|
151363
|
+
return;
|
|
151364
|
+
}
|
|
151365
|
+
const res = await sender.patchCard(target, card);
|
|
151366
|
+
if (!res.ok) log2.warn("\u538B\u7F29\u7ED3\u679C\u5361\u7247\u66F4\u65B0\u5931\u8D25", { sessionID, error: res.error ?? "unknown" });
|
|
151367
|
+
}
|
|
151368
|
+
function signCompactToken(sessionID, secret) {
|
|
151369
|
+
return signStop({ sessionID, ttlMs: 24 * 60 * 60 * 1e3 }, secret);
|
|
151370
|
+
}
|
|
149872
151371
|
/*! Bundled license information:
|
|
149873
151372
|
|
|
149874
151373
|
mime-db/index.js:
|