codex-to-im 1.0.20 → 1.0.21
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 +44 -4
- package/README_EN.md +44 -10
- package/config.env.example +22 -9
- package/dist/cli.mjs +272 -3
- package/dist/daemon.mjs +645 -317
- package/dist/ui-server.mjs +1485 -725
- package/docs/install-windows.md +41 -17
- package/package.json +1 -1
- package/scripts/doctor.sh +12 -5
package/dist/ui-server.mjs
CHANGED
|
@@ -4575,6 +4575,12 @@ import fs9 from "node:fs";
|
|
|
4575
4575
|
import fs from "node:fs";
|
|
4576
4576
|
import os from "node:os";
|
|
4577
4577
|
import path from "node:path";
|
|
4578
|
+
function toFeishuConfig(channel) {
|
|
4579
|
+
return channel?.provider === "feishu" ? channel.config : void 0;
|
|
4580
|
+
}
|
|
4581
|
+
function toWeixinConfig(channel) {
|
|
4582
|
+
return channel?.provider === "weixin" ? channel.config : void 0;
|
|
4583
|
+
}
|
|
4578
4584
|
var LEGACY_CTI_HOME = path.join(os.homedir(), ".claude-to-im");
|
|
4579
4585
|
var DEFAULT_CTI_HOME = path.join(os.homedir(), ".codex-to-im");
|
|
4580
4586
|
var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
|
|
@@ -4585,6 +4591,7 @@ function resolveDefaultCtiHome() {
|
|
|
4585
4591
|
}
|
|
4586
4592
|
var CTI_HOME = process.env.CTI_HOME || resolveDefaultCtiHome();
|
|
4587
4593
|
var CONFIG_PATH = path.join(CTI_HOME, "config.env");
|
|
4594
|
+
var CONFIG_V2_PATH = path.join(CTI_HOME, "config.v2.json");
|
|
4588
4595
|
function expandHomePath(value) {
|
|
4589
4596
|
if (!value) return value;
|
|
4590
4597
|
if (value === "~") return os.homedir();
|
|
@@ -4638,48 +4645,187 @@ function parseReasoningEffort(value) {
|
|
|
4638
4645
|
}
|
|
4639
4646
|
return void 0;
|
|
4640
4647
|
}
|
|
4641
|
-
function
|
|
4642
|
-
const
|
|
4648
|
+
function normalizeFeishuSite(value) {
|
|
4649
|
+
const normalized = (value || "").trim().replace(/\/+$/, "").toLowerCase();
|
|
4650
|
+
if (!normalized) return "feishu";
|
|
4651
|
+
if (normalized === "lark") return "lark";
|
|
4652
|
+
if (normalized === "feishu") return "feishu";
|
|
4653
|
+
if (normalized.includes("open.larksuite.com")) return "lark";
|
|
4654
|
+
return "feishu";
|
|
4655
|
+
}
|
|
4656
|
+
function feishuSiteToApiBaseUrl(site) {
|
|
4657
|
+
return normalizeFeishuSite(site) === "lark" ? "https://open.larksuite.com" : "https://open.feishu.cn";
|
|
4658
|
+
}
|
|
4659
|
+
function nowIso() {
|
|
4660
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
4661
|
+
}
|
|
4662
|
+
function ensureConfigDir() {
|
|
4663
|
+
fs.mkdirSync(CTI_HOME, { recursive: true });
|
|
4664
|
+
}
|
|
4665
|
+
function readConfigV2File() {
|
|
4666
|
+
try {
|
|
4667
|
+
const parsed = JSON.parse(fs.readFileSync(CONFIG_V2_PATH, "utf-8"));
|
|
4668
|
+
if (parsed && parsed.schemaVersion === 2 && parsed.runtime && Array.isArray(parsed.channels)) {
|
|
4669
|
+
return parsed;
|
|
4670
|
+
}
|
|
4671
|
+
return null;
|
|
4672
|
+
} catch {
|
|
4673
|
+
return null;
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
function writeConfigV2File(config) {
|
|
4677
|
+
ensureConfigDir();
|
|
4678
|
+
const tmpPath = CONFIG_V2_PATH + ".tmp";
|
|
4679
|
+
fs.writeFileSync(tmpPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
4680
|
+
fs.renameSync(tmpPath, CONFIG_V2_PATH);
|
|
4681
|
+
}
|
|
4682
|
+
function normalizeChannelId(value) {
|
|
4683
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
|
|
4684
|
+
}
|
|
4685
|
+
function defaultAliasForProvider(provider) {
|
|
4686
|
+
return provider === "feishu" ? "\u98DE\u4E66" : "\u5FAE\u4FE1";
|
|
4687
|
+
}
|
|
4688
|
+
function buildDefaultChannelId(provider) {
|
|
4689
|
+
return `${provider}-default`;
|
|
4690
|
+
}
|
|
4691
|
+
function migrateLegacyEnvToV2(env) {
|
|
4643
4692
|
const rawRuntime = env.get("CTI_RUNTIME") || "codex";
|
|
4644
4693
|
const runtime = ["claude", "codex", "auto"].includes(rawRuntime) ? rawRuntime : "codex";
|
|
4694
|
+
const enabledChannels = splitCsv(env.get("CTI_ENABLED_CHANNELS")) ?? ["feishu"];
|
|
4695
|
+
const timestamp = nowIso();
|
|
4696
|
+
const channels = [];
|
|
4697
|
+
const hasFeishuConfig = Boolean(
|
|
4698
|
+
env.get("CTI_FEISHU_APP_ID") || env.get("CTI_FEISHU_APP_SECRET") || env.get("CTI_FEISHU_ALLOWED_USERS") || enabledChannels.includes("feishu")
|
|
4699
|
+
);
|
|
4700
|
+
if (hasFeishuConfig) {
|
|
4701
|
+
channels.push({
|
|
4702
|
+
id: buildDefaultChannelId("feishu"),
|
|
4703
|
+
alias: defaultAliasForProvider("feishu"),
|
|
4704
|
+
provider: "feishu",
|
|
4705
|
+
enabled: enabledChannels.includes("feishu"),
|
|
4706
|
+
createdAt: timestamp,
|
|
4707
|
+
updatedAt: timestamp,
|
|
4708
|
+
config: {
|
|
4709
|
+
appId: env.get("CTI_FEISHU_APP_ID") || void 0,
|
|
4710
|
+
appSecret: env.get("CTI_FEISHU_APP_SECRET") || void 0,
|
|
4711
|
+
site: normalizeFeishuSite(env.get("CTI_FEISHU_SITE") || env.get("CTI_FEISHU_DOMAIN")),
|
|
4712
|
+
allowedUsers: splitCsv(env.get("CTI_FEISHU_ALLOWED_USERS")),
|
|
4713
|
+
streamingEnabled: env.has("CTI_FEISHU_STREAMING_ENABLED") ? env.get("CTI_FEISHU_STREAMING_ENABLED") === "true" : true,
|
|
4714
|
+
feedbackMarkdownEnabled: env.has("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED") ? env.get("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED") === "true" : true
|
|
4715
|
+
}
|
|
4716
|
+
});
|
|
4717
|
+
}
|
|
4718
|
+
const hasWeixinConfig = Boolean(
|
|
4719
|
+
env.get("CTI_WEIXIN_BASE_URL") || env.get("CTI_WEIXIN_CDN_BASE_URL") || env.get("CTI_WEIXIN_MEDIA_ENABLED") || enabledChannels.includes("weixin")
|
|
4720
|
+
);
|
|
4721
|
+
if (hasWeixinConfig) {
|
|
4722
|
+
channels.push({
|
|
4723
|
+
id: buildDefaultChannelId("weixin"),
|
|
4724
|
+
alias: defaultAliasForProvider("weixin"),
|
|
4725
|
+
provider: "weixin",
|
|
4726
|
+
enabled: enabledChannels.includes("weixin"),
|
|
4727
|
+
createdAt: timestamp,
|
|
4728
|
+
updatedAt: timestamp,
|
|
4729
|
+
config: {
|
|
4730
|
+
baseUrl: env.get("CTI_WEIXIN_BASE_URL") || void 0,
|
|
4731
|
+
cdnBaseUrl: env.get("CTI_WEIXIN_CDN_BASE_URL") || void 0,
|
|
4732
|
+
mediaEnabled: env.has("CTI_WEIXIN_MEDIA_ENABLED") ? env.get("CTI_WEIXIN_MEDIA_ENABLED") === "true" : void 0,
|
|
4733
|
+
feedbackMarkdownEnabled: env.has("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED") ? env.get("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED") === "true" : false
|
|
4734
|
+
}
|
|
4735
|
+
});
|
|
4736
|
+
}
|
|
4737
|
+
return {
|
|
4738
|
+
schemaVersion: 2,
|
|
4739
|
+
runtime: {
|
|
4740
|
+
provider: runtime,
|
|
4741
|
+
defaultWorkspaceRoot: expandHomePath(env.get("CTI_DEFAULT_WORKSPACE_ROOT")) || void 0,
|
|
4742
|
+
defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
|
|
4743
|
+
defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
|
|
4744
|
+
historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
|
|
4745
|
+
codexSkipGitRepoCheck: env.has("CTI_CODEX_SKIP_GIT_REPO_CHECK") ? env.get("CTI_CODEX_SKIP_GIT_REPO_CHECK") === "true" : true,
|
|
4746
|
+
codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
|
|
4747
|
+
codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
|
|
4748
|
+
uiAllowLan: env.get("CTI_UI_ALLOW_LAN") === "true",
|
|
4749
|
+
uiAccessToken: env.get("CTI_UI_ACCESS_TOKEN") || void 0,
|
|
4750
|
+
autoApprove: env.get("CTI_AUTO_APPROVE") === "true"
|
|
4751
|
+
},
|
|
4752
|
+
channels
|
|
4753
|
+
};
|
|
4754
|
+
}
|
|
4755
|
+
function getChannelByProvider(config, provider) {
|
|
4756
|
+
const preferredId = buildDefaultChannelId(provider);
|
|
4757
|
+
return config.channels.find((channel) => channel.id === preferredId) || config.channels.find((channel) => channel.provider === provider);
|
|
4758
|
+
}
|
|
4759
|
+
function expandConfig(v2) {
|
|
4760
|
+
return {
|
|
4761
|
+
schemaVersion: 2,
|
|
4762
|
+
channels: v2.channels,
|
|
4763
|
+
runtime: v2.runtime.provider,
|
|
4764
|
+
enabledChannels: Array.from(new Set(
|
|
4765
|
+
v2.channels.filter((channel) => channel.enabled).map((channel) => channel.provider)
|
|
4766
|
+
)),
|
|
4767
|
+
defaultWorkspaceRoot: v2.runtime.defaultWorkspaceRoot,
|
|
4768
|
+
defaultModel: v2.runtime.defaultModel,
|
|
4769
|
+
defaultMode: v2.runtime.defaultMode || "code",
|
|
4770
|
+
historyMessageLimit: v2.runtime.historyMessageLimit ?? 8,
|
|
4771
|
+
codexSkipGitRepoCheck: v2.runtime.codexSkipGitRepoCheck ?? true,
|
|
4772
|
+
codexSandboxMode: v2.runtime.codexSandboxMode ?? "workspace-write",
|
|
4773
|
+
codexReasoningEffort: v2.runtime.codexReasoningEffort ?? "medium",
|
|
4774
|
+
uiAllowLan: v2.runtime.uiAllowLan === true,
|
|
4775
|
+
uiAccessToken: v2.runtime.uiAccessToken || void 0,
|
|
4776
|
+
autoApprove: v2.runtime.autoApprove === true
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
function buildV2FileFromExpandedConfig(config, current) {
|
|
4780
|
+
const hasExplicitChannels = Array.isArray(config.channels);
|
|
4781
|
+
let channels = hasExplicitChannels ? [...config.channels || []] : [...current?.channels || []];
|
|
4645
4782
|
return {
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4783
|
+
schemaVersion: 2,
|
|
4784
|
+
runtime: {
|
|
4785
|
+
provider: config.runtime,
|
|
4786
|
+
defaultWorkspaceRoot: config.defaultWorkspaceRoot,
|
|
4787
|
+
defaultModel: config.defaultModel,
|
|
4788
|
+
defaultMode: config.defaultMode,
|
|
4789
|
+
historyMessageLimit: config.historyMessageLimit,
|
|
4790
|
+
codexSkipGitRepoCheck: config.codexSkipGitRepoCheck,
|
|
4791
|
+
codexSandboxMode: config.codexSandboxMode,
|
|
4792
|
+
codexReasoningEffort: config.codexReasoningEffort,
|
|
4793
|
+
uiAllowLan: config.uiAllowLan,
|
|
4794
|
+
uiAccessToken: config.uiAccessToken,
|
|
4795
|
+
autoApprove: config.autoApprove
|
|
4796
|
+
},
|
|
4797
|
+
channels: channels.map((channel) => ({
|
|
4798
|
+
...channel,
|
|
4799
|
+
id: normalizeChannelId(channel.id),
|
|
4800
|
+
alias: channel.alias?.trim() || defaultAliasForProvider(channel.provider)
|
|
4801
|
+
}))
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
function loadConfig() {
|
|
4805
|
+
const current = readConfigV2File();
|
|
4806
|
+
if (current) return expandConfig(current);
|
|
4807
|
+
const legacyEnv = loadRawConfigEnv();
|
|
4808
|
+
if (legacyEnv.size > 0) {
|
|
4809
|
+
const migrated = migrateLegacyEnvToV2(legacyEnv);
|
|
4810
|
+
writeConfigV2File(migrated);
|
|
4811
|
+
return expandConfig(migrated);
|
|
4812
|
+
}
|
|
4813
|
+
const empty = {
|
|
4814
|
+
schemaVersion: 2,
|
|
4815
|
+
runtime: {
|
|
4816
|
+
provider: "codex",
|
|
4817
|
+
defaultWorkspaceRoot: DEFAULT_WORKSPACE_ROOT,
|
|
4818
|
+
defaultMode: "code",
|
|
4819
|
+
historyMessageLimit: 8,
|
|
4820
|
+
codexSkipGitRepoCheck: true,
|
|
4821
|
+
codexSandboxMode: "workspace-write",
|
|
4822
|
+
codexReasoningEffort: "medium",
|
|
4823
|
+
uiAllowLan: false,
|
|
4824
|
+
autoApprove: false
|
|
4825
|
+
},
|
|
4826
|
+
channels: []
|
|
4682
4827
|
};
|
|
4828
|
+
return expandConfig(empty);
|
|
4683
4829
|
}
|
|
4684
4830
|
function formatEnvLine(key, value) {
|
|
4685
4831
|
if (value === void 0 || value === "") return "";
|
|
@@ -4687,130 +4833,139 @@ function formatEnvLine(key, value) {
|
|
|
4687
4833
|
`;
|
|
4688
4834
|
}
|
|
4689
4835
|
function saveConfig(config) {
|
|
4836
|
+
const current = readConfigV2File();
|
|
4837
|
+
const next = buildV2FileFromExpandedConfig(config, current);
|
|
4838
|
+
writeConfigV2File(next);
|
|
4690
4839
|
let out = "";
|
|
4691
|
-
out += formatEnvLine("CTI_RUNTIME",
|
|
4840
|
+
out += formatEnvLine("CTI_RUNTIME", next.runtime.provider);
|
|
4692
4841
|
out += formatEnvLine(
|
|
4693
4842
|
"CTI_ENABLED_CHANNELS",
|
|
4694
|
-
|
|
4695
|
-
);
|
|
4696
|
-
out += formatEnvLine("CTI_DEFAULT_WORKSPACE_ROOT", config.defaultWorkspaceRoot);
|
|
4697
|
-
if (config.defaultModel) out += formatEnvLine("CTI_DEFAULT_MODEL", config.defaultModel);
|
|
4698
|
-
out += formatEnvLine("CTI_DEFAULT_MODE", config.defaultMode);
|
|
4699
|
-
if (config.historyMessageLimit !== void 0)
|
|
4700
|
-
out += formatEnvLine("CTI_HISTORY_MESSAGE_LIMIT", String(config.historyMessageLimit));
|
|
4701
|
-
if (config.codexSkipGitRepoCheck !== void 0)
|
|
4702
|
-
out += formatEnvLine("CTI_CODEX_SKIP_GIT_REPO_CHECK", String(config.codexSkipGitRepoCheck));
|
|
4703
|
-
out += formatEnvLine("CTI_CODEX_SANDBOX_MODE", config.codexSandboxMode);
|
|
4704
|
-
out += formatEnvLine("CTI_CODEX_REASONING_EFFORT", config.codexReasoningEffort);
|
|
4705
|
-
out += formatEnvLine("CTI_UI_ALLOW_LAN", String(config.uiAllowLan === true));
|
|
4706
|
-
out += formatEnvLine("CTI_UI_ACCESS_TOKEN", config.uiAccessToken);
|
|
4707
|
-
out += formatEnvLine("CTI_TG_BOT_TOKEN", config.tgBotToken);
|
|
4708
|
-
out += formatEnvLine("CTI_TG_CHAT_ID", config.tgChatId);
|
|
4709
|
-
out += formatEnvLine(
|
|
4710
|
-
"CTI_TG_ALLOWED_USERS",
|
|
4711
|
-
config.tgAllowedUsers?.join(",")
|
|
4712
|
-
);
|
|
4713
|
-
out += formatEnvLine("CTI_FEISHU_APP_ID", config.feishuAppId);
|
|
4714
|
-
out += formatEnvLine("CTI_FEISHU_APP_SECRET", config.feishuAppSecret);
|
|
4715
|
-
out += formatEnvLine("CTI_FEISHU_DOMAIN", config.feishuDomain);
|
|
4716
|
-
out += formatEnvLine(
|
|
4717
|
-
"CTI_FEISHU_ALLOWED_USERS",
|
|
4718
|
-
config.feishuAllowedUsers?.join(",")
|
|
4719
|
-
);
|
|
4720
|
-
if (config.feishuStreamingEnabled !== void 0)
|
|
4721
|
-
out += formatEnvLine(
|
|
4722
|
-
"CTI_FEISHU_STREAMING_ENABLED",
|
|
4723
|
-
String(config.feishuStreamingEnabled)
|
|
4724
|
-
);
|
|
4725
|
-
if (config.feishuCommandMarkdownEnabled !== void 0)
|
|
4726
|
-
out += formatEnvLine(
|
|
4727
|
-
"CTI_FEISHU_COMMAND_MARKDOWN_ENABLED",
|
|
4728
|
-
String(config.feishuCommandMarkdownEnabled)
|
|
4729
|
-
);
|
|
4730
|
-
out += formatEnvLine("CTI_DISCORD_BOT_TOKEN", config.discordBotToken);
|
|
4731
|
-
out += formatEnvLine(
|
|
4732
|
-
"CTI_DISCORD_ALLOWED_USERS",
|
|
4733
|
-
config.discordAllowedUsers?.join(",")
|
|
4734
|
-
);
|
|
4735
|
-
out += formatEnvLine(
|
|
4736
|
-
"CTI_DISCORD_ALLOWED_CHANNELS",
|
|
4737
|
-
config.discordAllowedChannels?.join(",")
|
|
4738
|
-
);
|
|
4739
|
-
out += formatEnvLine(
|
|
4740
|
-
"CTI_DISCORD_ALLOWED_GUILDS",
|
|
4741
|
-
config.discordAllowedGuilds?.join(",")
|
|
4742
|
-
);
|
|
4743
|
-
out += formatEnvLine("CTI_QQ_APP_ID", config.qqAppId);
|
|
4744
|
-
out += formatEnvLine("CTI_QQ_APP_SECRET", config.qqAppSecret);
|
|
4745
|
-
out += formatEnvLine(
|
|
4746
|
-
"CTI_QQ_ALLOWED_USERS",
|
|
4747
|
-
config.qqAllowedUsers?.join(",")
|
|
4843
|
+
Array.from(new Set(next.channels.filter((channel) => channel.enabled).map((channel) => channel.provider))).join(",")
|
|
4748
4844
|
);
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
if (
|
|
4756
|
-
out += formatEnvLine("
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4845
|
+
out += formatEnvLine("CTI_DEFAULT_WORKSPACE_ROOT", next.runtime.defaultWorkspaceRoot);
|
|
4846
|
+
out += formatEnvLine("CTI_DEFAULT_MODEL", next.runtime.defaultModel);
|
|
4847
|
+
out += formatEnvLine("CTI_DEFAULT_MODE", next.runtime.defaultMode);
|
|
4848
|
+
if (next.runtime.historyMessageLimit !== void 0) {
|
|
4849
|
+
out += formatEnvLine("CTI_HISTORY_MESSAGE_LIMIT", String(next.runtime.historyMessageLimit));
|
|
4850
|
+
}
|
|
4851
|
+
if (next.runtime.codexSkipGitRepoCheck !== void 0) {
|
|
4852
|
+
out += formatEnvLine("CTI_CODEX_SKIP_GIT_REPO_CHECK", String(next.runtime.codexSkipGitRepoCheck));
|
|
4853
|
+
}
|
|
4854
|
+
out += formatEnvLine("CTI_CODEX_SANDBOX_MODE", next.runtime.codexSandboxMode);
|
|
4855
|
+
out += formatEnvLine("CTI_CODEX_REASONING_EFFORT", next.runtime.codexReasoningEffort);
|
|
4856
|
+
out += formatEnvLine("CTI_UI_ALLOW_LAN", String(next.runtime.uiAllowLan === true));
|
|
4857
|
+
out += formatEnvLine("CTI_UI_ACCESS_TOKEN", next.runtime.uiAccessToken);
|
|
4858
|
+
const feishu = getChannelByProvider(next, "feishu");
|
|
4859
|
+
const feishuConfig = toFeishuConfig(feishu);
|
|
4860
|
+
if (feishuConfig) {
|
|
4861
|
+
out += formatEnvLine("CTI_FEISHU_APP_ID", feishuConfig.appId);
|
|
4862
|
+
out += formatEnvLine("CTI_FEISHU_APP_SECRET", feishuConfig.appSecret);
|
|
4863
|
+
out += formatEnvLine("CTI_FEISHU_SITE", feishuConfig.site);
|
|
4864
|
+
out += formatEnvLine("CTI_FEISHU_ALLOWED_USERS", feishuConfig.allowedUsers?.join(","));
|
|
4865
|
+
if (feishuConfig.streamingEnabled !== void 0) {
|
|
4866
|
+
out += formatEnvLine("CTI_FEISHU_STREAMING_ENABLED", String(feishuConfig.streamingEnabled));
|
|
4867
|
+
}
|
|
4868
|
+
if (feishuConfig.feedbackMarkdownEnabled !== void 0) {
|
|
4869
|
+
out += formatEnvLine("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED", String(feishuConfig.feedbackMarkdownEnabled));
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
const weixin = getChannelByProvider(next, "weixin");
|
|
4873
|
+
const weixinConfig = toWeixinConfig(weixin);
|
|
4874
|
+
if (weixinConfig) {
|
|
4875
|
+
out += formatEnvLine("CTI_WEIXIN_BASE_URL", weixinConfig.baseUrl);
|
|
4876
|
+
out += formatEnvLine("CTI_WEIXIN_CDN_BASE_URL", weixinConfig.cdnBaseUrl);
|
|
4877
|
+
if (weixinConfig.mediaEnabled !== void 0) {
|
|
4878
|
+
out += formatEnvLine("CTI_WEIXIN_MEDIA_ENABLED", String(weixinConfig.mediaEnabled));
|
|
4879
|
+
}
|
|
4880
|
+
if (weixinConfig.feedbackMarkdownEnabled !== void 0) {
|
|
4881
|
+
out += formatEnvLine("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED", String(weixinConfig.feedbackMarkdownEnabled));
|
|
4882
|
+
}
|
|
4883
|
+
}
|
|
4884
|
+
out += formatEnvLine("CTI_AUTO_APPROVE", String(next.runtime.autoApprove === true));
|
|
4885
|
+
ensureConfigDir();
|
|
4764
4886
|
const tmpPath = CONFIG_PATH + ".tmp";
|
|
4765
4887
|
fs.writeFileSync(tmpPath, out, { mode: 384 });
|
|
4766
4888
|
fs.renameSync(tmpPath, CONFIG_PATH);
|
|
4767
4889
|
}
|
|
4890
|
+
function listChannelInstances(config) {
|
|
4891
|
+
return [...config?.channels || loadConfig().channels || []];
|
|
4892
|
+
}
|
|
4893
|
+
function findChannelInstance(channelId, config) {
|
|
4894
|
+
return listChannelInstances(config).find((channel) => channel.id === channelId);
|
|
4895
|
+
}
|
|
4768
4896
|
function configToSettings(config) {
|
|
4769
4897
|
const m = /* @__PURE__ */ new Map();
|
|
4898
|
+
const current = {
|
|
4899
|
+
schemaVersion: 2,
|
|
4900
|
+
runtime: {
|
|
4901
|
+
provider: config.runtime,
|
|
4902
|
+
defaultMode: config.defaultMode
|
|
4903
|
+
},
|
|
4904
|
+
channels: config.channels || []
|
|
4905
|
+
};
|
|
4906
|
+
const feishu = getChannelByProvider(current, "feishu");
|
|
4907
|
+
const weixin = getChannelByProvider(current, "weixin");
|
|
4908
|
+
const feishuConfig = toFeishuConfig(feishu);
|
|
4909
|
+
const weixinConfig = toWeixinConfig(weixin);
|
|
4770
4910
|
m.set("remote_bridge_enabled", "true");
|
|
4911
|
+
if (config.defaultWorkspaceRoot) {
|
|
4912
|
+
m.set("bridge_default_workspace_root", config.defaultWorkspaceRoot);
|
|
4913
|
+
}
|
|
4914
|
+
if (config.defaultModel) {
|
|
4915
|
+
m.set("bridge_default_model", config.defaultModel);
|
|
4916
|
+
m.set("default_model", config.defaultModel);
|
|
4917
|
+
}
|
|
4918
|
+
m.set("bridge_default_mode", config.defaultMode);
|
|
4919
|
+
m.set(
|
|
4920
|
+
"bridge_history_message_limit",
|
|
4921
|
+
String(config.historyMessageLimit && config.historyMessageLimit > 0 ? config.historyMessageLimit : 8)
|
|
4922
|
+
);
|
|
4923
|
+
m.set(
|
|
4924
|
+
"bridge_codex_skip_git_repo_check",
|
|
4925
|
+
config.codexSkipGitRepoCheck === true ? "true" : "false"
|
|
4926
|
+
);
|
|
4927
|
+
m.set(
|
|
4928
|
+
"bridge_codex_sandbox_mode",
|
|
4929
|
+
config.codexSandboxMode || "workspace-write"
|
|
4930
|
+
);
|
|
4931
|
+
m.set(
|
|
4932
|
+
"bridge_codex_reasoning_effort",
|
|
4933
|
+
config.codexReasoningEffort || "medium"
|
|
4934
|
+
);
|
|
4935
|
+
m.set(
|
|
4936
|
+
"bridge_channel_instances_json",
|
|
4937
|
+
JSON.stringify(config.channels || [])
|
|
4938
|
+
);
|
|
4771
4939
|
m.set(
|
|
4772
4940
|
"bridge_telegram_enabled",
|
|
4773
4941
|
config.enabledChannels.includes("telegram") ? "true" : "false"
|
|
4774
4942
|
);
|
|
4775
4943
|
if (config.tgBotToken) m.set("telegram_bot_token", config.tgBotToken);
|
|
4776
|
-
if (config.tgAllowedUsers)
|
|
4777
|
-
m.set("telegram_bridge_allowed_users", config.tgAllowedUsers.join(","));
|
|
4944
|
+
if (config.tgAllowedUsers) m.set("telegram_bridge_allowed_users", config.tgAllowedUsers.join(","));
|
|
4778
4945
|
if (config.tgChatId) m.set("telegram_chat_id", config.tgChatId);
|
|
4779
4946
|
m.set(
|
|
4780
4947
|
"bridge_discord_enabled",
|
|
4781
4948
|
config.enabledChannels.includes("discord") ? "true" : "false"
|
|
4782
4949
|
);
|
|
4783
|
-
if (config.discordBotToken)
|
|
4784
|
-
|
|
4785
|
-
if (config.
|
|
4786
|
-
|
|
4787
|
-
if (config.discordAllowedChannels)
|
|
4788
|
-
m.set(
|
|
4789
|
-
"bridge_discord_allowed_channels",
|
|
4790
|
-
config.discordAllowedChannels.join(",")
|
|
4791
|
-
);
|
|
4792
|
-
if (config.discordAllowedGuilds)
|
|
4793
|
-
m.set(
|
|
4794
|
-
"bridge_discord_allowed_guilds",
|
|
4795
|
-
config.discordAllowedGuilds.join(",")
|
|
4796
|
-
);
|
|
4950
|
+
if (config.discordBotToken) m.set("bridge_discord_bot_token", config.discordBotToken);
|
|
4951
|
+
if (config.discordAllowedUsers) m.set("bridge_discord_allowed_users", config.discordAllowedUsers.join(","));
|
|
4952
|
+
if (config.discordAllowedChannels) m.set("bridge_discord_allowed_channels", config.discordAllowedChannels.join(","));
|
|
4953
|
+
if (config.discordAllowedGuilds) m.set("bridge_discord_allowed_guilds", config.discordAllowedGuilds.join(","));
|
|
4797
4954
|
m.set(
|
|
4798
4955
|
"bridge_feishu_enabled",
|
|
4799
|
-
|
|
4956
|
+
feishu?.enabled === true ? "true" : "false"
|
|
4800
4957
|
);
|
|
4801
|
-
if (
|
|
4802
|
-
if (
|
|
4803
|
-
|
|
4804
|
-
if (
|
|
4805
|
-
if (config.feishuAllowedUsers)
|
|
4806
|
-
m.set("bridge_feishu_allowed_users", config.feishuAllowedUsers.join(","));
|
|
4958
|
+
if (feishuConfig?.appId) m.set("bridge_feishu_app_id", feishuConfig.appId);
|
|
4959
|
+
if (feishuConfig?.appSecret) m.set("bridge_feishu_app_secret", feishuConfig.appSecret);
|
|
4960
|
+
if (feishuConfig?.site) m.set("bridge_feishu_site", feishuConfig.site);
|
|
4961
|
+
if (feishuConfig?.allowedUsers) m.set("bridge_feishu_allowed_users", feishuConfig.allowedUsers.join(","));
|
|
4807
4962
|
m.set(
|
|
4808
4963
|
"bridge_feishu_streaming_enabled",
|
|
4809
|
-
|
|
4964
|
+
feishuConfig?.streamingEnabled === false ? "false" : "true"
|
|
4810
4965
|
);
|
|
4811
4966
|
m.set(
|
|
4812
4967
|
"bridge_feishu_command_markdown_enabled",
|
|
4813
|
-
|
|
4968
|
+
feishuConfig?.feedbackMarkdownEnabled === false ? "false" : "true"
|
|
4814
4969
|
);
|
|
4815
4970
|
m.set(
|
|
4816
4971
|
"bridge_qq_enabled",
|
|
@@ -4818,50 +4973,26 @@ function configToSettings(config) {
|
|
|
4818
4973
|
);
|
|
4819
4974
|
if (config.qqAppId) m.set("bridge_qq_app_id", config.qqAppId);
|
|
4820
4975
|
if (config.qqAppSecret) m.set("bridge_qq_app_secret", config.qqAppSecret);
|
|
4821
|
-
if (config.qqAllowedUsers)
|
|
4822
|
-
|
|
4823
|
-
if (config.qqImageEnabled !== void 0)
|
|
4976
|
+
if (config.qqAllowedUsers) m.set("bridge_qq_allowed_users", config.qqAllowedUsers.join(","));
|
|
4977
|
+
if (config.qqImageEnabled !== void 0) {
|
|
4824
4978
|
m.set("bridge_qq_image_enabled", String(config.qqImageEnabled));
|
|
4825
|
-
|
|
4979
|
+
}
|
|
4980
|
+
if (config.qqMaxImageSize !== void 0) {
|
|
4826
4981
|
m.set("bridge_qq_max_image_size", String(config.qqMaxImageSize));
|
|
4982
|
+
}
|
|
4827
4983
|
m.set(
|
|
4828
4984
|
"bridge_weixin_enabled",
|
|
4829
|
-
|
|
4830
|
-
);
|
|
4831
|
-
if (config.weixinMediaEnabled !== void 0)
|
|
4832
|
-
m.set("bridge_weixin_media_enabled", String(config.weixinMediaEnabled));
|
|
4833
|
-
m.set(
|
|
4834
|
-
"bridge_weixin_command_markdown_enabled",
|
|
4835
|
-
config.weixinCommandMarkdownEnabled === true ? "true" : "false"
|
|
4985
|
+
weixin?.enabled === true ? "true" : "false"
|
|
4836
4986
|
);
|
|
4837
|
-
if (
|
|
4838
|
-
m.set("
|
|
4839
|
-
if (config.weixinCdnBaseUrl)
|
|
4840
|
-
m.set("bridge_weixin_cdn_base_url", config.weixinCdnBaseUrl);
|
|
4841
|
-
if (config.defaultWorkspaceRoot) {
|
|
4842
|
-
m.set("bridge_default_workspace_root", config.defaultWorkspaceRoot);
|
|
4987
|
+
if (weixinConfig?.mediaEnabled !== void 0) {
|
|
4988
|
+
m.set("bridge_weixin_media_enabled", String(weixinConfig.mediaEnabled));
|
|
4843
4989
|
}
|
|
4844
|
-
if (config.defaultModel) {
|
|
4845
|
-
m.set("bridge_default_model", config.defaultModel);
|
|
4846
|
-
m.set("default_model", config.defaultModel);
|
|
4847
|
-
}
|
|
4848
|
-
m.set("bridge_default_mode", config.defaultMode);
|
|
4849
|
-
m.set(
|
|
4850
|
-
"bridge_history_message_limit",
|
|
4851
|
-
String(config.historyMessageLimit && config.historyMessageLimit > 0 ? config.historyMessageLimit : 8)
|
|
4852
|
-
);
|
|
4853
|
-
m.set(
|
|
4854
|
-
"bridge_codex_skip_git_repo_check",
|
|
4855
|
-
config.codexSkipGitRepoCheck === true ? "true" : "false"
|
|
4856
|
-
);
|
|
4857
|
-
m.set(
|
|
4858
|
-
"bridge_codex_sandbox_mode",
|
|
4859
|
-
config.codexSandboxMode || "workspace-write"
|
|
4860
|
-
);
|
|
4861
4990
|
m.set(
|
|
4862
|
-
"
|
|
4863
|
-
|
|
4991
|
+
"bridge_weixin_command_markdown_enabled",
|
|
4992
|
+
weixinConfig?.feedbackMarkdownEnabled === true ? "true" : "false"
|
|
4864
4993
|
);
|
|
4994
|
+
if (weixinConfig?.baseUrl) m.set("bridge_weixin_base_url", weixinConfig.baseUrl);
|
|
4995
|
+
if (weixinConfig?.cdnBaseUrl) m.set("bridge_weixin_cdn_base_url", weixinConfig.cdnBaseUrl);
|
|
4865
4996
|
return m;
|
|
4866
4997
|
}
|
|
4867
4998
|
|
|
@@ -5598,8 +5729,24 @@ function isArchivedDesktopThread(threadId) {
|
|
|
5598
5729
|
|
|
5599
5730
|
// src/session-bindings.ts
|
|
5600
5731
|
import path4 from "node:path";
|
|
5601
|
-
function
|
|
5602
|
-
return
|
|
5732
|
+
function asChannelProvider(value) {
|
|
5733
|
+
return value === "feishu" || value === "weixin" ? value : void 0;
|
|
5734
|
+
}
|
|
5735
|
+
function resolveChannelMeta(channelType, provider) {
|
|
5736
|
+
const instance = findChannelInstance(channelType, loadConfig());
|
|
5737
|
+
if (instance) {
|
|
5738
|
+
return {
|
|
5739
|
+
provider: instance.provider,
|
|
5740
|
+
alias: instance.alias
|
|
5741
|
+
};
|
|
5742
|
+
}
|
|
5743
|
+
return {
|
|
5744
|
+
provider,
|
|
5745
|
+
alias: channelType
|
|
5746
|
+
};
|
|
5747
|
+
}
|
|
5748
|
+
function formatChannelLabel(binding) {
|
|
5749
|
+
return binding.channelAlias?.trim() || resolveChannelMeta(binding.channelType, asChannelProvider(binding.channelProvider)).alias || binding.channelType;
|
|
5603
5750
|
}
|
|
5604
5751
|
function formatBindingChatTarget(binding) {
|
|
5605
5752
|
return binding.chatDisplayName?.trim() || binding.chatId;
|
|
@@ -5620,7 +5767,7 @@ function assertBindingTargetAvailable(store, current, opts) {
|
|
|
5620
5767
|
);
|
|
5621
5768
|
if (!conflict) return;
|
|
5622
5769
|
throw new Error(
|
|
5623
|
-
`\u8BE5\u4F1A\u8BDD\u5DF2\u7ED1\u5B9A\u5230 ${formatChannelLabel(conflict
|
|
5770
|
+
`\u8BE5\u4F1A\u8BDD\u5DF2\u7ED1\u5B9A\u5230 ${formatChannelLabel(conflict)} \u804A\u5929 ${formatBindingChatTarget(conflict)}\u3002\u4E00\u4E2A\u4F1A\u8BDD\u53EA\u80FD\u7ED1\u5B9A\u4E00\u4E2A\u804A\u5929\u3002`
|
|
5624
5771
|
);
|
|
5625
5772
|
}
|
|
5626
5773
|
function getSessionName(session) {
|
|
@@ -5641,8 +5788,11 @@ function bindStoreToSession(store, channelType, chatId, sessionId) {
|
|
|
5641
5788
|
{ channelType, chatId },
|
|
5642
5789
|
{ sessionId: session.id, sdkSessionId: session.sdk_session_id || void 0 }
|
|
5643
5790
|
);
|
|
5791
|
+
const meta = resolveChannelMeta(channelType);
|
|
5644
5792
|
return store.upsertChannelBinding({
|
|
5645
5793
|
channelType,
|
|
5794
|
+
channelProvider: meta.provider,
|
|
5795
|
+
channelAlias: meta.alias,
|
|
5646
5796
|
chatId,
|
|
5647
5797
|
codepilotSessionId: session.id,
|
|
5648
5798
|
sdkSessionId: session.sdk_session_id || "",
|
|
@@ -5657,10 +5807,13 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
|
5657
5807
|
{ channelType, chatId },
|
|
5658
5808
|
{ sdkSessionId }
|
|
5659
5809
|
);
|
|
5810
|
+
const meta = resolveChannelMeta(channelType);
|
|
5660
5811
|
const existing = store.findSessionBySdkSessionId(sdkSessionId);
|
|
5661
5812
|
if (existing) {
|
|
5662
5813
|
return store.upsertChannelBinding({
|
|
5663
5814
|
channelType,
|
|
5815
|
+
channelProvider: meta.provider,
|
|
5816
|
+
channelAlias: meta.alias,
|
|
5664
5817
|
chatId,
|
|
5665
5818
|
codepilotSessionId: existing.id,
|
|
5666
5819
|
sdkSessionId,
|
|
@@ -5682,6 +5835,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
|
5682
5835
|
store.updateSdkSessionId(session.id, sdkSessionId);
|
|
5683
5836
|
return store.upsertChannelBinding({
|
|
5684
5837
|
channelType,
|
|
5838
|
+
channelProvider: meta.provider,
|
|
5839
|
+
channelAlias: meta.alias,
|
|
5685
5840
|
chatId,
|
|
5686
5841
|
codepilotSessionId: session.id,
|
|
5687
5842
|
sdkSessionId,
|
|
@@ -5716,6 +5871,8 @@ function listBindingSummaries(store) {
|
|
|
5716
5871
|
return {
|
|
5717
5872
|
id: binding.id,
|
|
5718
5873
|
channelType: binding.channelType,
|
|
5874
|
+
channelProvider: binding.channelProvider,
|
|
5875
|
+
channelAlias: binding.channelAlias,
|
|
5719
5876
|
chatId: binding.chatId,
|
|
5720
5877
|
chatUserId: binding.chatUserId,
|
|
5721
5878
|
chatDisplayName: binding.chatDisplayName,
|
|
@@ -5733,7 +5890,9 @@ function listBindingSummaries(store) {
|
|
|
5733
5890
|
mirrorLastEventAt: session?.mirror_last_event_at
|
|
5734
5891
|
};
|
|
5735
5892
|
}).sort((a, b) => {
|
|
5736
|
-
|
|
5893
|
+
const aLabel = a.channelAlias || a.channelType;
|
|
5894
|
+
const bLabel = b.channelAlias || b.channelType;
|
|
5895
|
+
if (aLabel !== bLabel) return aLabel.localeCompare(bLabel);
|
|
5737
5896
|
return a.chatId.localeCompare(b.chatId);
|
|
5738
5897
|
});
|
|
5739
5898
|
}
|
|
@@ -5788,6 +5947,8 @@ var bridgePidFile = path5.join(runtimeDir, "bridge.pid");
|
|
|
5788
5947
|
var bridgeStatusFile = path5.join(runtimeDir, "status.json");
|
|
5789
5948
|
var uiStatusFile = path5.join(runtimeDir, "ui-server.json");
|
|
5790
5949
|
var uiPort = 4781;
|
|
5950
|
+
var bridgeAutostartTaskName = "CodexToIMBridge";
|
|
5951
|
+
var bridgeAutostartLauncherFile = path5.join(runtimeDir, "bridge-autostart.ps1");
|
|
5791
5952
|
var WINDOWS_HIDE = process.platform === "win32" ? { windowsHide: true } : {};
|
|
5792
5953
|
function ensureDirs() {
|
|
5793
5954
|
fs4.mkdirSync(runtimeDir, { recursive: true });
|
|
@@ -5821,6 +5982,49 @@ function isProcessAlive(pid) {
|
|
|
5821
5982
|
function sleep(ms) {
|
|
5822
5983
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5823
5984
|
}
|
|
5985
|
+
function getCurrentWindowsUser() {
|
|
5986
|
+
const user = process.env.USERNAME || os4.userInfo().username;
|
|
5987
|
+
const domain = process.env.USERDOMAIN;
|
|
5988
|
+
return domain ? `${domain}\\${user}` : user;
|
|
5989
|
+
}
|
|
5990
|
+
function escapePowerShellSingleQuoted(value) {
|
|
5991
|
+
return value.replace(/'/g, "''");
|
|
5992
|
+
}
|
|
5993
|
+
function runCommand(command, args, options = {}) {
|
|
5994
|
+
return new Promise((resolve, reject) => {
|
|
5995
|
+
const child = spawn(command, args, {
|
|
5996
|
+
cwd: options.cwd,
|
|
5997
|
+
env: options.env,
|
|
5998
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5999
|
+
...WINDOWS_HIDE
|
|
6000
|
+
});
|
|
6001
|
+
let stdout = "";
|
|
6002
|
+
let stderr = "";
|
|
6003
|
+
child.stdout.on("data", (chunk) => {
|
|
6004
|
+
stdout += chunk.toString();
|
|
6005
|
+
});
|
|
6006
|
+
child.stderr.on("data", (chunk) => {
|
|
6007
|
+
stderr += chunk.toString();
|
|
6008
|
+
});
|
|
6009
|
+
child.on("error", reject);
|
|
6010
|
+
child.on("close", (code) => {
|
|
6011
|
+
resolve({ code: code ?? 0, stdout, stderr });
|
|
6012
|
+
});
|
|
6013
|
+
});
|
|
6014
|
+
}
|
|
6015
|
+
async function runPowerShell(script) {
|
|
6016
|
+
const result = await runCommand(
|
|
6017
|
+
"powershell.exe",
|
|
6018
|
+
["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", script]
|
|
6019
|
+
);
|
|
6020
|
+
if (result.code !== 0) {
|
|
6021
|
+
throw new Error((result.stderr || result.stdout || "PowerShell command failed.").trim());
|
|
6022
|
+
}
|
|
6023
|
+
return result.stdout.trim();
|
|
6024
|
+
}
|
|
6025
|
+
function parsePowerShellJson(raw) {
|
|
6026
|
+
return JSON.parse(raw);
|
|
6027
|
+
}
|
|
5824
6028
|
function getPackageRoot() {
|
|
5825
6029
|
return packageRoot;
|
|
5826
6030
|
}
|
|
@@ -5932,6 +6136,60 @@ async function restartBridge() {
|
|
|
5932
6136
|
await stopBridge();
|
|
5933
6137
|
return await startBridge();
|
|
5934
6138
|
}
|
|
6139
|
+
async function getBridgeAutostartStatus() {
|
|
6140
|
+
const base = {
|
|
6141
|
+
supported: process.platform === "win32",
|
|
6142
|
+
installed: false,
|
|
6143
|
+
enabled: false,
|
|
6144
|
+
mode: "startup",
|
|
6145
|
+
taskName: bridgeAutostartTaskName,
|
|
6146
|
+
runAsUser: process.platform === "win32" ? getCurrentWindowsUser() : void 0,
|
|
6147
|
+
launcherPath: bridgeAutostartLauncherFile
|
|
6148
|
+
};
|
|
6149
|
+
if (process.platform !== "win32") {
|
|
6150
|
+
return {
|
|
6151
|
+
...base,
|
|
6152
|
+
error: "\u5F53\u524D\u53EA\u652F\u6301 Windows \u81EA\u52A8\u542F\u52A8\u3002"
|
|
6153
|
+
};
|
|
6154
|
+
}
|
|
6155
|
+
const script = [
|
|
6156
|
+
`$task = Get-ScheduledTask -TaskName '${escapePowerShellSingleQuoted(bridgeAutostartTaskName)}' -ErrorAction SilentlyContinue`,
|
|
6157
|
+
"if (-not $task) {",
|
|
6158
|
+
" [pscustomobject]@{",
|
|
6159
|
+
" supported = $true",
|
|
6160
|
+
" installed = $false",
|
|
6161
|
+
" enabled = $false",
|
|
6162
|
+
` mode = 'startup'`,
|
|
6163
|
+
` taskName = '${escapePowerShellSingleQuoted(bridgeAutostartTaskName)}'`,
|
|
6164
|
+
` launcherPath = '${escapePowerShellSingleQuoted(bridgeAutostartLauncherFile)}'`,
|
|
6165
|
+
" } | ConvertTo-Json -Compress",
|
|
6166
|
+
" exit 0",
|
|
6167
|
+
"}",
|
|
6168
|
+
`$info = Get-ScheduledTaskInfo -TaskName '${escapePowerShellSingleQuoted(bridgeAutostartTaskName)}' -ErrorAction SilentlyContinue`,
|
|
6169
|
+
"[pscustomobject]@{",
|
|
6170
|
+
" supported = $true",
|
|
6171
|
+
" installed = $true",
|
|
6172
|
+
" enabled = [bool]$task.Settings.Enabled",
|
|
6173
|
+
` mode = 'startup'`,
|
|
6174
|
+
` taskName = '${escapePowerShellSingleQuoted(bridgeAutostartTaskName)}'`,
|
|
6175
|
+
` launcherPath = '${escapePowerShellSingleQuoted(bridgeAutostartLauncherFile)}'`,
|
|
6176
|
+
" runAsUser = $task.Principal.UserId",
|
|
6177
|
+
" state = [string]$task.State",
|
|
6178
|
+
"} | ConvertTo-Json -Compress"
|
|
6179
|
+
].join("\n");
|
|
6180
|
+
try {
|
|
6181
|
+
const raw = await runPowerShell(script);
|
|
6182
|
+
return {
|
|
6183
|
+
...base,
|
|
6184
|
+
...parsePowerShellJson(raw)
|
|
6185
|
+
};
|
|
6186
|
+
} catch (error) {
|
|
6187
|
+
return {
|
|
6188
|
+
...base,
|
|
6189
|
+
error: error instanceof Error ? error.message : String(error)
|
|
6190
|
+
};
|
|
6191
|
+
}
|
|
6192
|
+
}
|
|
5935
6193
|
function getBridgeLogs(lines = 200) {
|
|
5936
6194
|
ensureDirs();
|
|
5937
6195
|
const filePath = path5.join(logsDir, "bridge.log");
|
|
@@ -6007,6 +6265,35 @@ function uuid() {
|
|
|
6007
6265
|
function now() {
|
|
6008
6266
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
6009
6267
|
}
|
|
6268
|
+
function defaultAliasForProvider2(provider) {
|
|
6269
|
+
if (provider === "feishu") return "\u98DE\u4E66";
|
|
6270
|
+
if (provider === "weixin") return "\u5FAE\u4FE1";
|
|
6271
|
+
return void 0;
|
|
6272
|
+
}
|
|
6273
|
+
function normalizeLegacyBinding(binding) {
|
|
6274
|
+
const config = loadConfig();
|
|
6275
|
+
const legacyProvider = binding.channelType === "feishu" || binding.channelType === "weixin" ? binding.channelType : void 0;
|
|
6276
|
+
const resolvedInstance = legacyProvider ? (config.channels || []).find((channel) => channel.provider === legacyProvider) : findChannelInstance(binding.channelType, config);
|
|
6277
|
+
if (!resolvedInstance && !legacyProvider) {
|
|
6278
|
+
return {
|
|
6279
|
+
...binding,
|
|
6280
|
+
active: binding.active !== false
|
|
6281
|
+
};
|
|
6282
|
+
}
|
|
6283
|
+
const channelType = resolvedInstance?.id || binding.channelType;
|
|
6284
|
+
const channelProvider = resolvedInstance?.provider || legacyProvider || binding.channelProvider;
|
|
6285
|
+
const channelAlias = resolvedInstance?.alias || binding.channelAlias || defaultAliasForProvider2(channelProvider);
|
|
6286
|
+
return {
|
|
6287
|
+
...binding,
|
|
6288
|
+
channelType,
|
|
6289
|
+
channelProvider,
|
|
6290
|
+
channelAlias,
|
|
6291
|
+
active: binding.active !== false
|
|
6292
|
+
};
|
|
6293
|
+
}
|
|
6294
|
+
function didBindingChange(before, after) {
|
|
6295
|
+
return before.channelType !== after.channelType || before.channelProvider !== after.channelProvider || before.channelAlias !== after.channelAlias || before.active !== false !== after.active;
|
|
6296
|
+
}
|
|
6010
6297
|
var JsonFileStore = class {
|
|
6011
6298
|
settings;
|
|
6012
6299
|
dynamicSettings;
|
|
@@ -6064,7 +6351,19 @@ var JsonFileStore = class {
|
|
|
6064
6351
|
path6.join(DATA_DIR, "bindings.json"),
|
|
6065
6352
|
{}
|
|
6066
6353
|
);
|
|
6067
|
-
|
|
6354
|
+
const normalized = /* @__PURE__ */ new Map();
|
|
6355
|
+
let changed = false;
|
|
6356
|
+
for (const binding of Object.values(bindings)) {
|
|
6357
|
+
const normalizedBinding = normalizeLegacyBinding(binding);
|
|
6358
|
+
if (didBindingChange(binding, normalizedBinding)) {
|
|
6359
|
+
changed = true;
|
|
6360
|
+
}
|
|
6361
|
+
normalized.set(`${normalizedBinding.channelType}:${normalizedBinding.chatId}`, normalizedBinding);
|
|
6362
|
+
}
|
|
6363
|
+
this.bindings = normalized;
|
|
6364
|
+
if (changed) {
|
|
6365
|
+
this.persistBindings();
|
|
6366
|
+
}
|
|
6068
6367
|
}
|
|
6069
6368
|
persistSessions() {
|
|
6070
6369
|
writeJson(
|
|
@@ -6144,6 +6443,8 @@ var JsonFileStore = class {
|
|
|
6144
6443
|
...existing,
|
|
6145
6444
|
codepilotSessionId: data.codepilotSessionId,
|
|
6146
6445
|
sdkSessionId: data.sdkSessionId ?? existing.sdkSessionId,
|
|
6446
|
+
channelProvider: data.channelProvider ?? existing.channelProvider,
|
|
6447
|
+
channelAlias: data.channelAlias ?? existing.channelAlias,
|
|
6147
6448
|
chatUserId: data.chatUserId ?? existing.chatUserId,
|
|
6148
6449
|
chatDisplayName: data.chatDisplayName ?? existing.chatDisplayName,
|
|
6149
6450
|
workingDirectory: data.workingDirectory,
|
|
@@ -6158,6 +6459,8 @@ var JsonFileStore = class {
|
|
|
6158
6459
|
const binding = {
|
|
6159
6460
|
id: uuid(),
|
|
6160
6461
|
channelType: data.channelType,
|
|
6462
|
+
channelProvider: data.channelProvider,
|
|
6463
|
+
channelAlias: data.channelAlias,
|
|
6161
6464
|
chatId: data.chatId,
|
|
6162
6465
|
chatUserId: data.chatUserId,
|
|
6163
6466
|
chatDisplayName: data.chatDisplayName,
|
|
@@ -6791,10 +7094,9 @@ async function refreshSession(previous, baseUrl) {
|
|
|
6791
7094
|
console.log(`[weixin-login] QR code refreshed (${next.refreshCount}/${MAX_REFRESHES})`);
|
|
6792
7095
|
return next;
|
|
6793
7096
|
}
|
|
6794
|
-
async function runWeixinLogin() {
|
|
7097
|
+
async function runWeixinLogin(config = {}) {
|
|
6795
7098
|
ensureRuntimeDir();
|
|
6796
|
-
|
|
6797
|
-
let session = await createSession(0, config.weixinBaseUrl);
|
|
7099
|
+
let session = await createSession(0, config.baseUrl);
|
|
6798
7100
|
await writeQrHtml(session);
|
|
6799
7101
|
const opened = openQrHtml();
|
|
6800
7102
|
console.log("[weixin-login] WeChat QR login started");
|
|
@@ -6805,10 +7107,10 @@ async function runWeixinLogin() {
|
|
|
6805
7107
|
let lastStatus = session.status;
|
|
6806
7108
|
while (true) {
|
|
6807
7109
|
if (Date.now() - session.startedAt > QR_TTL_MS) {
|
|
6808
|
-
session = await refreshSession(session, config.
|
|
7110
|
+
session = await refreshSession(session, config.baseUrl);
|
|
6809
7111
|
lastStatus = session.status;
|
|
6810
7112
|
}
|
|
6811
|
-
const response = await pollLoginQrStatus(session.qrcode, config.
|
|
7113
|
+
const response = await pollLoginQrStatus(session.qrcode, config.baseUrl);
|
|
6812
7114
|
switch (response.status) {
|
|
6813
7115
|
case "wait":
|
|
6814
7116
|
session.status = "waiting";
|
|
@@ -6826,8 +7128,8 @@ async function runWeixinLogin() {
|
|
|
6826
7128
|
upsertWeixinAccount({
|
|
6827
7129
|
accountId,
|
|
6828
7130
|
userId: response.ilink_user_id || "",
|
|
6829
|
-
baseUrl: config.
|
|
6830
|
-
cdnBaseUrl: config.
|
|
7131
|
+
baseUrl: config.baseUrl || response.baseurl || DEFAULT_BASE_URL,
|
|
7132
|
+
cdnBaseUrl: config.cdnBaseUrl || DEFAULT_CDN_BASE_URL,
|
|
6831
7133
|
token: response.bot_token,
|
|
6832
7134
|
name: accountId,
|
|
6833
7135
|
enabled: true
|
|
@@ -6840,7 +7142,7 @@ async function runWeixinLogin() {
|
|
|
6840
7142
|
return { accountId, htmlPath: HTML_PATH };
|
|
6841
7143
|
}
|
|
6842
7144
|
case "expired":
|
|
6843
|
-
session = await refreshSession(session, config.
|
|
7145
|
+
session = await refreshSession(session, config.baseUrl);
|
|
6844
7146
|
lastStatus = session.status;
|
|
6845
7147
|
continue;
|
|
6846
7148
|
default:
|
|
@@ -6928,13 +7230,12 @@ function listSelectableCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH)
|
|
|
6928
7230
|
// src/ui-server.ts
|
|
6929
7231
|
var port = 4781;
|
|
6930
7232
|
var serverStartTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
6931
|
-
var supportedChannels = ["feishu", "weixin"];
|
|
6932
7233
|
var AUTH_COOKIE_NAME = "cti_ui_auth";
|
|
6933
7234
|
var availableCodexModels = listSelectableCodexModels();
|
|
6934
7235
|
var availableCodexModelSlugs = new Set(availableCodexModels.map((model) => model.slug));
|
|
6935
7236
|
var FEISHU_CHAT_LABEL_TTL_MS = 5 * 60 * 1e3;
|
|
6936
7237
|
var feishuChatLabelCache = /* @__PURE__ */ new Map();
|
|
6937
|
-
var feishuTenantTokenCache =
|
|
7238
|
+
var feishuTenantTokenCache = /* @__PURE__ */ new Map();
|
|
6938
7239
|
function parsePreferredPort() {
|
|
6939
7240
|
const raw = Number(process.env.CTI_UI_PORT || "4781");
|
|
6940
7241
|
if (!Number.isInteger(raw) || raw <= 0 || raw > 65535) return 4781;
|
|
@@ -7019,9 +7320,47 @@ function parsePositiveInt2(value, fallback) {
|
|
|
7019
7320
|
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
7020
7321
|
return Math.floor(parsed);
|
|
7021
7322
|
}
|
|
7323
|
+
function normalizeChannelAlias(value, provider) {
|
|
7324
|
+
const trimmed = value?.trim();
|
|
7325
|
+
if (trimmed) return trimmed;
|
|
7326
|
+
return provider === "feishu" ? "\u98DE\u4E66" : "\u5FAE\u4FE1";
|
|
7327
|
+
}
|
|
7328
|
+
function normalizeChannelId2(value) {
|
|
7329
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
|
|
7330
|
+
}
|
|
7331
|
+
function buildChannelId(provider, alias, takenIds, currentId) {
|
|
7332
|
+
const base = normalizeChannelId2(`${provider}-${alias}`);
|
|
7333
|
+
if (!takenIds.has(base) || base === currentId) return base;
|
|
7334
|
+
let suffix = 2;
|
|
7335
|
+
while (takenIds.has(`${base}-${suffix}`) && `${base}-${suffix}` !== currentId) {
|
|
7336
|
+
suffix += 1;
|
|
7337
|
+
}
|
|
7338
|
+
return `${base}-${suffix}`;
|
|
7339
|
+
}
|
|
7340
|
+
function parseChannelProvider(value) {
|
|
7341
|
+
if (value === "feishu" || value === "weixin") return value;
|
|
7342
|
+
return void 0;
|
|
7343
|
+
}
|
|
7022
7344
|
function createUiStore() {
|
|
7023
7345
|
return new JsonFileStore(configToSettings(loadConfig()));
|
|
7024
7346
|
}
|
|
7347
|
+
function cloneChannel(channel) {
|
|
7348
|
+
return {
|
|
7349
|
+
...channel,
|
|
7350
|
+
config: { ...channel.config }
|
|
7351
|
+
};
|
|
7352
|
+
}
|
|
7353
|
+
function channelToPayload(channel) {
|
|
7354
|
+
return {
|
|
7355
|
+
id: channel.id,
|
|
7356
|
+
alias: channel.alias,
|
|
7357
|
+
provider: channel.provider,
|
|
7358
|
+
enabled: channel.enabled,
|
|
7359
|
+
createdAt: channel.createdAt,
|
|
7360
|
+
updatedAt: channel.updatedAt,
|
|
7361
|
+
config: { ...channel.config }
|
|
7362
|
+
};
|
|
7363
|
+
}
|
|
7025
7364
|
function generateAccessToken() {
|
|
7026
7365
|
return crypto4.randomBytes(18).toString("base64url");
|
|
7027
7366
|
}
|
|
@@ -7093,7 +7432,6 @@ function isRemoteAuthenticated(request, config) {
|
|
|
7093
7432
|
function configToPayload(config) {
|
|
7094
7433
|
return {
|
|
7095
7434
|
runtime: config.runtime,
|
|
7096
|
-
enabledChannels: config.enabledChannels,
|
|
7097
7435
|
defaultWorkspaceRoot: config.defaultWorkspaceRoot || "",
|
|
7098
7436
|
defaultModel: config.defaultModel || "",
|
|
7099
7437
|
codexDefaultModel: readConfiguredCodexModel() || "",
|
|
@@ -7106,27 +7444,19 @@ function configToPayload(config) {
|
|
|
7106
7444
|
uiAllowLan: config.uiAllowLan === true,
|
|
7107
7445
|
uiAccessToken: config.uiAccessToken || "",
|
|
7108
7446
|
autoApprove: config.autoApprove === true,
|
|
7109
|
-
|
|
7110
|
-
feishuAppSecret: config.feishuAppSecret || "",
|
|
7111
|
-
feishuDomain: config.feishuDomain || "https://open.feishu.cn",
|
|
7112
|
-
feishuAllowedUsers: config.feishuAllowedUsers?.join(",") || "",
|
|
7113
|
-
feishuStreamingEnabled: config.feishuStreamingEnabled !== false,
|
|
7114
|
-
feishuCommandMarkdownEnabled: config.feishuCommandMarkdownEnabled !== false,
|
|
7115
|
-
weixinMediaEnabled: config.weixinMediaEnabled === true,
|
|
7116
|
-
weixinCommandMarkdownEnabled: config.weixinCommandMarkdownEnabled === true
|
|
7447
|
+
channels: (config.channels || []).map(channelToPayload)
|
|
7117
7448
|
};
|
|
7118
7449
|
}
|
|
7119
7450
|
function mergeConfig(payload) {
|
|
7120
7451
|
const current = loadConfig();
|
|
7121
7452
|
const rawDefaultModel = typeof payload.defaultModel === "string" ? payload.defaultModel.trim() : void 0;
|
|
7122
|
-
const requestedChannels = Array.isArray(payload.enabledChannels) ? payload.enabledChannels.filter((value) => typeof value === "string") : current.enabledChannels;
|
|
7123
7453
|
const uiAllowLan = payload.uiAllowLan === true;
|
|
7124
7454
|
const requestedUiAccessToken = asString(payload.uiAccessToken);
|
|
7125
7455
|
const uiAccessToken = requestedUiAccessToken || current.uiAccessToken || (uiAllowLan ? generateAccessToken() : void 0);
|
|
7126
7456
|
return {
|
|
7127
7457
|
...current,
|
|
7128
7458
|
runtime: payload.runtime === "claude" || payload.runtime === "auto" ? payload.runtime : "codex",
|
|
7129
|
-
enabledChannels:
|
|
7459
|
+
enabledChannels: current.enabledChannels,
|
|
7130
7460
|
defaultWorkspaceRoot: asString(payload.defaultWorkspaceRoot),
|
|
7131
7461
|
defaultModel: rawDefaultModel === void 0 ? current.defaultModel : rawDefaultModel === "" ? void 0 : availableCodexModelSlugs.has(rawDefaultModel) ? rawDefaultModel : current.defaultModel,
|
|
7132
7462
|
defaultMode: payload.defaultMode === "plan" || payload.defaultMode === "ask" ? payload.defaultMode : "code",
|
|
@@ -7137,14 +7467,57 @@ function mergeConfig(payload) {
|
|
|
7137
7467
|
uiAllowLan,
|
|
7138
7468
|
uiAccessToken,
|
|
7139
7469
|
autoApprove: payload.autoApprove === true,
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7470
|
+
channels: current.channels
|
|
7471
|
+
};
|
|
7472
|
+
}
|
|
7473
|
+
function mergeChannelInstance(payload, current) {
|
|
7474
|
+
const provider = parseChannelProvider(payload.provider);
|
|
7475
|
+
if (!provider) {
|
|
7476
|
+
throw new Error("\u901A\u9053\u63D0\u4F9B\u65B9\u53EA\u80FD\u662F\u98DE\u4E66\u6216\u5FAE\u4FE1\u3002");
|
|
7477
|
+
}
|
|
7478
|
+
const existingId = asString(payload.id);
|
|
7479
|
+
const existing = existingId ? findChannelInstance(existingId, current) : void 0;
|
|
7480
|
+
const alias = normalizeChannelAlias(asString(payload.alias), provider);
|
|
7481
|
+
const baseChannels = (current.channels || []).map(cloneChannel);
|
|
7482
|
+
const takenIds = new Set(baseChannels.map((channel) => channel.id));
|
|
7483
|
+
const channelId = existing?.id || buildChannelId(provider, alias, takenIds);
|
|
7484
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
7485
|
+
let nextConfig;
|
|
7486
|
+
if (provider === "feishu") {
|
|
7487
|
+
nextConfig = {
|
|
7488
|
+
appId: asString(payload.appId),
|
|
7489
|
+
appSecret: asString(payload.appSecret),
|
|
7490
|
+
site: normalizeFeishuSite(asString(payload.site) || asString(payload.domain)),
|
|
7491
|
+
allowedUsers: parseCsv(payload.allowedUsers),
|
|
7492
|
+
streamingEnabled: payload.streamingEnabled !== false,
|
|
7493
|
+
feedbackMarkdownEnabled: payload.feedbackMarkdownEnabled !== false
|
|
7494
|
+
};
|
|
7495
|
+
} else {
|
|
7496
|
+
nextConfig = {
|
|
7497
|
+
accountId: asString(payload.accountId),
|
|
7498
|
+
baseUrl: asString(payload.baseUrl),
|
|
7499
|
+
cdnBaseUrl: asString(payload.cdnBaseUrl),
|
|
7500
|
+
mediaEnabled: payload.mediaEnabled === true,
|
|
7501
|
+
feedbackMarkdownEnabled: payload.feedbackMarkdownEnabled === true
|
|
7502
|
+
};
|
|
7503
|
+
}
|
|
7504
|
+
const nextChannel = {
|
|
7505
|
+
id: channelId,
|
|
7506
|
+
alias,
|
|
7507
|
+
provider,
|
|
7508
|
+
enabled: payload.enabled !== false,
|
|
7509
|
+
createdAt: existing?.createdAt || now3,
|
|
7510
|
+
updatedAt: now3,
|
|
7511
|
+
config: nextConfig
|
|
7512
|
+
};
|
|
7513
|
+
const nextChannels = existing ? baseChannels.map((channel) => channel.id === existing.id ? nextChannel : channel) : [...baseChannels, nextChannel];
|
|
7514
|
+
return {
|
|
7515
|
+
config: {
|
|
7516
|
+
...current,
|
|
7517
|
+
channels: nextChannels,
|
|
7518
|
+
enabledChannels: Array.from(new Set(nextChannels.filter((channel) => channel.enabled).map((channel) => channel.provider)))
|
|
7519
|
+
},
|
|
7520
|
+
channel: nextChannel
|
|
7148
7521
|
};
|
|
7149
7522
|
}
|
|
7150
7523
|
function getWeixinAccountsPayload() {
|
|
@@ -7159,17 +7532,38 @@ function getWeixinAccountsPayload() {
|
|
|
7159
7532
|
updatedAt: account.updatedAt
|
|
7160
7533
|
}));
|
|
7161
7534
|
}
|
|
7162
|
-
|
|
7163
|
-
|
|
7535
|
+
function getChannelLabel(channel) {
|
|
7536
|
+
const providerLabel = channel.provider === "weixin" ? "\u5FAE\u4FE1" : "\u98DE\u4E66";
|
|
7537
|
+
return channel.alias?.trim() ? `${channel.alias} \xB7 ${providerLabel}` : providerLabel;
|
|
7538
|
+
}
|
|
7539
|
+
function getFeishuSite(channel) {
|
|
7540
|
+
const feishu = channel.config;
|
|
7541
|
+
return normalizeFeishuSite(feishu.site);
|
|
7542
|
+
}
|
|
7543
|
+
function getFeishuDomain(channel) {
|
|
7544
|
+
return feishuSiteToApiBaseUrl(getFeishuSite(channel));
|
|
7545
|
+
}
|
|
7546
|
+
function getFeishuTokenCacheKey(channel) {
|
|
7547
|
+
const feishu = channel.config;
|
|
7548
|
+
return [
|
|
7549
|
+
channel.id,
|
|
7550
|
+
feishu.appId || "",
|
|
7551
|
+
feishu.appSecret || "",
|
|
7552
|
+
getFeishuDomain(channel)
|
|
7553
|
+
].join(":");
|
|
7554
|
+
}
|
|
7555
|
+
async function validateFeishuCredentials(channel) {
|
|
7556
|
+
const feishu = channel.config;
|
|
7557
|
+
if (!feishu.appId || !feishu.appSecret) {
|
|
7164
7558
|
return { ok: false, message: "Feishu App ID / App Secret \u4E0D\u80FD\u4E3A\u7A7A\u3002" };
|
|
7165
7559
|
}
|
|
7166
|
-
const domain =
|
|
7560
|
+
const domain = getFeishuDomain(channel);
|
|
7167
7561
|
const response = await fetch(`${domain}/open-apis/auth/v3/tenant_access_token/internal`, {
|
|
7168
7562
|
method: "POST",
|
|
7169
7563
|
headers: { "Content-Type": "application/json" },
|
|
7170
7564
|
body: JSON.stringify({
|
|
7171
|
-
app_id:
|
|
7172
|
-
app_secret:
|
|
7565
|
+
app_id: feishu.appId,
|
|
7566
|
+
app_secret: feishu.appSecret
|
|
7173
7567
|
})
|
|
7174
7568
|
});
|
|
7175
7569
|
const data = await response.json();
|
|
@@ -7178,42 +7572,40 @@ async function validateFeishuCredentials(config) {
|
|
|
7178
7572
|
}
|
|
7179
7573
|
return {
|
|
7180
7574
|
ok: false,
|
|
7181
|
-
message:
|
|
7575
|
+
message: `${getChannelLabel(channel)} \u6821\u9A8C\u5931\u8D25\uFF1A${data.msg || `HTTP ${response.status}`}`
|
|
7182
7576
|
};
|
|
7183
7577
|
}
|
|
7184
|
-
function
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
const domain = getFeishuDomain(config);
|
|
7578
|
+
async function getFeishuTenantAccessToken(channel) {
|
|
7579
|
+
const feishu = channel.config;
|
|
7580
|
+
if (!feishu.appId || !feishu.appSecret) return null;
|
|
7581
|
+
const domain = getFeishuDomain(channel);
|
|
7582
|
+
const cacheKey = getFeishuTokenCacheKey(channel);
|
|
7190
7583
|
const now3 = Date.now();
|
|
7191
|
-
|
|
7192
|
-
|
|
7584
|
+
const cached = feishuTenantTokenCache.get(cacheKey);
|
|
7585
|
+
if (cached && cached.expiresAt > now3 + 6e4) {
|
|
7586
|
+
return cached.token;
|
|
7193
7587
|
}
|
|
7194
7588
|
const response = await fetch(`${domain}/open-apis/auth/v3/tenant_access_token/internal`, {
|
|
7195
7589
|
method: "POST",
|
|
7196
7590
|
headers: { "Content-Type": "application/json" },
|
|
7197
7591
|
body: JSON.stringify({
|
|
7198
|
-
app_id:
|
|
7199
|
-
app_secret:
|
|
7592
|
+
app_id: feishu.appId,
|
|
7593
|
+
app_secret: feishu.appSecret
|
|
7200
7594
|
})
|
|
7201
7595
|
});
|
|
7202
7596
|
const data = await response.json();
|
|
7203
7597
|
if (!response.ok || data.code !== 0 || !data.tenant_access_token) {
|
|
7204
7598
|
return null;
|
|
7205
7599
|
}
|
|
7206
|
-
feishuTenantTokenCache
|
|
7207
|
-
appId: config.feishuAppId,
|
|
7208
|
-
appSecret: config.feishuAppSecret,
|
|
7209
|
-
domain,
|
|
7600
|
+
feishuTenantTokenCache.set(cacheKey, {
|
|
7210
7601
|
token: data.tenant_access_token,
|
|
7211
7602
|
expiresAt: now3 + Math.max(60, Number(data.expire || 7200)) * 1e3
|
|
7212
|
-
};
|
|
7603
|
+
});
|
|
7213
7604
|
return data.tenant_access_token;
|
|
7214
7605
|
}
|
|
7215
7606
|
async function resolveFeishuBindingDisplay(config, binding) {
|
|
7216
|
-
|
|
7607
|
+
const channel = findChannelInstance(binding.channelType, config);
|
|
7608
|
+
if (!channel || channel.provider !== "feishu") {
|
|
7217
7609
|
return {
|
|
7218
7610
|
chatDisplayName: binding.chatDisplayName,
|
|
7219
7611
|
chatUserId: binding.chatUserId
|
|
@@ -7226,14 +7618,14 @@ async function resolveFeishuBindingDisplay(config, binding) {
|
|
|
7226
7618
|
chatUserId: cached.userId || binding.chatUserId
|
|
7227
7619
|
};
|
|
7228
7620
|
}
|
|
7229
|
-
const token = await getFeishuTenantAccessToken(
|
|
7621
|
+
const token = await getFeishuTenantAccessToken(channel);
|
|
7230
7622
|
if (!token) {
|
|
7231
7623
|
return {
|
|
7232
7624
|
chatDisplayName: binding.chatDisplayName,
|
|
7233
7625
|
chatUserId: binding.chatUserId
|
|
7234
7626
|
};
|
|
7235
7627
|
}
|
|
7236
|
-
const domain = getFeishuDomain(
|
|
7628
|
+
const domain = getFeishuDomain(channel);
|
|
7237
7629
|
try {
|
|
7238
7630
|
const chatResponse = await fetch(
|
|
7239
7631
|
`${domain}/open-apis/im/v1/chats/${encodeURIComponent(binding.chatId)}`,
|
|
@@ -7283,7 +7675,7 @@ async function buildBindingsPayload(store, config) {
|
|
|
7283
7675
|
const bindings = listBindingSummaries(store);
|
|
7284
7676
|
const enriched = await Promise.all(bindings.map(async (binding) => {
|
|
7285
7677
|
const resolved = await resolveFeishuBindingDisplay(config, binding);
|
|
7286
|
-
if (
|
|
7678
|
+
if ((resolved.chatDisplayName !== binding.chatDisplayName || resolved.chatUserId !== binding.chatUserId) && (resolved.chatDisplayName || resolved.chatUserId)) {
|
|
7287
7679
|
store.updateChannelBinding(binding.id, {
|
|
7288
7680
|
chatDisplayName: resolved.chatDisplayName,
|
|
7289
7681
|
chatUserId: resolved.chatUserId
|
|
@@ -7297,13 +7689,29 @@ async function buildBindingsPayload(store, config) {
|
|
|
7297
7689
|
}));
|
|
7298
7690
|
return {
|
|
7299
7691
|
bindings: enriched,
|
|
7300
|
-
channels: {
|
|
7301
|
-
feishu: enriched.filter((binding) => binding.channelType === "feishu"),
|
|
7302
|
-
weixin: enriched.filter((binding) => binding.channelType === "weixin")
|
|
7303
|
-
},
|
|
7304
7692
|
options: listBindingTargetOptions(store, 12)
|
|
7305
7693
|
};
|
|
7306
7694
|
}
|
|
7695
|
+
function syncBindingChannelMeta(store, channel) {
|
|
7696
|
+
for (const binding of store.listChannelBindings(channel.id)) {
|
|
7697
|
+
store.updateChannelBinding(binding.id, {
|
|
7698
|
+
channelProvider: channel.provider,
|
|
7699
|
+
channelAlias: channel.alias
|
|
7700
|
+
});
|
|
7701
|
+
}
|
|
7702
|
+
}
|
|
7703
|
+
function deleteChannelInstance(current, channelId) {
|
|
7704
|
+
const channels = current.channels || [];
|
|
7705
|
+
const nextChannels = channels.filter((channel) => channel.id !== channelId);
|
|
7706
|
+
if (nextChannels.length === channels.length) {
|
|
7707
|
+
throw new Error("\u6307\u5B9A\u7684\u901A\u9053\u4E0D\u5B58\u5728\u3002");
|
|
7708
|
+
}
|
|
7709
|
+
return {
|
|
7710
|
+
...current,
|
|
7711
|
+
channels: nextChannels,
|
|
7712
|
+
enabledChannels: Array.from(new Set(nextChannels.filter((channel) => channel.enabled).map((channel) => channel.provider)))
|
|
7713
|
+
};
|
|
7714
|
+
}
|
|
7307
7715
|
async function testCodexConnection(config) {
|
|
7308
7716
|
const provider = new CodexProvider(new PendingPermissions());
|
|
7309
7717
|
const abortController = new AbortController();
|
|
@@ -8202,63 +8610,212 @@ function renderHtml() {
|
|
|
8202
8610
|
overflow: hidden;
|
|
8203
8611
|
}
|
|
8204
8612
|
|
|
8205
|
-
.channel-
|
|
8206
|
-
display:
|
|
8207
|
-
|
|
8208
|
-
gap:
|
|
8209
|
-
padding: 0 20px;
|
|
8210
|
-
border-bottom: 1px solid var(--border);
|
|
8211
|
-
background: #ffffff;
|
|
8613
|
+
.channel-layout {
|
|
8614
|
+
display: grid;
|
|
8615
|
+
grid-template-columns: 280px minmax(0, 1fr);
|
|
8616
|
+
gap: 20px;
|
|
8212
8617
|
}
|
|
8213
8618
|
|
|
8214
|
-
.
|
|
8619
|
+
.channel-sidebar {
|
|
8620
|
+
border-right: 1px solid var(--border);
|
|
8621
|
+
padding-right: 20px;
|
|
8215
8622
|
display: grid;
|
|
8216
|
-
gap:
|
|
8623
|
+
gap: 12px;
|
|
8624
|
+
align-content: start;
|
|
8217
8625
|
}
|
|
8218
8626
|
|
|
8219
|
-
.
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
background: var(--surface-soft);
|
|
8223
|
-
overflow: hidden;
|
|
8627
|
+
.channel-sidebar-meta {
|
|
8628
|
+
color: var(--muted);
|
|
8629
|
+
font-size: 12px;
|
|
8224
8630
|
}
|
|
8225
8631
|
|
|
8226
|
-
.
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
font-size: 14px;
|
|
8230
|
-
font-weight: 700;
|
|
8231
|
-
border-bottom: 1px solid var(--border);
|
|
8232
|
-
background: #ffffff;
|
|
8632
|
+
.channel-list {
|
|
8633
|
+
display: grid;
|
|
8634
|
+
gap: 8px;
|
|
8233
8635
|
}
|
|
8234
8636
|
|
|
8235
|
-
.
|
|
8637
|
+
.channel-list-item {
|
|
8638
|
+
width: 100%;
|
|
8639
|
+
text-align: left;
|
|
8640
|
+
border-radius: 10px;
|
|
8641
|
+
padding: 12px 14px;
|
|
8236
8642
|
display: grid;
|
|
8643
|
+
gap: 8px;
|
|
8237
8644
|
}
|
|
8238
8645
|
|
|
8239
|
-
.
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
gap: 16px;
|
|
8244
|
-
padding: 10px 14px;
|
|
8245
|
-
align-items: start;
|
|
8646
|
+
.channel-list-item.active {
|
|
8647
|
+
border-color: rgba(22, 119, 255, 0.30);
|
|
8648
|
+
background: rgba(22, 119, 255, 0.06);
|
|
8649
|
+
color: var(--text);
|
|
8246
8650
|
}
|
|
8247
8651
|
|
|
8248
|
-
.
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
font-weight: 700;
|
|
8254
|
-
text-transform: uppercase;
|
|
8255
|
-
letter-spacing: .04em;
|
|
8256
|
-
background: #fcfcfd;
|
|
8257
|
-
border-top: 1px solid var(--border);
|
|
8652
|
+
.channel-list-item-head {
|
|
8653
|
+
display: flex;
|
|
8654
|
+
justify-content: space-between;
|
|
8655
|
+
align-items: center;
|
|
8656
|
+
gap: 10px;
|
|
8258
8657
|
}
|
|
8259
8658
|
|
|
8260
|
-
.
|
|
8261
|
-
|
|
8659
|
+
.channel-list-item-title {
|
|
8660
|
+
font-weight: 700;
|
|
8661
|
+
min-width: 0;
|
|
8662
|
+
word-break: break-word;
|
|
8663
|
+
}
|
|
8664
|
+
|
|
8665
|
+
.channel-list-item-provider,
|
|
8666
|
+
.channel-list-item-meta {
|
|
8667
|
+
color: var(--muted);
|
|
8668
|
+
font-size: 12px;
|
|
8669
|
+
}
|
|
8670
|
+
|
|
8671
|
+
.channel-list-item-stats {
|
|
8672
|
+
display: flex;
|
|
8673
|
+
justify-content: space-between;
|
|
8674
|
+
align-items: center;
|
|
8675
|
+
gap: 12px;
|
|
8676
|
+
font-size: 12px;
|
|
8677
|
+
color: var(--muted);
|
|
8678
|
+
}
|
|
8679
|
+
|
|
8680
|
+
.channel-list-item-status {
|
|
8681
|
+
color: var(--text);
|
|
8682
|
+
font-weight: 600;
|
|
8683
|
+
}
|
|
8684
|
+
|
|
8685
|
+
.channel-editor {
|
|
8686
|
+
min-width: 0;
|
|
8687
|
+
}
|
|
8688
|
+
|
|
8689
|
+
.channel-editor-summary {
|
|
8690
|
+
display: grid;
|
|
8691
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
8692
|
+
gap: 12px;
|
|
8693
|
+
margin-bottom: 18px;
|
|
8694
|
+
}
|
|
8695
|
+
|
|
8696
|
+
.channel-editor-stat {
|
|
8697
|
+
border: 1px solid var(--border);
|
|
8698
|
+
border-radius: 8px;
|
|
8699
|
+
background: var(--surface-soft);
|
|
8700
|
+
padding: 12px 14px;
|
|
8701
|
+
display: grid;
|
|
8702
|
+
gap: 4px;
|
|
8703
|
+
}
|
|
8704
|
+
|
|
8705
|
+
.channel-editor-stat strong {
|
|
8706
|
+
font-size: 12px;
|
|
8707
|
+
color: var(--muted);
|
|
8708
|
+
font-weight: 600;
|
|
8709
|
+
}
|
|
8710
|
+
|
|
8711
|
+
.channel-editor-stat span {
|
|
8712
|
+
font-size: 14px;
|
|
8713
|
+
font-weight: 700;
|
|
8714
|
+
color: var(--text);
|
|
8715
|
+
}
|
|
8716
|
+
|
|
8717
|
+
.editor-section {
|
|
8718
|
+
border-top: 1px solid var(--border);
|
|
8719
|
+
padding-top: 16px;
|
|
8720
|
+
display: grid;
|
|
8721
|
+
gap: 14px;
|
|
8722
|
+
}
|
|
8723
|
+
|
|
8724
|
+
.editor-section-title {
|
|
8725
|
+
margin: 0;
|
|
8726
|
+
font-size: 14px;
|
|
8727
|
+
font-weight: 700;
|
|
8728
|
+
}
|
|
8729
|
+
|
|
8730
|
+
.toolbar-split {
|
|
8731
|
+
display: flex;
|
|
8732
|
+
justify-content: space-between;
|
|
8733
|
+
align-items: flex-start;
|
|
8734
|
+
gap: 12px;
|
|
8735
|
+
flex-wrap: wrap;
|
|
8736
|
+
}
|
|
8737
|
+
|
|
8738
|
+
.toolbar-danger {
|
|
8739
|
+
display: flex;
|
|
8740
|
+
gap: 10px;
|
|
8741
|
+
flex-wrap: wrap;
|
|
8742
|
+
}
|
|
8743
|
+
|
|
8744
|
+
button.danger {
|
|
8745
|
+
border-color: rgba(220, 38, 38, 0.24);
|
|
8746
|
+
color: var(--danger);
|
|
8747
|
+
}
|
|
8748
|
+
|
|
8749
|
+
button.danger:hover {
|
|
8750
|
+
border-color: var(--danger);
|
|
8751
|
+
color: var(--danger);
|
|
8752
|
+
}
|
|
8753
|
+
|
|
8754
|
+
.inline-select {
|
|
8755
|
+
display: inline-grid;
|
|
8756
|
+
gap: 6px;
|
|
8757
|
+
color: var(--muted);
|
|
8758
|
+
font-size: 12px;
|
|
8759
|
+
font-weight: 500;
|
|
8760
|
+
}
|
|
8761
|
+
|
|
8762
|
+
.channel-tabs {
|
|
8763
|
+
display: flex;
|
|
8764
|
+
align-items: flex-end;
|
|
8765
|
+
gap: 0;
|
|
8766
|
+
padding: 0 20px;
|
|
8767
|
+
border-bottom: 1px solid var(--border);
|
|
8768
|
+
background: #ffffff;
|
|
8769
|
+
}
|
|
8770
|
+
|
|
8771
|
+
.command-sections {
|
|
8772
|
+
display: grid;
|
|
8773
|
+
gap: 14px;
|
|
8774
|
+
}
|
|
8775
|
+
|
|
8776
|
+
.command-section {
|
|
8777
|
+
border: 1px solid var(--border);
|
|
8778
|
+
border-radius: 8px;
|
|
8779
|
+
background: var(--surface-soft);
|
|
8780
|
+
overflow: hidden;
|
|
8781
|
+
}
|
|
8782
|
+
|
|
8783
|
+
.command-section-title {
|
|
8784
|
+
margin: 0;
|
|
8785
|
+
padding: 10px 14px;
|
|
8786
|
+
font-size: 14px;
|
|
8787
|
+
font-weight: 700;
|
|
8788
|
+
border-bottom: 1px solid var(--border);
|
|
8789
|
+
background: #ffffff;
|
|
8790
|
+
}
|
|
8791
|
+
|
|
8792
|
+
.command-list {
|
|
8793
|
+
display: grid;
|
|
8794
|
+
}
|
|
8795
|
+
|
|
8796
|
+
.command-list-head,
|
|
8797
|
+
.command-item {
|
|
8798
|
+
display: grid;
|
|
8799
|
+
grid-template-columns: 220px 320px minmax(0, 1fr);
|
|
8800
|
+
gap: 16px;
|
|
8801
|
+
padding: 10px 14px;
|
|
8802
|
+
align-items: start;
|
|
8803
|
+
}
|
|
8804
|
+
|
|
8805
|
+
.command-list-head {
|
|
8806
|
+
padding-top: 12px;
|
|
8807
|
+
padding-bottom: 8px;
|
|
8808
|
+
color: var(--muted);
|
|
8809
|
+
font-size: 12px;
|
|
8810
|
+
font-weight: 700;
|
|
8811
|
+
text-transform: uppercase;
|
|
8812
|
+
letter-spacing: .04em;
|
|
8813
|
+
background: #fcfcfd;
|
|
8814
|
+
border-top: 1px solid var(--border);
|
|
8815
|
+
}
|
|
8816
|
+
|
|
8817
|
+
.command-item:first-child {
|
|
8818
|
+
border-top: 0;
|
|
8262
8819
|
}
|
|
8263
8820
|
|
|
8264
8821
|
.command-item code {
|
|
@@ -8464,6 +9021,9 @@ function renderHtml() {
|
|
|
8464
9021
|
.sidebar { border-right: 0; border-bottom: 1px solid var(--sidebar-border); }
|
|
8465
9022
|
.nav { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
|
8466
9023
|
.main { padding: 20px 20px 28px; }
|
|
9024
|
+
.channel-layout { grid-template-columns: 1fr; }
|
|
9025
|
+
.channel-sidebar { border-right: 0; padding-right: 0; }
|
|
9026
|
+
.channel-editor-summary { grid-template-columns: 1fr; }
|
|
8467
9027
|
.field-row,
|
|
8468
9028
|
.field-row.triple,
|
|
8469
9029
|
.command-item,
|
|
@@ -8516,6 +9076,10 @@ function renderHtml() {
|
|
|
8516
9076
|
<strong>Bridge</strong>
|
|
8517
9077
|
<div class="status-value" id="bridgeStatus">-</div>
|
|
8518
9078
|
</div>
|
|
9079
|
+
<div class="status-card">
|
|
9080
|
+
<strong>Bridge \u5F00\u673A\u81EA\u542F\u52A8</strong>
|
|
9081
|
+
<div class="status-value" id="autostartStatus">-</div>
|
|
9082
|
+
</div>
|
|
8519
9083
|
<div class="status-card">
|
|
8520
9084
|
<strong>Codex Skill</strong>
|
|
8521
9085
|
<div class="status-value" id="integrationStatus">-</div>
|
|
@@ -8559,6 +9123,14 @@ function renderHtml() {
|
|
|
8559
9123
|
<div class="notice">\u5DF2\u63A5\u901A\uFF1A\u4FDD\u5B58\u914D\u7F6E\u3001\u540E\u53F0\u542F\u505C\u3001\u98DE\u4E66\u51ED\u636E\u6D4B\u8BD5\u3001\u5FAE\u4FE1\u626B\u7801\u3001Codex \u8FDE\u63A5\u6D4B\u8BD5\u3001\u684C\u9762\u4F1A\u8BDD\u53D1\u73B0\u3001IM \u7ED1\u5B9A\u67E5\u770B\u4E0E\u7F51\u9875\u4FA7\u5207\u6362\u3002</div>
|
|
8560
9124
|
</div>
|
|
8561
9125
|
|
|
9126
|
+
<div class="panel-block">
|
|
9127
|
+
<p class="panel-subtitle">Bridge \u5F00\u673A\u81EA\u542F\u52A8</p>
|
|
9128
|
+
<div class="notice" id="autostartNotice">\u6B63\u5728\u68C0\u67E5\u5F53\u524D Windows \u4EFB\u52A1\u8BA1\u5212\u7A0B\u5E8F\u72B6\u6001\u2026</div>
|
|
9129
|
+
<div class="actions" style="margin-top: 12px;">
|
|
9130
|
+
<button id="refreshAutostartBtn">\u5237\u65B0\u5F00\u673A\u81EA\u542F\u52A8\u72B6\u6001</button>
|
|
9131
|
+
</div>
|
|
9132
|
+
</div>
|
|
9133
|
+
|
|
8562
9134
|
<div class="panel-block">
|
|
8563
9135
|
<p class="panel-subtitle">\u53EF\u9009 Codex Skill</p>
|
|
8564
9136
|
<div class="notice">bridge \u4E0D\u518D\u6CE8\u5165\u53D1\u9001\u9644\u4EF6\u7684\u63D0\u793A\u8BCD\u3002\u9700\u8981\u8BA9 Codex \u77E5\u9053\u201C\u53EF\u4EE5\u628A\u672C\u5730\u56FE\u7247/\u6587\u4EF6\u56DE\u53D1\u5230 IM\u201D\u65F6\uFF0C\u8BF7\u5B89\u88C5\u8FD9\u4E2A\u53EF\u9009 skill\u3002</div>
|
|
@@ -8705,10 +9277,8 @@ function renderHtml() {
|
|
|
8705
9277
|
</label>
|
|
8706
9278
|
</div>
|
|
8707
9279
|
<div class="small">\u672A\u7ED1\u5B9A\u7684 IM \u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF08\u7B49\u540C <code>/t 0</code>\uFF09\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u53EA\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u9ED8\u8BA4\u6A21\u578B\u5019\u9009\u9879\u6765\u81EA\u542F\u52A8\u65F6\u8BFB\u53D6\u7684 Codex \u6A21\u578B\u7F13\u5B58\uFF1A\u9690\u85CF\u6A21\u578B\u4E0D\u4F1A\u5C55\u793A\uFF0CCLI only \u6A21\u578B\u4F1A\u6807\u6210\u201C\u4EC5 IM / CLI\u201D\u3002\u7559\u7A7A\u5219\u7EE7\u7EED\u8DDF\u968F Codex \u5F53\u524D\u9ED8\u8BA4\u6A21\u578B\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002</div>
|
|
8708
|
-
<div class="small">\u5F53\u524D\u9700\u8981\u91CD\u542F Bridge \u7684\u914D\u7F6E\uFF1A<code>Runtime</code>\u3001<code>\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</code>\u3001<code>\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</code>\
|
|
9280
|
+
<div class="small">\u5F53\u524D\u9700\u8981\u91CD\u542F Bridge \u7684\u914D\u7F6E\uFF1A<code>Runtime</code>\u3001<code>\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</code>\u3001<code>\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</code>\u3002\u901A\u9053\u5B9E\u4F8B\u7684\u63A5\u5165\u914D\u7F6E\u8BF7\u5728\u201C\u901A\u9053\u201D\u9875\u7EF4\u62A4\u3002</div>
|
|
8709
9281
|
<div class="checkbox-row">
|
|
8710
|
-
<label class="checkbox"><input id="channelFeishu" type="checkbox" checked /> \u542F\u7528\u98DE\u4E66</label>
|
|
8711
|
-
<label class="checkbox"><input id="channelWeixin" type="checkbox" /> \u542F\u7528\u5FAE\u4FE1</label>
|
|
8712
9282
|
<label class="checkbox"><input id="autoApprove" type="checkbox" /> \u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</label>
|
|
8713
9283
|
</div>
|
|
8714
9284
|
<div class="checkbox-row">
|
|
@@ -8813,112 +9383,35 @@ function renderHtml() {
|
|
|
8813
9383
|
</div>
|
|
8814
9384
|
</div>
|
|
8815
9385
|
|
|
8816
|
-
<section class="panel channel-
|
|
8817
|
-
<div class="
|
|
8818
|
-
<
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
<div class="channel-view active" data-channel="feishu" role="tabpanel">
|
|
8823
|
-
<section id="feishu">
|
|
8824
|
-
<div class="panel-header">
|
|
8825
|
-
<div>
|
|
8826
|
-
<h2>\u98DE\u4E66 / Lark</h2>
|
|
8827
|
-
<p>\u586B\u5199\u51ED\u636E\u3001\u6D4B\u8BD5\u53EF\u7528\u6027\uFF0C\u5E76\u67E5\u770B\u5F53\u524D\u98DE\u4E66\u804A\u5929\u7ED1\u5B9A\u5230\u54EA\u6761\u4F1A\u8BDD\u3002</p>
|
|
8828
|
-
</div>
|
|
8829
|
-
<div class="toolbar">
|
|
8830
|
-
<button id="saveFeishuChannelBtn">\u4FDD\u5B58\u901A\u9053\u914D\u7F6E</button>
|
|
8831
|
-
<button id="testFeishuBtn">\u6D4B\u8BD5\u98DE\u4E66\u51ED\u636E</button>
|
|
8832
|
-
<button id="refreshFeishuStateBtn">\u5237\u65B0\u72B6\u6001</button>
|
|
8833
|
-
</div>
|
|
8834
|
-
</div>
|
|
8835
|
-
|
|
8836
|
-
<div class="fields">
|
|
8837
|
-
<div class="field-row">
|
|
8838
|
-
<label>
|
|
8839
|
-
App ID
|
|
8840
|
-
<input id="feishuAppId" />
|
|
8841
|
-
</label>
|
|
8842
|
-
<label>
|
|
8843
|
-
App Secret
|
|
8844
|
-
<input id="feishuAppSecret" />
|
|
8845
|
-
</label>
|
|
8846
|
-
</div>
|
|
8847
|
-
<div class="field-row">
|
|
8848
|
-
<label>
|
|
8849
|
-
Domain
|
|
8850
|
-
<input id="feishuDomain" value="https://open.feishu.cn" />
|
|
8851
|
-
</label>
|
|
8852
|
-
<label>
|
|
8853
|
-
Allowed Users
|
|
8854
|
-
<input id="feishuAllowedUsers" placeholder="\u591A\u4E2A user_id \u7528\u9017\u53F7\u5206\u9694" />
|
|
8855
|
-
</label>
|
|
8856
|
-
</div>
|
|
8857
|
-
<div class="checkbox-row">
|
|
8858
|
-
<label class="checkbox"><input id="feishuStreamingEnabled" type="checkbox" checked /> \u542F\u7528\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247</label>
|
|
8859
|
-
</div>
|
|
8860
|
-
<div class="checkbox-row">
|
|
8861
|
-
<label class="checkbox"><input id="feishuCommandMarkdownEnabled" type="checkbox" checked /> \u53CD\u9988\u4F7F\u7528markdown</label>
|
|
8862
|
-
</div>
|
|
8863
|
-
<div class="small">\u9700\u8981\u98DE\u4E66\u4FA7\u5DF2\u5F00\u901A\u53EF\u66F4\u65B0\u5361\u7247\u7684\u76F8\u5173\u80FD\u529B\uFF1B\u5982\u679C\u6743\u9650\u4E0D\u8DB3\uFF0C\u4F1A\u81EA\u52A8\u56DE\u9000\u4E3A\u6700\u7EC8\u7ED3\u679C\u6D88\u606F\u3002</div>
|
|
8864
|
-
<div class="small">\u5F71\u54CD\u901A\u8FC7 bridge \u53D1\u9001\u5230\u98DE\u4E66\u7684\u6587\u672C\u53CD\u9988\uFF0C\u5305\u62EC\u666E\u901A\u56DE\u590D\u3001\u5171\u4EAB\u684C\u9762\u7EBF\u7A0B\u955C\u50CF\u548C <code>/h</code>\u3001<code>/status</code>\u3001<code>/threads</code> \u8FD9\u7C7B\u7CFB\u7EDF\u53CD\u9988\u3002</div>
|
|
8865
|
-
<div class="small">\u4FEE\u6539\u98DE\u4E66 <code>App ID</code>\u3001<code>App Secret</code>\u3001<code>Domain</code> \u540E\uFF0C\u9700\u8981\u91CD\u542F Bridge \u8BA9\u5BA2\u6237\u7AEF\u91CD\u65B0\u521D\u59CB\u5316\uFF1B\u767D\u540D\u5355\u3001\u6D41\u5F0F\u5F00\u5173\u3001markdown \u5F00\u5173\u4F1A\u5373\u65F6\u751F\u6548\u3002</div>
|
|
8866
|
-
</div>
|
|
8867
|
-
|
|
8868
|
-
<div class="panel-block">
|
|
8869
|
-
<p class="panel-subtitle">\u901A\u9053\u72B6\u6001</p>
|
|
8870
|
-
<div class="small" id="feishuRuntimeMeta">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
9386
|
+
<section class="panel channel-workspace">
|
|
9387
|
+
<div class="panel-header">
|
|
9388
|
+
<div>
|
|
9389
|
+
<h2>\u901A\u9053\u5B9E\u4F8B</h2>
|
|
9390
|
+
<p>\u8FD9\u91CC\u7BA1\u7406\u591A\u4E2A\u98DE\u4E66\u6216\u5FAE\u4FE1\u673A\u5668\u4EBA\u5B9E\u4F8B\u3002\u5B9E\u4F8B\u53EA\u662F\u4E0D\u540C\u804A\u5929\u5165\u53E3\uFF0C\u4E0D\u4F1A\u6539\u53D8 Codex \u7684\u4F1A\u8BDD\u8BED\u4E49\u3002</p>
|
|
8871
9391
|
</div>
|
|
8872
|
-
<div class="
|
|
8873
|
-
<
|
|
8874
|
-
|
|
8875
|
-
|
|
9392
|
+
<div class="toolbar">
|
|
9393
|
+
<label class="inline-select">
|
|
9394
|
+
\u65B0\u901A\u9053
|
|
9395
|
+
<select id="newChannelProvider">
|
|
9396
|
+
<option value="feishu">\u98DE\u4E66</option>
|
|
9397
|
+
<option value="weixin">\u5FAE\u4FE1</option>
|
|
9398
|
+
</select>
|
|
9399
|
+
</label>
|
|
9400
|
+
<button id="createChannelBtn">\u65B0\u589E\u901A\u9053</button>
|
|
9401
|
+
<button id="refreshChannelsBtn">\u5237\u65B0\u72B6\u6001</button>
|
|
8876
9402
|
</div>
|
|
8877
|
-
|
|
8878
|
-
<div class="message" id="feishuMessage"></div>
|
|
8879
|
-
</section>
|
|
8880
9403
|
</div>
|
|
8881
9404
|
|
|
8882
|
-
<div class="channel-
|
|
8883
|
-
<
|
|
8884
|
-
|
|
8885
|
-
<div>
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
</div>
|
|
8889
|
-
<div class="toolbar">
|
|
8890
|
-
<button id="saveWeixinChannelBtn">\u4FDD\u5B58\u901A\u9053\u914D\u7F6E</button>
|
|
8891
|
-
<button id="weixinLoginBtn">\u5F00\u59CB\u5FAE\u4FE1\u626B\u7801</button>
|
|
8892
|
-
<button id="refreshWeixinStateBtn">\u5237\u65B0\u72B6\u6001</button>
|
|
8893
|
-
</div>
|
|
8894
|
-
</div>
|
|
8895
|
-
|
|
8896
|
-
<div class="fields">
|
|
8897
|
-
<div class="checkbox-row">
|
|
8898
|
-
<label class="checkbox"><input id="weixinMediaEnabled" type="checkbox" /> \u542F\u7528\u56FE\u7247 / \u6587\u4EF6 / \u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D</label>
|
|
8899
|
-
</div>
|
|
8900
|
-
<div class="checkbox-row">
|
|
8901
|
-
<label class="checkbox"><input id="weixinCommandMarkdownEnabled" type="checkbox" /> \u53CD\u9988\u4F7F\u7528markdown</label>
|
|
8902
|
-
</div>
|
|
8903
|
-
</div>
|
|
8904
|
-
<div class="small">\u5F71\u54CD\u901A\u8FC7 bridge \u53D1\u9001\u5230\u5FAE\u4FE1\u7684\u6587\u672C\u53CD\u9988\uFF0C\u5305\u62EC\u666E\u901A\u56DE\u590D\u3001\u5171\u4EAB\u684C\u9762\u7EBF\u7A0B\u955C\u50CF\u548C <code>/h</code>\u3001<code>/status</code>\u3001<code>/threads</code> \u8FD9\u7C7B\u7CFB\u7EDF\u53CD\u9988\u3002\u9ED8\u8BA4\u5173\u95ED\u3002</div>
|
|
8905
|
-
<div class="panel-block">
|
|
8906
|
-
<p class="panel-subtitle">\u901A\u9053\u72B6\u6001</p>
|
|
8907
|
-
<div class="small" id="weixinRuntimeMeta">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
8908
|
-
</div>
|
|
8909
|
-
<div class="panel-block">
|
|
8910
|
-
<p class="panel-subtitle">\u5DF2\u767B\u5F55\u5FAE\u4FE1\u8D26\u53F7</p>
|
|
8911
|
-
<div class="small" id="weixinAccountMeta">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
8912
|
-
<div class="binding-list" id="weixinAccounts" style="margin-top: 12px;"></div>
|
|
8913
|
-
</div>
|
|
8914
|
-
<div class="panel-block">
|
|
8915
|
-
<p class="panel-subtitle">\u5F53\u524D\u5FAE\u4FE1\u7ED1\u5B9A</p>
|
|
8916
|
-
<div class="small" id="weixinBindingMeta">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
8917
|
-
<div class="binding-list" id="weixinBindings" style="margin-top: 12px;"></div>
|
|
8918
|
-
</div>
|
|
8919
|
-
<div class="message" id="weixinMessage"></div>
|
|
9405
|
+
<div class="channel-layout">
|
|
9406
|
+
<aside class="channel-sidebar">
|
|
9407
|
+
<div class="channel-sidebar-meta" id="channelListMeta">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
9408
|
+
<div class="channel-list" id="channelList"></div>
|
|
9409
|
+
</aside>
|
|
9410
|
+
<section class="channel-editor" id="channelEditor">
|
|
9411
|
+
<div class="binding-empty">\u6B63\u5728\u52A0\u8F7D\u901A\u9053\u914D\u7F6E\u2026</div>
|
|
8920
9412
|
</section>
|
|
8921
9413
|
</div>
|
|
9414
|
+
<div class="message" id="channelMessage"></div>
|
|
8922
9415
|
</section>
|
|
8923
9416
|
</section>
|
|
8924
9417
|
|
|
@@ -8947,17 +9440,16 @@ function renderHtml() {
|
|
|
8947
9440
|
availableModels: [],
|
|
8948
9441
|
uiAccess: null,
|
|
8949
9442
|
bridgeStatus: null,
|
|
9443
|
+
autostartStatus: null,
|
|
8950
9444
|
desktopSessions: [],
|
|
8951
9445
|
bindings: [],
|
|
8952
9446
|
bindingOptions: [],
|
|
8953
|
-
|
|
8954
|
-
feishu: '',
|
|
8955
|
-
weixin: '',
|
|
8956
|
-
},
|
|
9447
|
+
activeBindingByChannelId: {},
|
|
8957
9448
|
weixinAccounts: [],
|
|
8958
9449
|
desktopRoot: '',
|
|
8959
9450
|
activePage: 'overview',
|
|
8960
|
-
|
|
9451
|
+
activeChannelId: '',
|
|
9452
|
+
channelDraft: null,
|
|
8961
9453
|
};
|
|
8962
9454
|
|
|
8963
9455
|
function escapeHtml(value) {
|
|
@@ -9068,16 +9560,6 @@ function renderHtml() {
|
|
|
9068
9560
|
return binding.chatDisplayName || binding.chatId || binding.id;
|
|
9069
9561
|
}
|
|
9070
9562
|
|
|
9071
|
-
function ensureActiveBinding(channelType, bindings) {
|
|
9072
|
-
const current = state.activeBindingByChannel[channelType];
|
|
9073
|
-
if (current && bindings.some((binding) => binding.id === current)) {
|
|
9074
|
-
return current;
|
|
9075
|
-
}
|
|
9076
|
-
const next = bindings[0] ? bindings[0].id : '';
|
|
9077
|
-
state.activeBindingByChannel[channelType] = next;
|
|
9078
|
-
return next;
|
|
9079
|
-
}
|
|
9080
|
-
|
|
9081
9563
|
function renderBindingCard(binding) {
|
|
9082
9564
|
return ''
|
|
9083
9565
|
+ '<article class="binding-item" data-binding-id="' + escapeHtml(binding.id) + '">'
|
|
@@ -9099,13 +9581,6 @@ function renderHtml() {
|
|
|
9099
9581
|
+ '</article>';
|
|
9100
9582
|
}
|
|
9101
9583
|
|
|
9102
|
-
function enabledChannelsFromForm() {
|
|
9103
|
-
const channels = [];
|
|
9104
|
-
if (document.getElementById('channelFeishu').checked) channels.push('feishu');
|
|
9105
|
-
if (document.getElementById('channelWeixin').checked) channels.push('weixin');
|
|
9106
|
-
return channels;
|
|
9107
|
-
}
|
|
9108
|
-
|
|
9109
9584
|
function formPayload() {
|
|
9110
9585
|
return {
|
|
9111
9586
|
runtime: document.getElementById('runtime').value,
|
|
@@ -9118,16 +9593,7 @@ function renderHtml() {
|
|
|
9118
9593
|
codexReasoningEffort: document.getElementById('codexReasoningEffort').value,
|
|
9119
9594
|
uiAllowLan: document.getElementById('uiAllowLan').checked,
|
|
9120
9595
|
uiAccessToken: document.getElementById('uiAccessToken').value,
|
|
9121
|
-
enabledChannels: enabledChannelsFromForm(),
|
|
9122
9596
|
autoApprove: document.getElementById('autoApprove').checked,
|
|
9123
|
-
feishuAppId: document.getElementById('feishuAppId').value,
|
|
9124
|
-
feishuAppSecret: document.getElementById('feishuAppSecret').value,
|
|
9125
|
-
feishuDomain: document.getElementById('feishuDomain').value,
|
|
9126
|
-
feishuAllowedUsers: document.getElementById('feishuAllowedUsers').value,
|
|
9127
|
-
feishuStreamingEnabled: document.getElementById('feishuStreamingEnabled').checked,
|
|
9128
|
-
feishuCommandMarkdownEnabled: document.getElementById('feishuCommandMarkdownEnabled').checked,
|
|
9129
|
-
weixinMediaEnabled: document.getElementById('weixinMediaEnabled').checked,
|
|
9130
|
-
weixinCommandMarkdownEnabled: document.getElementById('weixinCommandMarkdownEnabled').checked,
|
|
9131
9597
|
};
|
|
9132
9598
|
}
|
|
9133
9599
|
|
|
@@ -9179,7 +9645,7 @@ function renderHtml() {
|
|
|
9179
9645
|
|
|
9180
9646
|
if (syncHash !== false) {
|
|
9181
9647
|
const hash = nextPage === 'channels'
|
|
9182
|
-
? '#channels/' + state.
|
|
9648
|
+
? '#channels/' + (state.activeChannelId || '')
|
|
9183
9649
|
: '#' + nextPage;
|
|
9184
9650
|
if (window.location.hash !== hash) {
|
|
9185
9651
|
history.replaceState(null, '', hash);
|
|
@@ -9187,26 +9653,12 @@ function renderHtml() {
|
|
|
9187
9653
|
}
|
|
9188
9654
|
}
|
|
9189
9655
|
|
|
9190
|
-
function setActiveChannel(
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
document.querySelectorAll('.channel-tab').forEach((element) => {
|
|
9195
|
-
const node = element;
|
|
9196
|
-
const active = node.dataset.channel === nextChannel;
|
|
9197
|
-
node.classList.toggle('active', active);
|
|
9198
|
-
node.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
9199
|
-
});
|
|
9200
|
-
|
|
9201
|
-
document.querySelectorAll('.channel-view').forEach((element) => {
|
|
9202
|
-
const node = element;
|
|
9203
|
-
const active = node.dataset.channel === nextChannel;
|
|
9204
|
-
node.classList.toggle('active', active);
|
|
9205
|
-
node.hidden = !active;
|
|
9206
|
-
});
|
|
9656
|
+
function setActiveChannel(channelId, syncHash) {
|
|
9657
|
+
state.activeChannelId = channelId || '';
|
|
9658
|
+
renderChannelsWorkspace();
|
|
9207
9659
|
|
|
9208
9660
|
if (syncHash !== false && state.activePage === 'channels') {
|
|
9209
|
-
const hash = '#channels/' +
|
|
9661
|
+
const hash = '#channels/' + (state.activeChannelId || '');
|
|
9210
9662
|
if (window.location.hash !== hash) {
|
|
9211
9663
|
history.replaceState(null, '', hash);
|
|
9212
9664
|
}
|
|
@@ -9217,13 +9669,12 @@ function renderHtml() {
|
|
|
9217
9669
|
const raw = String(window.location.hash || '').replace(/^#/, '');
|
|
9218
9670
|
if (!raw) {
|
|
9219
9671
|
setActivePage('overview', false);
|
|
9220
|
-
setActiveChannel('feishu', false);
|
|
9221
9672
|
return;
|
|
9222
9673
|
}
|
|
9223
9674
|
|
|
9224
9675
|
if (raw.startsWith('channels/')) {
|
|
9225
9676
|
setActivePage('channels', false);
|
|
9226
|
-
setActiveChannel(raw.split('/')[1] || '
|
|
9677
|
+
setActiveChannel(raw.split('/')[1] || '', false);
|
|
9227
9678
|
return;
|
|
9228
9679
|
}
|
|
9229
9680
|
|
|
@@ -9270,21 +9721,44 @@ function renderHtml() {
|
|
|
9270
9721
|
});
|
|
9271
9722
|
}
|
|
9272
9723
|
|
|
9273
|
-
function
|
|
9274
|
-
|
|
9724
|
+
function providerLabel(provider) {
|
|
9725
|
+
if (provider === 'weixin') return '\u5FAE\u4FE1';
|
|
9726
|
+
if (provider === 'feishu') return '\u98DE\u4E66';
|
|
9727
|
+
return '\u901A\u9053';
|
|
9275
9728
|
}
|
|
9276
9729
|
|
|
9277
|
-
function
|
|
9278
|
-
return state.
|
|
9730
|
+
function configuredChannels() {
|
|
9731
|
+
return Array.isArray(state.config && state.config.channels) ? state.config.channels : [];
|
|
9279
9732
|
}
|
|
9280
9733
|
|
|
9281
|
-
function
|
|
9282
|
-
|
|
9734
|
+
function visibleChannels() {
|
|
9735
|
+
const channels = configuredChannels().slice();
|
|
9736
|
+
if (state.channelDraft) {
|
|
9737
|
+
channels.push(state.channelDraft);
|
|
9738
|
+
}
|
|
9739
|
+
return channels;
|
|
9740
|
+
}
|
|
9741
|
+
|
|
9742
|
+
function getChannelById(channelId) {
|
|
9743
|
+
if (state.channelDraft && state.channelDraft.id === channelId) return state.channelDraft;
|
|
9744
|
+
return configuredChannels().find((channel) => channel.id === channelId) || null;
|
|
9745
|
+
}
|
|
9746
|
+
|
|
9747
|
+
function adapterStatuses() {
|
|
9748
|
+
return state.bridgeStatus && Array.isArray(state.bridgeStatus.adapters) ? state.bridgeStatus.adapters : [];
|
|
9749
|
+
}
|
|
9750
|
+
|
|
9751
|
+
function getAdapterStatus(channelId) {
|
|
9752
|
+
return adapterStatuses().find((item) => item.channelType === channelId) || null;
|
|
9753
|
+
}
|
|
9754
|
+
|
|
9755
|
+
function isChannelRunning(channelId) {
|
|
9756
|
+
const status = getAdapterStatus(channelId);
|
|
9757
|
+
return Boolean(state.bridgeStatus && state.bridgeStatus.running && status && status.running);
|
|
9283
9758
|
}
|
|
9284
9759
|
|
|
9285
9760
|
const CONFIG_FIELD_LABELS = {
|
|
9286
9761
|
runtime: 'Runtime',
|
|
9287
|
-
enabledChannels: '\u901A\u9053\u542F\u7528\u72B6\u6001',
|
|
9288
9762
|
defaultWorkspaceRoot: '\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4',
|
|
9289
9763
|
defaultModel: '\u9ED8\u8BA4\u6A21\u578B',
|
|
9290
9764
|
defaultMode: '\u9ED8\u8BA4\u6A21\u5F0F',
|
|
@@ -9295,28 +9769,15 @@ function renderHtml() {
|
|
|
9295
9769
|
uiAllowLan: '\u5141\u8BB8\u5C40\u57DF\u7F51\u8BBF\u95EE Web \u63A7\u5236\u53F0',
|
|
9296
9770
|
uiAccessToken: '\u5C40\u57DF\u7F51\u8BBF\u95EE token',
|
|
9297
9771
|
autoApprove: '\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650',
|
|
9298
|
-
feishuAppId: '\u98DE\u4E66 App ID',
|
|
9299
|
-
feishuAppSecret: '\u98DE\u4E66 App Secret',
|
|
9300
|
-
feishuDomain: '\u98DE\u4E66 Domain',
|
|
9301
|
-
feishuAllowedUsers: '\u98DE\u4E66 Allowed Users',
|
|
9302
|
-
feishuStreamingEnabled: '\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247',
|
|
9303
|
-
feishuCommandMarkdownEnabled: '\u98DE\u4E66\u53CD\u9988markdown',
|
|
9304
|
-
weixinMediaEnabled: '\u5FAE\u4FE1\u56FE\u7247/\u6587\u4EF6/\u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D',
|
|
9305
|
-
weixinCommandMarkdownEnabled: '\u5FAE\u4FE1\u53CD\u9988markdown',
|
|
9306
9772
|
};
|
|
9307
9773
|
|
|
9308
9774
|
const BRIDGE_RESTART_FIELDS = new Set([
|
|
9309
9775
|
'runtime',
|
|
9310
9776
|
'codexSkipGitRepoCheck',
|
|
9311
9777
|
'autoApprove',
|
|
9312
|
-
'feishuAppId',
|
|
9313
|
-
'feishuAppSecret',
|
|
9314
|
-
'feishuDomain',
|
|
9315
9778
|
]);
|
|
9316
9779
|
|
|
9317
|
-
const AUTO_SYNC_FIELDS = new Set([
|
|
9318
|
-
'enabledChannels',
|
|
9319
|
-
]);
|
|
9780
|
+
const AUTO_SYNC_FIELDS = new Set([]);
|
|
9320
9781
|
|
|
9321
9782
|
const IMMEDIATE_FIELDS = new Set([
|
|
9322
9783
|
'defaultWorkspaceRoot',
|
|
@@ -9327,29 +9788,12 @@ function renderHtml() {
|
|
|
9327
9788
|
'codexReasoningEffort',
|
|
9328
9789
|
'uiAllowLan',
|
|
9329
9790
|
'uiAccessToken',
|
|
9330
|
-
'feishuAllowedUsers',
|
|
9331
|
-
'feishuStreamingEnabled',
|
|
9332
|
-
'feishuCommandMarkdownEnabled',
|
|
9333
|
-
'weixinMediaEnabled',
|
|
9334
|
-
'weixinCommandMarkdownEnabled',
|
|
9335
9791
|
]);
|
|
9336
9792
|
|
|
9337
9793
|
const SAVE_SCOPE_FIELDS = {
|
|
9338
9794
|
all: null,
|
|
9339
|
-
feishu: new Set([
|
|
9340
|
-
|
|
9341
|
-
'feishuAppId',
|
|
9342
|
-
'feishuAppSecret',
|
|
9343
|
-
'feishuDomain',
|
|
9344
|
-
'feishuAllowedUsers',
|
|
9345
|
-
'feishuStreamingEnabled',
|
|
9346
|
-
'feishuCommandMarkdownEnabled',
|
|
9347
|
-
]),
|
|
9348
|
-
weixin: new Set([
|
|
9349
|
-
'enabledChannels',
|
|
9350
|
-
'weixinMediaEnabled',
|
|
9351
|
-
'weixinCommandMarkdownEnabled',
|
|
9352
|
-
]),
|
|
9795
|
+
feishu: new Set([]),
|
|
9796
|
+
weixin: new Set([]),
|
|
9353
9797
|
};
|
|
9354
9798
|
|
|
9355
9799
|
function normalizeConfigValue(value) {
|
|
@@ -9412,63 +9856,40 @@ function renderHtml() {
|
|
|
9412
9856
|
return '\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002' + (notes.length > 0 ? ' ' + notes.join('\uFF1B') + '\u3002' : '');
|
|
9413
9857
|
}
|
|
9414
9858
|
|
|
9415
|
-
function
|
|
9416
|
-
|
|
9859
|
+
function channelDisplayLabel(channel) {
|
|
9860
|
+
const alias = String(channel.alias || '').trim();
|
|
9861
|
+
const provider = providerLabel(channel.provider);
|
|
9862
|
+
if (!alias) return provider;
|
|
9863
|
+
return alias === provider ? alias : alias + ' \xB7 ' + provider;
|
|
9417
9864
|
}
|
|
9418
9865
|
|
|
9419
|
-
function
|
|
9420
|
-
const label =
|
|
9421
|
-
if (
|
|
9422
|
-
return label + '\
|
|
9866
|
+
function formatChannelRuntimeLabel(channel) {
|
|
9867
|
+
const label = channelDisplayLabel(channel);
|
|
9868
|
+
if (channel.enabled === false) {
|
|
9869
|
+
return label + '\u5DF2\u505C\u7528\u3002';
|
|
9423
9870
|
}
|
|
9424
9871
|
if (!state.bridgeStatus || !state.bridgeStatus.running) {
|
|
9425
|
-
return label + '\u5DF2\
|
|
9872
|
+
return label + '\u5DF2\u914D\u7F6E\uFF0C\u4F46 Bridge \u8FD8\u6CA1\u542F\u52A8\u3002';
|
|
9426
9873
|
}
|
|
9427
|
-
|
|
9428
|
-
|
|
9874
|
+
const status = getAdapterStatus(channel.id);
|
|
9875
|
+
if (!status || !status.running) {
|
|
9876
|
+
return label + '\u5DF2\u4FDD\u5B58\uFF0CBridge \u4F1A\u5728\u51E0\u79D2\u5185\u81EA\u52A8\u540C\u6B65\u3002';
|
|
9429
9877
|
}
|
|
9430
9878
|
return label + '\u5DF2\u63A5\u901A\u5230\u5F53\u524D\u8FD0\u884C\u4E2D\u7684 Bridge\u3002';
|
|
9431
9879
|
}
|
|
9432
9880
|
|
|
9433
|
-
function emptyBindingText(
|
|
9434
|
-
const label =
|
|
9435
|
-
if (
|
|
9436
|
-
return label + '\
|
|
9437
|
-
}
|
|
9438
|
-
if (!state.bridgeStatus || !state.bridgeStatus.running) {
|
|
9439
|
-
return label + '\u5DF2\u542F\u7528\uFF0C\u4F46 Bridge \u8FD8\u6CA1\u542F\u52A8\u3002\u542F\u52A8\u540E\u624D\u4F1A\u521B\u5EFA\u7ED1\u5B9A\u3002';
|
|
9440
|
-
}
|
|
9441
|
-
if (!isChannelRunning(channelType)) {
|
|
9442
|
-
return label + '\u5DF2\u542F\u7528\uFF0CBridge \u4F1A\u5728\u51E0\u79D2\u5185\u81EA\u52A8\u540C\u6B65\u8FD9\u4E2A\u901A\u9053\uFF1B\u5982\u679C\u9875\u9762\u8FD8\u6CA1\u66F4\u65B0\uFF0C\u53EF\u624B\u52A8\u70B9\u201C\u5237\u65B0\u72B6\u6001\u201D\u3002';
|
|
9443
|
-
}
|
|
9444
|
-
return label + '\u5F53\u524D\u8FD8\u6CA1\u6709\u804A\u5929\u63A5\u5165\u3002\u5148\u4ECE' + label + '\u53D1\u4E00\u6761\u6D88\u606F\uFF0Cbridge \u624D\u4F1A\u521B\u5EFA\u7ED1\u5B9A\u3002';
|
|
9445
|
-
}
|
|
9446
|
-
|
|
9447
|
-
function quickSwitchState(channelType) {
|
|
9448
|
-
const label = channelLabel(channelType);
|
|
9449
|
-
if (!isChannelEnabled(channelType)) {
|
|
9450
|
-
return { disabled: true, title: label + '\u672A\u542F\u7528\u3002' };
|
|
9881
|
+
function emptyBindingText(channel) {
|
|
9882
|
+
const label = channelDisplayLabel(channel);
|
|
9883
|
+
if (channel.enabled === false) {
|
|
9884
|
+
return label + '\u5DF2\u505C\u7528\u3002\u542F\u7528\u540E\u624D\u4F1A\u521B\u5EFA\u804A\u5929\u7ED1\u5B9A\u3002';
|
|
9451
9885
|
}
|
|
9452
9886
|
if (!state.bridgeStatus || !state.bridgeStatus.running) {
|
|
9453
|
-
return
|
|
9887
|
+
return label + '\u5DF2\u914D\u7F6E\uFF0C\u4F46 Bridge \u8FD8\u6CA1\u542F\u52A8\u3002\u542F\u52A8\u540E\u624D\u4F1A\u521B\u5EFA\u7ED1\u5B9A\u3002';
|
|
9454
9888
|
}
|
|
9455
|
-
if (!isChannelRunning(
|
|
9456
|
-
return
|
|
9889
|
+
if (!isChannelRunning(channel.id)) {
|
|
9890
|
+
return label + '\u5DF2\u914D\u7F6E\uFF0CBridge \u4F1A\u5728\u51E0\u79D2\u5185\u81EA\u52A8\u540C\u6B65\uFF1B\u5982\u679C\u9875\u9762\u8FD8\u6CA1\u66F4\u65B0\uFF0C\u53EF\u624B\u52A8\u70B9\u201C\u5237\u65B0\u72B6\u6001\u201D\u3002';
|
|
9457
9891
|
}
|
|
9458
|
-
|
|
9459
|
-
const bindings = state.bindings.filter((item) => item.channelType === channelType);
|
|
9460
|
-
if (bindings.length === 0) {
|
|
9461
|
-
return { disabled: true, title: '\u5F53\u524D\u8FD8\u6CA1\u6709' + label + '\u804A\u5929\u7ED1\u5B9A\u3002\u5148\u8BA9' + label + '\u53D1\u6765\u4E00\u6761\u6D88\u606F\u3002' };
|
|
9462
|
-
}
|
|
9463
|
-
if (bindings.length > 1) {
|
|
9464
|
-
return { disabled: true, title: label + '\u6709\u591A\u4E2A\u7ED1\u5B9A\uFF0C\u8BF7\u5230\u901A\u9053\u9875\u5207\u6362\u3002' };
|
|
9465
|
-
}
|
|
9466
|
-
|
|
9467
|
-
return {
|
|
9468
|
-
disabled: false,
|
|
9469
|
-
title: '\u5207\u6362' + label + '\u5230\u5F53\u524D\u4F1A\u8BDD',
|
|
9470
|
-
bindingId: bindings[0].id,
|
|
9471
|
-
};
|
|
9892
|
+
return label + '\u5F53\u524D\u8FD8\u6CA1\u6709\u804A\u5929\u63A5\u5165\u3002\u5148\u4ECE\u8FD9\u4E2A\u673A\u5668\u4EBA\u53D1\u4E00\u6761\u6D88\u606F\u3002';
|
|
9472
9893
|
}
|
|
9473
9894
|
|
|
9474
9895
|
function currentThreadMarks(threadId) {
|
|
@@ -9479,11 +9900,11 @@ function renderHtml() {
|
|
|
9479
9900
|
for (const binding of state.bindings || []) {
|
|
9480
9901
|
const matchesThread = binding.currentThreadId === threadId || binding.currentTargetKey === currentTargetKey;
|
|
9481
9902
|
if (!matchesThread) continue;
|
|
9482
|
-
|
|
9903
|
+
const label = (binding.channelAlias || providerLabel(binding.channelProvider)) + ' \u5F53\u524D';
|
|
9904
|
+
counts.set(label, (counts.get(label) || 0) + 1);
|
|
9483
9905
|
}
|
|
9484
9906
|
|
|
9485
|
-
for (const [
|
|
9486
|
-
const label = channelType === 'weixin' ? '\u5FAE\u4FE1\u5F53\u524D' : '\u98DE\u4E66\u5F53\u524D';
|
|
9907
|
+
for (const [label, count] of counts.entries()) {
|
|
9487
9908
|
marks.push(count > 1 ? label + ' x' + count : label);
|
|
9488
9909
|
}
|
|
9489
9910
|
|
|
@@ -9505,7 +9926,10 @@ function renderHtml() {
|
|
|
9505
9926
|
}
|
|
9506
9927
|
|
|
9507
9928
|
function formatBindingAccount(binding) {
|
|
9508
|
-
|
|
9929
|
+
const alias = String(binding.channelAlias || '').trim();
|
|
9930
|
+
const provider = providerLabel(binding.channelProvider);
|
|
9931
|
+
const channel = alias ? (alias === provider ? alias : alias + ' \xB7 ' + provider) : provider;
|
|
9932
|
+
return channel + ' \xB7 ' + (binding.chatDisplayName || binding.chatId);
|
|
9509
9933
|
}
|
|
9510
9934
|
|
|
9511
9935
|
function bindingRuntimeText(binding) {
|
|
@@ -9533,9 +9957,6 @@ function renderHtml() {
|
|
|
9533
9957
|
}
|
|
9534
9958
|
|
|
9535
9959
|
function renderDesktopSessionCard(session) {
|
|
9536
|
-
const feishuSwitch = quickSwitchState('feishu');
|
|
9537
|
-
const weixinSwitch = quickSwitchState('weixin');
|
|
9538
|
-
const targetKey = 'desktop:' + session.threadId;
|
|
9539
9960
|
const originator = session.originator || 'Codex Desktop';
|
|
9540
9961
|
const marks = currentThreadMarks(session.threadId);
|
|
9541
9962
|
const markHtml = marks.map((mark) => '<span class="session-mark">' + escapeHtml(mark) + '</span>').join('');
|
|
@@ -9556,8 +9977,7 @@ function renderHtml() {
|
|
|
9556
9977
|
+ '<div class="session-path">' + escapeHtml(session.cwd || '(no cwd)') + '</div>'
|
|
9557
9978
|
+ '</div>'
|
|
9558
9979
|
+ '<div class="session-actions">'
|
|
9559
|
-
+ '<button type="button" data-action="
|
|
9560
|
-
+ '<button type="button" data-action="bind-channel" data-channel="weixin" data-binding-id="' + escapeHtml(weixinSwitch.bindingId || '') + '" data-target-key="' + escapeHtml(targetKey) + '" title="' + escapeHtml(weixinSwitch.title) + '"' + (weixinSwitch.disabled ? ' disabled' : '') + '>\u5FAE\u4FE1\u5207\u5230\u6B64\u4F1A\u8BDD</button>'
|
|
9980
|
+
+ '<button type="button" data-action="copy-thread" data-thread-id="' + escapeHtml(session.threadId) + '">\u590D\u5236 thread</button>'
|
|
9561
9981
|
+ '<button type="button" data-action="copy-bind-command" data-thread-id="' + escapeHtml(session.threadId) + '">\u590D\u5236\u547D\u4EE4</button>'
|
|
9562
9982
|
+ '</div>'
|
|
9563
9983
|
+ '</div>'
|
|
@@ -9642,14 +10062,14 @@ function renderHtml() {
|
|
|
9642
10062
|
allMeta.textContent = '\u6309\u6700\u8FD1\u6D3B\u52A8\u6392\u5E8F\uFF0C\u5171 ' + sessions.length + ' \u6761\u3002';
|
|
9643
10063
|
|
|
9644
10064
|
if (boundSessions.length === 0) {
|
|
9645
|
-
boundList.innerHTML = '<div class="binding-empty">\u5F53\u524D\u6CA1\u6709\u4EFB\u4F55\u684C\u9762\u4F1A\u8BDD\u6B63\u5728\u7ED1\u5B9A\u5230\
|
|
10065
|
+
boundList.innerHTML = '<div class="binding-empty">\u5F53\u524D\u6CA1\u6709\u4EFB\u4F55\u684C\u9762\u4F1A\u8BDD\u6B63\u5728\u7ED1\u5B9A\u5230\u804A\u5929\u5165\u53E3\u3002</div>';
|
|
9646
10066
|
} else {
|
|
9647
10067
|
boundList.innerHTML = boundSessions.map((session) => renderBoundDesktopSessionCard(session)).join('');
|
|
9648
10068
|
}
|
|
9649
10069
|
|
|
9650
10070
|
if (state.desktopSessions.length === 0) {
|
|
9651
10071
|
list.innerHTML = '<div class="notice ghost">\u5F53\u524D\u6CA1\u6709\u53D1\u73B0\u684C\u9762\u7AEF\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u6216\u8FD0\u884C\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u5230\u8FD9\u91CC\u5237\u65B0\u3002</div>';
|
|
9652
|
-
|
|
10072
|
+
renderChannelsWorkspace();
|
|
9653
10073
|
return;
|
|
9654
10074
|
}
|
|
9655
10075
|
|
|
@@ -9657,7 +10077,7 @@ function renderHtml() {
|
|
|
9657
10077
|
+ sessions.map((session) => renderDesktopSessionListItem(session)).join('')
|
|
9658
10078
|
+ '</div>';
|
|
9659
10079
|
|
|
9660
|
-
|
|
10080
|
+
renderChannelsWorkspace();
|
|
9661
10081
|
}
|
|
9662
10082
|
|
|
9663
10083
|
function rerenderDesktopSessions() {
|
|
@@ -9668,42 +10088,91 @@ function renderHtml() {
|
|
|
9668
10088
|
});
|
|
9669
10089
|
}
|
|
9670
10090
|
|
|
9671
|
-
function
|
|
9672
|
-
|
|
9673
|
-
'feishu',
|
|
9674
|
-
'feishuBindings',
|
|
9675
|
-
'feishuBindingMeta',
|
|
9676
|
-
emptyBindingText('feishu')
|
|
9677
|
-
);
|
|
9678
|
-
renderChannelBindings(
|
|
9679
|
-
'weixin',
|
|
9680
|
-
'weixinBindings',
|
|
9681
|
-
'weixinBindingMeta',
|
|
9682
|
-
emptyBindingText('weixin')
|
|
9683
|
-
);
|
|
10091
|
+
function bindingsForChannel(channelId) {
|
|
10092
|
+
return (state.bindings || []).filter((item) => item.channelType === channelId);
|
|
9684
10093
|
}
|
|
9685
10094
|
|
|
9686
|
-
function
|
|
9687
|
-
const
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
10095
|
+
function ensureActiveBinding(channelId, bindings) {
|
|
10096
|
+
const current = state.activeBindingByChannelId[channelId];
|
|
10097
|
+
if (current && bindings.some((binding) => binding.id === current)) {
|
|
10098
|
+
return current;
|
|
10099
|
+
}
|
|
10100
|
+
const next = bindings[0] ? bindings[0].id : '';
|
|
10101
|
+
state.activeBindingByChannelId[channelId] = next;
|
|
10102
|
+
return next;
|
|
10103
|
+
}
|
|
9693
10104
|
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
10105
|
+
function ensureActiveChannelId() {
|
|
10106
|
+
if (state.channelDraft && state.activeChannelId === state.channelDraft.id) {
|
|
10107
|
+
return state.activeChannelId;
|
|
10108
|
+
}
|
|
10109
|
+
const channels = visibleChannels();
|
|
10110
|
+
if (state.activeChannelId && channels.some((channel) => channel.id === state.activeChannelId)) {
|
|
10111
|
+
return state.activeChannelId;
|
|
10112
|
+
}
|
|
10113
|
+
state.activeChannelId = channels[0] ? channels[0].id : '';
|
|
10114
|
+
return state.activeChannelId;
|
|
10115
|
+
}
|
|
10116
|
+
|
|
10117
|
+
function getWeixinAccountOptions() {
|
|
10118
|
+
return Array.isArray(state.weixinAccounts) ? state.weixinAccounts : [];
|
|
10119
|
+
}
|
|
10120
|
+
|
|
10121
|
+
function renderChannelList() {
|
|
10122
|
+
const list = document.getElementById('channelList');
|
|
10123
|
+
const meta = document.getElementById('channelListMeta');
|
|
10124
|
+
const channels = visibleChannels();
|
|
10125
|
+
|
|
10126
|
+
meta.textContent = channels.length > 0
|
|
10127
|
+
? '\u5171 ' + channels.length + ' \u4E2A\u901A\u9053\u5B9E\u4F8B\u3002\u6BCF\u4E2A\u5B9E\u4F8B\u662F\u4E00\u4E2A\u72EC\u7ACB\u804A\u5929\u5165\u53E3\u3002'
|
|
10128
|
+
: '\u5F53\u524D\u8FD8\u6CA1\u6709\u901A\u9053\u5B9E\u4F8B\u3002\u5148\u65B0\u589E\u4E00\u4E2A\u98DE\u4E66\u6216\u5FAE\u4FE1\u673A\u5668\u4EBA\u3002';
|
|
10129
|
+
|
|
10130
|
+
if (channels.length === 0) {
|
|
10131
|
+
list.innerHTML = '<div class="binding-empty">\u5F53\u524D\u8FD8\u6CA1\u6709\u53EF\u7528\u901A\u9053\u5B9E\u4F8B\u3002</div>';
|
|
9697
10132
|
return;
|
|
9698
10133
|
}
|
|
9699
10134
|
|
|
9700
|
-
|
|
10135
|
+
ensureActiveChannelId();
|
|
10136
|
+
list.innerHTML = channels.map((channel) => {
|
|
10137
|
+
const adapter = getAdapterStatus(channel.id);
|
|
10138
|
+
const active = channel.id === state.activeChannelId;
|
|
10139
|
+
const bindingCount = bindingsForChannel(channel.id).length;
|
|
10140
|
+
const statusText = channel.enabled === false
|
|
10141
|
+
? '\u5DF2\u505C\u7528'
|
|
10142
|
+
: adapter && adapter.running
|
|
10143
|
+
? '\u8FD0\u884C\u4E2D'
|
|
10144
|
+
: state.bridgeStatus && state.bridgeStatus.running
|
|
10145
|
+
? '\u7B49\u5F85\u540C\u6B65'
|
|
10146
|
+
: 'Bridge \u672A\u542F\u52A8';
|
|
10147
|
+
return ''
|
|
10148
|
+
+ '<button type="button" class="channel-list-item' + (active ? ' active' : '') + '" data-action="select-channel" data-channel-id="' + escapeHtml(channel.id) + '">'
|
|
10149
|
+
+ '<div class="channel-list-item-head">'
|
|
10150
|
+
+ '<div class="channel-list-item-title">' + escapeHtml(channel.alias) + '</div>'
|
|
10151
|
+
+ '<span class="channel-list-item-provider">' + escapeHtml(providerLabel(channel.provider)) + '</span>'
|
|
10152
|
+
+ '</div>'
|
|
10153
|
+
+ '<div class="channel-list-item-stats">'
|
|
10154
|
+
+ '<span class="channel-list-item-status">' + escapeHtml(statusText) + '</span>'
|
|
10155
|
+
+ '<span>' + escapeHtml(bindingCount === 0 ? '\u672A\u7ED1\u5B9A\u804A\u5929' : ('\u5DF2\u7ED1\u5B9A ' + bindingCount + ' \u4E2A\u804A\u5929')) + '</span>'
|
|
10156
|
+
+ '</div>'
|
|
10157
|
+
+ '<div class="channel-list-item-meta">' + escapeHtml(channel.id) + '</div>'
|
|
10158
|
+
+ '</button>';
|
|
10159
|
+
}).join('');
|
|
10160
|
+
}
|
|
10161
|
+
|
|
10162
|
+
function renderChannelBindingsV2(channel) {
|
|
10163
|
+
const bindings = bindingsForChannel(channel.id);
|
|
10164
|
+
const emptyText = emptyBindingText(channel);
|
|
10165
|
+
if (bindings.length === 0) {
|
|
10166
|
+
return '<div class="binding-empty">' + escapeHtml(emptyText) + '</div>';
|
|
10167
|
+
}
|
|
10168
|
+
|
|
10169
|
+
const activeBindingId = ensureActiveBinding(channel.id, bindings);
|
|
9701
10170
|
const activeBinding = bindings.find((binding) => binding.id === activeBindingId) || bindings[0];
|
|
9702
10171
|
const tabs = bindings.length > 1
|
|
9703
10172
|
? '<div class="binding-tabs">' + bindings.map((binding) => (
|
|
9704
10173
|
'<button type="button" class="binding-tab' + (binding.id === activeBinding.id ? ' active' : '') + '"'
|
|
9705
10174
|
+ ' data-action="select-binding-tab"'
|
|
9706
|
-
+ ' data-channel="' + escapeHtml(
|
|
10175
|
+
+ ' data-channel-id="' + escapeHtml(channel.id) + '"'
|
|
9707
10176
|
+ ' data-binding-id="' + escapeHtml(binding.id) + '"'
|
|
9708
10177
|
+ ' title="' + escapeHtml(binding.chatId) + '">'
|
|
9709
10178
|
+ escapeHtml(bindingTabLabel(binding))
|
|
@@ -9711,51 +10180,129 @@ function renderHtml() {
|
|
|
9711
10180
|
)).join('') + '</div>'
|
|
9712
10181
|
: '';
|
|
9713
10182
|
|
|
9714
|
-
|
|
10183
|
+
return ''
|
|
10184
|
+
+ '<div class="small">\u5F53\u524D\u5DF2\u53D1\u73B0 ' + bindings.length + ' \u4E2A\u804A\u5929\u7ED1\u5B9A\u3002\u4E00\u4E2A\u4F1A\u8BDD\u540C\u4E00\u65F6\u523B\u53EA\u80FD\u7ED1\u5B9A\u4E00\u4E2A\u804A\u5929\u3002</div>'
|
|
10185
|
+
+ tabs
|
|
10186
|
+
+ renderBindingCard(activeBinding);
|
|
9715
10187
|
}
|
|
9716
10188
|
|
|
9717
|
-
function
|
|
9718
|
-
const
|
|
9719
|
-
const
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
if (accounts.length === 0) {
|
|
9723
|
-
meta.textContent = '\u5F53\u524D\u8FD8\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u5FAE\u4FE1\u8D26\u53F7\u3002\u5148\u70B9\u51FB\u201C\u5F00\u59CB\u5FAE\u4FE1\u626B\u7801\u201D\uFF0C\u7136\u540E\u5728\u624B\u673A\u4E0A\u786E\u8BA4\u3002';
|
|
9724
|
-
list.innerHTML = '<div class="binding-empty">\u626B\u7801\u6210\u529F\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u5F53\u524D\u5DF2\u4FDD\u5B58\u7684\u5FAE\u4FE1\u8D26\u53F7\u3002</div>';
|
|
10189
|
+
function renderChannelEditor() {
|
|
10190
|
+
const editor = document.getElementById('channelEditor');
|
|
10191
|
+
const channel = getChannelById(ensureActiveChannelId());
|
|
10192
|
+
if (!channel) {
|
|
10193
|
+
editor.innerHTML = '<div class="binding-empty">\u8BF7\u9009\u62E9\u4E00\u4E2A\u901A\u9053\u5B9E\u4F8B\uFF0C\u6216\u5148\u521B\u5EFA\u65B0\u901A\u9053\u3002</div>';
|
|
9725
10194
|
return;
|
|
9726
10195
|
}
|
|
9727
10196
|
|
|
9728
|
-
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
+ '</article>'
|
|
10197
|
+
const adapter = getAdapterStatus(channel.id);
|
|
10198
|
+
const statusText = formatChannelRuntimeLabel(channel);
|
|
10199
|
+
const feishu = channel.provider === 'feishu' ? (channel.config || {}) : {};
|
|
10200
|
+
const weixin = channel.provider === 'weixin' ? (channel.config || {}) : {};
|
|
10201
|
+
const weixinAccounts = getWeixinAccountOptions();
|
|
10202
|
+
const weixinAccountOptions = ['<option value="">\u672A\u7ED1\u5B9A\u8D26\u53F7</option>'].concat(
|
|
10203
|
+
weixinAccounts.map((account) => (
|
|
10204
|
+
'<option value="' + escapeHtml(account.accountId) + '"' + (account.accountId === weixin.accountId ? ' selected' : '') + '>'
|
|
10205
|
+
+ escapeHtml(account.name || account.accountId)
|
|
10206
|
+
+ '</option>'
|
|
10207
|
+
)),
|
|
9740
10208
|
).join('');
|
|
10209
|
+
const bindingsHtml = renderChannelBindingsV2(channel);
|
|
10210
|
+
const bindingCount = bindingsForChannel(channel.id).length;
|
|
10211
|
+
const detailsHtml = channel.provider === 'feishu'
|
|
10212
|
+
? ''
|
|
10213
|
+
+ '<div class="editor-section">'
|
|
10214
|
+
+ '<p class="editor-section-title">\u8FDE\u63A5\u914D\u7F6E</p>'
|
|
10215
|
+
+ '<div class="field-row">'
|
|
10216
|
+
+ '<label>App ID<input id="channelAppId" value="' + escapeHtml(feishu.appId || '') + '" /></label>'
|
|
10217
|
+
+ '<label>App Secret<input id="channelAppSecret" value="' + escapeHtml(feishu.appSecret || '') + '" /></label>'
|
|
10218
|
+
+ '</div>'
|
|
10219
|
+
+ '<div class="field-row">'
|
|
10220
|
+
+ '<label>\u7AD9\u70B9<select id="channelSite">'
|
|
10221
|
+
+ '<option value="feishu"' + ((feishu.site || 'feishu') === 'feishu' ? ' selected' : '') + '>Feishu</option>'
|
|
10222
|
+
+ '<option value="lark"' + (feishu.site === 'lark' ? ' selected' : '') + '>Lark</option>'
|
|
10223
|
+
+ '</select></label>'
|
|
10224
|
+
+ '<label>Allowed Users<input id="channelAllowedUsers" value="' + escapeHtml(Array.isArray(feishu.allowedUsers) ? feishu.allowedUsers.join(', ') : '') + '" placeholder="\u591A\u4E2A user_id \u7528\u9017\u53F7\u5206\u9694" /></label>'
|
|
10225
|
+
+ '</div>'
|
|
10226
|
+
+ '</div>'
|
|
10227
|
+
+ '<div class="editor-section">'
|
|
10228
|
+
+ '<p class="editor-section-title">\u884C\u4E3A\u5F00\u5173</p>'
|
|
10229
|
+
+ '<div class="checkbox-row">'
|
|
10230
|
+
+ '<label class="checkbox"><input id="channelStreamingEnabled" type="checkbox"' + (feishu.streamingEnabled !== false ? ' checked' : '') + ' /> \u542F\u7528\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247</label>'
|
|
10231
|
+
+ '<label class="checkbox"><input id="channelFeedbackMarkdownEnabled" type="checkbox"' + (feishu.feedbackMarkdownEnabled !== false ? ' checked' : '') + ' /> \u53CD\u9988\u4F7F\u7528markdown</label>'
|
|
10232
|
+
+ '</div>'
|
|
10233
|
+
+ '</div>'
|
|
10234
|
+
: ''
|
|
10235
|
+
+ '<div class="editor-section">'
|
|
10236
|
+
+ '<p class="editor-section-title">\u8FDE\u63A5\u914D\u7F6E</p>'
|
|
10237
|
+
+ '<div class="field-row">'
|
|
10238
|
+
+ '<label>\u5FAE\u4FE1\u8D26\u53F7<select id="channelAccountId">' + weixinAccountOptions + '</select></label>'
|
|
10239
|
+
+ '<label>Base URL<input id="channelBaseUrl" value="' + escapeHtml(weixin.baseUrl || '') + '" /></label>'
|
|
10240
|
+
+ '</div>'
|
|
10241
|
+
+ '<div class="field-row">'
|
|
10242
|
+
+ '<label>CDN Base URL<input id="channelCdnBaseUrl" value="' + escapeHtml(weixin.cdnBaseUrl || '') + '" /></label>'
|
|
10243
|
+
+ '<div></div>'
|
|
10244
|
+
+ '</div>'
|
|
10245
|
+
+ '</div>'
|
|
10246
|
+
+ '<div class="editor-section">'
|
|
10247
|
+
+ '<p class="editor-section-title">\u884C\u4E3A\u5F00\u5173</p>'
|
|
10248
|
+
+ '<div class="checkbox-row">'
|
|
10249
|
+
+ '<label class="checkbox"><input id="channelMediaEnabled" type="checkbox"' + (weixin.mediaEnabled === true ? ' checked' : '') + ' /> \u542F\u7528\u56FE\u7247 / \u6587\u4EF6 / \u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D</label>'
|
|
10250
|
+
+ '<label class="checkbox"><input id="channelFeedbackMarkdownEnabled" type="checkbox"' + (weixin.feedbackMarkdownEnabled === true ? ' checked' : '') + ' /> \u53CD\u9988\u4F7F\u7528markdown</label>'
|
|
10251
|
+
+ '</div>'
|
|
10252
|
+
+ '</div>';
|
|
10253
|
+
|
|
10254
|
+
editor.innerHTML = ''
|
|
10255
|
+
+ '<div class="panel-header">'
|
|
10256
|
+
+ '<div>'
|
|
10257
|
+
+ '<h2>' + escapeHtml(channel.alias) + '</h2>'
|
|
10258
|
+
+ '<p>' + escapeHtml(statusText) + (adapter && adapter.lastMessageAt ? ' \xB7 \u6700\u8FD1\u6D88\u606F ' + escapeHtml(formatTime(adapter.lastMessageAt)) : '') + '</p>'
|
|
10259
|
+
+ '</div>'
|
|
10260
|
+
+ '<div class="toolbar-split">'
|
|
10261
|
+
+ '<div class="toolbar">'
|
|
10262
|
+
+ '<button type="button" data-action="channel-save" data-channel-id="' + escapeHtml(channel.id) + '" class="primary">\u4FDD\u5B58\u901A\u9053</button>'
|
|
10263
|
+
+ '<button type="button" data-action="channel-test" data-channel-id="' + escapeHtml(channel.id) + '">\u6D4B\u8BD5\u5F53\u524D\u901A\u9053</button>'
|
|
10264
|
+
+ (channel.provider === 'weixin' ? '<button type="button" data-action="channel-weixin-login" data-channel-id="' + escapeHtml(channel.id) + '">\u5F00\u59CB\u5FAE\u4FE1\u626B\u7801</button>' : '')
|
|
10265
|
+
+ '</div>'
|
|
10266
|
+
+ '<div class="toolbar-danger">'
|
|
10267
|
+
+ '<button type="button" data-action="channel-delete" data-channel-id="' + escapeHtml(channel.id) + '" class="danger">\u5220\u9664\u901A\u9053</button>'
|
|
10268
|
+
+ '</div>'
|
|
10269
|
+
+ '</div>'
|
|
10270
|
+
+ '</div>'
|
|
10271
|
+
+ '<div class="channel-editor-summary">'
|
|
10272
|
+
+ '<div class="channel-editor-stat"><strong>\u5F53\u524D\u72B6\u6001</strong><span>' + escapeHtml(statusText) + '</span></div>'
|
|
10273
|
+
+ '<div class="channel-editor-stat"><strong>\u804A\u5929\u7ED1\u5B9A</strong><span>' + escapeHtml(String(bindingCount)) + '</span></div>'
|
|
10274
|
+
+ '<div class="channel-editor-stat"><strong>Provider</strong><span>' + escapeHtml(providerLabel(channel.provider)) + '</span></div>'
|
|
10275
|
+
+ '</div>'
|
|
10276
|
+
+ '<div class="fields">'
|
|
10277
|
+
+ '<div class="editor-section">'
|
|
10278
|
+
+ '<p class="editor-section-title">\u57FA\u7840\u4FE1\u606F</p>'
|
|
10279
|
+
+ '<div class="field-row triple">'
|
|
10280
|
+
+ '<label>\u522B\u540D<input id="channelAliasInput" value="' + escapeHtml(channel.alias) + '" /></label>'
|
|
10281
|
+
+ '<label>\u5B9E\u4F8B ID<input value="' + escapeHtml(channel.id) + '" disabled /></label>'
|
|
10282
|
+
+ '<label>Provider<input value="' + escapeHtml(providerLabel(channel.provider)) + '" disabled /></label>'
|
|
10283
|
+
+ '</div>'
|
|
10284
|
+
+ '<div class="checkbox-row">'
|
|
10285
|
+
+ '<label class="checkbox"><input id="channelEnabledInput" type="checkbox"' + (channel.enabled !== false ? ' checked' : '') + ' /> \u542F\u7528\u5F53\u524D\u901A\u9053</label>'
|
|
10286
|
+
+ '</div>'
|
|
10287
|
+
+ '</div>'
|
|
10288
|
+
+ detailsHtml
|
|
10289
|
+
+ '</div>'
|
|
10290
|
+
+ '<div class="panel-block">'
|
|
10291
|
+
+ '<p class="panel-subtitle">\u5F53\u524D\u7ED1\u5B9A</p>'
|
|
10292
|
+
+ bindingsHtml
|
|
10293
|
+
+ '</div>';
|
|
10294
|
+
}
|
|
10295
|
+
|
|
10296
|
+
function renderChannelsWorkspace() {
|
|
10297
|
+
renderChannelList();
|
|
10298
|
+
renderChannelEditor();
|
|
9741
10299
|
}
|
|
9742
10300
|
|
|
9743
10301
|
function renderBindings(result) {
|
|
9744
10302
|
state.bindings = result.bindings || [];
|
|
9745
10303
|
state.bindingOptions = result.options || [];
|
|
9746
10304
|
document.getElementById('bindingCount').textContent = String(state.bindings.length);
|
|
9747
|
-
|
|
9748
|
-
'feishu',
|
|
9749
|
-
'feishuBindings',
|
|
9750
|
-
'feishuBindingMeta',
|
|
9751
|
-
emptyBindingText('feishu')
|
|
9752
|
-
);
|
|
9753
|
-
renderChannelBindings(
|
|
9754
|
-
'weixin',
|
|
9755
|
-
'weixinBindings',
|
|
9756
|
-
'weixinBindingMeta',
|
|
9757
|
-
emptyBindingText('weixin')
|
|
9758
|
-
);
|
|
10305
|
+
renderChannelsWorkspace();
|
|
9759
10306
|
rerenderDesktopSessions();
|
|
9760
10307
|
}
|
|
9761
10308
|
|
|
@@ -9815,18 +10362,10 @@ function renderHtml() {
|
|
|
9815
10362
|
document.getElementById('codexReasoningEffort').value = config.codexReasoningEffort || 'medium';
|
|
9816
10363
|
document.getElementById('uiAllowLan').checked = config.uiAllowLan === true;
|
|
9817
10364
|
document.getElementById('uiAccessToken').value = config.uiAccessToken || '';
|
|
9818
|
-
document.getElementById('channelFeishu').checked = (config.enabledChannels || []).includes('feishu');
|
|
9819
|
-
document.getElementById('channelWeixin').checked = (config.enabledChannels || []).includes('weixin');
|
|
9820
10365
|
document.getElementById('autoApprove').checked = config.autoApprove === true;
|
|
9821
|
-
document.getElementById('feishuAppId').value = config.feishuAppId || '';
|
|
9822
|
-
document.getElementById('feishuAppSecret').value = config.feishuAppSecret || '';
|
|
9823
|
-
document.getElementById('feishuDomain').value = config.feishuDomain || 'https://open.feishu.cn';
|
|
9824
|
-
document.getElementById('feishuAllowedUsers').value = config.feishuAllowedUsers || '';
|
|
9825
|
-
document.getElementById('feishuStreamingEnabled').checked = config.feishuStreamingEnabled !== false;
|
|
9826
|
-
document.getElementById('feishuCommandMarkdownEnabled').checked = config.feishuCommandMarkdownEnabled !== false;
|
|
9827
|
-
document.getElementById('weixinMediaEnabled').checked = config.weixinMediaEnabled === true;
|
|
9828
|
-
document.getElementById('weixinCommandMarkdownEnabled').checked = config.weixinCommandMarkdownEnabled === true;
|
|
9829
10366
|
renderUiAccess();
|
|
10367
|
+
ensureActiveChannelId();
|
|
10368
|
+
renderChannelsWorkspace();
|
|
9830
10369
|
rerenderDesktopSessions();
|
|
9831
10370
|
}
|
|
9832
10371
|
|
|
@@ -9847,24 +10386,68 @@ function renderHtml() {
|
|
|
9847
10386
|
const config = await api('/api/config');
|
|
9848
10387
|
state.uiAccess = status.uiAccess || null;
|
|
9849
10388
|
state.bridgeStatus = status.bridge || null;
|
|
10389
|
+
state.autostartStatus = status.autostart || null;
|
|
9850
10390
|
state.weixinAccounts = status.weixin && Array.isArray(status.weixin.linkedAccounts) ? status.weixin.linkedAccounts : [];
|
|
9851
10391
|
fillForm(config);
|
|
9852
|
-
const runningChannelText =
|
|
10392
|
+
const runningChannelText = adapterStatuses().length
|
|
10393
|
+
? ' \xB7 ' + adapterStatuses().filter((item) => item.running).map((item) => item.channelAlias || item.channelType).join(', ')
|
|
10394
|
+
: '';
|
|
9853
10395
|
document.getElementById('bridgeStatus').textContent = status.bridge.running ? 'Running' + runningChannelText : 'Stopped';
|
|
10396
|
+
renderAutostartStatus(status.autostart || null);
|
|
9854
10397
|
document.getElementById('integrationStatus').textContent = status.codexIntegrationInstalled ? '\u5DF2\u5B89\u88C5' : '\u672A\u5B89\u88C5';
|
|
9855
10398
|
document.getElementById('runtimeStatus').textContent = config.runtime || 'codex';
|
|
9856
10399
|
document.getElementById('homeStatus').textContent = status.home;
|
|
9857
10400
|
document.getElementById('overviewHomeStatus').textContent = status.home;
|
|
9858
10401
|
document.getElementById('packageRoot').textContent = status.packageRoot;
|
|
9859
|
-
document.getElementById('feishuRuntimeMeta').textContent = channelRuntimeText('feishu');
|
|
9860
|
-
document.getElementById('weixinRuntimeMeta').textContent = channelRuntimeText('weixin');
|
|
9861
|
-
renderWeixinAccounts();
|
|
9862
10402
|
renderBindings({
|
|
9863
10403
|
bindings: state.bindings,
|
|
9864
10404
|
options: state.bindingOptions,
|
|
9865
10405
|
});
|
|
9866
10406
|
}
|
|
9867
10407
|
|
|
10408
|
+
function renderAutostartStatus(status) {
|
|
10409
|
+
const valueEl = document.getElementById('autostartStatus');
|
|
10410
|
+
const noticeEl = document.getElementById('autostartNotice');
|
|
10411
|
+
const refreshBtn = document.getElementById('refreshAutostartBtn');
|
|
10412
|
+
|
|
10413
|
+
if (!status || status.supported !== true) {
|
|
10414
|
+
valueEl.textContent = '\u4E0D\u652F\u6301';
|
|
10415
|
+
noticeEl.textContent = status && status.error
|
|
10416
|
+
? status.error
|
|
10417
|
+
: '\u5F53\u524D\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301 Bridge \u5F00\u673A\u81EA\u542F\u52A8\u3002';
|
|
10418
|
+
refreshBtn.disabled = true;
|
|
10419
|
+
return;
|
|
10420
|
+
}
|
|
10421
|
+
|
|
10422
|
+
if (status.error) {
|
|
10423
|
+
valueEl.textContent = '\u914D\u7F6E\u5F02\u5E38';
|
|
10424
|
+
noticeEl.textContent = status.error;
|
|
10425
|
+
refreshBtn.disabled = false;
|
|
10426
|
+
return;
|
|
10427
|
+
}
|
|
10428
|
+
|
|
10429
|
+
if (!status.installed) {
|
|
10430
|
+
valueEl.textContent = '\u672A\u542F\u7528';
|
|
10431
|
+
noticeEl.textContent = [
|
|
10432
|
+
'\u5982\u9700\u542F\u7528\uFF0C\u8BF7\u4EE5\u7BA1\u7406\u5458\u8EAB\u4EFD\u6253\u5F00 PowerShell \u6216\u7EC8\u7AEF\u6267\u884C\uFF1A',
|
|
10433
|
+
'codex-to-im autostart install',
|
|
10434
|
+
status.runAsUser ? '\u8FD0\u884C\u8D26\u53F7\uFF1A' + status.runAsUser : '',
|
|
10435
|
+
'\u5B89\u88C5\u65F6\u4F1A\u8981\u6C42\u8F93\u5165\u5F53\u524D Windows \u767B\u5F55\u5BC6\u7801\u3002',
|
|
10436
|
+
].filter(Boolean).join('\\n');
|
|
10437
|
+
refreshBtn.disabled = false;
|
|
10438
|
+
return;
|
|
10439
|
+
}
|
|
10440
|
+
|
|
10441
|
+
valueEl.textContent = status.enabled ? '\u5DF2\u542F\u7528' : '\u5DF2\u7981\u7528';
|
|
10442
|
+
noticeEl.textContent = [
|
|
10443
|
+
'\u65B9\u5F0F\uFF1AWindows \u4EFB\u52A1\u8BA1\u5212\u7A0B\u5E8F\uFF08\u5F00\u673A\u89E6\u53D1\uFF09',
|
|
10444
|
+
status.runAsUser ? '\u8FD0\u884C\u8D26\u53F7\uFF1A' + status.runAsUser : '',
|
|
10445
|
+
status.state ? '\u4EFB\u52A1\u72B6\u6001\uFF1A' + status.state : '',
|
|
10446
|
+
'\u5982\u9700\u5173\u95ED\uFF0C\u8BF7\u4EE5\u7BA1\u7406\u5458\u8EAB\u4EFD\u6267\u884C\uFF1Acodex-to-im autostart uninstall',
|
|
10447
|
+
].filter(Boolean).join(' \xB7 ');
|
|
10448
|
+
refreshBtn.disabled = false;
|
|
10449
|
+
}
|
|
10450
|
+
|
|
9868
10451
|
async function loadLogs() {
|
|
9869
10452
|
const logs = await api('/api/logs?lines=220');
|
|
9870
10453
|
document.getElementById('logsOutput').textContent = logs.logs || '\u6682\u65E0\u65E5\u5FD7';
|
|
@@ -9898,16 +10481,187 @@ function renderHtml() {
|
|
|
9898
10481
|
return saved;
|
|
9899
10482
|
}
|
|
9900
10483
|
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
10484
|
+
function createChannelDraft(provider) {
|
|
10485
|
+
state.channelDraft = {
|
|
10486
|
+
id: '__draft__:' + provider,
|
|
10487
|
+
alias: providerLabel(provider),
|
|
10488
|
+
provider,
|
|
10489
|
+
enabled: true,
|
|
10490
|
+
createdAt: new Date().toISOString(),
|
|
10491
|
+
updatedAt: new Date().toISOString(),
|
|
10492
|
+
config: provider === 'feishu'
|
|
10493
|
+
? {
|
|
10494
|
+
appId: '',
|
|
10495
|
+
appSecret: '',
|
|
10496
|
+
site: 'feishu',
|
|
10497
|
+
allowedUsers: [],
|
|
10498
|
+
streamingEnabled: true,
|
|
10499
|
+
feedbackMarkdownEnabled: true,
|
|
10500
|
+
}
|
|
10501
|
+
: {
|
|
10502
|
+
accountId: '',
|
|
10503
|
+
baseUrl: '',
|
|
10504
|
+
cdnBaseUrl: '',
|
|
10505
|
+
mediaEnabled: false,
|
|
10506
|
+
feedbackMarkdownEnabled: false,
|
|
10507
|
+
},
|
|
10508
|
+
};
|
|
10509
|
+
state.activeChannelId = state.channelDraft.id;
|
|
10510
|
+
renderChannelsWorkspace();
|
|
10511
|
+
}
|
|
10512
|
+
|
|
10513
|
+
function currentChannelEditorPayload(channel) {
|
|
10514
|
+
const payload = {
|
|
10515
|
+
provider: channel.provider,
|
|
10516
|
+
alias: document.getElementById('channelAliasInput').value,
|
|
10517
|
+
enabled: document.getElementById('channelEnabledInput').checked,
|
|
10518
|
+
};
|
|
10519
|
+
|
|
10520
|
+
if (!String(channel.id || '').startsWith('__draft__:')) {
|
|
10521
|
+
payload.id = channel.id;
|
|
10522
|
+
}
|
|
10523
|
+
|
|
10524
|
+
if (channel.provider === 'feishu') {
|
|
10525
|
+
payload.appId = document.getElementById('channelAppId').value;
|
|
10526
|
+
payload.appSecret = document.getElementById('channelAppSecret').value;
|
|
10527
|
+
payload.site = document.getElementById('channelSite').value;
|
|
10528
|
+
payload.allowedUsers = document.getElementById('channelAllowedUsers').value;
|
|
10529
|
+
payload.streamingEnabled = document.getElementById('channelStreamingEnabled').checked;
|
|
10530
|
+
payload.feedbackMarkdownEnabled = document.getElementById('channelFeedbackMarkdownEnabled').checked;
|
|
10531
|
+
return payload;
|
|
10532
|
+
}
|
|
10533
|
+
|
|
10534
|
+
payload.accountId = document.getElementById('channelAccountId').value;
|
|
10535
|
+
payload.baseUrl = document.getElementById('channelBaseUrl').value;
|
|
10536
|
+
payload.cdnBaseUrl = document.getElementById('channelCdnBaseUrl').value;
|
|
10537
|
+
payload.mediaEnabled = document.getElementById('channelMediaEnabled').checked;
|
|
10538
|
+
payload.feedbackMarkdownEnabled = document.getElementById('channelFeedbackMarkdownEnabled').checked;
|
|
10539
|
+
return payload;
|
|
10540
|
+
}
|
|
10541
|
+
|
|
10542
|
+
async function saveChannel(channel) {
|
|
10543
|
+
const result = await api('/api/channels/save', {
|
|
10544
|
+
method: 'POST',
|
|
10545
|
+
body: JSON.stringify(currentChannelEditorPayload(channel)),
|
|
9904
10546
|
});
|
|
9905
|
-
|
|
10547
|
+
state.channelDraft = null;
|
|
10548
|
+
fillForm(result.config);
|
|
10549
|
+
renderBindings(result);
|
|
10550
|
+
setActiveChannel(result.channel.id, false);
|
|
10551
|
+
return result;
|
|
10552
|
+
}
|
|
10553
|
+
|
|
10554
|
+
async function deleteCurrentChannel(channel) {
|
|
10555
|
+
if (String(channel.id || '').startsWith('__draft__:')) {
|
|
10556
|
+
state.channelDraft = null;
|
|
10557
|
+
state.activeChannelId = '';
|
|
10558
|
+
renderChannelsWorkspace();
|
|
10559
|
+
showMessage('channelMessage', 'success', '\u672A\u4FDD\u5B58\u7684\u65B0\u901A\u9053\u5DF2\u53D6\u6D88\u3002');
|
|
10560
|
+
return;
|
|
10561
|
+
}
|
|
9906
10562
|
|
|
9907
|
-
|
|
10563
|
+
const result = await api('/api/channels/delete', {
|
|
10564
|
+
method: 'POST',
|
|
10565
|
+
body: JSON.stringify({ channelId: channel.id }),
|
|
10566
|
+
});
|
|
10567
|
+
state.channelDraft = null;
|
|
10568
|
+
fillForm(result.config);
|
|
10569
|
+
renderBindings(result);
|
|
10570
|
+
showMessage('channelMessage', 'success', '\u901A\u9053\u5DF2\u5220\u9664\u3002');
|
|
10571
|
+
}
|
|
10572
|
+
|
|
10573
|
+
async function testCurrentChannel(channel) {
|
|
10574
|
+
if (String(channel.id || '').startsWith('__draft__:')) {
|
|
10575
|
+
const saved = await saveChannel(channel);
|
|
10576
|
+
channel = getChannelById(saved.channel.id);
|
|
10577
|
+
} else {
|
|
10578
|
+
await saveChannel(channel);
|
|
10579
|
+
channel = getChannelById(channel.id);
|
|
10580
|
+
}
|
|
10581
|
+
const result = await api('/api/channels/test', {
|
|
10582
|
+
method: 'POST',
|
|
10583
|
+
body: JSON.stringify({ channelId: channel.id }),
|
|
10584
|
+
});
|
|
10585
|
+
showMessage('channelMessage', result.ok ? 'success' : 'error', result.message);
|
|
10586
|
+
}
|
|
10587
|
+
|
|
10588
|
+
async function loginWeixinForChannel(channel) {
|
|
10589
|
+
if (String(channel.id || '').startsWith('__draft__:')) {
|
|
10590
|
+
const saved = await saveChannel(channel);
|
|
10591
|
+
channel = getChannelById(saved.channel.id);
|
|
10592
|
+
} else {
|
|
10593
|
+
await saveChannel(channel);
|
|
10594
|
+
channel = getChannelById(channel.id);
|
|
10595
|
+
}
|
|
10596
|
+
const result = await api('/api/channels/weixin-login', {
|
|
10597
|
+
method: 'POST',
|
|
10598
|
+
body: JSON.stringify({ channelId: channel.id }),
|
|
10599
|
+
});
|
|
10600
|
+
fillForm(result.config || state.config);
|
|
10601
|
+
await loadStatus();
|
|
10602
|
+
showMessage('channelMessage', result.ok ? 'success' : 'error', result.message);
|
|
10603
|
+
}
|
|
10604
|
+
|
|
10605
|
+
async function handleChannelEditorAction(event) {
|
|
10606
|
+
const source = event.target instanceof Element ? event.target : null;
|
|
10607
|
+
const target = source ? source.closest('button[data-action]') : null;
|
|
10608
|
+
if (!target) return;
|
|
10609
|
+
|
|
10610
|
+
const channelId = target.dataset.channelId || state.activeChannelId;
|
|
10611
|
+
const channel = getChannelById(channelId);
|
|
10612
|
+
if (!channel) return;
|
|
10613
|
+
|
|
10614
|
+
try {
|
|
10615
|
+
if (target.dataset.action === 'channel-save') {
|
|
10616
|
+
await saveChannel(channel);
|
|
10617
|
+
showMessage('channelMessage', 'success', '\u901A\u9053\u5DF2\u4FDD\u5B58\u3002');
|
|
10618
|
+
return;
|
|
10619
|
+
}
|
|
10620
|
+
if (target.dataset.action === 'channel-test') {
|
|
10621
|
+
await testCurrentChannel(channel);
|
|
10622
|
+
return;
|
|
10623
|
+
}
|
|
10624
|
+
if (target.dataset.action === 'channel-delete') {
|
|
10625
|
+
await deleteCurrentChannel(channel);
|
|
10626
|
+
return;
|
|
10627
|
+
}
|
|
10628
|
+
if (target.dataset.action === 'channel-weixin-login') {
|
|
10629
|
+
await loginWeixinForChannel(channel);
|
|
10630
|
+
return;
|
|
10631
|
+
}
|
|
10632
|
+
if (target.dataset.action === 'select-binding-tab') {
|
|
10633
|
+
state.activeBindingByChannelId[channel.id] = target.dataset.bindingId || '';
|
|
10634
|
+
renderChannelsWorkspace();
|
|
10635
|
+
return;
|
|
10636
|
+
}
|
|
10637
|
+
if (target.dataset.action === 'unbind-binding') {
|
|
10638
|
+
const result = await api('/api/bindings/delete', {
|
|
10639
|
+
method: 'POST',
|
|
10640
|
+
body: JSON.stringify({ bindingId: target.dataset.bindingId }),
|
|
10641
|
+
});
|
|
10642
|
+
renderBindings(result);
|
|
10643
|
+
showMessage('channelMessage', 'success', '\u804A\u5929\u7ED1\u5B9A\u5DF2\u89E3\u7ED1\u3002');
|
|
10644
|
+
return;
|
|
10645
|
+
}
|
|
10646
|
+
if (target.dataset.action === 'switch-binding-target') {
|
|
10647
|
+
const result = await api('/api/bindings/update', {
|
|
10648
|
+
method: 'POST',
|
|
10649
|
+
body: JSON.stringify({
|
|
10650
|
+
bindingId: target.dataset.bindingId,
|
|
10651
|
+
targetKey: target.dataset.targetKey,
|
|
10652
|
+
}),
|
|
10653
|
+
});
|
|
10654
|
+
renderBindings(result);
|
|
10655
|
+
showMessage('channelMessage', 'success', '\u804A\u5929\u7ED1\u5B9A\u5DF2\u66F4\u65B0\u3002');
|
|
10656
|
+
}
|
|
10657
|
+
} catch (error) {
|
|
10658
|
+
showMessage('channelMessage', 'error', error.message);
|
|
10659
|
+
}
|
|
10660
|
+
}
|
|
10661
|
+
|
|
10662
|
+
document.querySelectorAll('.nav-link').forEach((element) => {
|
|
9908
10663
|
element.addEventListener('click', () => {
|
|
9909
|
-
setActivePage('
|
|
9910
|
-
setActiveChannel(element.dataset.channel || 'feishu', true);
|
|
10664
|
+
setActivePage(element.dataset.page || 'overview', true);
|
|
9911
10665
|
});
|
|
9912
10666
|
});
|
|
9913
10667
|
|
|
@@ -9955,76 +10709,6 @@ function renderHtml() {
|
|
|
9955
10709
|
}
|
|
9956
10710
|
});
|
|
9957
10711
|
|
|
9958
|
-
document.getElementById('saveFeishuChannelBtn').addEventListener('click', async () => {
|
|
9959
|
-
try {
|
|
9960
|
-
await saveConfig({ messageId: 'feishuMessage', scope: 'feishu' });
|
|
9961
|
-
await loadStatus();
|
|
9962
|
-
await loadBindings();
|
|
9963
|
-
} catch (error) {
|
|
9964
|
-
showMessage('feishuMessage', 'error', error.message);
|
|
9965
|
-
}
|
|
9966
|
-
});
|
|
9967
|
-
|
|
9968
|
-
document.getElementById('testFeishuBtn').addEventListener('click', async () => {
|
|
9969
|
-
try {
|
|
9970
|
-
await saveConfig();
|
|
9971
|
-
await loadStatus();
|
|
9972
|
-
await loadBindings();
|
|
9973
|
-
const result = await api('/api/test/feishu', { method: 'POST' });
|
|
9974
|
-
showMessage('feishuMessage', result.ok ? 'success' : 'error', result.message);
|
|
9975
|
-
} catch (error) {
|
|
9976
|
-
showMessage('feishuMessage', 'error', error.message);
|
|
9977
|
-
}
|
|
9978
|
-
});
|
|
9979
|
-
|
|
9980
|
-
document.getElementById('refreshFeishuStateBtn').addEventListener('click', async () => {
|
|
9981
|
-
try {
|
|
9982
|
-
await loadStatus();
|
|
9983
|
-
await loadBindings();
|
|
9984
|
-
await loadDesktopSessions();
|
|
9985
|
-
showMessage('feishuMessage', 'success', '\u98DE\u4E66\u901A\u9053\u72B6\u6001\u5DF2\u5237\u65B0\u3002');
|
|
9986
|
-
} catch (error) {
|
|
9987
|
-
showMessage('feishuMessage', 'error', error.message);
|
|
9988
|
-
}
|
|
9989
|
-
});
|
|
9990
|
-
|
|
9991
|
-
document.getElementById('saveWeixinChannelBtn').addEventListener('click', async () => {
|
|
9992
|
-
try {
|
|
9993
|
-
await saveConfig({ messageId: 'weixinMessage', scope: 'weixin' });
|
|
9994
|
-
await loadStatus();
|
|
9995
|
-
await loadBindings();
|
|
9996
|
-
} catch (error) {
|
|
9997
|
-
showMessage('weixinMessage', 'error', error.message);
|
|
9998
|
-
}
|
|
9999
|
-
});
|
|
10000
|
-
|
|
10001
|
-
document.getElementById('refreshWeixinStateBtn').addEventListener('click', async () => {
|
|
10002
|
-
try {
|
|
10003
|
-
await loadStatus();
|
|
10004
|
-
await loadBindings();
|
|
10005
|
-
await loadDesktopSessions();
|
|
10006
|
-
showMessage('weixinMessage', 'success', '\u5FAE\u4FE1\u901A\u9053\u72B6\u6001\u5DF2\u5237\u65B0\u3002');
|
|
10007
|
-
} catch (error) {
|
|
10008
|
-
showMessage('weixinMessage', 'error', error.message);
|
|
10009
|
-
}
|
|
10010
|
-
});
|
|
10011
|
-
|
|
10012
|
-
document.getElementById('weixinLoginBtn').addEventListener('click', async () => {
|
|
10013
|
-
try {
|
|
10014
|
-
await saveConfig();
|
|
10015
|
-
showMessage('weixinMessage', 'success', '\u5FAE\u4FE1\u626B\u7801\u6D41\u7A0B\u5DF2\u542F\u52A8\uFF0C\u6D4F\u89C8\u5668\u4F1A\u6253\u5F00\u4E8C\u7EF4\u7801\u9875\u9762\u3002');
|
|
10016
|
-
const result = await api('/api/test/weixin', { method: 'POST' });
|
|
10017
|
-
await loadStatus();
|
|
10018
|
-
await loadBindings();
|
|
10019
|
-
const followup = isChannelRunning('weixin')
|
|
10020
|
-
? '\u5FAE\u4FE1\u8D26\u53F7\u5DF2\u4FDD\u5B58\u3002\u5F53\u524D Bridge \u5DF2\u52A0\u8F7D\u5FAE\u4FE1\u901A\u9053\uFF0C\u51E0\u79D2\u540E\u4F1A\u81EA\u52A8\u63A5\u5165\u65B0\u8D26\u53F7\u3002'
|
|
10021
|
-
: '\u5FAE\u4FE1\u8D26\u53F7\u5DF2\u4FDD\u5B58\u3002Bridge \u4F1A\u5728\u51E0\u79D2\u5185\u81EA\u52A8\u540C\u6B65\u5FAE\u4FE1\u901A\u9053\uFF1B\u5982\u679C\u9875\u9762\u8FD8\u6CA1\u66F4\u65B0\uFF0C\u53EF\u624B\u52A8\u70B9\u201C\u5237\u65B0\u72B6\u6001\u201D\u3002';
|
|
10022
|
-
showMessage('weixinMessage', result.ok ? 'success' : 'error', followup);
|
|
10023
|
-
} catch (error) {
|
|
10024
|
-
showMessage('weixinMessage', 'error', error.message);
|
|
10025
|
-
}
|
|
10026
|
-
});
|
|
10027
|
-
|
|
10028
10712
|
document.getElementById('startBridgeBtn').addEventListener('click', async () => {
|
|
10029
10713
|
try {
|
|
10030
10714
|
await saveConfig();
|
|
@@ -10086,6 +10770,15 @@ function renderHtml() {
|
|
|
10086
10770
|
}
|
|
10087
10771
|
});
|
|
10088
10772
|
|
|
10773
|
+
document.getElementById('refreshAutostartBtn').addEventListener('click', async () => {
|
|
10774
|
+
try {
|
|
10775
|
+
await loadStatus();
|
|
10776
|
+
showMessage('opsMessage', 'success', '\u5F00\u673A\u81EA\u542F\u52A8\u72B6\u6001\u5DF2\u5237\u65B0\u3002');
|
|
10777
|
+
} catch (error) {
|
|
10778
|
+
showMessage('opsMessage', 'error', error.message);
|
|
10779
|
+
}
|
|
10780
|
+
});
|
|
10781
|
+
|
|
10089
10782
|
document.getElementById('installIntegrationBtn').addEventListener('click', async () => {
|
|
10090
10783
|
try {
|
|
10091
10784
|
const result = await api('/api/install-codex-integration', { method: 'POST' });
|
|
@@ -10113,6 +10806,35 @@ function renderHtml() {
|
|
|
10113
10806
|
}
|
|
10114
10807
|
});
|
|
10115
10808
|
|
|
10809
|
+
document.getElementById('createChannelBtn').addEventListener('click', () => {
|
|
10810
|
+
const provider = document.getElementById('newChannelProvider').value === 'weixin' ? 'weixin' : 'feishu';
|
|
10811
|
+
createChannelDraft(provider);
|
|
10812
|
+
setActivePage('channels', false);
|
|
10813
|
+
setActiveChannel(state.activeChannelId, true);
|
|
10814
|
+
});
|
|
10815
|
+
|
|
10816
|
+
document.getElementById('refreshChannelsBtn').addEventListener('click', async () => {
|
|
10817
|
+
try {
|
|
10818
|
+
await loadStatus();
|
|
10819
|
+
await loadBindings();
|
|
10820
|
+
showMessage('channelMessage', 'success', '\u901A\u9053\u72B6\u6001\u5DF2\u5237\u65B0\u3002');
|
|
10821
|
+
} catch (error) {
|
|
10822
|
+
showMessage('channelMessage', 'error', error.message);
|
|
10823
|
+
}
|
|
10824
|
+
});
|
|
10825
|
+
|
|
10826
|
+
document.getElementById('channelList').addEventListener('click', (event) => {
|
|
10827
|
+
const source = event.target instanceof Element ? event.target : null;
|
|
10828
|
+
const target = source ? source.closest('button[data-channel-id]') : null;
|
|
10829
|
+
if (!target) return;
|
|
10830
|
+
setActivePage('channels', false);
|
|
10831
|
+
setActiveChannel(target.dataset.channelId || '', true);
|
|
10832
|
+
});
|
|
10833
|
+
|
|
10834
|
+
document.getElementById('channelEditor').addEventListener('click', (event) => {
|
|
10835
|
+
handleChannelEditorAction(event);
|
|
10836
|
+
});
|
|
10837
|
+
|
|
10116
10838
|
async function handleSessionListAction(event) {
|
|
10117
10839
|
const source = event.target instanceof Element ? event.target : null;
|
|
10118
10840
|
const target = source ? source.closest('button[data-action]') : null;
|
|
@@ -10139,59 +10861,20 @@ function renderHtml() {
|
|
|
10139
10861
|
if (!target) return;
|
|
10140
10862
|
|
|
10141
10863
|
if (target.dataset.action === 'unbind-binding') {
|
|
10142
|
-
|
|
10143
|
-
await handleBindingAction(event, channelType, 'desktopMessage');
|
|
10144
|
-
return;
|
|
10145
|
-
}
|
|
10146
|
-
|
|
10147
|
-
await handleSessionListAction(event);
|
|
10148
|
-
});
|
|
10149
|
-
|
|
10150
|
-
async function handleBindingAction(event, channelType, messageId) {
|
|
10151
|
-
const source = event.target instanceof Element ? event.target : null;
|
|
10152
|
-
const target = source ? source.closest('button[data-action]') : null;
|
|
10153
|
-
if (!target) return;
|
|
10154
|
-
|
|
10155
|
-
try {
|
|
10156
|
-
if (target.dataset.action === 'select-binding-tab') {
|
|
10157
|
-
state.activeBindingByChannel[channelType] = target.dataset.bindingId || '';
|
|
10158
|
-
rerenderBindingPanels();
|
|
10159
|
-
return;
|
|
10160
|
-
}
|
|
10161
|
-
if (target.dataset.action === 'unbind-binding') {
|
|
10864
|
+
try {
|
|
10162
10865
|
const result = await api('/api/bindings/delete', {
|
|
10163
10866
|
method: 'POST',
|
|
10164
|
-
body: JSON.stringify({
|
|
10165
|
-
bindingId: target.dataset.bindingId,
|
|
10166
|
-
}),
|
|
10867
|
+
body: JSON.stringify({ bindingId: target.dataset.bindingId }),
|
|
10167
10868
|
});
|
|
10168
10869
|
renderBindings(result);
|
|
10169
|
-
showMessage(
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
if (target.dataset.action !== 'switch-binding-target') {
|
|
10173
|
-
return;
|
|
10870
|
+
showMessage('desktopMessage', 'success', '\u804A\u5929\u7ED1\u5B9A\u5DF2\u89E3\u7ED1\u3002');
|
|
10871
|
+
} catch (error) {
|
|
10872
|
+
showMessage('desktopMessage', 'error', error.message);
|
|
10174
10873
|
}
|
|
10175
|
-
|
|
10176
|
-
method: 'POST',
|
|
10177
|
-
body: JSON.stringify({
|
|
10178
|
-
bindingId: target.dataset.bindingId,
|
|
10179
|
-
targetKey: target.dataset.targetKey,
|
|
10180
|
-
}),
|
|
10181
|
-
});
|
|
10182
|
-
renderBindings(result);
|
|
10183
|
-
showMessage(messageId, 'success', channelType === 'feishu' ? '\u98DE\u4E66\u7ED1\u5B9A\u5DF2\u66F4\u65B0\u3002' : '\u5FAE\u4FE1\u7ED1\u5B9A\u5DF2\u66F4\u65B0\u3002');
|
|
10184
|
-
} catch (error) {
|
|
10185
|
-
showMessage(messageId, 'error', error.message);
|
|
10874
|
+
return;
|
|
10186
10875
|
}
|
|
10187
|
-
}
|
|
10188
10876
|
|
|
10189
|
-
|
|
10190
|
-
handleBindingAction(event, 'feishu', 'feishuMessage');
|
|
10191
|
-
});
|
|
10192
|
-
|
|
10193
|
-
document.getElementById('weixinBindings').addEventListener('click', (event) => {
|
|
10194
|
-
handleBindingAction(event, 'weixin', 'weixinMessage');
|
|
10877
|
+
await handleSessionListAction(event);
|
|
10195
10878
|
});
|
|
10196
10879
|
|
|
10197
10880
|
syncPageFromHash();
|
|
@@ -10287,6 +10970,7 @@ var server = http.createServer(async (request, response) => {
|
|
|
10287
10970
|
if (request.method === "GET" && url.pathname === "/api/status") {
|
|
10288
10971
|
json(response, 200, {
|
|
10289
10972
|
bridge: getBridgeStatus(),
|
|
10973
|
+
autostart: await getBridgeAutostartStatus(),
|
|
10290
10974
|
ui: getUiServerStatus(),
|
|
10291
10975
|
uiAccess: buildUiAccessInfo(port, config, request),
|
|
10292
10976
|
home: CTI_HOME,
|
|
@@ -10324,17 +11008,93 @@ var server = http.createServer(async (request, response) => {
|
|
|
10324
11008
|
json(response, 200, { ok: true, config: configToPayload(loadConfig()) });
|
|
10325
11009
|
return;
|
|
10326
11010
|
}
|
|
10327
|
-
if (request.method === "POST" && url.pathname === "/api/
|
|
10328
|
-
const
|
|
10329
|
-
|
|
11011
|
+
if (request.method === "POST" && url.pathname === "/api/channels/save") {
|
|
11012
|
+
const payload = await readJsonBody(request);
|
|
11013
|
+
const current = loadConfig();
|
|
11014
|
+
const merged = mergeChannelInstance(payload, current);
|
|
11015
|
+
saveConfig(merged.config);
|
|
11016
|
+
const store = createUiStore();
|
|
11017
|
+
syncBindingChannelMeta(store, merged.channel);
|
|
11018
|
+
json(response, 200, {
|
|
11019
|
+
ok: true,
|
|
11020
|
+
channel: channelToPayload(merged.channel),
|
|
11021
|
+
config: configToPayload(loadConfig()),
|
|
11022
|
+
...await buildBindingsPayload(store, loadConfig())
|
|
11023
|
+
});
|
|
11024
|
+
return;
|
|
11025
|
+
}
|
|
11026
|
+
if (request.method === "POST" && url.pathname === "/api/channels/delete") {
|
|
11027
|
+
const payload = await readJsonBody(request);
|
|
11028
|
+
const channelId = asString(payload.channelId);
|
|
11029
|
+
if (!channelId) {
|
|
11030
|
+
json(response, 400, { error: "channelId \u4E0D\u80FD\u4E3A\u7A7A\u3002" });
|
|
11031
|
+
return;
|
|
11032
|
+
}
|
|
11033
|
+
const store = createUiStore();
|
|
11034
|
+
const bindings = store.listChannelBindings(channelId);
|
|
11035
|
+
if (bindings.length > 0) {
|
|
11036
|
+
json(response, 400, { error: "\u8BE5\u901A\u9053\u4ECD\u6709\u804A\u5929\u7ED1\u5B9A\uFF0C\u8BF7\u5148\u89E3\u7ED1\u540E\u518D\u5220\u9664\u3002" });
|
|
11037
|
+
return;
|
|
11038
|
+
}
|
|
11039
|
+
const next = deleteChannelInstance(loadConfig(), channelId);
|
|
11040
|
+
saveConfig(next);
|
|
11041
|
+
json(response, 200, {
|
|
11042
|
+
ok: true,
|
|
11043
|
+
config: configToPayload(loadConfig()),
|
|
11044
|
+
...await buildBindingsPayload(store, loadConfig())
|
|
11045
|
+
});
|
|
10330
11046
|
return;
|
|
10331
11047
|
}
|
|
10332
|
-
if (request.method === "POST" && url.pathname === "/api/test
|
|
10333
|
-
const
|
|
11048
|
+
if (request.method === "POST" && url.pathname === "/api/channels/test") {
|
|
11049
|
+
const payload = await readJsonBody(request);
|
|
11050
|
+
const channelId = asString(payload.channelId);
|
|
11051
|
+
if (!channelId) {
|
|
11052
|
+
json(response, 400, { error: "channelId \u4E0D\u80FD\u4E3A\u7A7A\u3002" });
|
|
11053
|
+
return;
|
|
11054
|
+
}
|
|
11055
|
+
const channel = findChannelInstance(channelId, loadConfig());
|
|
11056
|
+
if (!channel) {
|
|
11057
|
+
json(response, 404, { error: "\u6307\u5B9A\u7684\u901A\u9053\u4E0D\u5B58\u5728\u3002" });
|
|
11058
|
+
return;
|
|
11059
|
+
}
|
|
11060
|
+
if (channel.provider === "feishu") {
|
|
11061
|
+
json(response, 200, await validateFeishuCredentials(channel));
|
|
11062
|
+
return;
|
|
11063
|
+
}
|
|
11064
|
+
json(response, 200, {
|
|
11065
|
+
ok: true,
|
|
11066
|
+
message: "\u5FAE\u4FE1\u901A\u9053\u8BF7\u4F7F\u7528\u201C\u5F00\u59CB\u5FAE\u4FE1\u626B\u7801\u201D\u5E76\u9009\u62E9\u767B\u5F55\u8D26\u53F7\u8FDB\u884C\u9A8C\u8BC1\u3002"
|
|
11067
|
+
});
|
|
11068
|
+
return;
|
|
11069
|
+
}
|
|
11070
|
+
if (request.method === "POST" && url.pathname === "/api/channels/weixin-login") {
|
|
11071
|
+
const payload = await readJsonBody(request);
|
|
11072
|
+
const channelId = asString(payload.channelId);
|
|
11073
|
+
const current = loadConfig();
|
|
11074
|
+
const channel = channelId ? findChannelInstance(channelId, current) : void 0;
|
|
11075
|
+
const loginConfig = channel?.provider === "weixin" ? channel.config : {};
|
|
11076
|
+
const result = await runWeixinLogin(loginConfig);
|
|
11077
|
+
if (channelId) {
|
|
11078
|
+
if (channel && channel.provider === "weixin") {
|
|
11079
|
+
const merged = mergeChannelInstance({
|
|
11080
|
+
id: channel.id,
|
|
11081
|
+
provider: channel.provider,
|
|
11082
|
+
alias: channel.alias,
|
|
11083
|
+
enabled: channel.enabled,
|
|
11084
|
+
accountId: result.accountId,
|
|
11085
|
+
baseUrl: channel.config.baseUrl,
|
|
11086
|
+
cdnBaseUrl: channel.config.cdnBaseUrl,
|
|
11087
|
+
mediaEnabled: channel.config.mediaEnabled === true,
|
|
11088
|
+
feedbackMarkdownEnabled: channel.config.feedbackMarkdownEnabled === true
|
|
11089
|
+
}, current);
|
|
11090
|
+
saveConfig(merged.config);
|
|
11091
|
+
}
|
|
11092
|
+
}
|
|
10334
11093
|
json(response, 200, {
|
|
10335
11094
|
ok: true,
|
|
10336
11095
|
message: `\u5FAE\u4FE1\u626B\u7801\u6210\u529F\uFF0C\u8D26\u53F7 ${result.accountId} \u5DF2\u4FDD\u5B58\u3002`,
|
|
10337
|
-
htmlPath: result.htmlPath
|
|
11096
|
+
htmlPath: result.htmlPath,
|
|
11097
|
+
config: configToPayload(loadConfig())
|
|
10338
11098
|
});
|
|
10339
11099
|
return;
|
|
10340
11100
|
}
|