opencode-feishu-plugin 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +111 -458
- package/README.md +78 -268
- package/dist/index.js +106 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -145598,7 +145598,8 @@ function parseRootCard(value3) {
|
|
|
145598
145598
|
...value3.compactPending === true ? { compactPending: true } : {},
|
|
145599
145599
|
...compactError ? { compactError } : {},
|
|
145600
145600
|
...value3.compactButton === true ? { compactButton: true } : {},
|
|
145601
|
-
...note2 ? { note: note2 } : {}
|
|
145601
|
+
...note2 ? { note: note2 } : {},
|
|
145602
|
+
...value3.openedTopic === true ? { openedTopic: true } : {}
|
|
145602
145603
|
};
|
|
145603
145604
|
}
|
|
145604
145605
|
function parseStringArray(value3) {
|
|
@@ -148083,7 +148084,10 @@ function renderResumedBody(title, base2, now3) {
|
|
|
148083
148084
|
setup.push(`- \u6700\u8FD1\u6D3B\u52A8\uFF1A${relativeTime(base2.updatedAt, now3)}`);
|
|
148084
148085
|
}
|
|
148085
148086
|
if (setup.length > 0) lines.push("", ...setup);
|
|
148086
|
-
lines.push(
|
|
148087
|
+
lines.push(
|
|
148088
|
+
"",
|
|
148089
|
+
base2.openedTopic ? "\u2705 **\u8BDD\u9898\u5DF2\u6253\u5F00**\uFF1A\u76F4\u63A5\u5728\u672C\u8BDD\u9898\u5185\u56DE\u590D\u5373\u53EF\u7EE7\u7EED\u8FD9\u4E2A\u5386\u53F2\u4F1A\u8BDD\u3002" : "**\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"
|
|
148090
|
+
);
|
|
148087
148091
|
if (base2.summary || base2.summaryPending || base2.compactPending || base2.compactError) {
|
|
148088
148092
|
lines.push("", `**${base2.summaryLabel ?? "\u6458\u8981"}**\uFF1A`);
|
|
148089
148093
|
if (base2.summaryPending) lines.push("\u23F3 \u6B63\u5728\u603B\u7ED3\u8BE5\u4F1A\u8BDD\u2026");
|
|
@@ -148122,7 +148126,8 @@ function buildSessionOpenedCard(input) {
|
|
|
148122
148126
|
...input.summaryPending ? { summaryPending: true } : {},
|
|
148123
148127
|
...input.compactPending ? { compactPending: true } : {},
|
|
148124
148128
|
...input.compactError ? { compactError: input.compactError } : {},
|
|
148125
|
-
...input.compactButton ? { compactButton: true } : {}
|
|
148129
|
+
...input.compactButton ? { compactButton: true } : {},
|
|
148130
|
+
...input.openedTopic ? { openedTopic: true } : {}
|
|
148126
148131
|
};
|
|
148127
148132
|
return buildSessionRootCard(base2, void 0, {
|
|
148128
148133
|
now: input.now ?? Date.now(),
|
|
@@ -150046,21 +150051,20 @@ async function enterSessionThread(ctx, input) {
|
|
|
150046
150051
|
const onLimit = (report) => {
|
|
150047
150052
|
ctx.deps.log.warn("\u4F1A\u8BDD\u6062\u590D\u5361\u5185\u5BB9\u8D85\u9650\uFF0C\u5DF2\u964D\u7EA7", { sessionID, ...report });
|
|
150048
150053
|
};
|
|
150049
|
-
const
|
|
150054
|
+
const newNow = ctx.now();
|
|
150055
|
+
const baseInput = {
|
|
150050
150056
|
title: info?.title ?? "",
|
|
150051
150057
|
sessionID,
|
|
150052
150058
|
...dir ? { dir } : {},
|
|
150053
150059
|
...link2?.model ? { model: modelLabel(link2.model) } : {},
|
|
150054
150060
|
...info?.updatedAt ? { updatedAt: info.updatedAt } : {},
|
|
150055
|
-
now:
|
|
150061
|
+
now: newNow,
|
|
150056
150062
|
...ctx.deps.cardMaxTables !== void 0 ? { maxTables: ctx.deps.cardMaxTables } : {},
|
|
150057
150063
|
onLimit,
|
|
150058
|
-
|
|
150059
|
-
// 「🗜 压缩并总结」只在开关开启且运行时装配了签名时渲染。
|
|
150060
|
-
...showSummary && ctx.deps.signCompact ? { compactButton: { sessionID, token: ctx.deps.signCompact(sessionID) } } : {}
|
|
150064
|
+
openedTopic: true
|
|
150061
150065
|
};
|
|
150062
|
-
const
|
|
150063
|
-
const res = await ctx.deps.sender.sendCard(chatId,
|
|
150066
|
+
const rootCard = buildSessionOpenedCard(baseInput);
|
|
150067
|
+
const res = await ctx.deps.sender.sendCard(chatId, rootCard);
|
|
150064
150068
|
ctx.deps.log.info("\u53D1\u9001\u4F1A\u8BDD\u6062\u590D\u5361", {
|
|
150065
150069
|
sessionID,
|
|
150066
150070
|
source: input.source,
|
|
@@ -150082,26 +150086,63 @@ async function enterSessionThread(ctx, input) {
|
|
|
150082
150086
|
}
|
|
150083
150087
|
await ctx.deps.sessionMap.bindRoot(res.messageId, sessionID);
|
|
150084
150088
|
ctx.deps.log.info("resume card bound root to session", { sessionID, rootId: res.messageId });
|
|
150085
|
-
|
|
150089
|
+
const summaryBlock = {
|
|
150090
|
+
...showSummary ? { summaryPending: true } : {},
|
|
150091
|
+
...showSummary && ctx.deps.signCompact ? { compactButton: { sessionID, token: ctx.deps.signCompact(sessionID) } } : {}
|
|
150092
|
+
};
|
|
150093
|
+
const openerInput = { ...baseInput, ...summaryBlock };
|
|
150094
|
+
const openerRes = await ctx.deps.sender.replyCard(res.messageId, buildSessionOpenedCard(openerInput), {
|
|
150095
|
+
replyInThread: true
|
|
150096
|
+
});
|
|
150097
|
+
const openerMessageId = openerRes.ok ? openerRes.messageId : void 0;
|
|
150098
|
+
let threadId = openerRes.threadId;
|
|
150099
|
+
if (!threadId && openerMessageId) {
|
|
150100
|
+
threadId = (await ctx.deps.sender.getMessageMeta(openerMessageId))?.threadId;
|
|
150101
|
+
}
|
|
150102
|
+
const rootCardBase = {
|
|
150086
150103
|
style: "resumed",
|
|
150087
150104
|
sessionID,
|
|
150088
150105
|
title: info?.title ?? "",
|
|
150089
150106
|
...dir ? { dir } : {},
|
|
150090
150107
|
...link2?.model ? { model: modelLabel(link2.model) } : {},
|
|
150091
|
-
...info?.updatedAt ? { updatedAt: info.updatedAt } : {}
|
|
150092
|
-
|
|
150108
|
+
...info?.updatedAt ? { updatedAt: info.updatedAt } : {}
|
|
150109
|
+
};
|
|
150110
|
+
if (threadId) {
|
|
150111
|
+
await ctx.deps.sessionMap.bindThread(threadId, sessionID, chatId, operatorOpenId, res.messageId);
|
|
150112
|
+
ctx.deps.log.info("\u6062\u590D\u4F1A\u8BDD\u5DF2\u81EA\u52A8\u5F00\u8BDD\u9898", {
|
|
150113
|
+
sessionID,
|
|
150114
|
+
threadId,
|
|
150115
|
+
rootMessageId: res.messageId,
|
|
150116
|
+
openerMessageId
|
|
150117
|
+
});
|
|
150118
|
+
await ctx.deps.sessionMap.setRootCard(sessionID, { ...rootCardBase, openedTopic: true });
|
|
150119
|
+
if (showSummary && openerMessageId) {
|
|
150120
|
+
void patchResumeSummary(ctx, sessionID, dir, openerMessageId, openerInput, false);
|
|
150121
|
+
}
|
|
150122
|
+
return { ok: true, threadId, messageId: res.messageId };
|
|
150123
|
+
}
|
|
150124
|
+
ctx.deps.log.warn("\u6062\u590D\u4F1A\u8BDD\u81EA\u52A8\u5F00\u8BDD\u9898\u5931\u8D25\uFF0C\u56DE\u9000\u4E3A\u56DE\u590D\u6839\u5361", {
|
|
150125
|
+
sessionID,
|
|
150126
|
+
openError: openerRes.error ?? "unknown"
|
|
150127
|
+
});
|
|
150128
|
+
const fallbackInput = { ...baseInput, openedTopic: false, ...summaryBlock };
|
|
150129
|
+
await ctx.deps.sender.patchCard(res.messageId, buildSessionOpenedCard(fallbackInput));
|
|
150130
|
+
await ctx.deps.sessionMap.setRootCard(sessionID, {
|
|
150131
|
+
...rootCardBase,
|
|
150132
|
+
...showSummary ? { summaryPending: true, compactButton: Boolean(fallbackInput.compactButton) } : {}
|
|
150093
150133
|
});
|
|
150094
150134
|
if (showSummary) {
|
|
150095
|
-
void patchResumeSummary(ctx, sessionID, dir, res.messageId,
|
|
150135
|
+
void patchResumeSummary(ctx, sessionID, dir, res.messageId, fallbackInput, true);
|
|
150096
150136
|
}
|
|
150097
150137
|
return { ok: true, messageId: res.messageId };
|
|
150098
150138
|
}
|
|
150099
150139
|
var SUMMARY_LABEL = {
|
|
150100
150140
|
reused: "\u4F1A\u8BDD\u6458\u8981",
|
|
150101
150141
|
generated: "\u6458\u8981\uFF08\u5FEB\u6458\u8981\uFF09",
|
|
150142
|
+
excerpt: "\u6700\u8FD1\u4F1A\u8BDD\u8BB0\u5F55\uFF08\u622A\u53D6\u6458\u8981\uFF09",
|
|
150102
150143
|
compacted: "\u5DF2\u538B\u7F29 \xB7 \u4F1A\u8BDD\u6458\u8981"
|
|
150103
150144
|
};
|
|
150104
|
-
async function patchResumeSummary(ctx, sessionID, dir, messageId, cardInput) {
|
|
150145
|
+
async function patchResumeSummary(ctx, sessionID, dir, messageId, cardInput, persistBase) {
|
|
150105
150146
|
try {
|
|
150106
150147
|
const outcome = await ctx.deps.summarizeSession({
|
|
150107
150148
|
sessionID,
|
|
@@ -150110,9 +150151,11 @@ async function patchResumeSummary(ctx, sessionID, dir, messageId, cardInput) {
|
|
|
150110
150151
|
});
|
|
150111
150152
|
const summary = outcome.summary ?? "\uFF08\u6458\u8981\u751F\u6210\u5931\u8D25\uFF0C\u53EF\u76F4\u63A5\u53D1\u6D88\u606F\u7EE7\u7EED\uFF09";
|
|
150112
150153
|
const summaryLabel = SUMMARY_LABEL[outcome.source] ?? "\u6458\u8981";
|
|
150113
|
-
|
|
150114
|
-
|
|
150115
|
-
|
|
150154
|
+
if (persistBase) {
|
|
150155
|
+
const base2 = await ctx.deps.sessionMap.getRootCard(sessionID);
|
|
150156
|
+
if (base2) {
|
|
150157
|
+
await ctx.deps.sessionMap.setRootCard(sessionID, { ...base2, summaryPending: false, summary, summaryLabel });
|
|
150158
|
+
}
|
|
150116
150159
|
}
|
|
150117
150160
|
const res = await ctx.deps.sender.patchCard(
|
|
150118
150161
|
messageId,
|
|
@@ -150752,6 +150795,20 @@ function buildSummaryPrompt(transcript) {
|
|
|
150752
150795
|
\u4F1A\u8BDD\u6700\u8FD1\u8BB0\u5F55\uFF1A
|
|
150753
150796
|
${transcript}` : RESUME_SUMMARY_PROMPT;
|
|
150754
150797
|
}
|
|
150798
|
+
function buildExcerptSummary(transcript, maxLines = 5, maxChars = 900) {
|
|
150799
|
+
if (!transcript) return void 0;
|
|
150800
|
+
const lines = transcript.split("\n").filter(Boolean);
|
|
150801
|
+
if (lines.length === 0) return void 0;
|
|
150802
|
+
const out = [];
|
|
150803
|
+
let bytes = 0;
|
|
150804
|
+
for (const line of lines) {
|
|
150805
|
+
const size6 = Buffer.byteLength(line, "utf8");
|
|
150806
|
+
if (out.length >= maxLines || bytes + size6 > maxChars) break;
|
|
150807
|
+
out.push(line);
|
|
150808
|
+
bytes += size6;
|
|
150809
|
+
}
|
|
150810
|
+
return out.length > 0 ? out.join("\n") : void 0;
|
|
150811
|
+
}
|
|
150755
150812
|
async function summarizeSession(deps, input) {
|
|
150756
150813
|
const timeoutMs = Math.max(1, Math.floor(input.timeoutMs));
|
|
150757
150814
|
let messages;
|
|
@@ -150776,6 +150833,8 @@ async function summarizeSession(deps, input) {
|
|
|
150776
150833
|
);
|
|
150777
150834
|
const generated = extractGeneratedText(raw);
|
|
150778
150835
|
if (generated) return { summary: generated, source: "generated" };
|
|
150836
|
+
const excerpt = buildExcerptSummary(transcript);
|
|
150837
|
+
if (excerpt) return { summary: excerpt, source: "excerpt" };
|
|
150779
150838
|
return { source: "none", error: "empty-summary" };
|
|
150780
150839
|
} catch (err2) {
|
|
150781
150840
|
const error = errorMessage(err2);
|
|
@@ -150784,6 +150843,11 @@ async function summarizeSession(deps, input) {
|
|
|
150784
150843
|
timedOut: err2 instanceof SummaryTimeoutError,
|
|
150785
150844
|
error
|
|
150786
150845
|
});
|
|
150846
|
+
try {
|
|
150847
|
+
const excerpt = buildExcerptSummary(buildTranscript(messages));
|
|
150848
|
+
if (excerpt) return { summary: excerpt, source: "excerpt" };
|
|
150849
|
+
} catch {
|
|
150850
|
+
}
|
|
150787
150851
|
return { source: "none", error };
|
|
150788
150852
|
}
|
|
150789
150853
|
}
|
|
@@ -151788,13 +151852,32 @@ async function start(ctx, config, log2, logSink) {
|
|
|
151788
151852
|
})
|
|
151789
151853
|
});
|
|
151790
151854
|
const abort = new AbortController();
|
|
151855
|
+
const EVENT_RETRY_BASE_MS = 1e3;
|
|
151856
|
+
const EVENT_RETRY_MAX_MS = 3e4;
|
|
151857
|
+
const sleep3 = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
151791
151858
|
const subscription = (async () => {
|
|
151792
|
-
|
|
151793
|
-
|
|
151794
|
-
|
|
151859
|
+
let attempt = 0;
|
|
151860
|
+
while (!abort.signal.aborted) {
|
|
151861
|
+
try {
|
|
151862
|
+
for await (const event of ctx.event.subscribe({ signal: abort.signal })) {
|
|
151863
|
+
if (attempt > 0) {
|
|
151864
|
+
log2.info("\u4E8B\u4EF6\u8BA2\u9605\u5DF2\u91CD\u8FDE", { attempt });
|
|
151865
|
+
}
|
|
151866
|
+
attempt = 0;
|
|
151867
|
+
await handleEvent(event);
|
|
151868
|
+
}
|
|
151869
|
+
if (abort.signal.aborted) break;
|
|
151870
|
+
attempt += 1;
|
|
151871
|
+
const delay3 = Math.min(EVENT_RETRY_MAX_MS, EVENT_RETRY_BASE_MS * 2 ** Math.min(attempt, 5));
|
|
151872
|
+
log2.warn("\u4E8B\u4EF6\u8BA2\u9605\u6D41\u5DF2\u7ED3\u675F\uFF0C\u51C6\u5907\u91CD\u8FDE", { attempt, delayMs: delay3 });
|
|
151873
|
+
await sleep3(delay3);
|
|
151874
|
+
} catch (err2) {
|
|
151875
|
+
if (abort.signal.aborted) break;
|
|
151876
|
+
attempt += 1;
|
|
151877
|
+
const delay3 = Math.min(EVENT_RETRY_MAX_MS, EVENT_RETRY_BASE_MS * 2 ** Math.min(attempt, 5));
|
|
151878
|
+
log2.error("\u4E8B\u4EF6\u8BA2\u9605\u5F02\u5E38\uFF0C\u51C6\u5907\u91CD\u8FDE", { attempt, delayMs: delay3, error: errorMessage(err2) });
|
|
151879
|
+
await sleep3(delay3);
|
|
151795
151880
|
}
|
|
151796
|
-
} catch (err2) {
|
|
151797
|
-
if (!abort.signal.aborted) log2.error("\u4E8B\u4EF6\u8BA2\u9605\u5F02\u5E38\u9000\u51FA", { error: errorMessage(err2) });
|
|
151798
151881
|
}
|
|
151799
151882
|
})();
|
|
151800
151883
|
const eventDeps = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-feishu-plugin",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Feishu/Lark plugin for OpenCode V2 — single-user topics as sessions, in-card permission approvals, streaming cards. Minimal permissions, no public endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|