@ycodium-ai/plugin-im 0.2.2526 → 0.2.2544
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.md +20 -2
- package/dist/index.js +1065 -161
- package/locales/en.json +178 -0
- package/locales/zh-CN.json +178 -0
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -8846,7 +8846,7 @@ var require_mime_types = __commonJS({
|
|
|
8846
8846
|
exports.contentType = contentType;
|
|
8847
8847
|
exports.extension = extension;
|
|
8848
8848
|
exports.extensions = /* @__PURE__ */ Object.create(null);
|
|
8849
|
-
exports.lookup =
|
|
8849
|
+
exports.lookup = lookup2;
|
|
8850
8850
|
exports.types = /* @__PURE__ */ Object.create(null);
|
|
8851
8851
|
populateMaps(exports.extensions, exports.types);
|
|
8852
8852
|
function charset(type) {
|
|
@@ -8888,7 +8888,7 @@ var require_mime_types = __commonJS({
|
|
|
8888
8888
|
}
|
|
8889
8889
|
return exts[0];
|
|
8890
8890
|
}
|
|
8891
|
-
function
|
|
8891
|
+
function lookup2(path) {
|
|
8892
8892
|
if (!path || typeof path !== "string") {
|
|
8893
8893
|
return false;
|
|
8894
8894
|
}
|
|
@@ -15097,12 +15097,12 @@ var require_axios = __commonJS({
|
|
|
15097
15097
|
family
|
|
15098
15098
|
});
|
|
15099
15099
|
var normalizedLookupCache = /* @__PURE__ */ new WeakMap();
|
|
15100
|
-
var normalizeLookup = (
|
|
15101
|
-
let normalized = normalizedLookupCache.get(
|
|
15100
|
+
var normalizeLookup = (lookup2) => {
|
|
15101
|
+
let normalized = normalizedLookupCache.get(lookup2);
|
|
15102
15102
|
if (normalized) {
|
|
15103
15103
|
return normalized;
|
|
15104
15104
|
}
|
|
15105
|
-
const callbackLookup = callbackify(
|
|
15105
|
+
const callbackLookup = callbackify(lookup2, (value) => utils$1.isArray(value) ? value : [value]);
|
|
15106
15106
|
normalized = (hostname, opt, cb) => {
|
|
15107
15107
|
callbackLookup(hostname, opt, (err, arg0, arg1) => {
|
|
15108
15108
|
if (err) {
|
|
@@ -15117,7 +15117,7 @@ var require_axios = __commonJS({
|
|
|
15117
15117
|
opt.all ? cb(err, addresses) : cb(err, addresses[0].address, addresses[0].family);
|
|
15118
15118
|
});
|
|
15119
15119
|
};
|
|
15120
|
-
normalizedLookupCache.set(
|
|
15120
|
+
normalizedLookupCache.set(lookup2, normalized);
|
|
15121
15121
|
return normalized;
|
|
15122
15122
|
};
|
|
15123
15123
|
var http2Transport = {
|
|
@@ -15160,7 +15160,7 @@ var require_axios = __commonJS({
|
|
|
15160
15160
|
const own2 = (key) => utils$1.getSafeProp(config, key);
|
|
15161
15161
|
const transitional = own2("transitional") || transitionalDefaults;
|
|
15162
15162
|
let data = own2("data");
|
|
15163
|
-
let
|
|
15163
|
+
let lookup2 = own2("lookup");
|
|
15164
15164
|
let family = own2("family");
|
|
15165
15165
|
let httpVersion = own2("httpVersion");
|
|
15166
15166
|
if (httpVersion === void 0) httpVersion = 1;
|
|
@@ -15193,8 +15193,8 @@ var require_axios = __commonJS({
|
|
|
15193
15193
|
throw new AxiosError(`Unsupported protocol version '${httpVersion}'`, AxiosError.ERR_BAD_OPTION_VALUE, config);
|
|
15194
15194
|
}
|
|
15195
15195
|
const isHttp2 = httpVersion === 2;
|
|
15196
|
-
if (
|
|
15197
|
-
|
|
15196
|
+
if (lookup2) {
|
|
15197
|
+
lookup2 = normalizeLookup(lookup2);
|
|
15198
15198
|
}
|
|
15199
15199
|
const abortEmitter = new events.EventEmitter();
|
|
15200
15200
|
function abort(reason) {
|
|
@@ -15387,9 +15387,9 @@ var require_axios = __commonJS({
|
|
|
15387
15387
|
}));
|
|
15388
15388
|
}
|
|
15389
15389
|
headers.set("Accept-Encoding", utils$1.hasOwnProp(transitional, "advertiseZstdAcceptEncoding") && transitional.advertiseZstdAcceptEncoding === true ? ACCEPT_ENCODING_WITH_ZSTD : ACCEPT_ENCODING, false);
|
|
15390
|
-
if (isHttp2 &&
|
|
15390
|
+
if (isHttp2 && lookup2) {
|
|
15391
15391
|
http2Options = Object.assign(/* @__PURE__ */ Object.create(null), http2Options, {
|
|
15392
|
-
lookup
|
|
15392
|
+
lookup: lookup2
|
|
15393
15393
|
});
|
|
15394
15394
|
}
|
|
15395
15395
|
const options = Object.assign(/* @__PURE__ */ Object.create(null), {
|
|
@@ -15408,7 +15408,7 @@ var require_axios = __commonJS({
|
|
|
15408
15408
|
http2Options,
|
|
15409
15409
|
createConnection: void 0
|
|
15410
15410
|
});
|
|
15411
|
-
!utils$1.isUndefined(
|
|
15411
|
+
!utils$1.isUndefined(lookup2) && (options.lookup = lookup2);
|
|
15412
15412
|
let proxyApplied = false;
|
|
15413
15413
|
if (socketPath) {
|
|
15414
15414
|
if (typeof socketPath !== "string") {
|
|
@@ -123492,11 +123492,11 @@ var require_lib2 = __commonJS({
|
|
|
123492
123492
|
const AgentClass = url.startsWith("https:") ? https__default["default"].Agent : http__default["default"].Agent;
|
|
123493
123493
|
const agent = new AgentClass();
|
|
123494
123494
|
const family = pinnedIp.includes(":") ? 6 : 4;
|
|
123495
|
-
const
|
|
123495
|
+
const lookup2 = (_hostname, _opts, cb) => {
|
|
123496
123496
|
cb(null, pinnedIp, family);
|
|
123497
123497
|
};
|
|
123498
123498
|
const origCreateConnection = agent.createConnection.bind(agent);
|
|
123499
|
-
agent.createConnection = (opts, cb) => origCreateConnection(Object.assign(Object.assign({}, opts), { lookup }), cb);
|
|
123499
|
+
agent.createConnection = (opts, cb) => origCreateConnection(Object.assign(Object.assign({}, opts), { lookup: lookup2 }), cb);
|
|
123500
123500
|
return agent;
|
|
123501
123501
|
}
|
|
123502
123502
|
function composeMentionsTextPrefix(mentions) {
|
|
@@ -125927,13 +125927,41 @@ var teamArgument = (text, chinese) => {
|
|
|
125927
125927
|
const alias = text.match(/^换团队(?:\s+([\s\S]*))?$/);
|
|
125928
125928
|
return alias ? (alias[1] ?? "").trim() : void 0;
|
|
125929
125929
|
};
|
|
125930
|
+
var resumeArgument = (text, chinese) => {
|
|
125931
|
+
const match = text.match(/^\/resume(?:\s+([\s\S]*))?$/i);
|
|
125932
|
+
if (match) return (match[1] ?? "").trim();
|
|
125933
|
+
if (!chinese) return void 0;
|
|
125934
|
+
const alias = text.match(/^切换会话(?:\s+([\s\S]*))?$/);
|
|
125935
|
+
return alias ? (alias[1] ?? "").trim() : void 0;
|
|
125936
|
+
};
|
|
125937
|
+
var modelArgument = (text, chinese) => {
|
|
125938
|
+
const match = text.match(/^\/model(?:\s+([\s\S]*))?$/i);
|
|
125939
|
+
if (match) return (match[1] ?? "").trim();
|
|
125940
|
+
if (!chinese) return void 0;
|
|
125941
|
+
const alias = text.match(/^换模型(?:\s+([\s\S]*))?$/);
|
|
125942
|
+
return alias ? (alias[1] ?? "").trim() : void 0;
|
|
125943
|
+
};
|
|
125944
|
+
var planArgument = (text, chinese) => {
|
|
125945
|
+
const match = text.match(/^\/plan(?:\s+([\s\S]*))?$/i);
|
|
125946
|
+
if (match) return (match[1] ?? "").trim().toLowerCase();
|
|
125947
|
+
if (!chinese) return void 0;
|
|
125948
|
+
const alias = text.match(/^计划模式(?:\s+([\s\S]*))?$/);
|
|
125949
|
+
return alias ? (alias[1] ?? "").trim().toLowerCase() : void 0;
|
|
125950
|
+
};
|
|
125951
|
+
var planModeOf = (argument, chinese) => {
|
|
125952
|
+
if (argument === "") return "toggle";
|
|
125953
|
+
if (argument === "on" || chinese && argument === "\u5F00") return "on";
|
|
125954
|
+
if (argument === "off" || chinese && argument === "\u5173") return "off";
|
|
125955
|
+
return "invalid";
|
|
125956
|
+
};
|
|
125930
125957
|
var isThreadCommand = (text, chinese) => /^\/thread$/i.test(text.trim()) || chinese && text.trim() === "\u6362\u5BF9\u8BDD";
|
|
125931
125958
|
var ZH_ALIASES = {
|
|
125932
125959
|
\u505C: "stop",
|
|
125933
125960
|
\u505C\u6B62: "stop",
|
|
125934
125961
|
\u72B6\u6001: "status",
|
|
125935
125962
|
\u65B0\u5BF9\u8BDD: "new",
|
|
125936
|
-
\u5E2E\u52A9: "help"
|
|
125963
|
+
\u5E2E\u52A9: "help",
|
|
125964
|
+
\u4F1A\u8BDD\u5217\u8868: "sessions"
|
|
125937
125965
|
};
|
|
125938
125966
|
var resolveTeam = (query, teams) => {
|
|
125939
125967
|
const byId = teams.find((team) => team.teamId === query);
|
|
@@ -125950,6 +125978,15 @@ var parseChatCommand = (input) => {
|
|
|
125950
125978
|
if (/^\/status$/i.test(trimmed)) return { kind: "status" };
|
|
125951
125979
|
if (/^\/new$/i.test(trimmed)) return { kind: "new" };
|
|
125952
125980
|
if (/^\/help$/i.test(trimmed)) return { kind: "help" };
|
|
125981
|
+
if (/^\/sessions$/i.test(trimmed)) return { kind: "sessions" };
|
|
125982
|
+
const resume = resumeArgument(input.text, input.chinese);
|
|
125983
|
+
if (resume !== void 0) {
|
|
125984
|
+
return resume === "" ? { kind: "sessions" } : { kind: "resume", arg: resume };
|
|
125985
|
+
}
|
|
125986
|
+
const model = modelArgument(input.text, input.chinese);
|
|
125987
|
+
if (model !== void 0) return { kind: "model", arg: model };
|
|
125988
|
+
const plan = planArgument(input.text, input.chinese);
|
|
125989
|
+
if (plan !== void 0) return { kind: "plan", mode: planModeOf(plan, input.chinese) };
|
|
125953
125990
|
const query = teamArgument(input.text, input.chinese);
|
|
125954
125991
|
if (query !== void 0) {
|
|
125955
125992
|
if (input.teams.length === 0) return { kind: "noTeams" };
|
|
@@ -125965,19 +126002,157 @@ var parseChatCommand = (input) => {
|
|
|
125965
126002
|
}
|
|
125966
126003
|
return { kind: "message" };
|
|
125967
126004
|
};
|
|
125968
|
-
var helpText = () => [
|
|
125969
|
-
"
|
|
125970
|
-
"
|
|
125971
|
-
"
|
|
125972
|
-
"
|
|
125973
|
-
"
|
|
125974
|
-
"
|
|
125975
|
-
"
|
|
126005
|
+
var helpText = (t) => [
|
|
126006
|
+
t("help.title"),
|
|
126007
|
+
t("help.stop"),
|
|
126008
|
+
t("help.status"),
|
|
126009
|
+
t("help.new"),
|
|
126010
|
+
t("help.sessions"),
|
|
126011
|
+
t("help.resume"),
|
|
126012
|
+
t("help.model"),
|
|
126013
|
+
t("help.plan"),
|
|
126014
|
+
t("help.team"),
|
|
126015
|
+
t("help.thread"),
|
|
126016
|
+
t("help.aliases")
|
|
125976
126017
|
].join("\n");
|
|
125977
|
-
var describeTargets = (target, teams) => {
|
|
125978
|
-
const current = target.kind === "thread" ? "
|
|
125979
|
-
|
|
125980
|
-
|
|
126018
|
+
var describeTargets = (target, teams, t) => {
|
|
126019
|
+
const current = target.kind === "thread" ? t("targets.currentThread") : t("targets.currentTeam", {
|
|
126020
|
+
title: teams.find((team) => team.teamId === target.teamId)?.title ?? target.teamId
|
|
126021
|
+
});
|
|
126022
|
+
const list = teams.length === 0 ? t("targets.noTeams") : [t("targets.teamList"), ...teams.map((team) => `\xB7 ${team.title}`)].join("\n");
|
|
126023
|
+
return [current, "", list, "", t("targets.hint")].join("\n");
|
|
126024
|
+
};
|
|
126025
|
+
|
|
126026
|
+
// src/chatState.ts
|
|
126027
|
+
var IM_STATE_KEY = "chats";
|
|
126028
|
+
var IM_STATE_VERSION = 1;
|
|
126029
|
+
var OPENED_THREAD_LIMIT = 200;
|
|
126030
|
+
var APPROVAL_RECORD_LIMIT = 100;
|
|
126031
|
+
var emptyState = () => ({ chats: {}, opened: {}, approvals: {} });
|
|
126032
|
+
var DEFAULT_CHAT_RECORD = {
|
|
126033
|
+
threadId: null,
|
|
126034
|
+
target: { kind: "thread" },
|
|
126035
|
+
model: null,
|
|
126036
|
+
plan: false
|
|
126037
|
+
};
|
|
126038
|
+
var chatOf = (state, chatKey) => ({
|
|
126039
|
+
...DEFAULT_CHAT_RECORD,
|
|
126040
|
+
...state.chats[chatKey]
|
|
126041
|
+
});
|
|
126042
|
+
var findApprovalByToken = (state, token) => {
|
|
126043
|
+
for (const approval of Object.values(state.approvals)) {
|
|
126044
|
+
const button = approval.options.find((option) => option.token === token);
|
|
126045
|
+
if (button !== void 0) return { approval, button };
|
|
126046
|
+
}
|
|
126047
|
+
return void 0;
|
|
126048
|
+
};
|
|
126049
|
+
var openApprovalOf = (state, chatKey) => Object.values(state.approvals).findLast(
|
|
126050
|
+
(approval) => approval.chatKey === chatKey && !approval.resolved
|
|
126051
|
+
);
|
|
126052
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
126053
|
+
var nonEmpty = (value) => typeof value === "string" && value !== "" ? value : null;
|
|
126054
|
+
var readTarget = (value) => {
|
|
126055
|
+
if (!isRecord(value)) return null;
|
|
126056
|
+
if (value["kind"] === "thread") return { kind: "thread" };
|
|
126057
|
+
const teamId = nonEmpty(value["teamId"]);
|
|
126058
|
+
return value["kind"] === "team" && teamId !== null ? { kind: "team", teamId } : null;
|
|
126059
|
+
};
|
|
126060
|
+
var readButtons = (value) => {
|
|
126061
|
+
if (!Array.isArray(value)) return null;
|
|
126062
|
+
const buttons = [];
|
|
126063
|
+
for (const entry of value) {
|
|
126064
|
+
if (!isRecord(entry)) return null;
|
|
126065
|
+
const token = nonEmpty(entry["token"]);
|
|
126066
|
+
const decision = nonEmpty(entry["decision"]);
|
|
126067
|
+
const label = typeof entry["label"] === "string" ? entry["label"] : null;
|
|
126068
|
+
if (token === null || decision === null || label === null) return null;
|
|
126069
|
+
buttons.push({ token, label, decision });
|
|
126070
|
+
}
|
|
126071
|
+
return buttons.length === 0 ? null : buttons;
|
|
126072
|
+
};
|
|
126073
|
+
var keepNewest = (record, limit) => {
|
|
126074
|
+
const entries = Object.entries(record);
|
|
126075
|
+
return entries.length <= limit ? record : Object.fromEntries(entries.slice(entries.length - limit));
|
|
126076
|
+
};
|
|
126077
|
+
var withChat = (state, chatKey, patch) => ({
|
|
126078
|
+
...state,
|
|
126079
|
+
chats: { ...state.chats, [chatKey]: { ...chatOf(state, chatKey), ...patch } }
|
|
126080
|
+
});
|
|
126081
|
+
var foldImEvent = (state, name, data) => {
|
|
126082
|
+
if (!isRecord(data)) return state;
|
|
126083
|
+
switch (name) {
|
|
126084
|
+
case "chat-updated": {
|
|
126085
|
+
const chatKey = nonEmpty(data["chatKey"]);
|
|
126086
|
+
if (chatKey === null) return state;
|
|
126087
|
+
const patch = {};
|
|
126088
|
+
if (data["threadId"] === null) patch.threadId = null;
|
|
126089
|
+
else if (nonEmpty(data["threadId"]) !== null) patch.threadId = nonEmpty(data["threadId"]);
|
|
126090
|
+
const target = readTarget(data["target"]);
|
|
126091
|
+
if (target !== null) patch.target = target;
|
|
126092
|
+
if (data["model"] === null) patch.model = null;
|
|
126093
|
+
else if (isRecord(data["model"])) {
|
|
126094
|
+
const instanceId = nonEmpty(data["model"]["instanceId"]);
|
|
126095
|
+
const model = nonEmpty(data["model"]["model"]);
|
|
126096
|
+
if (instanceId !== null && model !== null) patch.model = { instanceId, model };
|
|
126097
|
+
}
|
|
126098
|
+
if (typeof data["plan"] === "boolean") patch.plan = data["plan"];
|
|
126099
|
+
return withChat(state, chatKey, patch);
|
|
126100
|
+
}
|
|
126101
|
+
case "thread-opened": {
|
|
126102
|
+
const chatKey = nonEmpty(data["chatKey"]);
|
|
126103
|
+
const threadId = nonEmpty(data["threadId"]);
|
|
126104
|
+
const projectId = nonEmpty(data["projectId"]);
|
|
126105
|
+
const openedAt = nonEmpty(data["openedAt"]);
|
|
126106
|
+
if (chatKey === null || threadId === null || projectId === null || openedAt === null) {
|
|
126107
|
+
return state;
|
|
126108
|
+
}
|
|
126109
|
+
const bound = withChat(state, chatKey, { threadId });
|
|
126110
|
+
return {
|
|
126111
|
+
...bound,
|
|
126112
|
+
opened: keepNewest(
|
|
126113
|
+
{ ...bound.opened, [threadId]: { chatKey, projectId, openedAt } },
|
|
126114
|
+
OPENED_THREAD_LIMIT
|
|
126115
|
+
)
|
|
126116
|
+
};
|
|
126117
|
+
}
|
|
126118
|
+
case "approval-offered": {
|
|
126119
|
+
const chatKey = nonEmpty(data["chatKey"]);
|
|
126120
|
+
const threadId = nonEmpty(data["threadId"]);
|
|
126121
|
+
const requestId = nonEmpty(data["requestId"]);
|
|
126122
|
+
const options = readButtons(data["options"]);
|
|
126123
|
+
if (chatKey === null || threadId === null || requestId === null || options === null) {
|
|
126124
|
+
return state;
|
|
126125
|
+
}
|
|
126126
|
+
return {
|
|
126127
|
+
...state,
|
|
126128
|
+
approvals: keepNewest(
|
|
126129
|
+
{
|
|
126130
|
+
...state.approvals,
|
|
126131
|
+
[requestId]: { chatKey, threadId, requestId, options, resolved: false }
|
|
126132
|
+
},
|
|
126133
|
+
APPROVAL_RECORD_LIMIT
|
|
126134
|
+
)
|
|
126135
|
+
};
|
|
126136
|
+
}
|
|
126137
|
+
case "approval-resolved": {
|
|
126138
|
+
const requestId = nonEmpty(data["requestId"]);
|
|
126139
|
+
const existing = requestId === null ? void 0 : state.approvals[requestId];
|
|
126140
|
+
if (requestId === null || existing === void 0) return state;
|
|
126141
|
+
return {
|
|
126142
|
+
...state,
|
|
126143
|
+
approvals: { ...state.approvals, [requestId]: { ...existing, resolved: true } }
|
|
126144
|
+
};
|
|
126145
|
+
}
|
|
126146
|
+
default:
|
|
126147
|
+
return state;
|
|
126148
|
+
}
|
|
126149
|
+
};
|
|
126150
|
+
var foldPluginEvent = (pluginId) => (state, event) => {
|
|
126151
|
+
if (event.type !== "plugin.event-appended" || !isRecord(event.payload)) return state;
|
|
126152
|
+
if (event.payload["pluginId"] !== pluginId) return state;
|
|
126153
|
+
const fullName = event.payload["name"];
|
|
126154
|
+
if (typeof fullName !== "string") return state;
|
|
126155
|
+
return foldImEvent(state, fullName.slice(fullName.lastIndexOf("/") + 1), event.payload["data"]);
|
|
125981
126156
|
};
|
|
125982
126157
|
|
|
125983
126158
|
// src/cooldown.ts
|
|
@@ -126455,13 +126630,502 @@ var makeLarkAdapter = (deps) => {
|
|
|
126455
126630
|
};
|
|
126456
126631
|
};
|
|
126457
126632
|
|
|
126633
|
+
// locales/en.json
|
|
126634
|
+
var en_default = {
|
|
126635
|
+
settings: {
|
|
126636
|
+
title: "Chat",
|
|
126637
|
+
description: "Connect chat groups to Ycodium. One row per group: create a bot on that platform, add it to the group, and paste its credentials. Pick a project and that group can start work; leave the project empty and the row only reports, on every project.",
|
|
126638
|
+
groups: "Groups",
|
|
126639
|
+
language: {
|
|
126640
|
+
label: "Reply language",
|
|
126641
|
+
description: "The language of the bot's own sentences in the group: help, status, confirmations and notices. Chinese shortcut commands only work when this is Chinese. Saving restarts the plugin.",
|
|
126642
|
+
zhCN: "\u4E2D\u6587",
|
|
126643
|
+
en: "English"
|
|
126644
|
+
},
|
|
126645
|
+
reportOnly: "Report only, all projects",
|
|
126646
|
+
archivedSuffix: "(archived)",
|
|
126647
|
+
runtimeMode: {
|
|
126648
|
+
approvalRequired: "Ask before commands and file changes",
|
|
126649
|
+
autoAcceptEdits: "Auto-accept edits, ask before other actions",
|
|
126650
|
+
auto: "Approve routine actions",
|
|
126651
|
+
fullAccess: "Commands and edits without prompts"
|
|
126652
|
+
},
|
|
126653
|
+
notifyMode: {
|
|
126654
|
+
turn: "One message per finished turn",
|
|
126655
|
+
message: "Every reply the agent completes"
|
|
126656
|
+
}
|
|
126657
|
+
},
|
|
126658
|
+
platform: {
|
|
126659
|
+
lark: "Lark",
|
|
126660
|
+
telegram: "Telegram",
|
|
126661
|
+
wecom: "WeCom"
|
|
126662
|
+
},
|
|
126663
|
+
column: {
|
|
126664
|
+
displayName: {
|
|
126665
|
+
label: "Name",
|
|
126666
|
+
placeholder: "Team chat"
|
|
126667
|
+
},
|
|
126668
|
+
platform: {
|
|
126669
|
+
label: "Platform"
|
|
126670
|
+
},
|
|
126671
|
+
larkAppId: {
|
|
126672
|
+
label: "Lark app ID"
|
|
126673
|
+
},
|
|
126674
|
+
larkAppSecret: {
|
|
126675
|
+
label: "Lark app secret"
|
|
126676
|
+
},
|
|
126677
|
+
telegramToken: {
|
|
126678
|
+
label: "Telegram bot token"
|
|
126679
|
+
},
|
|
126680
|
+
wecomBotId: {
|
|
126681
|
+
label: "WeCom bot ID"
|
|
126682
|
+
},
|
|
126683
|
+
wecomBotSecret: {
|
|
126684
|
+
label: "WeCom bot secret"
|
|
126685
|
+
},
|
|
126686
|
+
chatId: {
|
|
126687
|
+
label: "Group id",
|
|
126688
|
+
description: "The platform's own id for the group to post in."
|
|
126689
|
+
},
|
|
126690
|
+
allowedSenders: {
|
|
126691
|
+
label: "Who may command the bot",
|
|
126692
|
+
description: "Comma-separated user ids from that platform. Empty means anyone in the group can make the agent run things on this machine."
|
|
126693
|
+
},
|
|
126694
|
+
proxy: {
|
|
126695
|
+
label: "Proxy",
|
|
126696
|
+
description: "Some platforms are only reachable through a proxy on this machine, and which one can differ per row."
|
|
126697
|
+
},
|
|
126698
|
+
projectId: {
|
|
126699
|
+
label: "Project",
|
|
126700
|
+
description: "Where a message from this group starts its thread. Empty means the row only reports, and reports every project."
|
|
126701
|
+
},
|
|
126702
|
+
runtimeMode: {
|
|
126703
|
+
label: "What a chat message may do",
|
|
126704
|
+
description: "Anyone who can mention the bot starts a turn, so this is deliberately not full access by default. Whichever mode asks, the request lands in the group."
|
|
126705
|
+
},
|
|
126706
|
+
mode: {
|
|
126707
|
+
label: "How much to send",
|
|
126708
|
+
description: "A single turn can produce dozens of assistant messages \u2014 mostly commentary between tool calls \u2014 so one per finished turn is the readable default."
|
|
126709
|
+
}
|
|
126710
|
+
},
|
|
126711
|
+
reply: {
|
|
126712
|
+
notAllowed: "You are not on this group's allow list, so this tap had no effect.",
|
|
126713
|
+
noDefaultModel: 'Project "{{title}}" has no default model yet, so a thread cannot be started. Pick a default model for it in Ycodium, then message again.',
|
|
126714
|
+
projectArchived: 'Project "{{title}}" is archived. Restore it, then message again.',
|
|
126715
|
+
projectMissing: `The project bound to "{{group}}" is no longer on this machine (it may have been deleted), so a thread cannot be started. In Ycodium's chat settings, pick a project for this group again.`,
|
|
126716
|
+
threadGone: "The earlier session was deleted or archived, so this group now starts a new one.",
|
|
126717
|
+
teamGone: "The team this group was sending to no longer exists, so messages go to a normal session again."
|
|
126718
|
+
},
|
|
126719
|
+
approval: {
|
|
126720
|
+
allow: "Allow",
|
|
126721
|
+
deny: "Deny",
|
|
126722
|
+
alreadyHandled: "Already handled",
|
|
126723
|
+
replyHint: "Reply with the number."
|
|
126724
|
+
},
|
|
126725
|
+
command: {
|
|
126726
|
+
teamSelected: 'OK. From now on messages go to "{{title}}".',
|
|
126727
|
+
threadSelected: "OK. From now on messages start a normal session.",
|
|
126728
|
+
teamNotFound: 'No team is called "{{query}}", or more than one matches.',
|
|
126729
|
+
noTeams: "There are no teams on this machine yet.",
|
|
126730
|
+
newSession: "OK. The next message starts a new session.",
|
|
126731
|
+
stopNoSession: "Nothing is running in this group.",
|
|
126732
|
+
stopNoTurn: "No turn is running right now.",
|
|
126733
|
+
stopped: "Stopped. The session is still there \u2014 just keep talking."
|
|
126734
|
+
},
|
|
126735
|
+
status: {
|
|
126736
|
+
routedTeam: "Sent to: {{title}}",
|
|
126737
|
+
routedThread: "Normal session",
|
|
126738
|
+
nothingRunning: "{{where}}. Nothing is running.",
|
|
126739
|
+
session: "Session: {{title}}",
|
|
126740
|
+
running: "Running. Send /stop to stop it.",
|
|
126741
|
+
idle: "Idle.",
|
|
126742
|
+
model: "Model: {{model}}",
|
|
126743
|
+
planOn: "Plan mode: on"
|
|
126744
|
+
},
|
|
126745
|
+
targets: {
|
|
126746
|
+
currentThread: "This group is on a normal session.",
|
|
126747
|
+
currentTeam: "Sent to: {{title}}",
|
|
126748
|
+
noTeams: "There are no teams on this machine yet.",
|
|
126749
|
+
teamList: "Teams you can pick:",
|
|
126750
|
+
hint: "Use /team name to switch, /thread to go back to a normal session."
|
|
126751
|
+
},
|
|
126752
|
+
help: {
|
|
126753
|
+
title: "Commands:",
|
|
126754
|
+
stop: "\xB7 /stop \u2014 stop the turn that is running; the session stays",
|
|
126755
|
+
status: "\xB7 /status \u2014 what is going on right now",
|
|
126756
|
+
new: "\xB7 /new \u2014 forget the current session; the next message starts a new one",
|
|
126757
|
+
team: "\xB7 /team name \u2014 send the next messages to a team; /team alone lists the teams",
|
|
126758
|
+
thread: "\xB7 /thread \u2014 go back to a normal session",
|
|
126759
|
+
aliases: "Chinese shortcuts (\u505C / \u72B6\u6001 / \u65B0\u5BF9\u8BDD / \u4F1A\u8BDD\u5217\u8868 / \u5207\u6362\u4F1A\u8BDD / \u6362\u6A21\u578B / \u8BA1\u5212\u6A21\u5F0F / \u6362\u56E2\u961F / \u6362\u5BF9\u8BDD) work when the reply language is Chinese.",
|
|
126760
|
+
sessions: "\xB7 /sessions \u2014 list the sessions this bot opened for this group's project",
|
|
126761
|
+
resume: "\xB7 /resume number \u2014 switch to one of them (a number from /sessions, or the start of its id)",
|
|
126762
|
+
model: "\xB7 /model \u2014 see the model this group uses; /model number or /model instance/model switches it",
|
|
126763
|
+
plan: "\xB7 /plan \u2014 toggle plan mode (the agent proposes a plan instead of acting); /plan on, /plan off set it"
|
|
126764
|
+
},
|
|
126765
|
+
sessions: {
|
|
126766
|
+
title: "Sessions this bot opened for this group's project ({{count}}):",
|
|
126767
|
+
empty: "This bot has not opened any session for this group's project yet. Send a message to start one.",
|
|
126768
|
+
more: "{{count}} more not shown \u2014 reach them with /resume and the start of an id.",
|
|
126769
|
+
footer: "Switch with /resume number, or /resume and the start of an id.",
|
|
126770
|
+
untitled: "Untitled",
|
|
126771
|
+
unavailable: "Could not read the session list right now. Try again in a moment.",
|
|
126772
|
+
badge: {
|
|
126773
|
+
current: "\u2605 current",
|
|
126774
|
+
running: "\u25CF running",
|
|
126775
|
+
elsewhere: "in another chat"
|
|
126776
|
+
},
|
|
126777
|
+
age: {
|
|
126778
|
+
justNow: "just now",
|
|
126779
|
+
minutes: "{{count}} min ago",
|
|
126780
|
+
hours: "{{count}} h ago",
|
|
126781
|
+
days: "{{count}} d ago"
|
|
126782
|
+
}
|
|
126783
|
+
},
|
|
126784
|
+
resume: {
|
|
126785
|
+
notFound: 'No session matches "{{query}}". Use /sessions to see the list.',
|
|
126786
|
+
busy: "A turn is running in this group \u2014 send /stop first, then switch.",
|
|
126787
|
+
already: "This group is already on that session.",
|
|
126788
|
+
gone: "That session was deleted or archived, so it cannot be resumed.",
|
|
126789
|
+
runningElsewhere: "That session is running a turn in another chat \u2014 stop it there first.",
|
|
126790
|
+
done: 'Switched to "{{title}}". Send a message to keep going from there.'
|
|
126791
|
+
},
|
|
126792
|
+
model: {
|
|
126793
|
+
current: "Model: {{model}}",
|
|
126794
|
+
currentUnknown: "Model: not decided yet \u2014 a new session uses the project's default.",
|
|
126795
|
+
unavailable: "The available models cannot be read right now, so the model cannot be switched.",
|
|
126796
|
+
listTitle: "Available models:",
|
|
126797
|
+
more: "{{count}} more not shown \u2014 pick one with /model instance/model.",
|
|
126798
|
+
footer: "Switch with /model number, or /model instance/model.",
|
|
126799
|
+
notFound: 'No single model matches "{{query}}". Use /model to see the list.',
|
|
126800
|
+
setNow: "Model set to {{model}}. The current session uses it from its next turn.",
|
|
126801
|
+
setNext: "Model set to {{model}}. It applies to the next new session.",
|
|
126802
|
+
setFailed: "Could not switch the current session's model. Try again in a moment."
|
|
126803
|
+
},
|
|
126804
|
+
plan: {
|
|
126805
|
+
on: "Plan mode is on: from the next message the agent proposes a plan instead of acting. Send /plan off to leave it.",
|
|
126806
|
+
off: "Plan mode is off. Messages are handled normally again.",
|
|
126807
|
+
alreadyOn: "Plan mode is already on.",
|
|
126808
|
+
alreadyOff: "Plan mode is already off.",
|
|
126809
|
+
usage: "Usage: /plan toggles plan mode; /plan on and /plan off set it."
|
|
126810
|
+
}
|
|
126811
|
+
};
|
|
126812
|
+
|
|
126813
|
+
// locales/zh-CN.json
|
|
126814
|
+
var zh_CN_default = {
|
|
126815
|
+
settings: {
|
|
126816
|
+
title: "\u804A\u5929",
|
|
126817
|
+
description: "\u628A\u804A\u5929\u7FA4\u63A5\u5230 Ycodium\u3002\u4E00\u884C\u4E00\u4E2A\u7FA4\uFF1A\u5148\u5728\u5BF9\u5E94\u5E73\u53F0\u5EFA\u597D\u673A\u5668\u4EBA\u3001\u62C9\u8FDB\u7FA4\uFF0C\u518D\u628A\u5B83\u7684\u51ED\u636E\u586B\u8FDB\u6765\u3002\u9009\u4E86\u9879\u76EE\uFF0C\u8FD9\u4E2A\u7FA4\u5C31\u80FD\u6D3E\u6D3B\uFF1B\u9879\u76EE\u7559\u7A7A\uFF0C\u8FD9\u4E00\u884C\u5C31\u53EA\u5F80\u7FA4\u91CC\u62A5\uFF0C\u800C\u4E14\u62A5\u6240\u6709\u9879\u76EE\u3002",
|
|
126818
|
+
groups: "\u7FA4",
|
|
126819
|
+
language: {
|
|
126820
|
+
label: "\u56DE\u8BDD\u8BED\u8A00",
|
|
126821
|
+
description: "\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u81EA\u5DF1\u8BF4\u7684\u8BDD\u7528\u4EC0\u4E48\u8BED\u8A00\uFF1A\u5E2E\u52A9\u3001\u72B6\u6001\u3001\u786E\u8BA4\u548C\u5404\u79CD\u63D0\u793A\u3002\u4E2D\u6587\u5FEB\u6377\u547D\u4EE4\u53EA\u5728\u9009\u4E2D\u6587\u65F6\u8BA4\u3002\u4FDD\u5B58\u540E\u63D2\u4EF6\u4F1A\u91CD\u542F\u3002",
|
|
126822
|
+
zhCN: "\u4E2D\u6587",
|
|
126823
|
+
en: "English"
|
|
126824
|
+
},
|
|
126825
|
+
reportOnly: "\u53EA\u62A5\u4E0D\u6536\uFF0C\u62A5\u6240\u6709\u9879\u76EE",
|
|
126826
|
+
archivedSuffix: "\uFF08\u5DF2\u5F52\u6863\uFF09",
|
|
126827
|
+
runtimeMode: {
|
|
126828
|
+
approvalRequired: "\u547D\u4EE4\u548C\u6539\u6587\u4EF6\u524D\u5148\u95EE",
|
|
126829
|
+
autoAcceptEdits: "\u81EA\u52A8\u63A5\u53D7\u6539\u52A8\uFF0C\u5176\u4ED6\u64CD\u4F5C\u5148\u95EE",
|
|
126830
|
+
auto: "\u5E38\u89C4\u64CD\u4F5C\u81EA\u52A8\u6279\u51C6",
|
|
126831
|
+
fullAccess: "\u547D\u4EE4\u548C\u6539\u52A8\u90FD\u4E0D\u95EE"
|
|
126832
|
+
},
|
|
126833
|
+
notifyMode: {
|
|
126834
|
+
turn: "\u6BCF\u8F6E\u6536\u5C3E\u53D1\u4E00\u6761",
|
|
126835
|
+
message: "agent \u8BF4\u5B8C\u4E00\u53E5\u5C31\u53D1\u4E00\u53E5"
|
|
126836
|
+
}
|
|
126837
|
+
},
|
|
126838
|
+
platform: {
|
|
126839
|
+
lark: "\u98DE\u4E66",
|
|
126840
|
+
telegram: "Telegram",
|
|
126841
|
+
wecom: "\u4F01\u4E1A\u5FAE\u4FE1"
|
|
126842
|
+
},
|
|
126843
|
+
column: {
|
|
126844
|
+
displayName: {
|
|
126845
|
+
label: "\u540D\u79F0",
|
|
126846
|
+
placeholder: "\u56E2\u961F\u7FA4"
|
|
126847
|
+
},
|
|
126848
|
+
platform: {
|
|
126849
|
+
label: "\u5E73\u53F0"
|
|
126850
|
+
},
|
|
126851
|
+
larkAppId: {
|
|
126852
|
+
label: "\u98DE\u4E66\u5E94\u7528 ID"
|
|
126853
|
+
},
|
|
126854
|
+
larkAppSecret: {
|
|
126855
|
+
label: "\u98DE\u4E66\u5E94\u7528\u5BC6\u94A5"
|
|
126856
|
+
},
|
|
126857
|
+
telegramToken: {
|
|
126858
|
+
label: "Telegram \u673A\u5668\u4EBA\u4EE4\u724C"
|
|
126859
|
+
},
|
|
126860
|
+
wecomBotId: {
|
|
126861
|
+
label: "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA ID"
|
|
126862
|
+
},
|
|
126863
|
+
wecomBotSecret: {
|
|
126864
|
+
label: "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u5BC6\u94A5"
|
|
126865
|
+
},
|
|
126866
|
+
chatId: {
|
|
126867
|
+
label: "\u7FA4 id",
|
|
126868
|
+
description: "\u8BE5\u5E73\u53F0\u81EA\u5DF1\u7ED9\u8FD9\u4E2A\u7FA4\u7684 id\uFF0C\u673A\u5668\u4EBA\u5F80\u8FD9\u91CC\u53D1\u3002"
|
|
126869
|
+
},
|
|
126870
|
+
allowedSenders: {
|
|
126871
|
+
label: "\u8C01\u80FD\u6307\u6325\u673A\u5668\u4EBA",
|
|
126872
|
+
description: "\u8BE5\u5E73\u53F0\u7684\u7528\u6237 id\uFF0C\u9017\u53F7\u5206\u9694\u3002\u7559\u7A7A\u8868\u793A\u7FA4\u91CC\u4EFB\u4F55\u4EBA\u90FD\u80FD\u8BA9 agent \u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u8DD1\u4E1C\u897F\u3002"
|
|
126873
|
+
},
|
|
126874
|
+
proxy: {
|
|
126875
|
+
label: "\u4EE3\u7406",
|
|
126876
|
+
description: "\u6709\u4E9B\u5E73\u53F0\u53EA\u80FD\u7ECF\u672C\u673A\u4E0A\u7684\u67D0\u4E2A\u4EE3\u7406\u624D\u8FDE\u5F97\u4E0A\uFF0C\u800C\u4E14\u6BCF\u4E00\u884C\u53EF\u4EE5\u4E0D\u4E00\u6837\u3002"
|
|
126877
|
+
},
|
|
126878
|
+
projectId: {
|
|
126879
|
+
label: "\u9879\u76EE",
|
|
126880
|
+
description: "\u8FD9\u4E2A\u7FA4\u91CC\u7684\u6D88\u606F\u5728\u54EA\u4E2A\u9879\u76EE\u91CC\u5F00\u4F1A\u8BDD\u3002\u7559\u7A7A\u8868\u793A\u8FD9\u4E00\u884C\u53EA\u62A5\u4E0D\u6536\uFF0C\u5E76\u4E14\u62A5\u6240\u6709\u9879\u76EE\u3002"
|
|
126881
|
+
},
|
|
126882
|
+
runtimeMode: {
|
|
126883
|
+
label: "\u804A\u5929\u6D88\u606F\u80FD\u505A\u4EC0\u4E48",
|
|
126884
|
+
description: "\u4EFB\u4F55\u80FD @ \u5230\u673A\u5668\u4EBA\u7684\u4EBA\u90FD\u80FD\u5F00\u4E00\u8F6E\uFF0C\u6240\u4EE5\u9ED8\u8BA4\u6545\u610F\u4E0D\u7ED9\u6EE1\u6743\u9650\u3002\u4E0D\u8BBA\u9009\u54EA\u4E00\u6863\uFF0C\u8981\u62CD\u677F\u7684\u4E8B\u90FD\u4F1A\u6446\u5230\u7FA4\u91CC\u3002"
|
|
126885
|
+
},
|
|
126886
|
+
mode: {
|
|
126887
|
+
label: "\u53D1\u591A\u5C11",
|
|
126888
|
+
description: "\u4E00\u8F6E\u6D3B\u513F\u53EF\u80FD\u4EA7\u751F\u51E0\u5341\u6761\u52A9\u624B\u6D88\u606F\uFF0C\u5927\u591A\u662F\u5DE5\u5177\u8C03\u7528\u4E4B\u95F4\u7684\u788E\u788E\u5FF5\uFF0C\u6240\u4EE5\u9ED8\u8BA4\u6BCF\u8F6E\u6536\u5C3E\u53EA\u53D1\u4E00\u6761\uFF0C\u8BFB\u8D77\u6765\u624D\u4E0D\u7D2F\u3002"
|
|
126889
|
+
}
|
|
126890
|
+
},
|
|
126891
|
+
reply: {
|
|
126892
|
+
notAllowed: "\u4F60\u4E0D\u5728\u8FD9\u4E2A\u7FA4\u7684\u53EF\u6307\u6325\u540D\u5355\u91CC\uFF0C\u8FD9\u6B21\u70B9\u51FB\u6CA1\u6709\u751F\u6548\u3002",
|
|
126893
|
+
noDefaultModel: "\u9879\u76EE\u300C{{title}}\u300D\u8FD8\u6CA1\u6709\u9ED8\u8BA4\u6A21\u578B\uFF0C\u5F00\u4E0D\u4E86\u4F1A\u8BDD\u3002\u5148\u5728 Ycodium \u91CC\u7ED9\u5B83\u9009\u4E00\u4E2A\u9ED8\u8BA4\u6A21\u578B\uFF0C\u518D\u56DE\u6765\u53D1\u6D88\u606F\u3002",
|
|
126894
|
+
projectArchived: "\u9879\u76EE\u300C{{title}}\u300D\u5DF2\u5F52\u6863\uFF0C\u6062\u590D\u540E\u518D\u53D1\u6D88\u606F\u3002",
|
|
126895
|
+
projectMissing: "\u300C{{group}}\u300D\u7ED1\u7684\u9879\u76EE\u5DF2\u7ECF\u4E0D\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u4E86\uFF08\u53EF\u80FD\u88AB\u5220\u4E86\uFF09\uFF0C\u5F00\u4E0D\u4E86\u4F1A\u8BDD\u3002\u5230 Ycodium \u7684\u804A\u5929\u8BBE\u7F6E\u91CC\u7ED9\u8FD9\u4E2A\u7FA4\u91CD\u65B0\u9009\u4E00\u4E2A\u9879\u76EE\u3002",
|
|
126896
|
+
threadGone: "\u4E4B\u524D\u90A3\u6761\u4F1A\u8BDD\u5DF2\u88AB\u5220\u9664\u6216\u5F52\u6863\uFF0C\u8FD9\u4E2A\u7FA4\u6539\u4E3A\u5F00\u4E00\u6761\u65B0\u4F1A\u8BDD\u3002",
|
|
126897
|
+
teamGone: "\u8FD9\u4E2A\u7FA4\u539F\u6765\u6D3E\u7ED9\u7684\u961F\u5DF2\u7ECF\u4E0D\u5728\u4E86\uFF0C\u63A5\u4E0B\u6765\u6539\u56DE\u666E\u901A\u4F1A\u8BDD\u3002"
|
|
126898
|
+
},
|
|
126899
|
+
approval: {
|
|
126900
|
+
allow: "\u5141\u8BB8",
|
|
126901
|
+
deny: "\u62D2\u7EDD",
|
|
126902
|
+
alreadyHandled: "\u5DF2\u5904\u7406",
|
|
126903
|
+
replyHint: "\u56DE\u590D\u7F16\u53F7\u5373\u53EF\u3002"
|
|
126904
|
+
},
|
|
126905
|
+
command: {
|
|
126906
|
+
teamSelected: "\u597D\uFF0C\u63A5\u4E0B\u6765\u6D3E\u7ED9\u300C{{title}}\u300D\u3002",
|
|
126907
|
+
threadSelected: "\u597D\uFF0C\u63A5\u4E0B\u6765\u5F00\u666E\u901A\u4F1A\u8BDD\u3002",
|
|
126908
|
+
teamNotFound: "\u6CA1\u627E\u5230\u53EB\u300C{{query}}\u300D\u7684\u961F\uFF0C\u4E5F\u53EF\u80FD\u662F\u4E0D\u6B62\u4E00\u652F\u5BF9\u5F97\u4E0A\u3002",
|
|
126909
|
+
noTeams: "\u8FD9\u53F0\u673A\u5668\u4E0A\u8FD8\u6CA1\u6709\u56E2\u961F\u3002",
|
|
126910
|
+
newSession: "\u597D\uFF0C\u4E0B\u4E00\u53E5\u8BDD\u5F00\u4E00\u6761\u65B0\u4F1A\u8BDD\u3002",
|
|
126911
|
+
stopNoSession: "\u8FD9\u4E2A\u7FA4\u73B0\u5728\u6CA1\u6709\u5728\u8DD1\u7684\u6D3B\u513F\u3002",
|
|
126912
|
+
stopNoTurn: "\u73B0\u5728\u6CA1\u6709\u5728\u8DD1\u7684\u4E00\u8F6E\u3002",
|
|
126913
|
+
stopped: "\u505C\u4E86\u3002\u4F1A\u8BDD\u8FD8\u5728\uFF0C\u63A5\u7740\u8BF4\u5C31\u884C\u3002"
|
|
126914
|
+
},
|
|
126915
|
+
status: {
|
|
126916
|
+
routedTeam: "\u6D3E\u7ED9\uFF1A{{title}}",
|
|
126917
|
+
routedThread: "\u666E\u901A\u4F1A\u8BDD",
|
|
126918
|
+
nothingRunning: "{{where}}\u3002\u73B0\u5728\u6CA1\u6709\u5728\u8DD1\u7684\u6D3B\u513F\u3002",
|
|
126919
|
+
session: "\u4F1A\u8BDD\uFF1A{{title}}",
|
|
126920
|
+
running: "\u6B63\u5728\u8DD1\u3002\u60F3\u505C\u5C31\u6253 /stop\u3002",
|
|
126921
|
+
idle: "\u7A7A\u95F2\u7740\u3002",
|
|
126922
|
+
model: "\u6A21\u578B\uFF1A{{model}}",
|
|
126923
|
+
planOn: "\u8BA1\u5212\u6A21\u5F0F\uFF1A\u5F00"
|
|
126924
|
+
},
|
|
126925
|
+
targets: {
|
|
126926
|
+
currentThread: "\u73B0\u5728\u8FD9\u4E2A\u7FA4\u5F00\u7684\u662F\u666E\u901A\u4F1A\u8BDD\u3002",
|
|
126927
|
+
currentTeam: "\u73B0\u5728\u6D3E\u7ED9\uFF1A{{title}}",
|
|
126928
|
+
noTeams: "\u8FD9\u53F0\u673A\u5668\u4E0A\u8FD8\u6CA1\u6709\u56E2\u961F\u3002",
|
|
126929
|
+
teamList: "\u53EF\u9009\u7684\u961F\uFF1A",
|
|
126930
|
+
hint: "\u7528 /team \u961F\u540D \u5207\u6362\uFF0C/thread \u5207\u56DE\u666E\u901A\u4F1A\u8BDD\u3002"
|
|
126931
|
+
},
|
|
126932
|
+
help: {
|
|
126933
|
+
title: "\u80FD\u7528\u7684\u547D\u4EE4\uFF1A",
|
|
126934
|
+
stop: "\xB7 /stop \u2014\u2014 \u505C\u6389\u6B63\u5728\u8DD1\u7684\u8FD9\u4E00\u8F6E\uFF0C\u4F1A\u8BDD\u7559\u7740",
|
|
126935
|
+
status: "\xB7 /status \u2014\u2014 \u73B0\u5728\u5728\u5E72\u4EC0\u4E48",
|
|
126936
|
+
new: "\xB7 /new \u2014\u2014 \u5FD8\u6389\u5F53\u524D\u4F1A\u8BDD\uFF0C\u4E0B\u4E00\u53E5\u5F00\u65B0\u7684",
|
|
126937
|
+
team: "\xB7 /team \u961F\u540D \u2014\u2014 \u628A\u63A5\u4E0B\u6765\u7684\u6D3B\u6D3E\u7ED9\u4E00\u652F\u961F\uFF1B/team \u4E0D\u5E26\u540D\u5B57\u770B\u6709\u54EA\u4E9B\u961F",
|
|
126938
|
+
thread: "\xB7 /thread \u2014\u2014 \u5207\u56DE\u666E\u901A\u4F1A\u8BDD",
|
|
126939
|
+
aliases: "\u4E2D\u6587\u4E5F\u884C\uFF1A\u505C / \u72B6\u6001 / \u65B0\u5BF9\u8BDD / \u4F1A\u8BDD\u5217\u8868 / \u5207\u6362\u4F1A\u8BDD / \u6362\u6A21\u578B / \u8BA1\u5212\u6A21\u5F0F / \u6362\u56E2\u961F / \u6362\u5BF9\u8BDD\u3002",
|
|
126940
|
+
sessions: "\xB7 /sessions \u2014\u2014 \u5217\u51FA\u672C\u673A\u5668\u4EBA\u4E3A\u8FD9\u4E2A\u7FA4\u7684\u9879\u76EE\u5F00\u8FC7\u7684\u4F1A\u8BDD",
|
|
126941
|
+
resume: "\xB7 /resume \u7F16\u53F7 \u2014\u2014 \u5207\u5230\u5176\u4E2D\u4E00\u6761\uFF08/sessions \u91CC\u7684\u7F16\u53F7\uFF0C\u6216\u4F1A\u8BDD id \u7684\u5F00\u5934\uFF09",
|
|
126942
|
+
model: "\xB7 /model \u2014\u2014 \u770B\u8FD9\u4E2A\u7FA4\u7528\u7684\u6A21\u578B\uFF1B/model \u7F16\u53F7 \u6216 /model \u5B9E\u4F8B/\u6A21\u578B \u5207\u6362",
|
|
126943
|
+
plan: "\xB7 /plan \u2014\u2014 \u5F00\u5173\u8BA1\u5212\u6A21\u5F0F\uFF08agent \u5148\u51FA\u8BA1\u5212\u3001\u4E0D\u52A8\u624B\uFF09\uFF1B/plan on\u3001/plan off \u660E\u786E\u8BBE\u5B9A"
|
|
126944
|
+
},
|
|
126945
|
+
sessions: {
|
|
126946
|
+
title: "\u672C\u673A\u5668\u4EBA\u4E3A\u8FD9\u4E2A\u7FA4\u7684\u9879\u76EE\u5F00\u8FC7\u7684\u4F1A\u8BDD\uFF08{{count}} \u6761\uFF09\uFF1A",
|
|
126947
|
+
empty: "\u672C\u673A\u5668\u4EBA\u8FD8\u6CA1\u6709\u4E3A\u8FD9\u4E2A\u7FA4\u7684\u9879\u76EE\u5F00\u8FC7\u4F1A\u8BDD\uFF0C\u53D1\u4E00\u53E5\u8BDD\u5C31\u4F1A\u5F00\u4E00\u6761\u3002",
|
|
126948
|
+
more: "\u8FD8\u6709 {{count}} \u6761\u6CA1\u5217\u51FA\u2014\u2014\u7528 /resume \u52A0\u4F1A\u8BDD id \u7684\u5F00\u5934\u4E5F\u80FD\u5207\u5230\u3002",
|
|
126949
|
+
footer: "\u7528 /resume \u7F16\u53F7 \u5207\u6362\uFF0C\u6216 /resume \u52A0\u4F1A\u8BDD id \u7684\u5F00\u5934\u3002",
|
|
126950
|
+
untitled: "\uFF08\u65E0\u6807\u9898\uFF09",
|
|
126951
|
+
unavailable: "\u73B0\u5728\u8BFB\u4E0D\u51FA\u4F1A\u8BDD\u5217\u8868\uFF0C\u7A0D\u540E\u518D\u8BD5\u3002",
|
|
126952
|
+
badge: {
|
|
126953
|
+
current: "\u2605 \u5F53\u524D",
|
|
126954
|
+
running: "\u25CF \u5728\u8DD1",
|
|
126955
|
+
elsewhere: "\u63A5\u5728\u522B\u7684\u7FA4"
|
|
126956
|
+
},
|
|
126957
|
+
age: {
|
|
126958
|
+
justNow: "\u521A\u521A",
|
|
126959
|
+
minutes: "{{count}} \u5206\u949F\u524D",
|
|
126960
|
+
hours: "{{count}} \u5C0F\u65F6\u524D",
|
|
126961
|
+
days: "{{count}} \u5929\u524D"
|
|
126962
|
+
}
|
|
126963
|
+
},
|
|
126964
|
+
resume: {
|
|
126965
|
+
notFound: "\u6CA1\u6709\u54EA\u6761\u4F1A\u8BDD\u5BF9\u5F97\u4E0A\u300C{{query}}\u300D\u3002\u7528 /sessions \u770B\u770B\u6709\u54EA\u4E9B\u3002",
|
|
126966
|
+
busy: "\u8FD9\u4E2A\u7FA4\u6709\u4E00\u8F6E\u6B63\u5728\u8DD1\u2014\u2014\u5148 /stop\uFF0C\u518D\u5207\u6362\u3002",
|
|
126967
|
+
already: "\u8FD9\u4E2A\u7FA4\u5DF2\u7ECF\u5728\u90A3\u6761\u4F1A\u8BDD\u91CC\u4E86\u3002",
|
|
126968
|
+
gone: "\u90A3\u6761\u4F1A\u8BDD\u5DF2\u88AB\u5220\u9664\u6216\u5F52\u6863\uFF0C\u63A5\u4E0D\u4E0A\u4E86\u3002",
|
|
126969
|
+
runningElsewhere: "\u90A3\u6761\u4F1A\u8BDD\u6B63\u5728\u522B\u7684\u7FA4\u91CC\u8DD1\u7740\u4E00\u8F6E\u2014\u2014\u5148\u5230\u90A3\u8FB9\u505C\u6389\u5B83\u3002",
|
|
126970
|
+
done: "\u5DF2\u5207\u5230\u300C{{title}}\u300D\u3002\u53D1\u4E00\u53E5\u8BDD\u5C31\u4ECE\u90A3\u91CC\u63A5\u7740\u804A\u3002"
|
|
126971
|
+
},
|
|
126972
|
+
model: {
|
|
126973
|
+
current: "\u6A21\u578B\uFF1A{{model}}",
|
|
126974
|
+
currentUnknown: "\u6A21\u578B\uFF1A\u8FD8\u6CA1\u5B9A\u2014\u2014\u65B0\u5F00\u4F1A\u8BDD\u65F6\u7528\u9879\u76EE\u7684\u9ED8\u8BA4\u6A21\u578B\u3002",
|
|
126975
|
+
unavailable: "\u73B0\u5728\u8BFB\u4E0D\u51FA\u53EF\u9009\u7684\u6A21\u578B\uFF0C\u6CA1\u6CD5\u5207\u6362\u6A21\u578B\u3002",
|
|
126976
|
+
listTitle: "\u53EF\u9009\u7684\u6A21\u578B\uFF1A",
|
|
126977
|
+
more: "\u8FD8\u6709 {{count}} \u4E2A\u6CA1\u5217\u51FA\u2014\u2014\u7528 /model \u5B9E\u4F8B/\u6A21\u578B \u4E5F\u80FD\u9009\u5230\u3002",
|
|
126978
|
+
footer: "\u7528 /model \u7F16\u53F7 \u5207\u6362\uFF0C\u6216 /model \u5B9E\u4F8B/\u6A21\u578B\u3002",
|
|
126979
|
+
notFound: "\u6CA1\u6709\u552F\u4E00\u5BF9\u5F97\u4E0A\u300C{{query}}\u300D\u7684\u6A21\u578B\u3002\u7528 /model \u770B\u770B\u6709\u54EA\u4E9B\u3002",
|
|
126980
|
+
setNow: "\u6A21\u578B\u5DF2\u8BBE\u4E3A {{model}}\uFF0C\u5F53\u524D\u4F1A\u8BDD\u4ECE\u4E0B\u4E00\u8F6E\u8D77\u7528\u5B83\u3002",
|
|
126981
|
+
setNext: "\u6A21\u578B\u5DF2\u8BBE\u4E3A {{model}}\uFF0C\u4E0B\u4E00\u6761\u65B0\u4F1A\u8BDD\u8D77\u7528\u5B83\u3002",
|
|
126982
|
+
setFailed: "\u6CA1\u80FD\u5207\u6362\u5F53\u524D\u4F1A\u8BDD\u7684\u6A21\u578B\uFF0C\u7A0D\u540E\u518D\u8BD5\u3002"
|
|
126983
|
+
},
|
|
126984
|
+
plan: {
|
|
126985
|
+
on: "\u8BA1\u5212\u6A21\u5F0F\u5DF2\u5F00\uFF1A\u4ECE\u4E0B\u4E00\u6761\u6D88\u606F\u8D77\uFF0Cagent \u5148\u51FA\u8BA1\u5212\u3001\u4E0D\u52A8\u624B\u3002\u53D1 /plan off \u9000\u51FA\u3002",
|
|
126986
|
+
off: "\u8BA1\u5212\u6A21\u5F0F\u5DF2\u5173\uFF0C\u6D88\u606F\u7167\u5E38\u5904\u7406\u3002",
|
|
126987
|
+
alreadyOn: "\u8BA1\u5212\u6A21\u5F0F\u5DF2\u7ECF\u662F\u5F00\u7740\u7684\u3002",
|
|
126988
|
+
alreadyOff: "\u8BA1\u5212\u6A21\u5F0F\u5DF2\u7ECF\u662F\u5173\u7740\u7684\u3002",
|
|
126989
|
+
usage: "\u7528\u6CD5\uFF1A/plan \u5207\u6362\u8BA1\u5212\u6A21\u5F0F\uFF1B/plan on\u3001/plan off \u660E\u786E\u8BBE\u5B9A\u3002"
|
|
126990
|
+
}
|
|
126991
|
+
};
|
|
126992
|
+
|
|
126993
|
+
// src/messages.ts
|
|
126994
|
+
var DEFAULT_REPLY_LANGUAGE = "zh-CN";
|
|
126995
|
+
var parseReplyLanguage = (value) => value === "en" ? "en" : DEFAULT_REPLY_LANGUAGE;
|
|
126996
|
+
var CATALOGS = { en: en_default, "zh-CN": zh_CN_default };
|
|
126997
|
+
var lookup = (catalog, key) => {
|
|
126998
|
+
let node = catalog;
|
|
126999
|
+
for (const segment of key.split(".")) {
|
|
127000
|
+
if (typeof node !== "object") return void 0;
|
|
127001
|
+
node = node[segment];
|
|
127002
|
+
}
|
|
127003
|
+
return typeof node === "string" ? node : void 0;
|
|
127004
|
+
};
|
|
127005
|
+
var interpolate = (template, params) => params === void 0 ? template : template.replace(/{{\s*([\w.]+)\s*}}/g, (whole, name) => {
|
|
127006
|
+
const value = params[name];
|
|
127007
|
+
return value === void 0 ? whole : String(value);
|
|
127008
|
+
});
|
|
127009
|
+
var makeTranslate = (language) => {
|
|
127010
|
+
const catalog = CATALOGS[language];
|
|
127011
|
+
const optional = (key, params) => {
|
|
127012
|
+
const text = lookup(catalog, key);
|
|
127013
|
+
return text === void 0 ? void 0 : interpolate(text, params);
|
|
127014
|
+
};
|
|
127015
|
+
return Object.assign(
|
|
127016
|
+
(key, params) => optional(key, params) ?? key,
|
|
127017
|
+
{ optional, language }
|
|
127018
|
+
);
|
|
127019
|
+
};
|
|
127020
|
+
|
|
127021
|
+
// src/modelChoice.ts
|
|
127022
|
+
var MODEL_LIST_MAX = 30;
|
|
127023
|
+
var modelChoices = (instances) => instances.flatMap(
|
|
127024
|
+
(instance) => instance.enabled ? (instance.models ?? []).map(
|
|
127025
|
+
(model) => ({
|
|
127026
|
+
instanceId: instance.instanceId,
|
|
127027
|
+
model: model.slug,
|
|
127028
|
+
instanceName: instance.displayName ?? instance.instanceId,
|
|
127029
|
+
modelName: model.name === "" ? model.slug : model.name
|
|
127030
|
+
})
|
|
127031
|
+
) : []
|
|
127032
|
+
);
|
|
127033
|
+
var modelLabel = (choice) => `${choice.instanceName} \xB7 ${choice.modelName}`;
|
|
127034
|
+
var rawModelLabel = (selection) => `${selection.instanceId} \xB7 ${selection.model}`;
|
|
127035
|
+
var sameModel = (left, right) => left.instanceId === right.instanceId && left.model === right.model;
|
|
127036
|
+
var formatModels = (current, choices, t) => {
|
|
127037
|
+
const currentLabel = current === null ? t("model.currentUnknown") : t("model.current", {
|
|
127038
|
+
model: modelLabel(
|
|
127039
|
+
choices.find((choice) => sameModel(choice, current)) ?? {
|
|
127040
|
+
instanceName: current.instanceId,
|
|
127041
|
+
modelName: current.model
|
|
127042
|
+
}
|
|
127043
|
+
)
|
|
127044
|
+
});
|
|
127045
|
+
if (choices.length === 0) return [currentLabel, t("model.unavailable")].join("\n");
|
|
127046
|
+
const shown = choices.slice(0, MODEL_LIST_MAX);
|
|
127047
|
+
return [
|
|
127048
|
+
currentLabel,
|
|
127049
|
+
"",
|
|
127050
|
+
t("model.listTitle"),
|
|
127051
|
+
...shown.map(
|
|
127052
|
+
(choice, index) => `${String(index + 1)}. ${current !== null && sameModel(choice, current) ? "\u2605 " : ""}${modelLabel(choice)}`
|
|
127053
|
+
),
|
|
127054
|
+
...choices.length > shown.length ? [t("model.more", { count: choices.length - shown.length })] : [],
|
|
127055
|
+
"",
|
|
127056
|
+
t("model.footer")
|
|
127057
|
+
].join("\n");
|
|
127058
|
+
};
|
|
127059
|
+
var pickModel = (arg, choices) => {
|
|
127060
|
+
const wanted = arg.trim();
|
|
127061
|
+
if (wanted === "") return null;
|
|
127062
|
+
if (/^\d+$/.test(wanted)) return choices.slice(0, MODEL_LIST_MAX)[Number(wanted) - 1] ?? null;
|
|
127063
|
+
const needle = wanted.toLowerCase();
|
|
127064
|
+
const qualified = choices.filter(
|
|
127065
|
+
(choice) => `${choice.instanceId}/${choice.model}`.toLowerCase() === needle || `${choice.instanceId}/${choice.modelName}`.toLowerCase() === needle
|
|
127066
|
+
);
|
|
127067
|
+
if (qualified.length === 1) return qualified[0] ?? null;
|
|
127068
|
+
if (qualified.length > 1) return null;
|
|
127069
|
+
const named = choices.filter(
|
|
127070
|
+
(choice) => choice.model.toLowerCase() === needle || choice.modelName.toLowerCase() === needle
|
|
127071
|
+
);
|
|
127072
|
+
return named.length === 1 ? named[0] ?? null : null;
|
|
127073
|
+
};
|
|
127074
|
+
|
|
126458
127075
|
// src/projectArchive.ts
|
|
126459
|
-
var imProjectOptions = (projects, boundIds) => projects.flatMap((project) => {
|
|
127076
|
+
var imProjectOptions = (projects, boundIds, archivedSuffix) => projects.flatMap((project) => {
|
|
126460
127077
|
if (project.archivedAt == null) return [{ value: project.projectId, label: project.title }];
|
|
126461
|
-
return boundIds.has(project.projectId) ? [{ value: project.projectId, label: `${project.title}
|
|
127078
|
+
return boundIds.has(project.projectId) ? [{ value: project.projectId, label: `${project.title} ${archivedSuffix}` }] : [];
|
|
126462
127079
|
});
|
|
126463
|
-
|
|
126464
|
-
|
|
127080
|
+
|
|
127081
|
+
// src/sessionList.ts
|
|
127082
|
+
var SESSION_LIST_MAX = 20;
|
|
127083
|
+
var SESSION_ID_SHORT_LENGTH = 8;
|
|
127084
|
+
var ageLabel = (updatedAt, now, t) => {
|
|
127085
|
+
const at = Date.parse(updatedAt);
|
|
127086
|
+
if (Number.isNaN(at)) return "";
|
|
127087
|
+
const minutes = Math.floor(Math.max(0, now - at) / 6e4);
|
|
127088
|
+
if (minutes < 1) return t("sessions.age.justNow");
|
|
127089
|
+
if (minutes < 60) return t("sessions.age.minutes", { count: minutes });
|
|
127090
|
+
const hours = Math.floor(minutes / 60);
|
|
127091
|
+
if (hours < 24) return t("sessions.age.hours", { count: hours });
|
|
127092
|
+
return t("sessions.age.days", { count: Math.floor(hours / 24) });
|
|
127093
|
+
};
|
|
127094
|
+
var shortId = (threadId) => threadId.slice(0, SESSION_ID_SHORT_LENGTH);
|
|
127095
|
+
var sessionLine = (row, position, now, t) => {
|
|
127096
|
+
const title = row.title.replace(/\s+/g, " ").trim() || t("sessions.untitled");
|
|
127097
|
+
const age = ageLabel(row.updatedAt, now, t);
|
|
127098
|
+
const badges = [
|
|
127099
|
+
row.current ? t("sessions.badge.current") : null,
|
|
127100
|
+
row.running ? t("sessions.badge.running") : null,
|
|
127101
|
+
row.elsewhere ? t("sessions.badge.elsewhere") : null
|
|
127102
|
+
].filter((badge) => badge !== null);
|
|
127103
|
+
return [`${String(position)}. ${title}`, age, ...badges, shortId(row.threadId)].filter((part) => part !== "").join(" \xB7 ");
|
|
127104
|
+
};
|
|
127105
|
+
var formatSessions = (rows, now, t) => {
|
|
127106
|
+
if (rows.length === 0) return t("sessions.empty");
|
|
127107
|
+
const shown = rows.slice(0, SESSION_LIST_MAX);
|
|
127108
|
+
return [
|
|
127109
|
+
t("sessions.title", { count: rows.length }),
|
|
127110
|
+
...shown.map((row, index) => sessionLine(row, index + 1, now, t)),
|
|
127111
|
+
...rows.length > shown.length ? [t("sessions.more", { count: rows.length - shown.length })] : [],
|
|
127112
|
+
"",
|
|
127113
|
+
t("sessions.footer")
|
|
127114
|
+
].join("\n");
|
|
127115
|
+
};
|
|
127116
|
+
var listedThreadIds = (rows) => rows.slice(0, SESSION_LIST_MAX).map((row) => row.threadId);
|
|
127117
|
+
var pickSession = (arg, listed, rows) => {
|
|
127118
|
+
const wanted = arg.trim();
|
|
127119
|
+
if (wanted === "") return null;
|
|
127120
|
+
if (/^\d+$/.test(wanted)) {
|
|
127121
|
+
const index = Number(wanted);
|
|
127122
|
+
const ids = listed ?? listedThreadIds(rows);
|
|
127123
|
+
return ids[index - 1] ?? null;
|
|
127124
|
+
}
|
|
127125
|
+
const needle = wanted.toLowerCase();
|
|
127126
|
+
const matches = rows.filter((row) => row.threadId.toLowerCase().startsWith(needle));
|
|
127127
|
+
return matches.length === 1 ? matches[0]?.threadId ?? null : null;
|
|
127128
|
+
};
|
|
126465
127129
|
|
|
126466
127130
|
// src/telegramApi.ts
|
|
126467
127131
|
var API_BASE = "https://api.telegram.org";
|
|
@@ -127009,7 +127673,7 @@ var makeWecomAdapter = (deps) => {
|
|
|
127009
127673
|
"",
|
|
127010
127674
|
...request.options.map((option, index) => `${String(index + 1)}. ${option.label}`),
|
|
127011
127675
|
"",
|
|
127012
|
-
|
|
127676
|
+
request.replyHint
|
|
127013
127677
|
];
|
|
127014
127678
|
await (clients.get(binding.rowId)?.sendText(binding.chatId, lines.join("\n")) ?? Promise.resolve());
|
|
127015
127679
|
},
|
|
@@ -127022,13 +127686,13 @@ var makeWecomAdapter = (deps) => {
|
|
|
127022
127686
|
|
|
127023
127687
|
// src/index.ts
|
|
127024
127688
|
var GROUPS_FIELD = "groups";
|
|
127689
|
+
var REPLY_LANGUAGE_FIELD = "replyLanguage";
|
|
127025
127690
|
var SEEN_MESSAGE_LIMIT = 256;
|
|
127026
127691
|
var THREAD_PROJECT_CACHE_LIMIT = 256;
|
|
127027
127692
|
var TITLE_MAX_CHARS = 72;
|
|
127028
127693
|
var DEFAULT_PLATFORM = "lark";
|
|
127694
|
+
var SESSION_SCAN_LIMIT = 50;
|
|
127029
127695
|
var ARCHIVED_REPLY_COOLDOWN_MS = 10 * 6e4;
|
|
127030
|
-
var NOT_ALLOWED_NOTICE = "\u4F60\u4E0D\u5728\u8FD9\u4E2A\u7FA4\u7684\u53EF\u6307\u6325\u540D\u5355\u91CC\uFF0C\u8FD9\u6B21\u70B9\u51FB\u6CA1\u6709\u751F\u6548\u3002";
|
|
127031
|
-
var noDefaultModelReply = (title) => `\u9879\u76EE\u300C${title}\u300D\u8FD8\u6CA1\u6709\u9ED8\u8BA4\u6A21\u578B\uFF0C\u5F00\u4E0D\u4E86\u4F1A\u8BDD\u3002\u5148\u5728 Ycodium \u91CC\u7ED9\u5B83\u9009\u4E00\u4E2A\u9ED8\u8BA4\u6A21\u578B\uFF0C\u518D\u56DE\u6765\u53D1\u6D88\u606F\u3002`;
|
|
127032
127696
|
var INBOUND_RUNTIME_MODES = /* @__PURE__ */ new Set([
|
|
127033
127697
|
"approval-required",
|
|
127034
127698
|
"auto-accept-edits",
|
|
@@ -127047,6 +127711,7 @@ var imPlugin = definePlugin({
|
|
|
127047
127711
|
id: "im",
|
|
127048
127712
|
apiVersion: 2,
|
|
127049
127713
|
activate: async (ctx) => {
|
|
127714
|
+
const t = makeTranslate(parseReplyLanguage(ctx.config[REPLY_LANGUAGE_FIELD]));
|
|
127050
127715
|
const adapters = [
|
|
127051
127716
|
makeLarkAdapter({
|
|
127052
127717
|
http: ctx.http,
|
|
@@ -127092,84 +127757,99 @@ var imPlugin = definePlugin({
|
|
|
127092
127757
|
const platformColumn = {
|
|
127093
127758
|
key: "platform",
|
|
127094
127759
|
kind: "select",
|
|
127095
|
-
label: "
|
|
127760
|
+
label: t("column.platform.label"),
|
|
127096
127761
|
options: adapters.map((adapter) => ({
|
|
127097
127762
|
value: adapter.platform,
|
|
127098
|
-
|
|
127763
|
+
// 平台名在目录里有本地叫法(飞书、企业微信);没有就用适配器自己的名字。
|
|
127764
|
+
label: t.optional(`platform.${adapter.platform}`) ?? adapter.label,
|
|
127099
127765
|
icon: adapter.icon
|
|
127100
127766
|
}))
|
|
127101
127767
|
};
|
|
127102
127768
|
const credentialColumns = adapters.flatMap(
|
|
127103
127769
|
(adapter) => adapter.columns.map((column) => ({
|
|
127104
127770
|
...column,
|
|
127771
|
+
// 凭据列的字也走目录;适配器自己写的英文只是目录里没有这个键时的回落。
|
|
127772
|
+
label: t.optional(`column.${column.key}.label`) ?? column.label,
|
|
127105
127773
|
showWhen: { key: platformColumn.key, equals: [adapter.platform] }
|
|
127106
127774
|
}))
|
|
127107
127775
|
);
|
|
127108
127776
|
ctx.settingsCard({
|
|
127109
|
-
title: "
|
|
127110
|
-
description: "
|
|
127777
|
+
title: t("settings.title"),
|
|
127778
|
+
description: t("settings.description"),
|
|
127111
127779
|
fields: [
|
|
127780
|
+
{
|
|
127781
|
+
key: REPLY_LANGUAGE_FIELD,
|
|
127782
|
+
kind: "select",
|
|
127783
|
+
label: t("settings.language.label"),
|
|
127784
|
+
description: t("settings.language.description"),
|
|
127785
|
+
options: [
|
|
127786
|
+
{ value: "zh-CN", label: t("settings.language.zhCN") },
|
|
127787
|
+
{ value: "en", label: t("settings.language.en") }
|
|
127788
|
+
]
|
|
127789
|
+
},
|
|
127112
127790
|
{
|
|
127113
127791
|
key: GROUPS_FIELD,
|
|
127114
127792
|
kind: "table",
|
|
127115
|
-
label: "
|
|
127793
|
+
label: t("settings.groups"),
|
|
127116
127794
|
columns: [
|
|
127117
|
-
{
|
|
127795
|
+
{
|
|
127796
|
+
key: "displayName",
|
|
127797
|
+
kind: "text",
|
|
127798
|
+
label: t("column.displayName.label"),
|
|
127799
|
+
placeholder: t("column.displayName.placeholder")
|
|
127800
|
+
},
|
|
127118
127801
|
platformColumn,
|
|
127119
127802
|
...credentialColumns,
|
|
127120
127803
|
{
|
|
127121
127804
|
key: "chatId",
|
|
127122
127805
|
kind: "text",
|
|
127123
|
-
label: "
|
|
127124
|
-
description: "
|
|
127806
|
+
label: t("column.chatId.label"),
|
|
127807
|
+
description: t("column.chatId.description")
|
|
127125
127808
|
},
|
|
127126
127809
|
{
|
|
127127
127810
|
key: "allowedSenders",
|
|
127128
127811
|
kind: "text",
|
|
127129
|
-
label: "
|
|
127130
|
-
description: "
|
|
127812
|
+
label: t("column.allowedSenders.label"),
|
|
127813
|
+
description: t("column.allowedSenders.description")
|
|
127131
127814
|
},
|
|
127132
127815
|
{
|
|
127133
127816
|
// 选项由宿主填,连三态一起——插件只声明「这个格子装的是代理」,宿主因此
|
|
127134
127817
|
// 也就认得出这一行引用了哪个代理,删代理时拦得住(路线图 #64)。
|
|
127135
127818
|
key: "proxy",
|
|
127136
127819
|
kind: "proxy",
|
|
127137
|
-
label: "
|
|
127138
|
-
description: "
|
|
127820
|
+
label: t("column.proxy.label"),
|
|
127821
|
+
description: t("column.proxy.description")
|
|
127139
127822
|
},
|
|
127140
127823
|
{
|
|
127141
127824
|
key: "projectId",
|
|
127142
127825
|
kind: "select",
|
|
127143
|
-
label: "
|
|
127144
|
-
description: "
|
|
127826
|
+
label: t("column.projectId.label"),
|
|
127827
|
+
description: t("column.projectId.description"),
|
|
127145
127828
|
options: [
|
|
127146
|
-
{ value: "", label: "
|
|
127147
|
-
...imProjectOptions(projects, boundProjectIds)
|
|
127829
|
+
{ value: "", label: t("settings.reportOnly") },
|
|
127830
|
+
...imProjectOptions(projects, boundProjectIds, t("settings.archivedSuffix"))
|
|
127148
127831
|
]
|
|
127149
127832
|
},
|
|
127150
127833
|
{
|
|
127151
127834
|
key: "runtimeMode",
|
|
127152
127835
|
kind: "select",
|
|
127153
|
-
label: "
|
|
127154
|
-
description: "
|
|
127836
|
+
label: t("column.runtimeMode.label"),
|
|
127837
|
+
description: t("column.runtimeMode.description"),
|
|
127155
127838
|
options: [
|
|
127156
|
-
{ value: "approval-required", label: "
|
|
127157
|
-
{
|
|
127158
|
-
|
|
127159
|
-
|
|
127160
|
-
},
|
|
127161
|
-
{ value: "auto", label: "Approve routine actions" },
|
|
127162
|
-
{ value: "full-access", label: "Commands and edits without prompts" }
|
|
127839
|
+
{ value: "approval-required", label: t("settings.runtimeMode.approvalRequired") },
|
|
127840
|
+
{ value: "auto-accept-edits", label: t("settings.runtimeMode.autoAcceptEdits") },
|
|
127841
|
+
{ value: "auto", label: t("settings.runtimeMode.auto") },
|
|
127842
|
+
{ value: "full-access", label: t("settings.runtimeMode.fullAccess") }
|
|
127163
127843
|
]
|
|
127164
127844
|
},
|
|
127165
127845
|
{
|
|
127166
127846
|
key: "mode",
|
|
127167
127847
|
kind: "select",
|
|
127168
|
-
label: "
|
|
127169
|
-
description: "
|
|
127848
|
+
label: t("column.mode.label"),
|
|
127849
|
+
description: t("column.mode.description"),
|
|
127170
127850
|
options: [
|
|
127171
|
-
{ value: "turn", label: "
|
|
127172
|
-
{ value: "message", label: "
|
|
127851
|
+
{ value: "turn", label: t("settings.notifyMode.turn") },
|
|
127852
|
+
{ value: "message", label: t("settings.notifyMode.message") }
|
|
127173
127853
|
]
|
|
127174
127854
|
}
|
|
127175
127855
|
]
|
|
@@ -127352,65 +128032,90 @@ ${final.text}`, final.attachments);
|
|
|
127352
128032
|
await deliver(binding, event.summary);
|
|
127353
128033
|
}
|
|
127354
128034
|
});
|
|
127355
|
-
const threadByChat = /* @__PURE__ */ new Map();
|
|
127356
128035
|
const seen = /* @__PURE__ */ new Set();
|
|
127357
128036
|
const seenOrder = [];
|
|
127358
|
-
|
|
127359
|
-
const
|
|
127360
|
-
|
|
127361
|
-
|
|
127362
|
-
|
|
127363
|
-
|
|
127364
|
-
|
|
127365
|
-
|
|
127366
|
-
|
|
127367
|
-
|
|
128037
|
+
let state = emptyState();
|
|
128038
|
+
const stateHandle = ctx.derivedState({
|
|
128039
|
+
key: IM_STATE_KEY,
|
|
128040
|
+
version: IM_STATE_VERSION,
|
|
128041
|
+
events: ["plugin.event-appended"],
|
|
128042
|
+
init: emptyState,
|
|
128043
|
+
apply: foldPluginEvent(ctx.id)
|
|
128044
|
+
});
|
|
128045
|
+
const ready = stateHandle.get().then(
|
|
128046
|
+
(restored) => {
|
|
128047
|
+
state = restored;
|
|
128048
|
+
},
|
|
128049
|
+
(error) => {
|
|
128050
|
+
ctx.log.warn("chat could not restore its saved state", { error: describeError(error) });
|
|
127368
128051
|
}
|
|
128052
|
+
);
|
|
128053
|
+
let persisting = Promise.resolve();
|
|
128054
|
+
const commit = (name, data) => {
|
|
128055
|
+
state = foldImEvent(state, name, data);
|
|
128056
|
+
persisting = persisting.then(() => ctx.events.append({ name, aggregate: { kind: "plugin", id: ctx.id }, data })).then(
|
|
128057
|
+
() => void 0,
|
|
128058
|
+
(error) => {
|
|
128059
|
+
ctx.log.warn("chat could not save its state", { name, error: describeError(error) });
|
|
128060
|
+
}
|
|
128061
|
+
);
|
|
128062
|
+
};
|
|
128063
|
+
const bindChat = (chatKey, threadId) => {
|
|
128064
|
+
commit("chat-updated", { chatKey, threadId });
|
|
128065
|
+
};
|
|
128066
|
+
const answerApproval = async (approval, decision) => {
|
|
128067
|
+
commit("approval-resolved", { requestId: approval.requestId });
|
|
127369
128068
|
await ctx.commands.dispatch({
|
|
127370
128069
|
type: "thread.approval.respond",
|
|
127371
128070
|
commandId: crypto.randomUUID(),
|
|
127372
|
-
threadId:
|
|
127373
|
-
requestId:
|
|
127374
|
-
decision
|
|
128071
|
+
threadId: approval.threadId,
|
|
128072
|
+
requestId: approval.requestId,
|
|
128073
|
+
decision,
|
|
127375
128074
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
127376
128075
|
});
|
|
127377
|
-
ctx.log.info("chat answered an approval", {
|
|
127378
|
-
|
|
127379
|
-
|
|
127380
|
-
|
|
128076
|
+
ctx.log.info("chat answered an approval", { threadId: approval.threadId, decision });
|
|
128077
|
+
};
|
|
128078
|
+
const answerByToken = async (token) => {
|
|
128079
|
+
const found = findApprovalByToken(state, token);
|
|
128080
|
+
if (found === void 0 || found.approval.resolved) return;
|
|
128081
|
+
await answerApproval(found.approval, found.button.decision);
|
|
127381
128082
|
};
|
|
127382
128083
|
ctx.events.on("thread.approval-pending", async (event) => {
|
|
127383
128084
|
const threadId = event.threadId;
|
|
127384
128085
|
if (threadId === null) return;
|
|
128086
|
+
await ready;
|
|
127385
128087
|
const binding = readBindings().find(
|
|
127386
|
-
(candidate) =>
|
|
128088
|
+
(candidate) => chatOf(state, chatKeyOf(candidate)).threadId === threadId
|
|
127387
128089
|
);
|
|
127388
128090
|
if (binding === void 0) return;
|
|
127389
128091
|
const adapter = adapterFor(binding.platform);
|
|
127390
128092
|
if (adapter === void 0) return;
|
|
127391
128093
|
const pending = await ctx.projections.listPendingApprovals(threadId);
|
|
127392
|
-
const approval = pending
|
|
128094
|
+
const approval = pending.find(
|
|
128095
|
+
(candidate) => state.approvals[candidate.requestId] === void 0
|
|
128096
|
+
);
|
|
127393
128097
|
if (approval === void 0) return;
|
|
127394
128098
|
const options = approval.options.length > 0 ? approval.options : [
|
|
127395
|
-
{ decision: "accept", label: "
|
|
127396
|
-
{ decision: "decline", label: "
|
|
128099
|
+
{ decision: "accept", label: t("approval.allow") },
|
|
128100
|
+
{ decision: "decline", label: t("approval.deny") }
|
|
127397
128101
|
];
|
|
127398
|
-
const buttons = options.map((option) => {
|
|
127399
|
-
|
|
127400
|
-
|
|
127401
|
-
|
|
127402
|
-
|
|
127403
|
-
|
|
127404
|
-
|
|
127405
|
-
|
|
127406
|
-
|
|
128102
|
+
const buttons = options.map((option) => ({
|
|
128103
|
+
token: crypto.randomUUID().slice(0, 8),
|
|
128104
|
+
label: option.label,
|
|
128105
|
+
decision: option.decision
|
|
128106
|
+
}));
|
|
128107
|
+
commit("approval-offered", {
|
|
128108
|
+
chatKey: chatKeyOf(binding),
|
|
128109
|
+
threadId,
|
|
128110
|
+
requestId: approval.requestId,
|
|
128111
|
+
options: buttons
|
|
127407
128112
|
});
|
|
127408
|
-
openOptionsByChat.set(chatKeyOf(binding), buttons);
|
|
127409
128113
|
try {
|
|
127410
128114
|
await adapter.askApproval(binding, {
|
|
127411
128115
|
title: approval.appName ?? "Ycodium",
|
|
127412
128116
|
body: approval.detail ?? event.summary,
|
|
127413
|
-
options: buttons
|
|
128117
|
+
options: buttons.map(({ label, token }) => ({ label, token })),
|
|
128118
|
+
replyHint: t("approval.replyHint")
|
|
127414
128119
|
});
|
|
127415
128120
|
ctx.log.info("chat asked for an approval", { threadId, requestId: approval.requestId });
|
|
127416
128121
|
} catch (error) {
|
|
@@ -127419,17 +128124,20 @@ ${final.text}`, final.attachments);
|
|
|
127419
128124
|
});
|
|
127420
128125
|
const isAllowedSender = (binding, sender) => binding.allowedSenders.size === 0 || sender !== null && binding.allowedSenders.has(sender);
|
|
127421
128126
|
const handleApprovalClick = (token, operatorId) => {
|
|
127422
|
-
const
|
|
127423
|
-
if (
|
|
127424
|
-
|
|
128127
|
+
const found = findApprovalByToken(state, token);
|
|
128128
|
+
if (found === void 0) return null;
|
|
128129
|
+
if (found.approval.resolved) return t("approval.alreadyHandled");
|
|
128130
|
+
const target = readBindings().find(
|
|
128131
|
+
(binding) => chatKeyOf(binding) === found.approval.chatKey
|
|
128132
|
+
);
|
|
127425
128133
|
if (target === void 0 || !isAllowedSender(target, operatorId)) {
|
|
127426
128134
|
ctx.log.warn("chat ignored an approval click from someone not on the allow list", {
|
|
127427
|
-
group: target?.displayName ??
|
|
128135
|
+
group: target?.displayName ?? found.approval.chatKey,
|
|
127428
128136
|
operator: operatorId
|
|
127429
128137
|
});
|
|
127430
|
-
return
|
|
128138
|
+
return t("reply.notAllowed");
|
|
127431
128139
|
}
|
|
127432
|
-
void
|
|
128140
|
+
void answerApproval(found.approval, found.button.decision).catch((error) => {
|
|
127433
128141
|
ctx.log.warn("chat could not answer the approval", { error: describeError(error) });
|
|
127434
128142
|
});
|
|
127435
128143
|
return null;
|
|
@@ -127474,19 +128182,153 @@ ${final.text}`, final.attachments);
|
|
|
127474
128182
|
return [];
|
|
127475
128183
|
}
|
|
127476
128184
|
};
|
|
127477
|
-
const
|
|
128185
|
+
const targetOf = (binding) => chatOf(state, chatKeyOf(binding)).target;
|
|
127478
128186
|
const chatByRun = /* @__PURE__ */ new Map();
|
|
127479
|
-
const
|
|
127480
|
-
|
|
127481
|
-
|
|
127482
|
-
|
|
127483
|
-
|
|
127484
|
-
|
|
127485
|
-
(
|
|
127486
|
-
|
|
127487
|
-
|
|
127488
|
-
|
|
127489
|
-
|
|
128187
|
+
const fetchTeams = async (binding) => ctx.plugins.invoke({
|
|
128188
|
+
pluginId: "teams",
|
|
128189
|
+
command: "choices",
|
|
128190
|
+
payload: { projectId: binding.projectId }
|
|
128191
|
+
}).then(
|
|
128192
|
+
(result) => Array.isArray(result) ? result.flatMap(
|
|
128193
|
+
(row) => typeof row === "object" && row !== null && typeof row.teamId === "string" && typeof row.title === "string" ? [{ teamId: row.teamId, title: row.title }] : []
|
|
128194
|
+
) : null
|
|
128195
|
+
).catch(() => null);
|
|
128196
|
+
const listedByChat = /* @__PURE__ */ new Map();
|
|
128197
|
+
const sessionRowsFor = async (binding) => {
|
|
128198
|
+
const chatKey = chatKeyOf(binding);
|
|
128199
|
+
const candidates = Object.entries(state.opened).filter(([, opened]) => opened.projectId === binding.projectId).toReversed().slice(0, SESSION_SCAN_LIMIT);
|
|
128200
|
+
const threads = await Promise.all(
|
|
128201
|
+
candidates.map(([threadId]) => ctx.projections.getThread(threadId))
|
|
128202
|
+
);
|
|
128203
|
+
const rows = [];
|
|
128204
|
+
for (const thread of threads) {
|
|
128205
|
+
if (thread === null || thread.archivedAt != null) continue;
|
|
128206
|
+
rows.push({
|
|
128207
|
+
threadId: thread.threadId,
|
|
128208
|
+
title: thread.title,
|
|
128209
|
+
updatedAt: thread.updatedAt,
|
|
128210
|
+
running: thread.session?.activeTurnId != null,
|
|
128211
|
+
current: chatOf(state, chatKey).threadId === thread.threadId,
|
|
128212
|
+
elsewhere: Object.entries(state.chats).some(
|
|
128213
|
+
([otherKey, record]) => otherKey !== chatKey && record.threadId === thread.threadId
|
|
128214
|
+
)
|
|
128215
|
+
});
|
|
128216
|
+
}
|
|
128217
|
+
return rows.toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
128218
|
+
};
|
|
128219
|
+
const showSessions = async (binding) => {
|
|
128220
|
+
const rows = await sessionRowsFor(binding);
|
|
128221
|
+
listedByChat.set(chatKeyOf(binding), listedThreadIds(rows));
|
|
128222
|
+
await deliver(binding, formatSessions(rows, Date.now(), t));
|
|
128223
|
+
};
|
|
128224
|
+
const resumeSession = async (binding, arg) => {
|
|
128225
|
+
const chatKey = chatKeyOf(binding);
|
|
128226
|
+
const rows = await sessionRowsFor(binding);
|
|
128227
|
+
const picked = pickSession(arg, listedByChat.get(chatKey), rows);
|
|
128228
|
+
if (picked === null) {
|
|
128229
|
+
await deliver(binding, t("resume.notFound", { query: arg }));
|
|
128230
|
+
return;
|
|
128231
|
+
}
|
|
128232
|
+
const target = rows.find((row) => row.threadId === picked);
|
|
128233
|
+
if (target === void 0) {
|
|
128234
|
+
await deliver(binding, t("resume.gone"));
|
|
128235
|
+
return;
|
|
128236
|
+
}
|
|
128237
|
+
if (rows.some((row) => row.current && row.running)) {
|
|
128238
|
+
await deliver(binding, t("resume.busy"));
|
|
128239
|
+
return;
|
|
128240
|
+
}
|
|
128241
|
+
if (target.current) {
|
|
128242
|
+
await deliver(binding, t("resume.already"));
|
|
128243
|
+
return;
|
|
128244
|
+
}
|
|
128245
|
+
if (target.running && target.elsewhere) {
|
|
128246
|
+
await deliver(binding, t("resume.runningElsewhere"));
|
|
128247
|
+
return;
|
|
128248
|
+
}
|
|
128249
|
+
for (const [otherKey, record] of Object.entries(state.chats)) {
|
|
128250
|
+
if (otherKey !== chatKey && record.threadId === picked) bindChat(otherKey, null);
|
|
128251
|
+
}
|
|
128252
|
+
commit("chat-updated", { chatKey, threadId: picked, target: { kind: "thread" } });
|
|
128253
|
+
listedByChat.delete(chatKey);
|
|
128254
|
+
await deliver(binding, t("resume.done", { title: target.title }));
|
|
128255
|
+
};
|
|
128256
|
+
const currentModelOf = async (binding) => {
|
|
128257
|
+
const chat = chatOf(state, chatKeyOf(binding));
|
|
128258
|
+
if (chat.threadId !== null) {
|
|
128259
|
+
const thread = await ctx.projections.getThread(chat.threadId).catch(() => null);
|
|
128260
|
+
if (thread !== null) {
|
|
128261
|
+
return {
|
|
128262
|
+
instanceId: thread.modelSelection.instanceId,
|
|
128263
|
+
model: thread.modelSelection.model
|
|
128264
|
+
};
|
|
128265
|
+
}
|
|
128266
|
+
}
|
|
128267
|
+
if (chat.model !== null) return chat.model;
|
|
128268
|
+
const project = await ctx.projections.getProject(binding.projectId).catch(() => null);
|
|
128269
|
+
const fallback = project?.defaultModelSelection ?? null;
|
|
128270
|
+
return fallback === null ? null : { instanceId: fallback.instanceId, model: fallback.model };
|
|
128271
|
+
};
|
|
128272
|
+
const handleModel = async (binding, arg) => {
|
|
128273
|
+
const chatKey = chatKeyOf(binding);
|
|
128274
|
+
const instances = await ctx.providers.listInstances().catch(() => null);
|
|
128275
|
+
const choices = instances === null ? [] : modelChoices(instances);
|
|
128276
|
+
if (arg === "") {
|
|
128277
|
+
await deliver(binding, formatModels(await currentModelOf(binding), choices, t));
|
|
128278
|
+
return;
|
|
128279
|
+
}
|
|
128280
|
+
if (choices.length === 0) {
|
|
128281
|
+
await deliver(binding, t("model.unavailable"));
|
|
128282
|
+
return;
|
|
128283
|
+
}
|
|
128284
|
+
const picked = pickModel(arg, choices);
|
|
128285
|
+
if (picked === null) {
|
|
128286
|
+
await deliver(binding, t("model.notFound", { query: arg }));
|
|
128287
|
+
return;
|
|
128288
|
+
}
|
|
128289
|
+
const selection = { instanceId: picked.instanceId, model: picked.model };
|
|
128290
|
+
commit("chat-updated", { chatKey, model: selection });
|
|
128291
|
+
const threadId = chatOf(state, chatKey).threadId;
|
|
128292
|
+
if (threadId !== null && await threadStillUsable(binding, threadId)) {
|
|
128293
|
+
try {
|
|
128294
|
+
await ctx.commands.dispatch({
|
|
128295
|
+
type: "thread.meta.update",
|
|
128296
|
+
commandId: crypto.randomUUID(),
|
|
128297
|
+
threadId,
|
|
128298
|
+
modelSelection: selection
|
|
128299
|
+
});
|
|
128300
|
+
} catch (error) {
|
|
128301
|
+
ctx.log.warn("chat could not switch the thread model", { error: describeError(error) });
|
|
128302
|
+
await deliver(binding, t("model.setFailed"));
|
|
128303
|
+
return;
|
|
128304
|
+
}
|
|
128305
|
+
await deliver(binding, t("model.setNow", { model: modelLabel(picked) }));
|
|
128306
|
+
return;
|
|
128307
|
+
}
|
|
128308
|
+
await deliver(binding, t("model.setNext", { model: modelLabel(picked) }));
|
|
128309
|
+
};
|
|
128310
|
+
const handlePlan = async (binding, mode) => {
|
|
128311
|
+
if (mode === "invalid") {
|
|
128312
|
+
await deliver(binding, t("plan.usage"));
|
|
128313
|
+
return;
|
|
128314
|
+
}
|
|
128315
|
+
const chatKey = chatKeyOf(binding);
|
|
128316
|
+
const current = chatOf(state, chatKey).plan;
|
|
128317
|
+
const next = mode === "toggle" ? !current : mode === "on";
|
|
128318
|
+
if (next === current) {
|
|
128319
|
+
await deliver(binding, t(next ? "plan.alreadyOn" : "plan.alreadyOff"));
|
|
128320
|
+
return;
|
|
128321
|
+
}
|
|
128322
|
+
commit("chat-updated", { chatKey, plan: next });
|
|
128323
|
+
await deliver(binding, t(next ? "plan.on" : "plan.off"));
|
|
128324
|
+
};
|
|
128325
|
+
const handleCommand = async (binding, message, teams) => {
|
|
128326
|
+
const command = parseChatCommand({
|
|
128327
|
+
text: message.text,
|
|
128328
|
+
teams,
|
|
128329
|
+
// 中文别名只在回话语言是中文时认,免得英文用户打一个「停」就被当成命令。
|
|
128330
|
+
chinese: t.language === "zh-CN"
|
|
128331
|
+
});
|
|
127490
128332
|
const chatKey = chatKeyOf(binding);
|
|
127491
128333
|
if (command.kind !== "message") {
|
|
127492
128334
|
ctx.log.info("chat handled a command", {
|
|
@@ -127498,47 +128340,61 @@ ${final.text}`, final.attachments);
|
|
|
127498
128340
|
case "message":
|
|
127499
128341
|
return false;
|
|
127500
128342
|
case "selectTeam":
|
|
127501
|
-
|
|
127502
|
-
|
|
127503
|
-
|
|
128343
|
+
commit("chat-updated", {
|
|
128344
|
+
chatKey,
|
|
128345
|
+
target: { kind: "team", teamId: command.team.teamId },
|
|
128346
|
+
threadId: null
|
|
128347
|
+
});
|
|
128348
|
+
await deliver(binding, t("command.teamSelected", { title: command.team.title }));
|
|
127504
128349
|
return true;
|
|
127505
128350
|
case "selectThread":
|
|
127506
|
-
|
|
127507
|
-
|
|
127508
|
-
await deliver(binding, "\u597D\uFF0C\u63A5\u4E0B\u6765\u5F00\u666E\u901A\u4F1A\u8BDD\u3002");
|
|
128351
|
+
commit("chat-updated", { chatKey, target: { kind: "thread" }, threadId: null });
|
|
128352
|
+
await deliver(binding, t("command.threadSelected"));
|
|
127509
128353
|
return true;
|
|
127510
128354
|
case "showTargets":
|
|
127511
|
-
await deliver(
|
|
127512
|
-
binding,
|
|
127513
|
-
describeTargets(targetByChat.get(chatKey) ?? { kind: "thread" }, teams)
|
|
127514
|
-
);
|
|
128355
|
+
await deliver(binding, describeTargets(targetOf(binding), teams, t));
|
|
127515
128356
|
return true;
|
|
127516
128357
|
case "teamNotFound":
|
|
127517
128358
|
await deliver(
|
|
127518
128359
|
binding,
|
|
127519
128360
|
[
|
|
127520
|
-
|
|
128361
|
+
t("command.teamNotFound", { query: command.query }),
|
|
127521
128362
|
"",
|
|
127522
|
-
describeTargets(
|
|
128363
|
+
describeTargets(targetOf(binding), teams, t)
|
|
127523
128364
|
].join("\n")
|
|
127524
128365
|
);
|
|
127525
128366
|
return true;
|
|
127526
128367
|
case "noTeams":
|
|
127527
|
-
await deliver(binding, "
|
|
128368
|
+
await deliver(binding, t("command.noTeams"));
|
|
127528
128369
|
return true;
|
|
127529
128370
|
case "help":
|
|
127530
|
-
await deliver(binding, helpText());
|
|
128371
|
+
await deliver(binding, helpText(t));
|
|
128372
|
+
return true;
|
|
128373
|
+
case "sessions":
|
|
128374
|
+
await showSessions(binding);
|
|
128375
|
+
return true;
|
|
128376
|
+
case "resume":
|
|
128377
|
+
await resumeSession(binding, command.arg);
|
|
128378
|
+
return true;
|
|
128379
|
+
case "model":
|
|
128380
|
+
await handleModel(binding, command.arg);
|
|
128381
|
+
return true;
|
|
128382
|
+
case "plan":
|
|
128383
|
+
await handlePlan(binding, command.mode);
|
|
127531
128384
|
return true;
|
|
127532
128385
|
case "new":
|
|
127533
|
-
|
|
127534
|
-
await deliver(binding, "
|
|
128386
|
+
bindChat(chatKey, null);
|
|
128387
|
+
await deliver(binding, t("command.newSession"));
|
|
127535
128388
|
return true;
|
|
127536
128389
|
case "status": {
|
|
127537
|
-
const threadId =
|
|
127538
|
-
const routed =
|
|
127539
|
-
const where = routed.kind === "team" ?
|
|
128390
|
+
const threadId = chatOf(state, chatKey).threadId ?? void 0;
|
|
128391
|
+
const routed = targetOf(binding);
|
|
128392
|
+
const where = routed.kind === "team" ? t("status.routedTeam", {
|
|
128393
|
+
title: teams.find((team) => team.teamId === routed.teamId)?.title ?? routed.teamId
|
|
128394
|
+
}) : t("status.routedThread");
|
|
128395
|
+
const planLine = chatOf(state, chatKey).plan ? [t("status.planOn")] : [];
|
|
127540
128396
|
if (threadId === void 0) {
|
|
127541
|
-
await deliver(binding,
|
|
128397
|
+
await deliver(binding, [t("status.nothingRunning", { where }), ...planLine].join("\n"));
|
|
127542
128398
|
return true;
|
|
127543
128399
|
}
|
|
127544
128400
|
const thread = await ctx.projections.getThread(threadId);
|
|
@@ -127547,22 +128403,24 @@ ${final.text}`, final.attachments);
|
|
|
127547
128403
|
binding,
|
|
127548
128404
|
[
|
|
127549
128405
|
where,
|
|
127550
|
-
|
|
127551
|
-
|
|
128406
|
+
t("status.session", { title: thread?.title ?? threadId }),
|
|
128407
|
+
...thread === null ? [] : [t("status.model", { model: rawModelLabel(thread.modelSelection) })],
|
|
128408
|
+
...planLine,
|
|
128409
|
+
running ? t("status.running") : t("status.idle")
|
|
127552
128410
|
].join("\n")
|
|
127553
128411
|
);
|
|
127554
128412
|
return true;
|
|
127555
128413
|
}
|
|
127556
128414
|
case "stop": {
|
|
127557
|
-
const threadId =
|
|
128415
|
+
const threadId = chatOf(state, chatKey).threadId ?? void 0;
|
|
127558
128416
|
if (threadId === void 0) {
|
|
127559
|
-
await deliver(binding, "
|
|
128417
|
+
await deliver(binding, t("command.stopNoSession"));
|
|
127560
128418
|
return true;
|
|
127561
128419
|
}
|
|
127562
128420
|
const thread = await ctx.projections.getThread(threadId);
|
|
127563
128421
|
const activeTurnId = thread?.session?.activeTurnId ?? null;
|
|
127564
128422
|
if (activeTurnId === null) {
|
|
127565
|
-
await deliver(binding, "
|
|
128423
|
+
await deliver(binding, t("command.stopNoTurn"));
|
|
127566
128424
|
return true;
|
|
127567
128425
|
}
|
|
127568
128426
|
await ctx.commands.dispatch({
|
|
@@ -127573,7 +128431,7 @@ ${final.text}`, final.attachments);
|
|
|
127573
128431
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
127574
128432
|
});
|
|
127575
128433
|
await clearWorking(binding, threadId);
|
|
127576
|
-
await deliver(binding, "
|
|
128434
|
+
await deliver(binding, t("command.stopped"));
|
|
127577
128435
|
return true;
|
|
127578
128436
|
}
|
|
127579
128437
|
}
|
|
@@ -127599,10 +128457,28 @@ ${final.text}`, final.attachments);
|
|
|
127599
128457
|
}
|
|
127600
128458
|
ctx.log.info("chat started a team run", { group: binding.displayName, teamId, runId });
|
|
127601
128459
|
};
|
|
128460
|
+
const threadStillUsable = async (binding, threadId) => {
|
|
128461
|
+
try {
|
|
128462
|
+
const thread = await ctx.projections.getThread(threadId);
|
|
128463
|
+
return thread !== null && thread.archivedAt == null && thread.projectId === binding.projectId;
|
|
128464
|
+
} catch {
|
|
128465
|
+
return true;
|
|
128466
|
+
}
|
|
128467
|
+
};
|
|
128468
|
+
const interactionModeOf = (chatKey) => chatOf(state, chatKey).plan ? "plan" : "default";
|
|
127602
128469
|
const startTurn = async (binding, message) => {
|
|
127603
128470
|
const chatKey = chatKeyOf(binding);
|
|
127604
128471
|
const text = message.text;
|
|
127605
|
-
let threadId =
|
|
128472
|
+
let threadId = chatOf(state, chatKey).threadId ?? void 0;
|
|
128473
|
+
if (threadId !== void 0 && !await threadStillUsable(binding, threadId)) {
|
|
128474
|
+
ctx.log.info("chat dropped a saved thread that is no longer usable", {
|
|
128475
|
+
group: binding.displayName,
|
|
128476
|
+
threadId
|
|
128477
|
+
});
|
|
128478
|
+
bindChat(chatKey, null);
|
|
128479
|
+
threadId = void 0;
|
|
128480
|
+
await deliver(binding, t("reply.threadGone"));
|
|
128481
|
+
}
|
|
127606
128482
|
if (threadId === void 0) {
|
|
127607
128483
|
const project = await ctx.projections.getProject(binding.projectId);
|
|
127608
128484
|
if (project === null) {
|
|
@@ -127612,30 +128488,37 @@ ${final.text}`, final.attachments);
|
|
|
127612
128488
|
});
|
|
127613
128489
|
return null;
|
|
127614
128490
|
}
|
|
127615
|
-
|
|
128491
|
+
const modelSelection = chatOf(state, chatKey).model ?? project.defaultModelSelection;
|
|
128492
|
+
if (modelSelection === null) {
|
|
127616
128493
|
ctx.log.warn("chat cannot start a thread: the project has no default model", {
|
|
127617
128494
|
group: binding.displayName,
|
|
127618
128495
|
projectId: binding.projectId
|
|
127619
128496
|
});
|
|
127620
|
-
await deliver(binding,
|
|
128497
|
+
await deliver(binding, t("reply.noDefaultModel", { title: project.title }));
|
|
127621
128498
|
return null;
|
|
127622
128499
|
}
|
|
127623
|
-
|
|
128500
|
+
const createdThreadId = crypto.randomUUID();
|
|
128501
|
+
threadId = createdThreadId;
|
|
127624
128502
|
await ctx.commands.dispatch({
|
|
127625
128503
|
type: "thread.create",
|
|
127626
128504
|
commandId: crypto.randomUUID(),
|
|
127627
128505
|
threadId,
|
|
127628
128506
|
projectId: binding.projectId,
|
|
127629
128507
|
title: titleFrom(text || message.resource?.name || "Chat"),
|
|
127630
|
-
modelSelection
|
|
128508
|
+
modelSelection,
|
|
127631
128509
|
runtimeMode: binding.runtimeMode,
|
|
127632
|
-
interactionMode:
|
|
128510
|
+
interactionMode: interactionModeOf(chatKey),
|
|
127633
128511
|
branch: null,
|
|
127634
128512
|
worktreePath: null,
|
|
127635
128513
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
127636
128514
|
});
|
|
127637
|
-
|
|
127638
|
-
|
|
128515
|
+
commit("thread-opened", {
|
|
128516
|
+
chatKey,
|
|
128517
|
+
threadId: createdThreadId,
|
|
128518
|
+
projectId: binding.projectId,
|
|
128519
|
+
openedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
128520
|
+
});
|
|
128521
|
+
projectByThread.set(createdThreadId, binding.projectId);
|
|
127639
128522
|
}
|
|
127640
128523
|
const attachments = await collectAttachment(binding, threadId, message);
|
|
127641
128524
|
await ctx.commands.dispatch({
|
|
@@ -127650,7 +128533,7 @@ ${final.text}`, final.attachments);
|
|
|
127650
128533
|
},
|
|
127651
128534
|
titleSeed: titleFrom(text || attachments[0]?.name || "Chat"),
|
|
127652
128535
|
runtimeMode: binding.runtimeMode,
|
|
127653
|
-
interactionMode:
|
|
128536
|
+
interactionMode: interactionModeOf(chatKey),
|
|
127654
128537
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
127655
128538
|
});
|
|
127656
128539
|
ctx.log.info("chat started a turn from a message", {
|
|
@@ -127664,6 +128547,15 @@ ${final.text}`, final.attachments);
|
|
|
127664
128547
|
const connections = [];
|
|
127665
128548
|
const started = /* @__PURE__ */ new Set();
|
|
127666
128549
|
let disposed = false;
|
|
128550
|
+
const chatQueues = /* @__PURE__ */ new Map();
|
|
128551
|
+
const enqueueForChat = (chatKey, work) => {
|
|
128552
|
+
const run = (chatQueues.get(chatKey) ?? Promise.resolve()).then(work).catch((error) => {
|
|
128553
|
+
ctx.log.warn("chat could not handle the message", { error: describeError(error) });
|
|
128554
|
+
}).then(() => {
|
|
128555
|
+
if (chatQueues.get(chatKey) === run) chatQueues.delete(chatKey);
|
|
128556
|
+
});
|
|
128557
|
+
chatQueues.set(chatKey, run);
|
|
128558
|
+
};
|
|
127667
128559
|
const inboundHandlersFor = (platform) => ({
|
|
127668
128560
|
onError: (message) => ctx.log.warn("chat inbound connection failed", { platform, message }),
|
|
127669
128561
|
onApproval: handleApprovalClick,
|
|
@@ -127678,16 +128570,21 @@ ${final.text}`, final.attachments);
|
|
|
127678
128570
|
});
|
|
127679
128571
|
return;
|
|
127680
128572
|
}
|
|
127681
|
-
const open =
|
|
127682
|
-
const answerToken = open === void 0 ? null : adapterFor(target.platform)?.answerByText?.(
|
|
128573
|
+
const open = openApprovalOf(state, chatKeyOf(target));
|
|
128574
|
+
const answerToken = open === void 0 ? null : adapterFor(target.platform)?.answerByText?.(
|
|
128575
|
+
target,
|
|
128576
|
+
message.text,
|
|
128577
|
+
open.options.map(({ label, token }) => ({ label, token }))
|
|
128578
|
+
) ?? null;
|
|
127683
128579
|
if (answerToken !== null) {
|
|
127684
128580
|
void answerByToken(answerToken).catch((error) => {
|
|
127685
128581
|
ctx.log.warn("chat could not answer the approval", { error: describeError(error) });
|
|
127686
128582
|
});
|
|
127687
128583
|
return;
|
|
127688
128584
|
}
|
|
127689
|
-
|
|
127690
|
-
|
|
128585
|
+
enqueueForChat(chatKeyOf(target), async () => {
|
|
128586
|
+
const teams = await fetchTeams(target);
|
|
128587
|
+
if (await handleCommand(target, message, teams ?? [])) return;
|
|
127691
128588
|
const project = await ctx.projections.getProject(target.projectId);
|
|
127692
128589
|
if (project === null || project.archivedAt != null) {
|
|
127693
128590
|
if (project === null) {
|
|
@@ -127699,21 +128596,28 @@ ${final.text}`, final.attachments);
|
|
|
127699
128596
|
if (archivedReplyCooldown.tryAcquire(chatKeyOf(target))) {
|
|
127700
128597
|
await deliver(
|
|
127701
128598
|
target,
|
|
127702
|
-
project === null ?
|
|
128599
|
+
project === null ? t("reply.projectMissing", { group: target.displayName }) : t("reply.projectArchived", { title: project.title })
|
|
127703
128600
|
);
|
|
127704
128601
|
}
|
|
127705
128602
|
return;
|
|
127706
128603
|
}
|
|
127707
|
-
const routed =
|
|
128604
|
+
const routed = targetOf(target);
|
|
127708
128605
|
if (routed.kind === "team") {
|
|
127709
|
-
|
|
127710
|
-
|
|
127711
|
-
|
|
128606
|
+
if (teams !== null && !teams.some((team) => team.teamId === routed.teamId)) {
|
|
128607
|
+
commit("chat-updated", {
|
|
128608
|
+
chatKey: chatKeyOf(target),
|
|
128609
|
+
target: { kind: "thread" },
|
|
128610
|
+
threadId: null
|
|
128611
|
+
});
|
|
128612
|
+
await deliver(target, t("reply.teamGone"));
|
|
128613
|
+
} else {
|
|
128614
|
+
await startTeamRun(target, routed.teamId, message.text);
|
|
128615
|
+
await markWorking(target, chatKeyOf(target), message.messageId);
|
|
128616
|
+
return;
|
|
128617
|
+
}
|
|
127712
128618
|
}
|
|
127713
128619
|
const threadId = await startTurn(target, message);
|
|
127714
128620
|
if (threadId !== null) await markWorking(target, threadId, message.messageId);
|
|
127715
|
-
})().catch((error) => {
|
|
127716
|
-
ctx.log.warn("chat could not handle the message", { error: describeError(error) });
|
|
127717
128621
|
});
|
|
127718
128622
|
}
|
|
127719
128623
|
});
|
|
@@ -127723,7 +128627,7 @@ ${final.text}`, final.attachments);
|
|
|
127723
128627
|
const fingerprint = `${binding.platform}:${adapter.columns.map((column) => binding.values[column.key] ?? "").join(" ")}`;
|
|
127724
128628
|
if (started.has(fingerprint)) continue;
|
|
127725
128629
|
started.add(fingerprint);
|
|
127726
|
-
void
|
|
128630
|
+
void ready.then(() => adapter.connect(binding, inboundHandlersFor(binding.platform))).then((connection) => {
|
|
127727
128631
|
if (disposed) connection.close();
|
|
127728
128632
|
else connections.push(connection);
|
|
127729
128633
|
}).catch((error) => {
|