codex-to-im 0.1.2 → 0.1.6
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 +51 -4
- package/README_CN.md +49 -3
- package/config.env.example +36 -12
- package/dist/cli.mjs +9 -4
- package/dist/daemon.mjs +1766 -356
- package/dist/ui-server.mjs +1046 -110
- package/docs/install-windows.md +44 -6
- package/package.json +2 -1
- package/scripts/patch-codex-sdk-windows-hide.js +83 -0
package/dist/ui-server.mjs
CHANGED
|
@@ -4566,7 +4566,9 @@ var require_lib = __commonJS({
|
|
|
4566
4566
|
|
|
4567
4567
|
// src/ui-server.ts
|
|
4568
4568
|
import http from "node:http";
|
|
4569
|
+
import crypto4 from "node:crypto";
|
|
4569
4570
|
import net from "node:net";
|
|
4571
|
+
import os5 from "node:os";
|
|
4570
4572
|
|
|
4571
4573
|
// src/config.ts
|
|
4572
4574
|
import fs from "node:fs";
|
|
@@ -4574,6 +4576,7 @@ import os from "node:os";
|
|
|
4574
4576
|
import path from "node:path";
|
|
4575
4577
|
var LEGACY_CTI_HOME = path.join(os.homedir(), ".claude-to-im");
|
|
4576
4578
|
var DEFAULT_CTI_HOME = path.join(os.homedir(), ".codex-to-im");
|
|
4579
|
+
var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
|
|
4577
4580
|
function resolveDefaultCtiHome() {
|
|
4578
4581
|
if (fs.existsSync(DEFAULT_CTI_HOME)) return DEFAULT_CTI_HOME;
|
|
4579
4582
|
if (fs.existsSync(LEGACY_CTI_HOME)) return LEGACY_CTI_HOME;
|
|
@@ -4581,6 +4584,14 @@ function resolveDefaultCtiHome() {
|
|
|
4581
4584
|
}
|
|
4582
4585
|
var CTI_HOME = process.env.CTI_HOME || resolveDefaultCtiHome();
|
|
4583
4586
|
var CONFIG_PATH = path.join(CTI_HOME, "config.env");
|
|
4587
|
+
function expandHomePath(value) {
|
|
4588
|
+
if (!value) return value;
|
|
4589
|
+
if (value === "~") return os.homedir();
|
|
4590
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
4591
|
+
return path.join(os.homedir(), value.slice(2));
|
|
4592
|
+
}
|
|
4593
|
+
return value;
|
|
4594
|
+
}
|
|
4584
4595
|
function parseEnvFile(content) {
|
|
4585
4596
|
const entries = /* @__PURE__ */ new Map();
|
|
4586
4597
|
for (const line of content.split("\n")) {
|
|
@@ -4614,6 +4625,18 @@ function parsePositiveInt(value) {
|
|
|
4614
4625
|
if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
|
|
4615
4626
|
return Math.floor(parsed);
|
|
4616
4627
|
}
|
|
4628
|
+
function parseSandboxMode(value) {
|
|
4629
|
+
if (value === "read-only" || value === "workspace-write" || value === "danger-full-access") {
|
|
4630
|
+
return value;
|
|
4631
|
+
}
|
|
4632
|
+
return void 0;
|
|
4633
|
+
}
|
|
4634
|
+
function parseReasoningEffort(value) {
|
|
4635
|
+
if (value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh") {
|
|
4636
|
+
return value;
|
|
4637
|
+
}
|
|
4638
|
+
return void 0;
|
|
4639
|
+
}
|
|
4617
4640
|
function loadConfig() {
|
|
4618
4641
|
const env = loadRawConfigEnv();
|
|
4619
4642
|
const rawRuntime = env.get("CTI_RUNTIME") || "codex";
|
|
@@ -4621,11 +4644,16 @@ function loadConfig() {
|
|
|
4621
4644
|
return {
|
|
4622
4645
|
runtime,
|
|
4623
4646
|
enabledChannels: splitCsv(env.get("CTI_ENABLED_CHANNELS")) ?? ["feishu"],
|
|
4624
|
-
defaultWorkDir: env.get("CTI_DEFAULT_WORKDIR") || process.cwd(),
|
|
4647
|
+
defaultWorkDir: expandHomePath(env.get("CTI_DEFAULT_WORKDIR")) || process.cwd(),
|
|
4648
|
+
defaultWorkspaceRoot: expandHomePath(env.get("CTI_DEFAULT_WORKSPACE_ROOT")) || DEFAULT_WORKSPACE_ROOT,
|
|
4625
4649
|
defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
|
|
4626
4650
|
defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
|
|
4627
4651
|
historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
|
|
4628
4652
|
codexSkipGitRepoCheck: env.has("CTI_CODEX_SKIP_GIT_REPO_CHECK") ? env.get("CTI_CODEX_SKIP_GIT_REPO_CHECK") === "true" : true,
|
|
4653
|
+
codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
|
|
4654
|
+
codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
|
|
4655
|
+
uiAllowLan: env.get("CTI_UI_ALLOW_LAN") === "true",
|
|
4656
|
+
uiAccessToken: env.get("CTI_UI_ACCESS_TOKEN") || void 0,
|
|
4629
4657
|
tgBotToken: env.get("CTI_TG_BOT_TOKEN") || void 0,
|
|
4630
4658
|
tgChatId: env.get("CTI_TG_CHAT_ID") || void 0,
|
|
4631
4659
|
tgAllowedUsers: splitCsv(env.get("CTI_TG_ALLOWED_USERS")),
|
|
@@ -4634,6 +4662,7 @@ function loadConfig() {
|
|
|
4634
4662
|
feishuDomain: env.get("CTI_FEISHU_DOMAIN") || void 0,
|
|
4635
4663
|
feishuAllowedUsers: splitCsv(env.get("CTI_FEISHU_ALLOWED_USERS")),
|
|
4636
4664
|
feishuStreamingEnabled: env.has("CTI_FEISHU_STREAMING_ENABLED") ? env.get("CTI_FEISHU_STREAMING_ENABLED") === "true" : true,
|
|
4665
|
+
feishuCommandMarkdownEnabled: env.has("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED") ? env.get("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED") === "true" : true,
|
|
4637
4666
|
discordBotToken: env.get("CTI_DISCORD_BOT_TOKEN") || void 0,
|
|
4638
4667
|
discordAllowedUsers: splitCsv(env.get("CTI_DISCORD_ALLOWED_USERS")),
|
|
4639
4668
|
discordAllowedChannels: splitCsv(
|
|
@@ -4648,6 +4677,7 @@ function loadConfig() {
|
|
|
4648
4677
|
weixinBaseUrl: env.get("CTI_WEIXIN_BASE_URL") || void 0,
|
|
4649
4678
|
weixinCdnBaseUrl: env.get("CTI_WEIXIN_CDN_BASE_URL") || void 0,
|
|
4650
4679
|
weixinMediaEnabled: env.has("CTI_WEIXIN_MEDIA_ENABLED") ? env.get("CTI_WEIXIN_MEDIA_ENABLED") === "true" : void 0,
|
|
4680
|
+
weixinCommandMarkdownEnabled: env.has("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED") ? env.get("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED") === "true" : false,
|
|
4651
4681
|
autoApprove: env.get("CTI_AUTO_APPROVE") === "true"
|
|
4652
4682
|
};
|
|
4653
4683
|
}
|
|
@@ -4664,12 +4694,17 @@ function saveConfig(config) {
|
|
|
4664
4694
|
config.enabledChannels.join(",")
|
|
4665
4695
|
);
|
|
4666
4696
|
out += formatEnvLine("CTI_DEFAULT_WORKDIR", config.defaultWorkDir);
|
|
4697
|
+
out += formatEnvLine("CTI_DEFAULT_WORKSPACE_ROOT", config.defaultWorkspaceRoot);
|
|
4667
4698
|
if (config.defaultModel) out += formatEnvLine("CTI_DEFAULT_MODEL", config.defaultModel);
|
|
4668
4699
|
out += formatEnvLine("CTI_DEFAULT_MODE", config.defaultMode);
|
|
4669
4700
|
if (config.historyMessageLimit !== void 0)
|
|
4670
4701
|
out += formatEnvLine("CTI_HISTORY_MESSAGE_LIMIT", String(config.historyMessageLimit));
|
|
4671
4702
|
if (config.codexSkipGitRepoCheck !== void 0)
|
|
4672
4703
|
out += formatEnvLine("CTI_CODEX_SKIP_GIT_REPO_CHECK", String(config.codexSkipGitRepoCheck));
|
|
4704
|
+
out += formatEnvLine("CTI_CODEX_SANDBOX_MODE", config.codexSandboxMode);
|
|
4705
|
+
out += formatEnvLine("CTI_CODEX_REASONING_EFFORT", config.codexReasoningEffort);
|
|
4706
|
+
out += formatEnvLine("CTI_UI_ALLOW_LAN", String(config.uiAllowLan === true));
|
|
4707
|
+
out += formatEnvLine("CTI_UI_ACCESS_TOKEN", config.uiAccessToken);
|
|
4673
4708
|
out += formatEnvLine("CTI_TG_BOT_TOKEN", config.tgBotToken);
|
|
4674
4709
|
out += formatEnvLine("CTI_TG_CHAT_ID", config.tgChatId);
|
|
4675
4710
|
out += formatEnvLine(
|
|
@@ -4688,6 +4723,11 @@ function saveConfig(config) {
|
|
|
4688
4723
|
"CTI_FEISHU_STREAMING_ENABLED",
|
|
4689
4724
|
String(config.feishuStreamingEnabled)
|
|
4690
4725
|
);
|
|
4726
|
+
if (config.feishuCommandMarkdownEnabled !== void 0)
|
|
4727
|
+
out += formatEnvLine(
|
|
4728
|
+
"CTI_FEISHU_COMMAND_MARKDOWN_ENABLED",
|
|
4729
|
+
String(config.feishuCommandMarkdownEnabled)
|
|
4730
|
+
);
|
|
4691
4731
|
out += formatEnvLine("CTI_DISCORD_BOT_TOKEN", config.discordBotToken);
|
|
4692
4732
|
out += formatEnvLine(
|
|
4693
4733
|
"CTI_DISCORD_ALLOWED_USERS",
|
|
@@ -4715,6 +4755,12 @@ function saveConfig(config) {
|
|
|
4715
4755
|
out += formatEnvLine("CTI_WEIXIN_CDN_BASE_URL", config.weixinCdnBaseUrl);
|
|
4716
4756
|
if (config.weixinMediaEnabled !== void 0)
|
|
4717
4757
|
out += formatEnvLine("CTI_WEIXIN_MEDIA_ENABLED", String(config.weixinMediaEnabled));
|
|
4758
|
+
if (config.weixinCommandMarkdownEnabled !== void 0)
|
|
4759
|
+
out += formatEnvLine(
|
|
4760
|
+
"CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED",
|
|
4761
|
+
String(config.weixinCommandMarkdownEnabled)
|
|
4762
|
+
);
|
|
4763
|
+
out += formatEnvLine("CTI_AUTO_APPROVE", String(config.autoApprove === true));
|
|
4718
4764
|
fs.mkdirSync(CTI_HOME, { recursive: true });
|
|
4719
4765
|
const tmpPath = CONFIG_PATH + ".tmp";
|
|
4720
4766
|
fs.writeFileSync(tmpPath, out, { mode: 384 });
|
|
@@ -4763,6 +4809,10 @@ function configToSettings(config) {
|
|
|
4763
4809
|
"bridge_feishu_streaming_enabled",
|
|
4764
4810
|
config.feishuStreamingEnabled === false ? "false" : "true"
|
|
4765
4811
|
);
|
|
4812
|
+
m.set(
|
|
4813
|
+
"bridge_feishu_command_markdown_enabled",
|
|
4814
|
+
config.feishuCommandMarkdownEnabled === false ? "false" : "true"
|
|
4815
|
+
);
|
|
4766
4816
|
m.set(
|
|
4767
4817
|
"bridge_qq_enabled",
|
|
4768
4818
|
config.enabledChannels.includes("qq") ? "true" : "false"
|
|
@@ -4781,11 +4831,18 @@ function configToSettings(config) {
|
|
|
4781
4831
|
);
|
|
4782
4832
|
if (config.weixinMediaEnabled !== void 0)
|
|
4783
4833
|
m.set("bridge_weixin_media_enabled", String(config.weixinMediaEnabled));
|
|
4834
|
+
m.set(
|
|
4835
|
+
"bridge_weixin_command_markdown_enabled",
|
|
4836
|
+
config.weixinCommandMarkdownEnabled === true ? "true" : "false"
|
|
4837
|
+
);
|
|
4784
4838
|
if (config.weixinBaseUrl)
|
|
4785
4839
|
m.set("bridge_weixin_base_url", config.weixinBaseUrl);
|
|
4786
4840
|
if (config.weixinCdnBaseUrl)
|
|
4787
4841
|
m.set("bridge_weixin_cdn_base_url", config.weixinCdnBaseUrl);
|
|
4788
4842
|
m.set("bridge_default_work_dir", config.defaultWorkDir);
|
|
4843
|
+
if (config.defaultWorkspaceRoot) {
|
|
4844
|
+
m.set("bridge_default_workspace_root", config.defaultWorkspaceRoot);
|
|
4845
|
+
}
|
|
4789
4846
|
if (config.defaultModel) {
|
|
4790
4847
|
m.set("bridge_default_model", config.defaultModel);
|
|
4791
4848
|
m.set("default_model", config.defaultModel);
|
|
@@ -4799,6 +4856,14 @@ function configToSettings(config) {
|
|
|
4799
4856
|
"bridge_codex_skip_git_repo_check",
|
|
4800
4857
|
config.codexSkipGitRepoCheck === true ? "true" : "false"
|
|
4801
4858
|
);
|
|
4859
|
+
m.set(
|
|
4860
|
+
"bridge_codex_sandbox_mode",
|
|
4861
|
+
config.codexSandboxMode || "workspace-write"
|
|
4862
|
+
);
|
|
4863
|
+
m.set(
|
|
4864
|
+
"bridge_codex_reasoning_effort",
|
|
4865
|
+
config.codexReasoningEffort || "medium"
|
|
4866
|
+
);
|
|
4802
4867
|
return m;
|
|
4803
4868
|
}
|
|
4804
4869
|
|
|
@@ -4862,6 +4927,8 @@ var MIME_EXT = {
|
|
|
4862
4927
|
};
|
|
4863
4928
|
function toApprovalPolicy(permissionMode) {
|
|
4864
4929
|
switch (permissionMode) {
|
|
4930
|
+
case "never":
|
|
4931
|
+
return "never";
|
|
4865
4932
|
case "acceptEdits":
|
|
4866
4933
|
return "on-failure";
|
|
4867
4934
|
case "plan":
|
|
@@ -4878,6 +4945,18 @@ function shouldPassModelToCodex() {
|
|
|
4878
4945
|
function shouldSkipGitRepoCheck() {
|
|
4879
4946
|
return process.env.CTI_CODEX_SKIP_GIT_REPO_CHECK === "true";
|
|
4880
4947
|
}
|
|
4948
|
+
function normalizeSandboxMode(mode) {
|
|
4949
|
+
if (mode === "read-only" || mode === "workspace-write" || mode === "danger-full-access") {
|
|
4950
|
+
return mode;
|
|
4951
|
+
}
|
|
4952
|
+
return "workspace-write";
|
|
4953
|
+
}
|
|
4954
|
+
function normalizeReasoningEffort(value) {
|
|
4955
|
+
if (value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh") {
|
|
4956
|
+
return value;
|
|
4957
|
+
}
|
|
4958
|
+
return void 0;
|
|
4959
|
+
}
|
|
4881
4960
|
function shouldRetryFreshThread(message) {
|
|
4882
4961
|
const lower = message.toLowerCase();
|
|
4883
4962
|
return lower.includes("resuming session with different model") || lower.includes("no such session") || lower.includes("resume") && lower.includes("session");
|
|
@@ -4925,10 +5004,14 @@ var CodexProvider = class {
|
|
|
4925
5004
|
let savedThreadId = inMemoryThreadId || params.sdkSessionId || void 0;
|
|
4926
5005
|
const approvalPolicy = toApprovalPolicy(params.permissionMode);
|
|
4927
5006
|
const passModel = shouldPassModelToCodex();
|
|
5007
|
+
const sandboxMode = normalizeSandboxMode(params.sandboxMode);
|
|
5008
|
+
const modelReasoningEffort = normalizeReasoningEffort(params.modelReasoningEffort);
|
|
4928
5009
|
const threadOptions = {
|
|
4929
5010
|
...passModel && params.model ? { model: params.model } : {},
|
|
4930
5011
|
...params.workingDirectory ? { workingDirectory: params.workingDirectory } : {},
|
|
4931
5012
|
...shouldSkipGitRepoCheck() ? { skipGitRepoCheck: true } : {},
|
|
5013
|
+
sandboxMode,
|
|
5014
|
+
...modelReasoningEffort ? { modelReasoningEffort } : {},
|
|
4932
5015
|
approvalPolicy
|
|
4933
5016
|
};
|
|
4934
5017
|
const imageFiles = params.files?.filter(
|
|
@@ -5130,8 +5213,10 @@ var CodexProvider = class {
|
|
|
5130
5213
|
import fs3 from "node:fs";
|
|
5131
5214
|
import os3 from "node:os";
|
|
5132
5215
|
import path3 from "node:path";
|
|
5216
|
+
import crypto from "node:crypto";
|
|
5133
5217
|
var ACTIVE_WINDOW_MS = 15 * 60 * 1e3;
|
|
5134
5218
|
var MAX_SESSION_META_BYTES = 4 * 1024 * 1024;
|
|
5219
|
+
var MAX_SESSION_TITLE_SCAN_BYTES = 512 * 1024;
|
|
5135
5220
|
var TITLE_MAX_CHARS = 72;
|
|
5136
5221
|
function getCodexHome() {
|
|
5137
5222
|
return process.env.CODEX_HOME || path3.join(os3.homedir(), ".codex");
|
|
@@ -5189,6 +5274,24 @@ function readFirstLine(filePath, maxBytes = MAX_SESSION_META_BYTES) {
|
|
|
5189
5274
|
fs3.closeSync(fd);
|
|
5190
5275
|
}
|
|
5191
5276
|
}
|
|
5277
|
+
function readFilePrefix(filePath, maxBytes = MAX_SESSION_TITLE_SCAN_BYTES) {
|
|
5278
|
+
const fd = fs3.openSync(filePath, "r");
|
|
5279
|
+
try {
|
|
5280
|
+
const buffer = Buffer.alloc(Math.min(maxBytes, 64 * 1024));
|
|
5281
|
+
const chunks = [];
|
|
5282
|
+
let offset = 0;
|
|
5283
|
+
while (offset < maxBytes) {
|
|
5284
|
+
const bytesToRead = Math.min(buffer.length, maxBytes - offset);
|
|
5285
|
+
const bytesRead = fs3.readSync(fd, buffer, 0, bytesToRead, offset);
|
|
5286
|
+
if (bytesRead <= 0) break;
|
|
5287
|
+
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
5288
|
+
offset += bytesRead;
|
|
5289
|
+
}
|
|
5290
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
5291
|
+
} finally {
|
|
5292
|
+
fs3.closeSync(fd);
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5192
5295
|
function walkSessionFiles(dirPath, target) {
|
|
5193
5296
|
let entries;
|
|
5194
5297
|
try {
|
|
@@ -5210,6 +5313,7 @@ function walkSessionFiles(dirPath, target) {
|
|
|
5210
5313
|
function isDesktopLike(meta) {
|
|
5211
5314
|
const originator = meta?.originator?.toLowerCase() || "";
|
|
5212
5315
|
const source = meta?.source?.toLowerCase() || "";
|
|
5316
|
+
if (source === "exec") return false;
|
|
5213
5317
|
return originator.includes("desktop") || source === "vscode" || source === "desktop";
|
|
5214
5318
|
}
|
|
5215
5319
|
function loadThreadNameIndex(archivedThreadIds) {
|
|
@@ -5241,6 +5345,27 @@ function loadThreadNameIndex(archivedThreadIds) {
|
|
|
5241
5345
|
}
|
|
5242
5346
|
return new Map(Array.from(titles.entries()).map(([threadId, entry]) => [threadId, entry.title]));
|
|
5243
5347
|
}
|
|
5348
|
+
function buildFallbackTitle(threadId, filePath, cwd) {
|
|
5349
|
+
try {
|
|
5350
|
+
const content = readFilePrefix(filePath);
|
|
5351
|
+
for (const line of content.split(/\r?\n/)) {
|
|
5352
|
+
if (!line.trim()) continue;
|
|
5353
|
+
let parsed;
|
|
5354
|
+
try {
|
|
5355
|
+
parsed = JSON.parse(line);
|
|
5356
|
+
} catch {
|
|
5357
|
+
continue;
|
|
5358
|
+
}
|
|
5359
|
+
if (!isSessionEventLine(parsed) || parsed.payload?.type !== "user_message") continue;
|
|
5360
|
+
const firstUserMessage = trimTitle(normalizeFreeText(parsed.payload.message || ""));
|
|
5361
|
+
if (firstUserMessage) return firstUserMessage;
|
|
5362
|
+
}
|
|
5363
|
+
} catch {
|
|
5364
|
+
}
|
|
5365
|
+
const dirName = trimTitle(path3.basename(cwd || ""));
|
|
5366
|
+
if (dirName) return dirName;
|
|
5367
|
+
return `Session ${threadId.slice(0, 8)}`;
|
|
5368
|
+
}
|
|
5244
5369
|
function parseDesktopSession(filePath, threadNames, archivedThreadIds) {
|
|
5245
5370
|
const firstLine = readFirstLine(filePath);
|
|
5246
5371
|
if (!firstLine) return null;
|
|
@@ -5266,8 +5391,7 @@ function parseDesktopSession(filePath, threadNames, archivedThreadIds) {
|
|
|
5266
5391
|
const lastEventAt = stat.mtime.toISOString();
|
|
5267
5392
|
const firstSeenAt = parsed.payload.timestamp || parsed.timestamp || stat.birthtime.toISOString();
|
|
5268
5393
|
const threadId = parsed.payload.id;
|
|
5269
|
-
const title = threadNames.get(threadId);
|
|
5270
|
-
if (!title) return null;
|
|
5394
|
+
const title = threadNames.get(threadId) || buildFallbackTitle(threadId, filePath, cwd);
|
|
5271
5395
|
return {
|
|
5272
5396
|
threadId,
|
|
5273
5397
|
filePath,
|
|
@@ -5287,12 +5411,17 @@ function trimTitle(text2) {
|
|
|
5287
5411
|
if (normalized.length <= TITLE_MAX_CHARS) return normalized;
|
|
5288
5412
|
return `${normalized.slice(0, TITLE_MAX_CHARS - 3).trimEnd()}...`;
|
|
5289
5413
|
}
|
|
5414
|
+
function normalizeFreeText(text2) {
|
|
5415
|
+
return text2.replace(/\s+/g, " ").trim();
|
|
5416
|
+
}
|
|
5417
|
+
function isSessionEventLine(line) {
|
|
5418
|
+
return line.type === "event_msg";
|
|
5419
|
+
}
|
|
5290
5420
|
function listDesktopSessions(limit = 12) {
|
|
5291
5421
|
const root = getCodexSessionsRoot();
|
|
5292
5422
|
if (!fs3.existsSync(root)) return [];
|
|
5293
5423
|
const archivedThreadIds = loadArchivedThreadIds();
|
|
5294
5424
|
const threadNames = loadThreadNameIndex(archivedThreadIds);
|
|
5295
|
-
if (threadNames.size === 0) return [];
|
|
5296
5425
|
const files = [];
|
|
5297
5426
|
walkSessionFiles(root, files);
|
|
5298
5427
|
const sessions = [];
|
|
@@ -5313,10 +5442,15 @@ function isArchivedDesktopThread(threadId) {
|
|
|
5313
5442
|
// src/session-bindings.ts
|
|
5314
5443
|
import path4 from "node:path";
|
|
5315
5444
|
function getSessionName(session) {
|
|
5445
|
+
if (session.session_type === "draft") return "\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B";
|
|
5446
|
+
if (session.session_type === "history_summary") return "\u5386\u53F2\u6458\u8981\u7EBF\u7A0B";
|
|
5316
5447
|
if (session.name?.trim()) return session.name.trim();
|
|
5317
5448
|
if (session.working_directory) return path4.basename(session.working_directory);
|
|
5318
5449
|
return session.id.slice(0, 8);
|
|
5319
5450
|
}
|
|
5451
|
+
function getSessionMode(store, session) {
|
|
5452
|
+
return session.preferred_mode || store.getSetting("bridge_default_mode") || "code";
|
|
5453
|
+
}
|
|
5320
5454
|
function bindStoreToSession(store, channelType, chatId, sessionId) {
|
|
5321
5455
|
const session = store.getSession(sessionId);
|
|
5322
5456
|
if (!session) return null;
|
|
@@ -5326,7 +5460,8 @@ function bindStoreToSession(store, channelType, chatId, sessionId) {
|
|
|
5326
5460
|
codepilotSessionId: session.id,
|
|
5327
5461
|
sdkSessionId: session.sdk_session_id || "",
|
|
5328
5462
|
workingDirectory: session.working_directory,
|
|
5329
|
-
model: session.model
|
|
5463
|
+
model: session.model,
|
|
5464
|
+
mode: getSessionMode(store, session)
|
|
5330
5465
|
});
|
|
5331
5466
|
}
|
|
5332
5467
|
function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
@@ -5338,7 +5473,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
|
5338
5473
|
codepilotSessionId: existing.id,
|
|
5339
5474
|
sdkSessionId,
|
|
5340
5475
|
workingDirectory: opts?.workingDirectory || existing.working_directory,
|
|
5341
|
-
model: opts?.model || existing.model
|
|
5476
|
+
model: opts?.model || existing.model,
|
|
5477
|
+
mode: getSessionMode(store, existing)
|
|
5342
5478
|
});
|
|
5343
5479
|
}
|
|
5344
5480
|
const workingDirectory = opts?.workingDirectory || store.getSetting("bridge_default_work_dir") || process.env.HOME || "";
|
|
@@ -5358,7 +5494,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
|
5358
5494
|
codepilotSessionId: session.id,
|
|
5359
5495
|
sdkSessionId,
|
|
5360
5496
|
workingDirectory: workingDirectory || session.working_directory,
|
|
5361
|
-
model: model || session.model
|
|
5497
|
+
model: model || session.model,
|
|
5498
|
+
mode: getSessionMode(store, session)
|
|
5362
5499
|
});
|
|
5363
5500
|
}
|
|
5364
5501
|
function listBindingTargetOptions(_store, desktopLimit = 12) {
|
|
@@ -5395,7 +5532,11 @@ function listBindingSummaries(store) {
|
|
|
5395
5532
|
currentTargetLabel,
|
|
5396
5533
|
currentSessionId: binding.codepilotSessionId,
|
|
5397
5534
|
currentSessionName: session ? getSessionName(session) : binding.codepilotSessionId.slice(0, 8),
|
|
5398
|
-
currentThreadId
|
|
5535
|
+
currentThreadId,
|
|
5536
|
+
runtimeStatus: session?.runtime_status,
|
|
5537
|
+
queuedCount: session?.queued_count,
|
|
5538
|
+
mirrorStatus: session?.mirror_status,
|
|
5539
|
+
mirrorLastEventAt: session?.mirror_last_event_at
|
|
5399
5540
|
};
|
|
5400
5541
|
}).sort((a, b) => {
|
|
5401
5542
|
if (a.channelType !== b.channelType) return a.channelType.localeCompare(b.channelType);
|
|
@@ -5449,6 +5590,7 @@ var bridgePidFile = path5.join(runtimeDir, "bridge.pid");
|
|
|
5449
5590
|
var bridgeStatusFile = path5.join(runtimeDir, "status.json");
|
|
5450
5591
|
var uiStatusFile = path5.join(runtimeDir, "ui-server.json");
|
|
5451
5592
|
var uiPort = 4781;
|
|
5593
|
+
var WINDOWS_HIDE = process.platform === "win32" ? { windowsHide: true } : {};
|
|
5452
5594
|
function ensureDirs() {
|
|
5453
5595
|
fs4.mkdirSync(runtimeDir, { recursive: true });
|
|
5454
5596
|
fs4.mkdirSync(logsDir, { recursive: true });
|
|
@@ -5550,7 +5692,8 @@ async function startBridge() {
|
|
|
5550
5692
|
cwd: packageRoot,
|
|
5551
5693
|
detached: true,
|
|
5552
5694
|
env: buildDaemonEnv(),
|
|
5553
|
-
stdio: ["ignore", stdoutFd, stderrFd]
|
|
5695
|
+
stdio: ["ignore", stdoutFd, stderrFd],
|
|
5696
|
+
...WINDOWS_HIDE
|
|
5554
5697
|
});
|
|
5555
5698
|
child.unref();
|
|
5556
5699
|
const status = await waitForBridgeRunning();
|
|
@@ -5567,7 +5710,8 @@ async function stopBridge() {
|
|
|
5567
5710
|
if (process.platform === "win32") {
|
|
5568
5711
|
await new Promise((resolve) => {
|
|
5569
5712
|
const killer = spawn("cmd", ["/c", "taskkill", "/PID", String(status.pid), "/T", "/F"], {
|
|
5570
|
-
stdio: "ignore"
|
|
5713
|
+
stdio: "ignore",
|
|
5714
|
+
...WINDOWS_HIDE
|
|
5571
5715
|
});
|
|
5572
5716
|
killer.on("exit", () => resolve());
|
|
5573
5717
|
killer.on("error", () => resolve());
|
|
@@ -5635,7 +5779,7 @@ function isCodexIntegrationInstalled() {
|
|
|
5635
5779
|
// src/store.ts
|
|
5636
5780
|
import fs5 from "node:fs";
|
|
5637
5781
|
import path6 from "node:path";
|
|
5638
|
-
import
|
|
5782
|
+
import crypto2 from "node:crypto";
|
|
5639
5783
|
var DATA_DIR = path6.join(CTI_HOME, "data");
|
|
5640
5784
|
var MESSAGES_DIR = path6.join(DATA_DIR, "messages");
|
|
5641
5785
|
function ensureDir(dir) {
|
|
@@ -5658,13 +5802,14 @@ function writeJson(filePath, data) {
|
|
|
5658
5802
|
atomicWrite(filePath, JSON.stringify(data, null, 2));
|
|
5659
5803
|
}
|
|
5660
5804
|
function uuid() {
|
|
5661
|
-
return
|
|
5805
|
+
return crypto2.randomUUID();
|
|
5662
5806
|
}
|
|
5663
5807
|
function now() {
|
|
5664
5808
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5665
5809
|
}
|
|
5666
5810
|
var JsonFileStore = class {
|
|
5667
5811
|
settings;
|
|
5812
|
+
dynamicSettings;
|
|
5668
5813
|
sessions = /* @__PURE__ */ new Map();
|
|
5669
5814
|
bindings = /* @__PURE__ */ new Map();
|
|
5670
5815
|
messages = /* @__PURE__ */ new Map();
|
|
@@ -5673,8 +5818,9 @@ var JsonFileStore = class {
|
|
|
5673
5818
|
dedupKeys = /* @__PURE__ */ new Map();
|
|
5674
5819
|
locks = /* @__PURE__ */ new Map();
|
|
5675
5820
|
auditLog = [];
|
|
5676
|
-
constructor(settingsMap) {
|
|
5821
|
+
constructor(settingsMap, options) {
|
|
5677
5822
|
this.settings = settingsMap;
|
|
5823
|
+
this.dynamicSettings = options?.dynamicSettings === true;
|
|
5678
5824
|
ensureDir(DATA_DIR);
|
|
5679
5825
|
ensureDir(MESSAGES_DIR);
|
|
5680
5826
|
this.loadAll();
|
|
@@ -5769,7 +5915,19 @@ var JsonFileStore = class {
|
|
|
5769
5915
|
return msgs;
|
|
5770
5916
|
}
|
|
5771
5917
|
// ── Settings ──
|
|
5918
|
+
refreshSettings() {
|
|
5919
|
+
if (!this.dynamicSettings) return;
|
|
5920
|
+
try {
|
|
5921
|
+
const next = configToSettings(loadConfig());
|
|
5922
|
+
this.settings = new Map([
|
|
5923
|
+
...this.settings,
|
|
5924
|
+
...next
|
|
5925
|
+
]);
|
|
5926
|
+
} catch {
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5772
5929
|
getSetting(key) {
|
|
5930
|
+
this.refreshSettings();
|
|
5773
5931
|
return this.settings.get(key) ?? null;
|
|
5774
5932
|
}
|
|
5775
5933
|
// ── Channel Bindings ──
|
|
@@ -5788,6 +5946,7 @@ var JsonFileStore = class {
|
|
|
5788
5946
|
sdkSessionId: data.sdkSessionId ?? existing.sdkSessionId,
|
|
5789
5947
|
workingDirectory: data.workingDirectory,
|
|
5790
5948
|
model: data.model,
|
|
5949
|
+
mode: data.mode ?? existing.mode,
|
|
5791
5950
|
updatedAt: now()
|
|
5792
5951
|
};
|
|
5793
5952
|
this.bindings.set(key, updated);
|
|
@@ -5802,7 +5961,7 @@ var JsonFileStore = class {
|
|
|
5802
5961
|
sdkSessionId: data.sdkSessionId ?? "",
|
|
5803
5962
|
workingDirectory: data.workingDirectory,
|
|
5804
5963
|
model: data.model,
|
|
5805
|
-
mode: this.
|
|
5964
|
+
mode: data.mode || this.getSetting("bridge_default_mode") || "code",
|
|
5806
5965
|
active: true,
|
|
5807
5966
|
createdAt: now(),
|
|
5808
5967
|
updatedAt: now()
|
|
@@ -5845,14 +6004,23 @@ var JsonFileStore = class {
|
|
|
5845
6004
|
}
|
|
5846
6005
|
return null;
|
|
5847
6006
|
}
|
|
5848
|
-
createSession(name, model, systemPrompt, cwd,
|
|
6007
|
+
createSession(name, model, systemPrompt, cwd, mode, options) {
|
|
5849
6008
|
this.reloadSessions();
|
|
6009
|
+
const timestamp = now();
|
|
5850
6010
|
const session = {
|
|
5851
6011
|
id: uuid(),
|
|
5852
6012
|
name,
|
|
5853
|
-
working_directory: cwd || this.
|
|
6013
|
+
working_directory: cwd || this.getSetting("bridge_default_work_dir") || process.cwd(),
|
|
5854
6014
|
model,
|
|
5855
|
-
|
|
6015
|
+
preferred_mode: mode,
|
|
6016
|
+
system_prompt: systemPrompt,
|
|
6017
|
+
reasoning_effort: options?.reasoningEffort,
|
|
6018
|
+
session_type: options?.sessionType || "normal",
|
|
6019
|
+
hidden: options?.hidden === true,
|
|
6020
|
+
parent_session_id: options?.parentSessionId,
|
|
6021
|
+
expires_at: options?.expiresAt,
|
|
6022
|
+
created_at: timestamp,
|
|
6023
|
+
updated_at: timestamp
|
|
5856
6024
|
};
|
|
5857
6025
|
this.sessions.set(session.id, session);
|
|
5858
6026
|
this.persistSessions();
|
|
@@ -5863,9 +6031,40 @@ var JsonFileStore = class {
|
|
|
5863
6031
|
const s = this.sessions.get(sessionId);
|
|
5864
6032
|
if (s) {
|
|
5865
6033
|
s.provider_id = providerId;
|
|
6034
|
+
s.updated_at = now();
|
|
5866
6035
|
this.persistSessions();
|
|
5867
6036
|
}
|
|
5868
6037
|
}
|
|
6038
|
+
updateSession(sessionId, updates) {
|
|
6039
|
+
this.reloadSessions();
|
|
6040
|
+
const session = this.sessions.get(sessionId);
|
|
6041
|
+
if (!session) return;
|
|
6042
|
+
const next = {
|
|
6043
|
+
...session,
|
|
6044
|
+
...updates,
|
|
6045
|
+
id: session.id,
|
|
6046
|
+
updated_at: now()
|
|
6047
|
+
};
|
|
6048
|
+
this.sessions.set(sessionId, next);
|
|
6049
|
+
this.persistSessions();
|
|
6050
|
+
}
|
|
6051
|
+
deleteSession(sessionId) {
|
|
6052
|
+
this.reloadSessions();
|
|
6053
|
+
this.reloadBindings();
|
|
6054
|
+
this.sessions.delete(sessionId);
|
|
6055
|
+
for (const [key, binding] of this.bindings) {
|
|
6056
|
+
if (binding.codepilotSessionId === sessionId) {
|
|
6057
|
+
this.bindings.delete(key);
|
|
6058
|
+
}
|
|
6059
|
+
}
|
|
6060
|
+
this.messages.delete(sessionId);
|
|
6061
|
+
try {
|
|
6062
|
+
fs5.rmSync(path6.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
|
|
6063
|
+
} catch {
|
|
6064
|
+
}
|
|
6065
|
+
this.persistSessions();
|
|
6066
|
+
this.persistBindings();
|
|
6067
|
+
}
|
|
5869
6068
|
// ── Messages ──
|
|
5870
6069
|
addMessage(sessionId, role, content, _usage) {
|
|
5871
6070
|
const msgs = this.loadMessages(sessionId);
|
|
@@ -5905,6 +6104,26 @@ var JsonFileStore = class {
|
|
|
5905
6104
|
}
|
|
5906
6105
|
}
|
|
5907
6106
|
setSessionRuntimeStatus(_sessionId, _status) {
|
|
6107
|
+
this.reloadSessions();
|
|
6108
|
+
const session = this.sessions.get(_sessionId);
|
|
6109
|
+
if (!session) return;
|
|
6110
|
+
const queuedCount = session.queued_count && session.queued_count > 0 ? session.queued_count : 0;
|
|
6111
|
+
let runtimeStatus;
|
|
6112
|
+
if (_status === "running") {
|
|
6113
|
+
runtimeStatus = queuedCount > 0 ? "queued" : "running";
|
|
6114
|
+
} else if (_status === "idle") {
|
|
6115
|
+
runtimeStatus = queuedCount > 0 ? "queued" : "idle";
|
|
6116
|
+
} else {
|
|
6117
|
+
runtimeStatus = session.runtime_status;
|
|
6118
|
+
}
|
|
6119
|
+
const next = {
|
|
6120
|
+
...session,
|
|
6121
|
+
runtime_status: runtimeStatus,
|
|
6122
|
+
last_runtime_update_at: now(),
|
|
6123
|
+
updated_at: now()
|
|
6124
|
+
};
|
|
6125
|
+
this.sessions.set(_sessionId, next);
|
|
6126
|
+
this.persistSessions();
|
|
5908
6127
|
}
|
|
5909
6128
|
// ── SDK Session ──
|
|
5910
6129
|
updateSdkSessionId(sessionId, sdkSessionId) {
|
|
@@ -5913,6 +6132,7 @@ var JsonFileStore = class {
|
|
|
5913
6132
|
const s = this.sessions.get(sessionId);
|
|
5914
6133
|
if (s) {
|
|
5915
6134
|
s.sdk_session_id = sdkSessionId;
|
|
6135
|
+
s.updated_at = now();
|
|
5916
6136
|
this.persistSessions();
|
|
5917
6137
|
}
|
|
5918
6138
|
for (const [key, b] of this.bindings) {
|
|
@@ -5927,6 +6147,7 @@ var JsonFileStore = class {
|
|
|
5927
6147
|
const s = this.sessions.get(sessionId);
|
|
5928
6148
|
if (s) {
|
|
5929
6149
|
s.model = model;
|
|
6150
|
+
s.updated_at = now();
|
|
5930
6151
|
this.persistSessions();
|
|
5931
6152
|
}
|
|
5932
6153
|
}
|
|
@@ -5983,6 +6204,7 @@ var JsonFileStore = class {
|
|
|
5983
6204
|
permissionRequestId: link.permissionRequestId,
|
|
5984
6205
|
chatId: link.chatId,
|
|
5985
6206
|
messageId: link.messageId,
|
|
6207
|
+
sessionId: link.sessionId,
|
|
5986
6208
|
resolved: false,
|
|
5987
6209
|
suggestions: link.suggestions
|
|
5988
6210
|
};
|
|
@@ -6025,7 +6247,7 @@ import path8 from "node:path";
|
|
|
6025
6247
|
import { spawn as spawn2 } from "node:child_process";
|
|
6026
6248
|
|
|
6027
6249
|
// src/adapters/weixin/weixin-api.ts
|
|
6028
|
-
import
|
|
6250
|
+
import crypto3 from "node:crypto";
|
|
6029
6251
|
|
|
6030
6252
|
// src/adapters/weixin/weixin-types.ts
|
|
6031
6253
|
var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
@@ -6316,7 +6538,7 @@ function openQrHtml() {
|
|
|
6316
6538
|
return true;
|
|
6317
6539
|
}
|
|
6318
6540
|
if (process.platform === "win32") {
|
|
6319
|
-
const child2 = spawn2("cmd", ["/c", "start", "", HTML_PATH], { detached: true, stdio: "ignore" });
|
|
6541
|
+
const child2 = spawn2("cmd", ["/c", "start", "", HTML_PATH], { detached: true, stdio: "ignore", windowsHide: true });
|
|
6320
6542
|
child2.unref();
|
|
6321
6543
|
return true;
|
|
6322
6544
|
}
|
|
@@ -6438,6 +6660,7 @@ if (isMainModule) {
|
|
|
6438
6660
|
var port = 4781;
|
|
6439
6661
|
var serverStartTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
6440
6662
|
var supportedChannels = ["feishu", "weixin"];
|
|
6663
|
+
var AUTH_COOKIE_NAME = "cti_ui_auth";
|
|
6441
6664
|
function parsePreferredPort() {
|
|
6442
6665
|
const raw = Number(process.env.CTI_UI_PORT || "4781");
|
|
6443
6666
|
if (!Number.isInteger(raw) || raw <= 0 || raw > 65535) return 4781;
|
|
@@ -6448,7 +6671,7 @@ async function canListen(portToCheck) {
|
|
|
6448
6671
|
const probe = net.createServer();
|
|
6449
6672
|
probe.unref();
|
|
6450
6673
|
probe.once("error", () => resolve(false));
|
|
6451
|
-
probe.listen(portToCheck, "
|
|
6674
|
+
probe.listen(portToCheck, "0.0.0.0", () => {
|
|
6452
6675
|
probe.close(() => resolve(true));
|
|
6453
6676
|
});
|
|
6454
6677
|
});
|
|
@@ -6462,7 +6685,7 @@ async function resolveUiPort(preferredPort) {
|
|
|
6462
6685
|
const probe = net.createServer();
|
|
6463
6686
|
probe.unref();
|
|
6464
6687
|
probe.once("error", reject);
|
|
6465
|
-
probe.listen(0, "
|
|
6688
|
+
probe.listen(0, "0.0.0.0", () => {
|
|
6466
6689
|
const address = probe.address();
|
|
6467
6690
|
const dynamicPort = typeof address === "object" && address ? address.port : preferredPort;
|
|
6468
6691
|
probe.close((error) => {
|
|
@@ -6525,43 +6748,128 @@ function parsePositiveInt2(value, fallback) {
|
|
|
6525
6748
|
function createUiStore() {
|
|
6526
6749
|
return new JsonFileStore(configToSettings(loadConfig()));
|
|
6527
6750
|
}
|
|
6751
|
+
function generateAccessToken() {
|
|
6752
|
+
return crypto4.randomBytes(18).toString("base64url");
|
|
6753
|
+
}
|
|
6754
|
+
function timingSafeMatch(left, right) {
|
|
6755
|
+
if (!left || !right) return false;
|
|
6756
|
+
const leftBuffer = Buffer.from(left);
|
|
6757
|
+
const rightBuffer = Buffer.from(right);
|
|
6758
|
+
if (leftBuffer.length !== rightBuffer.length) return false;
|
|
6759
|
+
return crypto4.timingSafeEqual(leftBuffer, rightBuffer);
|
|
6760
|
+
}
|
|
6761
|
+
function parseCookies(request) {
|
|
6762
|
+
const header = request.headers.cookie;
|
|
6763
|
+
if (!header) return /* @__PURE__ */ new Map();
|
|
6764
|
+
return new Map(
|
|
6765
|
+
header.split(";").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
6766
|
+
const separator = part.indexOf("=");
|
|
6767
|
+
if (separator === -1) return [part, ""];
|
|
6768
|
+
return [part.slice(0, separator), decodeURIComponent(part.slice(separator + 1))];
|
|
6769
|
+
})
|
|
6770
|
+
);
|
|
6771
|
+
}
|
|
6772
|
+
function makeAuthCookie(token) {
|
|
6773
|
+
return `${AUTH_COOKIE_NAME}=${encodeURIComponent(token)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=2592000`;
|
|
6774
|
+
}
|
|
6775
|
+
function clearAuthCookie() {
|
|
6776
|
+
return `${AUTH_COOKIE_NAME}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
|
|
6777
|
+
}
|
|
6778
|
+
function redirect(response, location, cookie) {
|
|
6779
|
+
const headers = { Location: location };
|
|
6780
|
+
if (cookie) headers["Set-Cookie"] = cookie;
|
|
6781
|
+
response.writeHead(302, headers);
|
|
6782
|
+
response.end();
|
|
6783
|
+
}
|
|
6784
|
+
function getRemoteAddress(request) {
|
|
6785
|
+
return request.socket.remoteAddress || "";
|
|
6786
|
+
}
|
|
6787
|
+
function isLoopbackAddress(address) {
|
|
6788
|
+
return address === "127.0.0.1" || address === "::1" || address === "::ffff:127.0.0.1";
|
|
6789
|
+
}
|
|
6790
|
+
function isLocalRequest(request) {
|
|
6791
|
+
return isLoopbackAddress(getRemoteAddress(request));
|
|
6792
|
+
}
|
|
6793
|
+
function getLanUrls(currentPort) {
|
|
6794
|
+
const interfaces = os5.networkInterfaces();
|
|
6795
|
+
const urls = /* @__PURE__ */ new Set();
|
|
6796
|
+
for (const records of Object.values(interfaces)) {
|
|
6797
|
+
for (const record of records || []) {
|
|
6798
|
+
if (!record || record.internal || record.family !== "IPv4") continue;
|
|
6799
|
+
urls.add(`http://${record.address}:${currentPort}`);
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6802
|
+
return Array.from(urls).sort();
|
|
6803
|
+
}
|
|
6804
|
+
function buildUiAccessInfo(currentPort, config, request) {
|
|
6805
|
+
return {
|
|
6806
|
+
allowLan: config.uiAllowLan === true,
|
|
6807
|
+
localUrl: getUiServerUrl(currentPort),
|
|
6808
|
+
lanUrls: getLanUrls(currentPort),
|
|
6809
|
+
accessToken: config.uiAccessToken || "",
|
|
6810
|
+
requestIsLocal: request ? isLocalRequest(request) : true,
|
|
6811
|
+
authenticated: request ? isRemoteAuthenticated(request, config) : true
|
|
6812
|
+
};
|
|
6813
|
+
}
|
|
6814
|
+
function isRemoteAuthenticated(request, config) {
|
|
6815
|
+
if (isLocalRequest(request)) return true;
|
|
6816
|
+
if (config.uiAllowLan !== true) return false;
|
|
6817
|
+
return timingSafeMatch(parseCookies(request).get(AUTH_COOKIE_NAME), config.uiAccessToken);
|
|
6818
|
+
}
|
|
6528
6819
|
function configToPayload(config) {
|
|
6529
6820
|
return {
|
|
6530
6821
|
runtime: config.runtime,
|
|
6531
6822
|
enabledChannels: config.enabledChannels,
|
|
6532
6823
|
defaultWorkDir: config.defaultWorkDir,
|
|
6824
|
+
defaultWorkspaceRoot: config.defaultWorkspaceRoot || "",
|
|
6533
6825
|
defaultModel: config.defaultModel || "",
|
|
6534
6826
|
defaultMode: config.defaultMode,
|
|
6535
6827
|
historyMessageLimit: config.historyMessageLimit ?? 8,
|
|
6536
6828
|
codexSkipGitRepoCheck: config.codexSkipGitRepoCheck === true,
|
|
6829
|
+
codexSandboxMode: config.codexSandboxMode || "workspace-write",
|
|
6830
|
+
codexReasoningEffort: config.codexReasoningEffort || "medium",
|
|
6831
|
+
uiAllowLan: config.uiAllowLan === true,
|
|
6832
|
+
uiAccessToken: config.uiAccessToken || "",
|
|
6537
6833
|
autoApprove: config.autoApprove === true,
|
|
6538
6834
|
feishuAppId: config.feishuAppId || "",
|
|
6539
6835
|
feishuAppSecret: config.feishuAppSecret || "",
|
|
6540
6836
|
feishuDomain: config.feishuDomain || "https://open.feishu.cn",
|
|
6541
6837
|
feishuAllowedUsers: config.feishuAllowedUsers?.join(",") || "",
|
|
6542
6838
|
feishuStreamingEnabled: config.feishuStreamingEnabled !== false,
|
|
6543
|
-
|
|
6839
|
+
feishuCommandMarkdownEnabled: config.feishuCommandMarkdownEnabled !== false,
|
|
6840
|
+
weixinMediaEnabled: config.weixinMediaEnabled === true,
|
|
6841
|
+
weixinCommandMarkdownEnabled: config.weixinCommandMarkdownEnabled === true
|
|
6544
6842
|
};
|
|
6545
6843
|
}
|
|
6546
6844
|
function mergeConfig(payload) {
|
|
6547
6845
|
const current = loadConfig();
|
|
6548
6846
|
const requestedChannels = Array.isArray(payload.enabledChannels) ? payload.enabledChannels.filter((value) => typeof value === "string") : current.enabledChannels;
|
|
6847
|
+
const uiAllowLan = payload.uiAllowLan === true;
|
|
6848
|
+
const requestedUiAccessToken = asString(payload.uiAccessToken);
|
|
6849
|
+
const uiAccessToken = requestedUiAccessToken || current.uiAccessToken || (uiAllowLan ? generateAccessToken() : void 0);
|
|
6549
6850
|
return {
|
|
6550
6851
|
...current,
|
|
6551
6852
|
runtime: payload.runtime === "claude" || payload.runtime === "auto" ? payload.runtime : "codex",
|
|
6552
6853
|
enabledChannels: requestedChannels.filter((channel) => supportedChannels.includes(channel)),
|
|
6553
6854
|
defaultWorkDir: asString(payload.defaultWorkDir) || current.defaultWorkDir || process.cwd(),
|
|
6855
|
+
defaultWorkspaceRoot: asString(payload.defaultWorkspaceRoot),
|
|
6554
6856
|
defaultModel: asString(payload.defaultModel),
|
|
6555
6857
|
defaultMode: payload.defaultMode === "plan" || payload.defaultMode === "ask" ? payload.defaultMode : "code",
|
|
6556
6858
|
historyMessageLimit: asPositiveInt(payload.historyMessageLimit) || current.historyMessageLimit || 8,
|
|
6557
6859
|
codexSkipGitRepoCheck: payload.codexSkipGitRepoCheck === true,
|
|
6860
|
+
codexSandboxMode: payload.codexSandboxMode === "read-only" || payload.codexSandboxMode === "danger-full-access" ? payload.codexSandboxMode : "workspace-write",
|
|
6861
|
+
codexReasoningEffort: payload.codexReasoningEffort === "minimal" || payload.codexReasoningEffort === "low" || payload.codexReasoningEffort === "high" || payload.codexReasoningEffort === "xhigh" ? payload.codexReasoningEffort : "medium",
|
|
6862
|
+
uiAllowLan,
|
|
6863
|
+
uiAccessToken,
|
|
6558
6864
|
autoApprove: payload.autoApprove === true,
|
|
6559
6865
|
feishuAppId: asString(payload.feishuAppId),
|
|
6560
6866
|
feishuAppSecret: asString(payload.feishuAppSecret),
|
|
6561
6867
|
feishuDomain: asString(payload.feishuDomain) || "https://open.feishu.cn",
|
|
6562
6868
|
feishuAllowedUsers: parseCsv(payload.feishuAllowedUsers),
|
|
6563
6869
|
feishuStreamingEnabled: payload.feishuStreamingEnabled !== false,
|
|
6564
|
-
|
|
6870
|
+
feishuCommandMarkdownEnabled: payload.feishuCommandMarkdownEnabled !== false,
|
|
6871
|
+
weixinMediaEnabled: payload.weixinMediaEnabled === true,
|
|
6872
|
+
weixinCommandMarkdownEnabled: payload.weixinCommandMarkdownEnabled === true
|
|
6565
6873
|
};
|
|
6566
6874
|
}
|
|
6567
6875
|
function getWeixinAccountsPayload() {
|
|
@@ -6643,6 +6951,182 @@ async function testCodexConnection(config) {
|
|
|
6643
6951
|
clearTimeout(timeout);
|
|
6644
6952
|
}
|
|
6645
6953
|
}
|
|
6954
|
+
function renderLoginHtml() {
|
|
6955
|
+
return `<!doctype html>
|
|
6956
|
+
<html lang="zh-CN">
|
|
6957
|
+
<head>
|
|
6958
|
+
<meta charset="utf-8" />
|
|
6959
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6960
|
+
<title>Codex to IM \u767B\u5F55</title>
|
|
6961
|
+
<style>
|
|
6962
|
+
:root {
|
|
6963
|
+
--bg: #f5f7fa;
|
|
6964
|
+
--surface: #ffffff;
|
|
6965
|
+
--border: #e5e7eb;
|
|
6966
|
+
--border-strong: #d0d7e2;
|
|
6967
|
+
--text: #111827;
|
|
6968
|
+
--muted: #667085;
|
|
6969
|
+
--primary: #1677ff;
|
|
6970
|
+
--primary-strong: #0958d9;
|
|
6971
|
+
--danger: #dc2626;
|
|
6972
|
+
}
|
|
6973
|
+
* { box-sizing: border-box; }
|
|
6974
|
+
body {
|
|
6975
|
+
margin: 0;
|
|
6976
|
+
min-height: 100vh;
|
|
6977
|
+
display: grid;
|
|
6978
|
+
place-items: center;
|
|
6979
|
+
padding: 24px;
|
|
6980
|
+
background: var(--bg);
|
|
6981
|
+
color: var(--text);
|
|
6982
|
+
font: 14px/1.5 "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif;
|
|
6983
|
+
}
|
|
6984
|
+
.auth-card {
|
|
6985
|
+
width: min(420px, 100%);
|
|
6986
|
+
background: var(--surface);
|
|
6987
|
+
border: 1px solid var(--border);
|
|
6988
|
+
border-radius: 10px;
|
|
6989
|
+
padding: 24px;
|
|
6990
|
+
}
|
|
6991
|
+
h1 {
|
|
6992
|
+
margin: 0 0 8px;
|
|
6993
|
+
font-size: 24px;
|
|
6994
|
+
line-height: 1.2;
|
|
6995
|
+
}
|
|
6996
|
+
p {
|
|
6997
|
+
margin: 0 0 18px;
|
|
6998
|
+
color: var(--muted);
|
|
6999
|
+
}
|
|
7000
|
+
label {
|
|
7001
|
+
display: grid;
|
|
7002
|
+
gap: 6px;
|
|
7003
|
+
color: var(--muted);
|
|
7004
|
+
font-weight: 500;
|
|
7005
|
+
}
|
|
7006
|
+
input {
|
|
7007
|
+
width: 100%;
|
|
7008
|
+
border: 1px solid var(--border-strong);
|
|
7009
|
+
border-radius: 8px;
|
|
7010
|
+
padding: 10px 12px;
|
|
7011
|
+
font: inherit;
|
|
7012
|
+
}
|
|
7013
|
+
input:focus {
|
|
7014
|
+
outline: 2px solid rgba(22, 119, 255, 0.14);
|
|
7015
|
+
border-color: var(--primary);
|
|
7016
|
+
}
|
|
7017
|
+
button {
|
|
7018
|
+
margin-top: 16px;
|
|
7019
|
+
width: 100%;
|
|
7020
|
+
border: 1px solid var(--primary);
|
|
7021
|
+
background: var(--primary);
|
|
7022
|
+
color: #ffffff;
|
|
7023
|
+
border-radius: 8px;
|
|
7024
|
+
padding: 10px 14px;
|
|
7025
|
+
font: inherit;
|
|
7026
|
+
cursor: pointer;
|
|
7027
|
+
}
|
|
7028
|
+
button:hover {
|
|
7029
|
+
background: var(--primary-strong);
|
|
7030
|
+
border-color: var(--primary-strong);
|
|
7031
|
+
}
|
|
7032
|
+
.message {
|
|
7033
|
+
display: none;
|
|
7034
|
+
margin-top: 14px;
|
|
7035
|
+
padding: 10px 12px;
|
|
7036
|
+
border-radius: 8px;
|
|
7037
|
+
background: rgba(220, 38, 38, 0.08);
|
|
7038
|
+
color: var(--danger);
|
|
7039
|
+
}
|
|
7040
|
+
.message.show { display: block; }
|
|
7041
|
+
</style>
|
|
7042
|
+
</head>
|
|
7043
|
+
<body>
|
|
7044
|
+
<section class="auth-card">
|
|
7045
|
+
<h1>\u8BBF\u95EE Codex to IM</h1>
|
|
7046
|
+
<p>\u5F53\u524D\u5DE5\u4F5C\u53F0\u5DF2\u5F00\u542F\u5C40\u57DF\u7F51\u8BBF\u95EE\u3002\u8BF7\u8F93\u5165\u8BBF\u95EE token\uFF0C\u9A8C\u8BC1\u901A\u8FC7\u540E\u624D\u80FD\u67E5\u770B\u548C\u4FEE\u6539\u914D\u7F6E\u3002</p>
|
|
7047
|
+
<form id="loginForm">
|
|
7048
|
+
<label>
|
|
7049
|
+
\u8BBF\u95EE token
|
|
7050
|
+
<input id="token" name="token" autocomplete="off" spellcheck="false" />
|
|
7051
|
+
</label>
|
|
7052
|
+
<button type="submit">\u767B\u5F55</button>
|
|
7053
|
+
</form>
|
|
7054
|
+
<div class="message" id="message"></div>
|
|
7055
|
+
</section>
|
|
7056
|
+
<script>
|
|
7057
|
+
const form = document.getElementById('loginForm');
|
|
7058
|
+
const message = document.getElementById('message');
|
|
7059
|
+
const tokenInput = document.getElementById('token');
|
|
7060
|
+
form.addEventListener('submit', async (event) => {
|
|
7061
|
+
event.preventDefault();
|
|
7062
|
+
message.className = 'message';
|
|
7063
|
+
message.textContent = '';
|
|
7064
|
+
|
|
7065
|
+
try {
|
|
7066
|
+
const response = await fetch('/api/auth/login', {
|
|
7067
|
+
method: 'POST',
|
|
7068
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7069
|
+
body: JSON.stringify({ token: tokenInput.value }),
|
|
7070
|
+
});
|
|
7071
|
+
const text = await response.text();
|
|
7072
|
+
const data = text ? JSON.parse(text) : {};
|
|
7073
|
+
if (!response.ok) {
|
|
7074
|
+
throw new Error(data.error || '\u767B\u5F55\u5931\u8D25');
|
|
7075
|
+
}
|
|
7076
|
+
window.location.href = '/';
|
|
7077
|
+
} catch (error) {
|
|
7078
|
+
message.className = 'message show';
|
|
7079
|
+
message.textContent = error instanceof Error ? error.message : String(error);
|
|
7080
|
+
}
|
|
7081
|
+
});
|
|
7082
|
+
</script>
|
|
7083
|
+
</body>
|
|
7084
|
+
</html>`;
|
|
7085
|
+
}
|
|
7086
|
+
function renderAccessDeniedHtml() {
|
|
7087
|
+
return `<!doctype html>
|
|
7088
|
+
<html lang="zh-CN">
|
|
7089
|
+
<head>
|
|
7090
|
+
<meta charset="utf-8" />
|
|
7091
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7092
|
+
<title>Codex to IM</title>
|
|
7093
|
+
<style>
|
|
7094
|
+
body {
|
|
7095
|
+
margin: 0;
|
|
7096
|
+
min-height: 100vh;
|
|
7097
|
+
display: grid;
|
|
7098
|
+
place-items: center;
|
|
7099
|
+
padding: 24px;
|
|
7100
|
+
background: #f5f7fa;
|
|
7101
|
+
color: #111827;
|
|
7102
|
+
font: 14px/1.5 "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif;
|
|
7103
|
+
}
|
|
7104
|
+
.card {
|
|
7105
|
+
width: min(420px, 100%);
|
|
7106
|
+
background: #ffffff;
|
|
7107
|
+
border: 1px solid #e5e7eb;
|
|
7108
|
+
border-radius: 10px;
|
|
7109
|
+
padding: 24px;
|
|
7110
|
+
}
|
|
7111
|
+
h1 {
|
|
7112
|
+
margin: 0 0 8px;
|
|
7113
|
+
font-size: 24px;
|
|
7114
|
+
line-height: 1.2;
|
|
7115
|
+
}
|
|
7116
|
+
p {
|
|
7117
|
+
margin: 0;
|
|
7118
|
+
color: #667085;
|
|
7119
|
+
}
|
|
7120
|
+
</style>
|
|
7121
|
+
</head>
|
|
7122
|
+
<body>
|
|
7123
|
+
<section class="card">
|
|
7124
|
+
<h1>\u5F53\u524D\u672A\u5F00\u653E\u5C40\u57DF\u7F51\u8BBF\u95EE</h1>
|
|
7125
|
+
<p>\u8FD9\u4E2A Web \u5DE5\u4F5C\u53F0\u76EE\u524D\u53EA\u5141\u8BB8\u672C\u673A\u8BBF\u95EE\u3002\u8BF7\u5148\u5728\u672C\u673A\u914D\u7F6E\u9875\u4E2D\u52FE\u9009\u201C\u5141\u8BB8\u5C40\u57DF\u7F51\u8BBF\u95EE Web \u63A7\u5236\u53F0\u201D\u3002</p>
|
|
7126
|
+
</section>
|
|
7127
|
+
</body>
|
|
7128
|
+
</html>`;
|
|
7129
|
+
}
|
|
6646
7130
|
function renderHtml() {
|
|
6647
7131
|
return `<!doctype html>
|
|
6648
7132
|
<html lang="zh-CN">
|
|
@@ -6956,43 +7440,80 @@ function renderHtml() {
|
|
|
6956
7440
|
|
|
6957
7441
|
.message {
|
|
6958
7442
|
display: none;
|
|
6959
|
-
margin-top: 14px;
|
|
6960
|
-
padding: 10px 12px;
|
|
6961
|
-
border-radius: 8px;
|
|
6962
7443
|
}
|
|
6963
7444
|
|
|
6964
|
-
.message.show { display: block; }
|
|
6965
|
-
.message.success { background: rgba(21, 128, 61, 0.10); color: var(--success); }
|
|
6966
|
-
.message.error { background: rgba(220, 38, 38, 0.10); color: var(--danger); }
|
|
6967
|
-
|
|
6968
7445
|
.global-message-host {
|
|
6969
7446
|
position: fixed;
|
|
6970
|
-
top:
|
|
7447
|
+
top: 18px;
|
|
6971
7448
|
left: 50%;
|
|
6972
7449
|
transform: translateX(-50%);
|
|
6973
7450
|
display: grid;
|
|
6974
|
-
gap:
|
|
6975
|
-
z-index:
|
|
7451
|
+
gap: 12px;
|
|
7452
|
+
z-index: 2400;
|
|
6976
7453
|
pointer-events: none;
|
|
6977
7454
|
}
|
|
6978
7455
|
|
|
6979
7456
|
.global-message {
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
7457
|
+
display: inline-flex;
|
|
7458
|
+
align-items: center;
|
|
7459
|
+
gap: 10px;
|
|
7460
|
+
min-width: 260px;
|
|
7461
|
+
max-width: min(640px, calc(100vw - 32px));
|
|
7462
|
+
padding: 11px 14px;
|
|
7463
|
+
border-radius: 10px;
|
|
7464
|
+
border: 1px solid rgba(208, 215, 226, 0.88);
|
|
7465
|
+
background: rgba(255, 255, 255, 0.98);
|
|
6986
7466
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
|
|
6987
7467
|
color: var(--text);
|
|
7468
|
+
line-height: 1.45;
|
|
7469
|
+
animation: message-enter 160ms ease;
|
|
6988
7470
|
}
|
|
6989
7471
|
|
|
6990
7472
|
.global-message.success {
|
|
6991
|
-
border-color: rgba(
|
|
7473
|
+
border-color: rgba(22, 163, 74, 0.22);
|
|
6992
7474
|
}
|
|
6993
7475
|
|
|
6994
7476
|
.global-message.error {
|
|
6995
|
-
border-color: rgba(220, 38, 38, 0.
|
|
7477
|
+
border-color: rgba(220, 38, 38, 0.24);
|
|
7478
|
+
}
|
|
7479
|
+
|
|
7480
|
+
.global-message-icon {
|
|
7481
|
+
flex: 0 0 auto;
|
|
7482
|
+
width: 18px;
|
|
7483
|
+
height: 18px;
|
|
7484
|
+
border-radius: 999px;
|
|
7485
|
+
display: inline-flex;
|
|
7486
|
+
align-items: center;
|
|
7487
|
+
justify-content: center;
|
|
7488
|
+
font-size: 12px;
|
|
7489
|
+
font-weight: 700;
|
|
7490
|
+
background: rgba(15, 23, 42, 0.06);
|
|
7491
|
+
}
|
|
7492
|
+
|
|
7493
|
+
.global-message.success .global-message-icon {
|
|
7494
|
+
color: var(--success);
|
|
7495
|
+
background: rgba(22, 163, 74, 0.12);
|
|
7496
|
+
}
|
|
7497
|
+
|
|
7498
|
+
.global-message.error .global-message-icon {
|
|
7499
|
+
color: var(--danger);
|
|
7500
|
+
background: rgba(220, 38, 38, 0.10);
|
|
7501
|
+
}
|
|
7502
|
+
|
|
7503
|
+
.global-message-content {
|
|
7504
|
+
min-width: 0;
|
|
7505
|
+
word-break: break-word;
|
|
7506
|
+
}
|
|
7507
|
+
|
|
7508
|
+
@keyframes message-enter {
|
|
7509
|
+
from {
|
|
7510
|
+
opacity: 0;
|
|
7511
|
+
transform: translateY(-6px);
|
|
7512
|
+
}
|
|
7513
|
+
to {
|
|
7514
|
+
opacity: 1;
|
|
7515
|
+
transform: translateY(0);
|
|
7516
|
+
}
|
|
6996
7517
|
}
|
|
6997
7518
|
|
|
6998
7519
|
.info-list {
|
|
@@ -7210,11 +7731,24 @@ function renderHtml() {
|
|
|
7210
7731
|
display: grid;
|
|
7211
7732
|
}
|
|
7212
7733
|
|
|
7734
|
+
.command-list-head,
|
|
7213
7735
|
.command-item {
|
|
7214
7736
|
display: grid;
|
|
7215
|
-
grid-template-columns:
|
|
7737
|
+
grid-template-columns: 220px 320px minmax(0, 1fr);
|
|
7216
7738
|
gap: 16px;
|
|
7217
7739
|
padding: 10px 14px;
|
|
7740
|
+
align-items: start;
|
|
7741
|
+
}
|
|
7742
|
+
|
|
7743
|
+
.command-list-head {
|
|
7744
|
+
padding-top: 12px;
|
|
7745
|
+
padding-bottom: 8px;
|
|
7746
|
+
color: var(--muted);
|
|
7747
|
+
font-size: 12px;
|
|
7748
|
+
font-weight: 700;
|
|
7749
|
+
text-transform: uppercase;
|
|
7750
|
+
letter-spacing: .04em;
|
|
7751
|
+
background: #fcfcfd;
|
|
7218
7752
|
border-top: 1px solid var(--border);
|
|
7219
7753
|
}
|
|
7220
7754
|
|
|
@@ -7226,6 +7760,15 @@ function renderHtml() {
|
|
|
7226
7760
|
word-break: break-all;
|
|
7227
7761
|
}
|
|
7228
7762
|
|
|
7763
|
+
.command-col-command,
|
|
7764
|
+
.command-col-original {
|
|
7765
|
+
min-width: 0;
|
|
7766
|
+
}
|
|
7767
|
+
|
|
7768
|
+
.command-col-desc {
|
|
7769
|
+
color: #475467;
|
|
7770
|
+
}
|
|
7771
|
+
|
|
7229
7772
|
.channel-tab {
|
|
7230
7773
|
border: 0;
|
|
7231
7774
|
border-bottom: 2px solid transparent;
|
|
@@ -7398,6 +7941,7 @@ function renderHtml() {
|
|
|
7398
7941
|
.field-row,
|
|
7399
7942
|
.field-row.triple,
|
|
7400
7943
|
.command-item,
|
|
7944
|
+
.command-list-head,
|
|
7401
7945
|
.binding-controls { grid-template-columns: 1fr; }
|
|
7402
7946
|
.status-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
7403
7947
|
}
|
|
@@ -7539,7 +8083,7 @@ function renderHtml() {
|
|
|
7539
8083
|
</div>
|
|
7540
8084
|
|
|
7541
8085
|
<section class="panel" id="desktop">
|
|
7542
|
-
<div class="notice">\u8FD9\u91CC\u53EA\u5C55\u793A\u5728 Codex \u684C\u9762\u7D22\u5F15\u91CC\u6709\u540D\u5B57\u7684\u7EBF\u7A0B\uFF0C\u548C
|
|
8086
|
+
<div class="notice">\u8FD9\u91CC\u53EA\u5C55\u793A\u5728 Codex \u684C\u9762\u7D22\u5F15\u91CC\u6709\u540D\u5B57\u7684\u7EBF\u7A0B\uFF0C\u548C Codex Desktop App \u5DE6\u4FA7\u5217\u8868\u4FDD\u6301\u4E00\u81F4\u3002</div>
|
|
7543
8087
|
<div class="notice" style="margin-top: 12px;">\u6700\u77ED\u8DEF\u5F84\uFF1A\u627E\u5230\u76EE\u6807 thread\uFF0C\u7136\u540E\u628A <code>/thread 019d1da4</code> \u8FD9\u6837\u7684\u547D\u4EE4\u53D1\u7ED9\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u6216\u76F4\u63A5\u5230\u201C\u901A\u9053\u201D\u9875\u5207\u6362\u7ED1\u5B9A\u3002</div>
|
|
7544
8088
|
<div class="small" id="desktopSessionMeta" style="margin: 14px 0 16px;">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
7545
8089
|
<div class="session-list" id="desktopSessionsList"></div>
|
|
@@ -7559,7 +8103,7 @@ function renderHtml() {
|
|
|
7559
8103
|
<div class="panel-header">
|
|
7560
8104
|
<div>
|
|
7561
8105
|
<h2>\u57FA\u7840\u914D\u7F6E</h2>
|
|
7562
|
-
<p>\u4FDD\u5B58\u540E\u4F1A\u5199\u5165\u672C\u5730\u914D\u7F6E\u76EE\u5F55\uFF1B\
|
|
8106
|
+
<p>\u4FDD\u5B58\u540E\u4F1A\u5199\u5165\u672C\u5730\u914D\u7F6E\u76EE\u5F55\u3002\u9ED8\u8BA4\u76EE\u5F55\u3001\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u3001Sandbox\u3001\u601D\u8003\u7EA7\u522B\u7B49\u4F1A\u5728\u4E0B\u4E00\u6B21\u8BF7\u6C42\u751F\u6548\uFF1B\u901A\u9053\u542F\u505C\u4F1A\u81EA\u52A8\u540C\u6B65\uFF1B\u53EA\u6709\u5C11\u6570\u8FD0\u884C\u65F6\u914D\u7F6E\u9700\u8981\u91CD\u542F Bridge\u3002</p>
|
|
7563
8107
|
</div>
|
|
7564
8108
|
<div class="toolbar">
|
|
7565
8109
|
<button class="primary" id="saveConfigBtn">\u4FDD\u5B58\u914D\u7F6E</button>
|
|
@@ -7593,10 +8137,36 @@ function renderHtml() {
|
|
|
7593
8137
|
\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55
|
|
7594
8138
|
<input id="defaultWorkDir" placeholder="D:\\workspace\\project" />
|
|
7595
8139
|
</label>
|
|
8140
|
+
<label>
|
|
8141
|
+
\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4
|
|
8142
|
+
<input id="defaultWorkspaceRoot" placeholder="\u7559\u7A7A\u65F6\u4F7F\u7528 ~/cx2im" />
|
|
8143
|
+
</label>
|
|
7596
8144
|
<label>
|
|
7597
8145
|
\u9ED8\u8BA4\u6A21\u578B
|
|
7598
8146
|
<input id="defaultModel" placeholder="\u7559\u7A7A\u5219\u4F7F\u7528 runtime \u9ED8\u8BA4\u6A21\u578B" />
|
|
7599
8147
|
</label>
|
|
8148
|
+
<div class="field-row">
|
|
8149
|
+
<label>
|
|
8150
|
+
Codex \u6587\u4EF6\u7CFB\u7EDF\u6743\u9650
|
|
8151
|
+
<select id="codexSandboxMode">
|
|
8152
|
+
<option value="workspace-write">workspace-write</option>
|
|
8153
|
+
<option value="read-only">read-only</option>
|
|
8154
|
+
<option value="danger-full-access">danger-full-access</option>
|
|
8155
|
+
</select>
|
|
8156
|
+
</label>
|
|
8157
|
+
<label>
|
|
8158
|
+
Codex \u601D\u8003\u7EA7\u522B
|
|
8159
|
+
<select id="codexReasoningEffort">
|
|
8160
|
+
<option value="medium">medium</option>
|
|
8161
|
+
<option value="minimal">minimal</option>
|
|
8162
|
+
<option value="low">low</option>
|
|
8163
|
+
<option value="high">high</option>
|
|
8164
|
+
<option value="xhigh">xhigh</option>
|
|
8165
|
+
</select>
|
|
8166
|
+
</label>
|
|
8167
|
+
</div>
|
|
8168
|
+
<div class="small">\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u201D\u7528\u4E8E\u65B0\u4F1A\u8BDD\u9ED8\u8BA4 cwd\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\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\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>
|
|
8169
|
+
<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>\u3001\u98DE\u4E66 <code>App ID</code>/<code>App Secret</code>/<code>Domain</code>\u3002</div>
|
|
7600
8170
|
<div class="checkbox-row">
|
|
7601
8171
|
<label class="checkbox"><input id="channelFeishu" type="checkbox" checked /> \u542F\u7528\u98DE\u4E66</label>
|
|
7602
8172
|
<label class="checkbox"><input id="channelWeixin" type="checkbox" /> \u542F\u7528\u5FAE\u4FE1</label>
|
|
@@ -7606,6 +8176,28 @@ function renderHtml() {
|
|
|
7606
8176
|
<label class="checkbox"><input id="codexSkipGitRepoCheck" type="checkbox" checked /> \u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</label>
|
|
7607
8177
|
</div>
|
|
7608
8178
|
<div class="small">\u5982\u679C\u65B0\u5EFA\u4F1A\u8BDD\u62A5 \u201CNot inside a trusted directory\u201D\uFF0C\u53EF\u4EE5\u6253\u5F00\u8FD9\u4E2A\u9009\u9879\u3002\u4FEE\u6539\u540E\u9700\u8981\u91CD\u542F Bridge \u624D\u4F1A\u751F\u6548\u3002</div>
|
|
8179
|
+
<div class="checkbox-row" style="margin-top: 12px;">
|
|
8180
|
+
<label class="checkbox"><input id="uiAllowLan" type="checkbox" /> \u5141\u8BB8\u5C40\u57DF\u7F51\u8BBF\u95EE Web \u63A7\u5236\u53F0</label>
|
|
8181
|
+
</div>
|
|
8182
|
+
<div class="notice" id="uiAccessSummary">\u9ED8\u8BA4\u4EC5\u5141\u8BB8\u672C\u673A\u8BBF\u95EE\u5F53\u524D\u5DE5\u4F5C\u53F0\u3002</div>
|
|
8183
|
+
<div id="uiLanDetails" hidden>
|
|
8184
|
+
<div class="field-row" style="margin-top: 16px;">
|
|
8185
|
+
<label>
|
|
8186
|
+
\u8BBF\u95EE token
|
|
8187
|
+
<input id="uiAccessToken" readonly />
|
|
8188
|
+
</label>
|
|
8189
|
+
<div style="display: grid; gap: 10px; align-content: end;">
|
|
8190
|
+
<div class="toolbar">
|
|
8191
|
+
<button type="button" id="copyUiTokenBtn">\u590D\u5236 token</button>
|
|
8192
|
+
<button type="button" id="regenerateUiTokenBtn">\u91CD\u65B0\u751F\u6210 token</button>
|
|
8193
|
+
</div>
|
|
8194
|
+
<div class="toolbar">
|
|
8195
|
+
<button type="button" id="copyUiLanLinkBtn">\u590D\u5236\u5C40\u57DF\u7F51\u767B\u5F55\u94FE\u63A5</button>
|
|
8196
|
+
</div>
|
|
8197
|
+
</div>
|
|
8198
|
+
</div>
|
|
8199
|
+
<div class="info-list" id="uiAccessUrls" style="margin-top: 16px;"></div>
|
|
8200
|
+
</div>
|
|
7609
8201
|
</div>
|
|
7610
8202
|
|
|
7611
8203
|
<div class="message" id="configMessage"></div>
|
|
@@ -7628,45 +8220,42 @@ function renderHtml() {
|
|
|
7628
8220
|
</div>
|
|
7629
8221
|
</div>
|
|
7630
8222
|
|
|
7631
|
-
<div class="notice" style="margin-bottom: 16px;">\u6700\u77ED\u4F7F\u7528\u8DEF\u5F84\uFF1A\u5148\u53D1 <code>/
|
|
8223
|
+
<div class="notice" style="margin-bottom: 16px;">\u6700\u77ED\u4F7F\u7528\u8DEF\u5F84\uFF1A\u5148\u53D1 <code>/t</code> \u67E5\u770B\u6700\u8FD1\u4F1A\u8BDD\uFF0C\u518D\u53D1 <code>/t 1</code> \u63A5\u7BA1\uFF1B\u4E4B\u540E\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002\u8FD9\u91CC\u4FDD\u7559\u539F\u59CB\u547D\u4EE4\uFF0C\u4EC5\u7528\u4E8E\u540E\u53F0\u67E5\u9605\u548C\u517C\u5BB9\u65E7\u7528\u6CD5\u3002</div>
|
|
7632
8224
|
|
|
7633
8225
|
<div class="command-sections">
|
|
7634
8226
|
<section class="command-section">
|
|
7635
8227
|
<h3 class="command-section-title">\u6700\u5E38\u7528</h3>
|
|
7636
8228
|
<div class="command-list">
|
|
7637
|
-
<div class="command-
|
|
7638
|
-
<div class="command-item"><code>/
|
|
7639
|
-
<div class="command-item"><code>/
|
|
7640
|
-
<div class="command-item"><code
|
|
7641
|
-
<div class="command-item"><code>/
|
|
7642
|
-
<div class="command-item"><code>/
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
<section class="command-section">
|
|
7647
|
-
<h3 class="command-section-title">\u5207\u6362\u4E0E\u7ED1\u5B9A</h3>
|
|
7648
|
-
<div class="command-list">
|
|
7649
|
-
<div class="command-item"><code>/sessions</code><div>\u5217\u51FA\u5185\u90E8\u4F1A\u8BDD\u3002</div></div>
|
|
7650
|
-
<div class="command-item"><code>/use <session-id | \u5E8F\u53F7></code><div>\u5207\u6362\u5230\u5DF2\u6709\u5185\u90E8\u4F1A\u8BDD\u3002</div></div>
|
|
7651
|
-
<div class="command-item"><code>/bind <session-id | thread-id | \u5E8F\u53F7></code><div>\u667A\u80FD\u7ED1\u5B9A\uFF0C\u517C\u5BB9\u65E7\u7528\u6CD5\uFF1B\u53EF\u7ED1\u5B9A\u5185\u90E8\u4F1A\u8BDD\u6216\u684C\u9762 thread\u3002</div></div>
|
|
8229
|
+
<div class="command-list-head"><div>\u547D\u4EE4</div><div>\u539F\u59CB\u547D\u4EE4</div><div>\u8BF4\u660E</div></div>
|
|
8230
|
+
<div class="command-item"><div class="command-col-command"><code>/</code></div><div class="command-col-original"><code>/status</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u3002</div></div>
|
|
8231
|
+
<div class="command-item"><div class="command-col-command"><code>/h</code></div><div class="command-col-original"><code>/help</code></div><div class="command-col-desc">\u67E5\u770B\u5E2E\u52A9\u3002</div></div>
|
|
8232
|
+
<div class="command-item"><div class="command-col-command"><code>/t</code></div><div class="command-col-original"><code>/threads</code></div><div class="command-col-desc">\u5217\u51FA\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
|
|
8233
|
+
<div class="command-item"><div class="command-col-command"><code>/t <\u5E8F\u53F7></code></div><div class="command-col-original"><code>/thread <\u5E8F\u53F7></code></div><div class="command-col-desc">\u6309\u5E8F\u53F7\u63A5\u7BA1\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
|
|
8234
|
+
<div class="command-item"><div class="command-col-command"><code>/n [\u7EDD\u5BF9\u8DEF\u5F84 | \u9879\u76EE\u540D]</code></div><div class="command-col-original"><code>/new [\u7EDD\u5BF9\u8DEF\u5F84 | \u9879\u76EE\u540D]</code></div><div class="command-col-desc">\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u76F8\u5BF9\u9879\u76EE\u540D\u4F1A\u5728\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u4E0B\u521B\u5EFA\u76EE\u5F55\u3002</div></div>
|
|
8235
|
+
<div class="command-item"><div class="command-col-command"><code>\u76F4\u63A5\u53D1\u9001\u6587\u672C</code></div><div class="command-col-original">\u2014</div><div class="command-col-desc">\u7EE7\u7EED\u5F53\u524D\u5DF2\u7ED1\u5B9A\u4F1A\u8BDD\u3002</div></div>
|
|
8236
|
+
<div class="command-item"><div class="command-col-command"><code>/his</code></div><div class="command-col-original"><code>/history</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u6574\u7406\u540E\u7684\u6458\u8981\u3002</div></div>
|
|
8237
|
+
<div class="command-item"><div class="command-col-command"><code>/his raw</code></div><div class="command-col-original"><code>/history raw</code></div><div class="command-col-desc">\u67E5\u770B\u6700\u8FD1 N \u6761\u539F\u59CB\u6D88\u606F\u3002</div></div>
|
|
7652
8238
|
</div>
|
|
7653
8239
|
</section>
|
|
7654
8240
|
|
|
7655
8241
|
<section class="command-section">
|
|
7656
|
-
<h3 class="command-section-title">\
|
|
8242
|
+
<h3 class="command-section-title">\u8BBE\u7F6E\u4E0E\u5207\u6362</h3>
|
|
7657
8243
|
<div class="command-list">
|
|
7658
|
-
<div class="command-
|
|
7659
|
-
<div class="command-item"><code>/
|
|
7660
|
-
<div class="command-item"><code>/
|
|
7661
|
-
<div class="command-item"><code>/
|
|
8244
|
+
<div class="command-list-head"><div>\u547D\u4EE4</div><div>\u539F\u59CB\u547D\u4EE4</div><div>\u8BF4\u660E</div></div>
|
|
8245
|
+
<div class="command-item"><div class="command-col-command"><code>/m</code></div><div class="command-col-original"><code>/mode</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u6A21\u5F0F\uFF1B\u53EF\u9009 <code>code</code>\u3001<code>plan</code>\u3001<code>ask</code>\u3002</div></div>
|
|
8246
|
+
<div class="command-item"><div class="command-col-command"><code>/r</code></div><div class="command-col-original"><code>/reasoning</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u601D\u8003\u7EA7\u522B\uFF1B\u53EF\u9009 <code>1=minimal</code>\u3001<code>2=low</code>\u3001<code>3=medium</code>\u3001<code>4=high</code>\u3001<code>5=xhigh</code>\u3002</div></div>
|
|
8247
|
+
<div class="command-item"><div class="command-col-command"><code>/t 0</code></div><div class="command-col-original"><code>/thread 0</code></div><div class="command-col-desc">\u5207\u6362\u5230\u5F53\u524D\u804A\u5929\u7684\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\u3002</div></div>
|
|
8248
|
+
<div class="command-item"><div class="command-col-command"><code>/t 0 reset</code></div><div class="command-col-original"><code>/thread 0 reset</code></div><div class="command-col-desc">\u4E22\u5F03\u5F53\u524D\u8349\u7A3F\u4E0A\u4E0B\u6587\u5E76\u91CD\u5EFA\u4E00\u6761\u65B0\u7684\u8349\u7A3F\u7EBF\u7A0B\u3002</div></div>
|
|
8249
|
+
<div class="command-item"><div class="command-col-command">\u2014</div><div class="command-col-original"><code>/stop</code></div><div class="command-col-desc">\u505C\u6B62\u5F53\u524D\u4EFB\u52A1\u3002</div></div>
|
|
7662
8250
|
</div>
|
|
7663
8251
|
</section>
|
|
7664
8252
|
|
|
7665
8253
|
<section class="command-section">
|
|
7666
8254
|
<h3 class="command-section-title">\u6743\u9650</h3>
|
|
7667
8255
|
<div class="command-list">
|
|
7668
|
-
<div class="command-
|
|
7669
|
-
<div class="command-item"><
|
|
8256
|
+
<div class="command-list-head"><div>\u547D\u4EE4</div><div>\u539F\u59CB\u547D\u4EE4</div><div>\u8BF4\u660E</div></div>
|
|
8257
|
+
<div class="command-item"><div class="command-col-command">\u2014</div><div class="command-col-original"><code>/perm allow|allow_session|deny <id></code></div><div class="command-col-desc">\u6587\u672C\u65B9\u5F0F\u5904\u7406\u4E00\u4E2A\u5F85\u6279\u51C6\u6743\u9650\u3002</div></div>
|
|
8258
|
+
<div class="command-item"><div class="command-col-command"><code>1 / 2 / 3</code></div><div class="command-col-original">\u2014</div><div class="command-col-desc">\u5FEB\u901F\u5904\u7406\u5355\u4E2A\u5F85\u6279\u51C6\u6743\u9650\u3002</div></div>
|
|
7670
8259
|
</div>
|
|
7671
8260
|
</section>
|
|
7672
8261
|
</div>
|
|
@@ -7697,6 +8286,7 @@ function renderHtml() {
|
|
|
7697
8286
|
<div class="toolbar">
|
|
7698
8287
|
<button id="saveFeishuChannelBtn">\u4FDD\u5B58\u901A\u9053\u914D\u7F6E</button>
|
|
7699
8288
|
<button id="testFeishuBtn">\u6D4B\u8BD5\u98DE\u4E66\u51ED\u636E</button>
|
|
8289
|
+
<button id="refreshFeishuStateBtn">\u5237\u65B0\u72B6\u6001</button>
|
|
7700
8290
|
</div>
|
|
7701
8291
|
</div>
|
|
7702
8292
|
|
|
@@ -7724,7 +8314,12 @@ function renderHtml() {
|
|
|
7724
8314
|
<div class="checkbox-row">
|
|
7725
8315
|
<label class="checkbox"><input id="feishuStreamingEnabled" type="checkbox" checked /> \u542F\u7528\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247</label>
|
|
7726
8316
|
</div>
|
|
8317
|
+
<div class="checkbox-row">
|
|
8318
|
+
<label class="checkbox"><input id="feishuCommandMarkdownEnabled" type="checkbox" checked /> \u547D\u4EE4\u53CD\u9988\u4F7F\u7528 Markdown</label>
|
|
8319
|
+
</div>
|
|
7727
8320
|
<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>
|
|
8321
|
+
<div class="small">\u53EA\u5F71\u54CD <code>/h</code>\u3001<code>/status</code>\u3001<code>/threads</code> \u8FD9\u7C7B\u7CFB\u7EDF\u53CD\u9988\uFF0C\u4E0D\u5F71\u54CD Codex \u539F\u59CB\u56DE\u590D\u3002</div>
|
|
8322
|
+
<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>
|
|
7728
8323
|
</div>
|
|
7729
8324
|
|
|
7730
8325
|
<div class="panel-block">
|
|
@@ -7751,6 +8346,7 @@ function renderHtml() {
|
|
|
7751
8346
|
<div class="toolbar">
|
|
7752
8347
|
<button id="saveWeixinChannelBtn">\u4FDD\u5B58\u901A\u9053\u914D\u7F6E</button>
|
|
7753
8348
|
<button id="weixinLoginBtn">\u5F00\u59CB\u5FAE\u4FE1\u626B\u7801</button>
|
|
8349
|
+
<button id="refreshWeixinStateBtn">\u5237\u65B0\u72B6\u6001</button>
|
|
7754
8350
|
</div>
|
|
7755
8351
|
</div>
|
|
7756
8352
|
|
|
@@ -7758,7 +8354,11 @@ function renderHtml() {
|
|
|
7758
8354
|
<div class="checkbox-row">
|
|
7759
8355
|
<label class="checkbox"><input id="weixinMediaEnabled" type="checkbox" /> \u542F\u7528\u56FE\u7247 / \u6587\u4EF6 / \u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D</label>
|
|
7760
8356
|
</div>
|
|
8357
|
+
<div class="checkbox-row">
|
|
8358
|
+
<label class="checkbox"><input id="weixinCommandMarkdownEnabled" type="checkbox" /> \u547D\u4EE4\u53CD\u9988\u4F7F\u7528 Markdown</label>
|
|
8359
|
+
</div>
|
|
7761
8360
|
</div>
|
|
8361
|
+
<div class="small">\u53EA\u5F71\u54CD <code>/h</code>\u3001<code>/status</code>\u3001<code>/threads</code> \u8FD9\u7C7B\u7CFB\u7EDF\u53CD\u9988\uFF0C\u4E0D\u5F71\u54CD Codex \u539F\u59CB\u56DE\u590D\u3002\u9ED8\u8BA4\u5173\u95ED\u3002</div>
|
|
7762
8362
|
<div class="panel-block">
|
|
7763
8363
|
<p class="panel-subtitle">\u901A\u9053\u72B6\u6001</p>
|
|
7764
8364
|
<div class="small" id="weixinRuntimeMeta">\u6B63\u5728\u52A0\u8F7D\u2026</div>
|
|
@@ -7801,6 +8401,7 @@ function renderHtml() {
|
|
|
7801
8401
|
<script>
|
|
7802
8402
|
const state = {
|
|
7803
8403
|
config: null,
|
|
8404
|
+
uiAccess: null,
|
|
7804
8405
|
bridgeStatus: null,
|
|
7805
8406
|
desktopSessions: [],
|
|
7806
8407
|
bindings: [],
|
|
@@ -7890,8 +8491,13 @@ function renderHtml() {
|
|
|
7890
8491
|
defaultMode: document.getElementById('defaultMode').value,
|
|
7891
8492
|
historyMessageLimit: document.getElementById('historyMessageLimit').value,
|
|
7892
8493
|
defaultWorkDir: document.getElementById('defaultWorkDir').value,
|
|
8494
|
+
defaultWorkspaceRoot: document.getElementById('defaultWorkspaceRoot').value,
|
|
7893
8495
|
defaultModel: document.getElementById('defaultModel').value,
|
|
7894
8496
|
codexSkipGitRepoCheck: document.getElementById('codexSkipGitRepoCheck').checked,
|
|
8497
|
+
codexSandboxMode: document.getElementById('codexSandboxMode').value,
|
|
8498
|
+
codexReasoningEffort: document.getElementById('codexReasoningEffort').value,
|
|
8499
|
+
uiAllowLan: document.getElementById('uiAllowLan').checked,
|
|
8500
|
+
uiAccessToken: document.getElementById('uiAccessToken').value,
|
|
7895
8501
|
enabledChannels: enabledChannelsFromForm(),
|
|
7896
8502
|
autoApprove: document.getElementById('autoApprove').checked,
|
|
7897
8503
|
feishuAppId: document.getElementById('feishuAppId').value,
|
|
@@ -7899,15 +8505,19 @@ function renderHtml() {
|
|
|
7899
8505
|
feishuDomain: document.getElementById('feishuDomain').value,
|
|
7900
8506
|
feishuAllowedUsers: document.getElementById('feishuAllowedUsers').value,
|
|
7901
8507
|
feishuStreamingEnabled: document.getElementById('feishuStreamingEnabled').checked,
|
|
8508
|
+
feishuCommandMarkdownEnabled: document.getElementById('feishuCommandMarkdownEnabled').checked,
|
|
7902
8509
|
weixinMediaEnabled: document.getElementById('weixinMediaEnabled').checked,
|
|
8510
|
+
weixinCommandMarkdownEnabled: document.getElementById('weixinCommandMarkdownEnabled').checked,
|
|
7903
8511
|
};
|
|
7904
8512
|
}
|
|
7905
8513
|
|
|
7906
8514
|
function showMessage(id, type, message) {
|
|
7907
8515
|
const node = document.getElementById(id);
|
|
7908
|
-
if (
|
|
7909
|
-
|
|
7910
|
-
|
|
8516
|
+
if (node) {
|
|
8517
|
+
node.className = 'message';
|
|
8518
|
+
node.textContent = '';
|
|
8519
|
+
}
|
|
8520
|
+
showGlobalMessage(type, message);
|
|
7911
8521
|
}
|
|
7912
8522
|
|
|
7913
8523
|
function showGlobalMessage(type, message) {
|
|
@@ -7916,7 +8526,16 @@ function renderHtml() {
|
|
|
7916
8526
|
|
|
7917
8527
|
const item = document.createElement('div');
|
|
7918
8528
|
item.className = 'global-message ' + (type || 'success');
|
|
7919
|
-
|
|
8529
|
+
const icon = document.createElement('span');
|
|
8530
|
+
icon.className = 'global-message-icon';
|
|
8531
|
+
icon.textContent = type === 'error' ? '!' : '\u2713';
|
|
8532
|
+
|
|
8533
|
+
const content = document.createElement('div');
|
|
8534
|
+
content.className = 'global-message-content';
|
|
8535
|
+
content.textContent = message;
|
|
8536
|
+
|
|
8537
|
+
item.appendChild(icon);
|
|
8538
|
+
item.appendChild(content);
|
|
7920
8539
|
host.appendChild(item);
|
|
7921
8540
|
|
|
7922
8541
|
window.setTimeout(() => {
|
|
@@ -8043,11 +8662,136 @@ function renderHtml() {
|
|
|
8043
8662
|
return Boolean(state.bridgeStatus && state.bridgeStatus.running && runningChannels().includes(channelType));
|
|
8044
8663
|
}
|
|
8045
8664
|
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8665
|
+
const CONFIG_FIELD_LABELS = {
|
|
8666
|
+
runtime: 'Runtime',
|
|
8667
|
+
enabledChannels: '\u901A\u9053\u542F\u7528\u72B6\u6001',
|
|
8668
|
+
defaultWorkDir: '\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55',
|
|
8669
|
+
defaultWorkspaceRoot: '\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4',
|
|
8670
|
+
defaultModel: '\u9ED8\u8BA4\u6A21\u578B',
|
|
8671
|
+
defaultMode: '\u9ED8\u8BA4\u6A21\u5F0F',
|
|
8672
|
+
historyMessageLimit: '/history \u8FD4\u56DE\u6761\u6570',
|
|
8673
|
+
codexSkipGitRepoCheck: '\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex',
|
|
8674
|
+
codexSandboxMode: 'Codex \u6587\u4EF6\u7CFB\u7EDF\u6743\u9650',
|
|
8675
|
+
codexReasoningEffort: 'Codex \u601D\u8003\u7EA7\u522B',
|
|
8676
|
+
uiAllowLan: '\u5141\u8BB8\u5C40\u57DF\u7F51\u8BBF\u95EE Web \u63A7\u5236\u53F0',
|
|
8677
|
+
uiAccessToken: '\u5C40\u57DF\u7F51\u8BBF\u95EE token',
|
|
8678
|
+
autoApprove: '\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650',
|
|
8679
|
+
feishuAppId: '\u98DE\u4E66 App ID',
|
|
8680
|
+
feishuAppSecret: '\u98DE\u4E66 App Secret',
|
|
8681
|
+
feishuDomain: '\u98DE\u4E66 Domain',
|
|
8682
|
+
feishuAllowedUsers: '\u98DE\u4E66 Allowed Users',
|
|
8683
|
+
feishuStreamingEnabled: '\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247',
|
|
8684
|
+
feishuCommandMarkdownEnabled: '\u98DE\u4E66\u547D\u4EE4 Markdown',
|
|
8685
|
+
weixinMediaEnabled: '\u5FAE\u4FE1\u56FE\u7247/\u6587\u4EF6/\u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D',
|
|
8686
|
+
weixinCommandMarkdownEnabled: '\u5FAE\u4FE1\u547D\u4EE4 Markdown',
|
|
8687
|
+
};
|
|
8688
|
+
|
|
8689
|
+
const BRIDGE_RESTART_FIELDS = new Set([
|
|
8690
|
+
'runtime',
|
|
8691
|
+
'codexSkipGitRepoCheck',
|
|
8692
|
+
'autoApprove',
|
|
8693
|
+
'feishuAppId',
|
|
8694
|
+
'feishuAppSecret',
|
|
8695
|
+
'feishuDomain',
|
|
8696
|
+
]);
|
|
8697
|
+
|
|
8698
|
+
const AUTO_SYNC_FIELDS = new Set([
|
|
8699
|
+
'enabledChannels',
|
|
8700
|
+
]);
|
|
8701
|
+
|
|
8702
|
+
const IMMEDIATE_FIELDS = new Set([
|
|
8703
|
+
'defaultWorkDir',
|
|
8704
|
+
'defaultWorkspaceRoot',
|
|
8705
|
+
'defaultModel',
|
|
8706
|
+
'defaultMode',
|
|
8707
|
+
'historyMessageLimit',
|
|
8708
|
+
'codexSandboxMode',
|
|
8709
|
+
'codexReasoningEffort',
|
|
8710
|
+
'uiAllowLan',
|
|
8711
|
+
'uiAccessToken',
|
|
8712
|
+
'feishuAllowedUsers',
|
|
8713
|
+
'feishuStreamingEnabled',
|
|
8714
|
+
'feishuCommandMarkdownEnabled',
|
|
8715
|
+
'weixinMediaEnabled',
|
|
8716
|
+
'weixinCommandMarkdownEnabled',
|
|
8717
|
+
]);
|
|
8718
|
+
|
|
8719
|
+
const SAVE_SCOPE_FIELDS = {
|
|
8720
|
+
all: null,
|
|
8721
|
+
feishu: new Set([
|
|
8722
|
+
'enabledChannels',
|
|
8723
|
+
'feishuAppId',
|
|
8724
|
+
'feishuAppSecret',
|
|
8725
|
+
'feishuDomain',
|
|
8726
|
+
'feishuAllowedUsers',
|
|
8727
|
+
'feishuStreamingEnabled',
|
|
8728
|
+
'feishuCommandMarkdownEnabled',
|
|
8729
|
+
]),
|
|
8730
|
+
weixin: new Set([
|
|
8731
|
+
'enabledChannels',
|
|
8732
|
+
'weixinMediaEnabled',
|
|
8733
|
+
'weixinCommandMarkdownEnabled',
|
|
8734
|
+
]),
|
|
8735
|
+
};
|
|
8736
|
+
|
|
8737
|
+
function normalizeConfigValue(value) {
|
|
8738
|
+
if (Array.isArray(value)) {
|
|
8739
|
+
return value.slice().map((item) => String(item)).sort().join('|');
|
|
8740
|
+
}
|
|
8741
|
+
if (value === undefined || value === null) return '';
|
|
8742
|
+
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
8743
|
+
return String(value);
|
|
8744
|
+
}
|
|
8745
|
+
|
|
8746
|
+
function listChangedConfigFields(before, after, scope) {
|
|
8747
|
+
const allowedFields = SAVE_SCOPE_FIELDS[scope] || null;
|
|
8748
|
+
const keys = new Set([
|
|
8749
|
+
...Object.keys(before || {}),
|
|
8750
|
+
...Object.keys(after || {}),
|
|
8751
|
+
]);
|
|
8752
|
+
|
|
8753
|
+
return Array.from(keys).filter((key) => {
|
|
8754
|
+
if (allowedFields && !allowedFields.has(key)) return false;
|
|
8755
|
+
return normalizeConfigValue(before ? before[key] : undefined) !== normalizeConfigValue(after ? after[key] : undefined);
|
|
8756
|
+
});
|
|
8757
|
+
}
|
|
8758
|
+
|
|
8759
|
+
function formatFieldLabels(fields) {
|
|
8760
|
+
return fields
|
|
8761
|
+
.map((field) => CONFIG_FIELD_LABELS[field] || field)
|
|
8762
|
+
.join('\u3001');
|
|
8763
|
+
}
|
|
8764
|
+
|
|
8765
|
+
function buildConfigSaveMessage(before, after, scope) {
|
|
8766
|
+
const changed = listChangedConfigFields(before, after, scope);
|
|
8767
|
+
if (changed.length === 0) {
|
|
8768
|
+
return '\u914D\u7F6E\u672A\u53D8\u66F4\u3002';
|
|
8769
|
+
}
|
|
8770
|
+
|
|
8771
|
+
const restartFields = changed.filter((field) => BRIDGE_RESTART_FIELDS.has(field));
|
|
8772
|
+
const autoSyncFields = changed.filter((field) => AUTO_SYNC_FIELDS.has(field));
|
|
8773
|
+
const immediateFields = changed.filter((field) => IMMEDIATE_FIELDS.has(field));
|
|
8774
|
+
const notes = [];
|
|
8775
|
+
|
|
8776
|
+
if (immediateFields.length > 0) {
|
|
8777
|
+
notes.push('\u5DF2\u5373\u65F6\u751F\u6548\uFF1A' + formatFieldLabels(immediateFields));
|
|
8778
|
+
}
|
|
8779
|
+
if (autoSyncFields.length > 0) {
|
|
8780
|
+
notes.push(
|
|
8781
|
+
(state.bridgeStatus && state.bridgeStatus.running)
|
|
8782
|
+
? '\u4F1A\u5728\u51E0\u79D2\u5185\u81EA\u52A8\u540C\u6B65\uFF1A' + formatFieldLabels(autoSyncFields)
|
|
8783
|
+
: '\u4F1A\u5728\u4E0B\u6B21\u542F\u52A8 Bridge \u65F6\u751F\u6548\uFF1A' + formatFieldLabels(autoSyncFields),
|
|
8784
|
+
);
|
|
8785
|
+
}
|
|
8786
|
+
if (restartFields.length > 0) {
|
|
8787
|
+
notes.push(
|
|
8788
|
+
(state.bridgeStatus && state.bridgeStatus.running)
|
|
8789
|
+
? '\u9700\u8981\u91CD\u542F Bridge \u540E\u751F\u6548\uFF1A' + formatFieldLabels(restartFields)
|
|
8790
|
+
: '\u4F1A\u5728\u4E0B\u6B21\u542F\u52A8 Bridge \u65F6\u751F\u6548\uFF1A' + formatFieldLabels(restartFields),
|
|
8791
|
+
);
|
|
8792
|
+
}
|
|
8793
|
+
|
|
8794
|
+
return '\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002' + (notes.length > 0 ? ' ' + notes.join('\uFF1B') + '\u3002' : '');
|
|
8051
8795
|
}
|
|
8052
8796
|
|
|
8053
8797
|
function channelLabel(channelType) {
|
|
@@ -8063,7 +8807,7 @@ function renderHtml() {
|
|
|
8063
8807
|
return label + '\u5DF2\u542F\u7528\uFF0C\u4F46 Bridge \u8FD8\u6CA1\u542F\u52A8\u3002\u542F\u52A8 Bridge \u540E\u624D\u4F1A\u771F\u6B63\u63A5\u901A\u3002';
|
|
8064
8808
|
}
|
|
8065
8809
|
if (!isChannelRunning(channelType)) {
|
|
8066
|
-
return label + '\u5DF2\u5199\u5165\u914D\u7F6E\
|
|
8810
|
+
return label + '\u5DF2\u5199\u5165\u914D\u7F6E\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';
|
|
8067
8811
|
}
|
|
8068
8812
|
return label + '\u5DF2\u63A5\u901A\u5230\u5F53\u524D\u8FD0\u884C\u4E2D\u7684 Bridge\u3002';
|
|
8069
8813
|
}
|
|
@@ -8077,7 +8821,7 @@ function renderHtml() {
|
|
|
8077
8821
|
return label + '\u5DF2\u542F\u7528\uFF0C\u4F46 Bridge \u8FD8\u6CA1\u542F\u52A8\u3002\u542F\u52A8\u540E\u624D\u4F1A\u521B\u5EFA\u7ED1\u5B9A\u3002';
|
|
8078
8822
|
}
|
|
8079
8823
|
if (!isChannelRunning(channelType)) {
|
|
8080
|
-
return label + '\u5DF2\u542F\u7528\
|
|
8824
|
+
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';
|
|
8081
8825
|
}
|
|
8082
8826
|
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';
|
|
8083
8827
|
}
|
|
@@ -8091,7 +8835,7 @@ function renderHtml() {
|
|
|
8091
8835
|
return { disabled: true, title: 'Bridge \u8FD8\u6CA1\u542F\u52A8\u3002\u542F\u52A8\u540E\u518D\u5207\u6362' + label + '\u4F1A\u8BDD\u3002' };
|
|
8092
8836
|
}
|
|
8093
8837
|
if (!isChannelRunning(channelType)) {
|
|
8094
|
-
return { disabled: true, title: label + '\u5DF2\u5199\u5165\u914D\u7F6E\
|
|
8838
|
+
return { disabled: true, title: label + '\u5DF2\u5199\u5165\u914D\u7F6E\uFF0CBridge \u4F1A\u5728\u51E0\u79D2\u5185\u81EA\u52A8\u540C\u6B65\uFF1B\u540C\u6B65\u5B8C\u6210\u540E\u518D\u5207\u6362\u4F1A\u8BDD\u3002' };
|
|
8095
8839
|
}
|
|
8096
8840
|
|
|
8097
8841
|
const bindings = state.bindings.filter((item) => item.channelType === channelType);
|
|
@@ -8128,6 +8872,30 @@ function renderHtml() {
|
|
|
8128
8872
|
return marks;
|
|
8129
8873
|
}
|
|
8130
8874
|
|
|
8875
|
+
function bindingRuntimeText(binding) {
|
|
8876
|
+
const status = binding.runtimeStatus || 'idle';
|
|
8877
|
+
const queuedCount = Number(binding.queuedCount || 0);
|
|
8878
|
+
if (status === 'queued') {
|
|
8879
|
+
return queuedCount > 0 ? '\u6392\u961F\u4E2D\uFF08' + queuedCount + '\uFF09' : '\u6392\u961F\u4E2D';
|
|
8880
|
+
}
|
|
8881
|
+
if (status === 'running') {
|
|
8882
|
+
return '\u8FD0\u884C\u4E2D';
|
|
8883
|
+
}
|
|
8884
|
+
return '\u7A7A\u95F2';
|
|
8885
|
+
}
|
|
8886
|
+
|
|
8887
|
+
function bindingMirrorText(binding) {
|
|
8888
|
+
if (binding.mirrorStatus === 'watching') {
|
|
8889
|
+
return binding.mirrorLastEventAt
|
|
8890
|
+
? '\u76D1\u542C\u4E2D \xB7 \u6700\u8FD1\u540C\u6B65 ' + formatTime(binding.mirrorLastEventAt)
|
|
8891
|
+
: '\u76D1\u542C\u4E2D';
|
|
8892
|
+
}
|
|
8893
|
+
if (binding.mirrorStatus === 'stale') {
|
|
8894
|
+
return '\u5F85\u6062\u590D\uFF08\u6682\u65F6\u6CA1\u5B9A\u4F4D\u5230\u684C\u9762 thread \u6587\u4EF6\uFF09';
|
|
8895
|
+
}
|
|
8896
|
+
return '\u672A\u76D1\u542C';
|
|
8897
|
+
}
|
|
8898
|
+
|
|
8131
8899
|
function renderDesktopSessionCard(session) {
|
|
8132
8900
|
const feishuSwitch = quickSwitchState('feishu');
|
|
8133
8901
|
const weixinSwitch = quickSwitchState('weixin');
|
|
@@ -8171,7 +8939,7 @@ function renderHtml() {
|
|
|
8171
8939
|
|
|
8172
8940
|
const list = document.getElementById('desktopSessionsList');
|
|
8173
8941
|
if (state.desktopSessions.length === 0) {
|
|
8174
|
-
list.innerHTML = '<div class="notice ghost">\u5F53\u524D\u6CA1\u6709\u53D1\u73B0\u684C\u9762\u7AEF\u4F1A\u8BDD\u3002\u5148\u5728 Codex
|
|
8942
|
+
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>';
|
|
8175
8943
|
rerenderBindingPanels();
|
|
8176
8944
|
return;
|
|
8177
8945
|
}
|
|
@@ -8240,6 +9008,8 @@ function renderHtml() {
|
|
|
8240
9008
|
+ '<div class="binding-detail">\u5F53\u524D\u4F1A\u8BDD\uFF1A<code>' + escapeHtml(binding.currentSessionId.slice(0, 8)) + '...</code> \xB7 ' + escapeHtml(binding.currentSessionName) + '</div>'
|
|
8241
9009
|
+ '<div class="binding-detail">\u5F53\u524D\u76EE\u6807\uFF1A' + escapeHtml(binding.currentTargetLabel || '\u672A\u7ED1\u5B9A') + '</div>'
|
|
8242
9010
|
+ '<div class="binding-detail">\u5F53\u524D thread\uFF1A<code>' + escapeHtml(binding.currentThreadId || 'not-shared') + '</code></div>'
|
|
9011
|
+
+ '<div class="binding-detail">\u8FD0\u884C\u72B6\u6001\uFF1A' + escapeHtml(bindingRuntimeText(binding)) + '</div>'
|
|
9012
|
+
+ '<div class="binding-detail">\u5171\u4EAB\u955C\u50CF\uFF1A' + escapeHtml(bindingMirrorText(binding)) + '</div>'
|
|
8243
9013
|
+ '<div class="binding-detail">\u76EE\u5F55\uFF1A' + escapeHtml(binding.workingDirectory || '~') + '</div>'
|
|
8244
9014
|
+ renderBindingTable(binding)
|
|
8245
9015
|
+ '</article>';
|
|
@@ -8291,14 +9061,63 @@ function renderHtml() {
|
|
|
8291
9061
|
rerenderDesktopSessions();
|
|
8292
9062
|
}
|
|
8293
9063
|
|
|
9064
|
+
function renderUiAccess() {
|
|
9065
|
+
const config = state.config || {};
|
|
9066
|
+
const uiAccess = state.uiAccess || {};
|
|
9067
|
+
const allowLan = config.uiAllowLan === true;
|
|
9068
|
+
const token = config.uiAccessToken || '';
|
|
9069
|
+
const lanUrls = Array.isArray(uiAccess.lanUrls) ? uiAccess.lanUrls : [];
|
|
9070
|
+
const localUrl = uiAccess.localUrl || window.location.origin;
|
|
9071
|
+
const summary = document.getElementById('uiAccessSummary');
|
|
9072
|
+
const details = document.getElementById('uiLanDetails');
|
|
9073
|
+
const tokenInput = document.getElementById('uiAccessToken');
|
|
9074
|
+
const urlList = document.getElementById('uiAccessUrls');
|
|
9075
|
+
const copyTokenBtn = document.getElementById('copyUiTokenBtn');
|
|
9076
|
+
const copyLanLinkBtn = document.getElementById('copyUiLanLinkBtn');
|
|
9077
|
+
|
|
9078
|
+
document.getElementById('uiAllowLan').checked = allowLan;
|
|
9079
|
+
tokenInput.value = token;
|
|
9080
|
+
details.hidden = !allowLan;
|
|
9081
|
+
copyTokenBtn.disabled = !allowLan || !token;
|
|
9082
|
+
copyLanLinkBtn.disabled = !allowLan || !token || lanUrls.length === 0;
|
|
9083
|
+
|
|
9084
|
+
if (!allowLan) {
|
|
9085
|
+
summary.textContent = '\u9ED8\u8BA4\u4EC5\u5141\u8BB8\u672C\u673A\u8BBF\u95EE\u5F53\u524D\u5DE5\u4F5C\u53F0\u3002\u5F00\u542F\u540E\uFF0C\u5C40\u57DF\u7F51\u8BBE\u5907\u9700\u8981\u5148\u8F93\u5165\u8BBF\u95EE token\u3002';
|
|
9086
|
+
urlList.innerHTML = '';
|
|
9087
|
+
return;
|
|
9088
|
+
}
|
|
9089
|
+
|
|
9090
|
+
summary.textContent = '\u5C40\u57DF\u7F51\u8BBF\u95EE\u5DF2\u5F00\u542F\u3002\u975E\u672C\u673A\u8BBE\u5907\u8BBF\u95EE\u65F6\u9700\u8981\u5148\u8F93\u5165 token\uFF1B\u672C\u673A\u8BBF\u95EE\u4ECD\u7136\u4E0D\u53D7\u5F71\u54CD\u3002';
|
|
9091
|
+
const items = [
|
|
9092
|
+
'<div class="info-item"><strong>\u672C\u673A\u5730\u5740</strong><div class="mono">' + escapeHtml(localUrl) + '</div></div>',
|
|
9093
|
+
];
|
|
9094
|
+
|
|
9095
|
+
if (lanUrls.length === 0) {
|
|
9096
|
+
items.push('<div class="info-item"><strong>\u5C40\u57DF\u7F51\u5730\u5740</strong><div>\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u7684 IPv4 \u5730\u5740\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u3002</div></div>');
|
|
9097
|
+
} else {
|
|
9098
|
+
for (const lanUrl of lanUrls) {
|
|
9099
|
+
items.push(
|
|
9100
|
+
'<div class="info-item"><strong>\u5C40\u57DF\u7F51\u5730\u5740</strong><div class="mono">' + escapeHtml(lanUrl) + '</div><div class="small">\u767B\u5F55\u94FE\u63A5\uFF1A' + escapeHtml(lanUrl + '/?token=' + token) + '</div></div>'
|
|
9101
|
+
);
|
|
9102
|
+
}
|
|
9103
|
+
}
|
|
9104
|
+
|
|
9105
|
+
urlList.innerHTML = items.join('');
|
|
9106
|
+
}
|
|
9107
|
+
|
|
8294
9108
|
function fillForm(config) {
|
|
8295
9109
|
state.config = config;
|
|
8296
9110
|
document.getElementById('runtime').value = config.runtime || 'codex';
|
|
8297
9111
|
document.getElementById('defaultMode').value = config.defaultMode || 'code';
|
|
8298
9112
|
document.getElementById('historyMessageLimit').value = String(config.historyMessageLimit || 8);
|
|
8299
9113
|
document.getElementById('defaultWorkDir').value = config.defaultWorkDir || '';
|
|
9114
|
+
document.getElementById('defaultWorkspaceRoot').value = config.defaultWorkspaceRoot || '';
|
|
8300
9115
|
document.getElementById('defaultModel').value = config.defaultModel || '';
|
|
8301
9116
|
document.getElementById('codexSkipGitRepoCheck').checked = config.codexSkipGitRepoCheck === true;
|
|
9117
|
+
document.getElementById('codexSandboxMode').value = config.codexSandboxMode || 'workspace-write';
|
|
9118
|
+
document.getElementById('codexReasoningEffort').value = config.codexReasoningEffort || 'medium';
|
|
9119
|
+
document.getElementById('uiAllowLan').checked = config.uiAllowLan === true;
|
|
9120
|
+
document.getElementById('uiAccessToken').value = config.uiAccessToken || '';
|
|
8302
9121
|
document.getElementById('channelFeishu').checked = (config.enabledChannels || []).includes('feishu');
|
|
8303
9122
|
document.getElementById('channelWeixin').checked = (config.enabledChannels || []).includes('weixin');
|
|
8304
9123
|
document.getElementById('autoApprove').checked = config.autoApprove === true;
|
|
@@ -8307,7 +9126,10 @@ function renderHtml() {
|
|
|
8307
9126
|
document.getElementById('feishuDomain').value = config.feishuDomain || 'https://open.feishu.cn';
|
|
8308
9127
|
document.getElementById('feishuAllowedUsers').value = config.feishuAllowedUsers || '';
|
|
8309
9128
|
document.getElementById('feishuStreamingEnabled').checked = config.feishuStreamingEnabled !== false;
|
|
9129
|
+
document.getElementById('feishuCommandMarkdownEnabled').checked = config.feishuCommandMarkdownEnabled !== false;
|
|
8310
9130
|
document.getElementById('weixinMediaEnabled').checked = config.weixinMediaEnabled === true;
|
|
9131
|
+
document.getElementById('weixinCommandMarkdownEnabled').checked = config.weixinCommandMarkdownEnabled === true;
|
|
9132
|
+
renderUiAccess();
|
|
8311
9133
|
rerenderDesktopSessions();
|
|
8312
9134
|
}
|
|
8313
9135
|
|
|
@@ -8326,6 +9148,7 @@ function renderHtml() {
|
|
|
8326
9148
|
async function loadStatus() {
|
|
8327
9149
|
const status = await api('/api/status');
|
|
8328
9150
|
const config = await api('/api/config');
|
|
9151
|
+
state.uiAccess = status.uiAccess || null;
|
|
8329
9152
|
state.bridgeStatus = status.bridge || null;
|
|
8330
9153
|
state.weixinAccounts = status.weixin && Array.isArray(status.weixin.linkedAccounts) ? status.weixin.linkedAccounts : [];
|
|
8331
9154
|
fillForm(config);
|
|
@@ -8360,19 +9183,21 @@ function renderHtml() {
|
|
|
8360
9183
|
renderBindings(result);
|
|
8361
9184
|
}
|
|
8362
9185
|
|
|
8363
|
-
async function saveConfig() {
|
|
9186
|
+
async function saveConfig(options) {
|
|
9187
|
+
const opts = options || {};
|
|
9188
|
+
const beforeConfig = state.config || {};
|
|
8364
9189
|
const saved = await api('/api/config', {
|
|
8365
9190
|
method: 'POST',
|
|
8366
9191
|
body: JSON.stringify(formPayload()),
|
|
8367
9192
|
});
|
|
8368
9193
|
fillForm(saved.config);
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
9194
|
+
if (opts.messageId) {
|
|
9195
|
+
showMessage(
|
|
9196
|
+
opts.messageId,
|
|
9197
|
+
'success',
|
|
9198
|
+
buildConfigSaveMessage(beforeConfig, saved.config, opts.scope || 'all'),
|
|
9199
|
+
);
|
|
9200
|
+
}
|
|
8376
9201
|
return saved;
|
|
8377
9202
|
}
|
|
8378
9203
|
|
|
@@ -8391,9 +9216,41 @@ function renderHtml() {
|
|
|
8391
9216
|
|
|
8392
9217
|
window.addEventListener('hashchange', syncPageFromHash);
|
|
8393
9218
|
|
|
9219
|
+
document.getElementById('copyUiTokenBtn').addEventListener('click', async () => {
|
|
9220
|
+
try {
|
|
9221
|
+
await copyText(document.getElementById('uiAccessToken').value, '\u8BBF\u95EE token \u5DF2\u590D\u5236\u3002');
|
|
9222
|
+
} catch (error) {
|
|
9223
|
+
showMessage('configMessage', 'error', error.message);
|
|
9224
|
+
}
|
|
9225
|
+
});
|
|
9226
|
+
|
|
9227
|
+
document.getElementById('copyUiLanLinkBtn').addEventListener('click', async () => {
|
|
9228
|
+
try {
|
|
9229
|
+
const urls = state.uiAccess && Array.isArray(state.uiAccess.lanUrls) ? state.uiAccess.lanUrls : [];
|
|
9230
|
+
const token = document.getElementById('uiAccessToken').value;
|
|
9231
|
+
if (!urls.length || !token) {
|
|
9232
|
+
throw new Error('\u5F53\u524D\u8FD8\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5C40\u57DF\u7F51\u767B\u5F55\u94FE\u63A5\u3002');
|
|
9233
|
+
}
|
|
9234
|
+
await copyText(urls[0] + '/?token=' + token, '\u5C40\u57DF\u7F51\u767B\u5F55\u94FE\u63A5\u5DF2\u590D\u5236\u3002');
|
|
9235
|
+
} catch (error) {
|
|
9236
|
+
showMessage('configMessage', 'error', error.message);
|
|
9237
|
+
}
|
|
9238
|
+
});
|
|
9239
|
+
|
|
9240
|
+
document.getElementById('regenerateUiTokenBtn').addEventListener('click', () => {
|
|
9241
|
+
if (!window.crypto || typeof window.crypto.randomUUID !== 'function') {
|
|
9242
|
+
showMessage('configMessage', 'error', '\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u751F\u6210 token\u3002');
|
|
9243
|
+
return;
|
|
9244
|
+
}
|
|
9245
|
+
document.getElementById('uiAccessToken').value =
|
|
9246
|
+
window.crypto.randomUUID().replaceAll('-', '') + window.crypto.randomUUID().replaceAll('-', '');
|
|
9247
|
+
renderUiAccess();
|
|
9248
|
+
showMessage('configMessage', 'success', '\u5DF2\u751F\u6210\u65B0\u7684\u8BBF\u95EE token\uFF0C\u70B9\u51FB\u201C\u4FDD\u5B58\u914D\u7F6E\u201D\u540E\u751F\u6548\u3002');
|
|
9249
|
+
});
|
|
9250
|
+
|
|
8394
9251
|
document.getElementById('saveConfigBtn').addEventListener('click', async () => {
|
|
8395
9252
|
try {
|
|
8396
|
-
await saveConfig();
|
|
9253
|
+
await saveConfig({ messageId: 'configMessage', scope: 'all' });
|
|
8397
9254
|
await loadStatus();
|
|
8398
9255
|
await loadBindings();
|
|
8399
9256
|
} catch (error) {
|
|
@@ -8403,16 +9260,9 @@ function renderHtml() {
|
|
|
8403
9260
|
|
|
8404
9261
|
document.getElementById('saveFeishuChannelBtn').addEventListener('click', async () => {
|
|
8405
9262
|
try {
|
|
8406
|
-
await saveConfig();
|
|
9263
|
+
await saveConfig({ messageId: 'feishuMessage', scope: 'feishu' });
|
|
8407
9264
|
await loadStatus();
|
|
8408
9265
|
await loadBindings();
|
|
8409
|
-
showMessage(
|
|
8410
|
-
'feishuMessage',
|
|
8411
|
-
'success',
|
|
8412
|
-
bridgeNeedsRestart()
|
|
8413
|
-
? '\u98DE\u4E66\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002\u5F53\u524D Bridge \u8FD8\u5728\u4F7F\u7528\u65E7\u901A\u9053\u914D\u7F6E\uFF0C\u70B9\u51FB\u201C\u91CD\u542F Bridge\u201D\u540E\u751F\u6548\u3002'
|
|
8414
|
-
: '\u98DE\u4E66\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002'
|
|
8415
|
-
);
|
|
8416
9266
|
} catch (error) {
|
|
8417
9267
|
showMessage('feishuMessage', 'error', error.message);
|
|
8418
9268
|
}
|
|
@@ -8430,18 +9280,33 @@ function renderHtml() {
|
|
|
8430
9280
|
}
|
|
8431
9281
|
});
|
|
8432
9282
|
|
|
9283
|
+
document.getElementById('refreshFeishuStateBtn').addEventListener('click', async () => {
|
|
9284
|
+
try {
|
|
9285
|
+
await loadStatus();
|
|
9286
|
+
await loadBindings();
|
|
9287
|
+
await loadDesktopSessions();
|
|
9288
|
+
showMessage('feishuMessage', 'success', '\u98DE\u4E66\u901A\u9053\u72B6\u6001\u5DF2\u5237\u65B0\u3002');
|
|
9289
|
+
} catch (error) {
|
|
9290
|
+
showMessage('feishuMessage', 'error', error.message);
|
|
9291
|
+
}
|
|
9292
|
+
});
|
|
9293
|
+
|
|
8433
9294
|
document.getElementById('saveWeixinChannelBtn').addEventListener('click', async () => {
|
|
8434
9295
|
try {
|
|
8435
|
-
await saveConfig();
|
|
9296
|
+
await saveConfig({ messageId: 'weixinMessage', scope: 'weixin' });
|
|
8436
9297
|
await loadStatus();
|
|
8437
9298
|
await loadBindings();
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
9299
|
+
} catch (error) {
|
|
9300
|
+
showMessage('weixinMessage', 'error', error.message);
|
|
9301
|
+
}
|
|
9302
|
+
});
|
|
9303
|
+
|
|
9304
|
+
document.getElementById('refreshWeixinStateBtn').addEventListener('click', async () => {
|
|
9305
|
+
try {
|
|
9306
|
+
await loadStatus();
|
|
9307
|
+
await loadBindings();
|
|
9308
|
+
await loadDesktopSessions();
|
|
9309
|
+
showMessage('weixinMessage', 'success', '\u5FAE\u4FE1\u901A\u9053\u72B6\u6001\u5DF2\u5237\u65B0\u3002');
|
|
8445
9310
|
} catch (error) {
|
|
8446
9311
|
showMessage('weixinMessage', 'error', error.message);
|
|
8447
9312
|
}
|
|
@@ -8456,7 +9321,7 @@ function renderHtml() {
|
|
|
8456
9321
|
await loadBindings();
|
|
8457
9322
|
const followup = isChannelRunning('weixin')
|
|
8458
9323
|
? '\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'
|
|
8459
|
-
: '\u5FAE\u4FE1\u8D26\u53F7\u5DF2\u4FDD\u5B58\
|
|
9324
|
+
: '\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';
|
|
8460
9325
|
showMessage('weixinMessage', result.ok ? 'success' : 'error', followup);
|
|
8461
9326
|
} catch (error) {
|
|
8462
9327
|
showMessage('weixinMessage', 'error', error.message);
|
|
@@ -8628,6 +9493,10 @@ function renderHtml() {
|
|
|
8628
9493
|
Promise.all([loadStatus(), loadBindings(), loadDesktopSessions(), loadLogs()]).catch((error) => {
|
|
8629
9494
|
showMessage('opsMessage', 'error', error.message);
|
|
8630
9495
|
});
|
|
9496
|
+
|
|
9497
|
+
setInterval(() => {
|
|
9498
|
+
loadBindings().catch(() => {});
|
|
9499
|
+
}, 4000);
|
|
8631
9500
|
</script>
|
|
8632
9501
|
</body>
|
|
8633
9502
|
</html>`;
|
|
@@ -8635,7 +9504,63 @@ function renderHtml() {
|
|
|
8635
9504
|
var server = http.createServer(async (request, response) => {
|
|
8636
9505
|
try {
|
|
8637
9506
|
const url = new URL(request.url || "/", getUiServerUrl(port));
|
|
9507
|
+
const config = loadConfig();
|
|
9508
|
+
const localRequest = isLocalRequest(request);
|
|
9509
|
+
const queryToken = asString(url.searchParams.get("token"));
|
|
9510
|
+
if (request.method === "GET" && !localRequest && config.uiAllowLan === true && timingSafeMatch(queryToken, config.uiAccessToken)) {
|
|
9511
|
+
const redirectUrl = new URL(url.pathname || "/", getUiServerUrl(port));
|
|
9512
|
+
redirect(response, `${redirectUrl.pathname}${redirectUrl.search}`, makeAuthCookie(config.uiAccessToken || ""));
|
|
9513
|
+
return;
|
|
9514
|
+
}
|
|
9515
|
+
if (request.method === "GET" && url.pathname === "/login") {
|
|
9516
|
+
if (localRequest || isRemoteAuthenticated(request, config)) {
|
|
9517
|
+
redirect(response, "/");
|
|
9518
|
+
return;
|
|
9519
|
+
}
|
|
9520
|
+
if (config.uiAllowLan !== true) {
|
|
9521
|
+
html(response, renderAccessDeniedHtml());
|
|
9522
|
+
return;
|
|
9523
|
+
}
|
|
9524
|
+
html(response, renderLoginHtml());
|
|
9525
|
+
return;
|
|
9526
|
+
}
|
|
9527
|
+
if (request.method === "POST" && url.pathname === "/api/auth/login") {
|
|
9528
|
+
if (config.uiAllowLan !== true) {
|
|
9529
|
+
json(response, 403, { error: "\u5F53\u524D\u672A\u5F00\u542F\u5C40\u57DF\u7F51\u8BBF\u95EE\u3002" });
|
|
9530
|
+
return;
|
|
9531
|
+
}
|
|
9532
|
+
const payload = await readJsonBody(request);
|
|
9533
|
+
const token = asString(payload.token);
|
|
9534
|
+
if (!timingSafeMatch(token, config.uiAccessToken)) {
|
|
9535
|
+
json(response, 401, { error: "\u8BBF\u95EE token \u4E0D\u6B63\u786E\u3002" });
|
|
9536
|
+
return;
|
|
9537
|
+
}
|
|
9538
|
+
response.writeHead(200, {
|
|
9539
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
9540
|
+
"Set-Cookie": makeAuthCookie(config.uiAccessToken || "")
|
|
9541
|
+
});
|
|
9542
|
+
response.end(JSON.stringify({ ok: true }));
|
|
9543
|
+
return;
|
|
9544
|
+
}
|
|
9545
|
+
if (request.method === "POST" && url.pathname === "/api/auth/logout") {
|
|
9546
|
+
response.writeHead(200, {
|
|
9547
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
9548
|
+
"Set-Cookie": clearAuthCookie()
|
|
9549
|
+
});
|
|
9550
|
+
response.end(JSON.stringify({ ok: true }));
|
|
9551
|
+
return;
|
|
9552
|
+
}
|
|
8638
9553
|
if (request.method === "GET" && url.pathname === "/") {
|
|
9554
|
+
if (!localRequest) {
|
|
9555
|
+
if (config.uiAllowLan !== true) {
|
|
9556
|
+
html(response, renderAccessDeniedHtml());
|
|
9557
|
+
return;
|
|
9558
|
+
}
|
|
9559
|
+
if (!isRemoteAuthenticated(request, config)) {
|
|
9560
|
+
html(response, renderLoginHtml());
|
|
9561
|
+
return;
|
|
9562
|
+
}
|
|
9563
|
+
}
|
|
8639
9564
|
html(response, renderHtml());
|
|
8640
9565
|
return;
|
|
8641
9566
|
}
|
|
@@ -8643,10 +9568,21 @@ var server = http.createServer(async (request, response) => {
|
|
|
8643
9568
|
json(response, 200, { ok: true });
|
|
8644
9569
|
return;
|
|
8645
9570
|
}
|
|
9571
|
+
if (!localRequest) {
|
|
9572
|
+
if (config.uiAllowLan !== true) {
|
|
9573
|
+
json(response, 403, { error: "\u5F53\u524D\u672A\u5F00\u542F\u5C40\u57DF\u7F51\u8BBF\u95EE\u3002" });
|
|
9574
|
+
return;
|
|
9575
|
+
}
|
|
9576
|
+
if (!isRemoteAuthenticated(request, config)) {
|
|
9577
|
+
json(response, 401, { error: "\u9700\u8981\u5148\u767B\u5F55\u5E76\u63D0\u4F9B\u8BBF\u95EE token\u3002" });
|
|
9578
|
+
return;
|
|
9579
|
+
}
|
|
9580
|
+
}
|
|
8646
9581
|
if (request.method === "GET" && url.pathname === "/api/status") {
|
|
8647
9582
|
json(response, 200, {
|
|
8648
9583
|
bridge: getBridgeStatus(),
|
|
8649
9584
|
ui: getUiServerStatus(),
|
|
9585
|
+
uiAccess: buildUiAccessInfo(port, config, request),
|
|
8650
9586
|
home: CTI_HOME,
|
|
8651
9587
|
packageRoot: getPackageRoot(),
|
|
8652
9588
|
codexIntegrationInstalled: isCodexIntegrationInstalled(),
|
|
@@ -8658,7 +9594,7 @@ var server = http.createServer(async (request, response) => {
|
|
|
8658
9594
|
return;
|
|
8659
9595
|
}
|
|
8660
9596
|
if (request.method === "GET" && url.pathname === "/api/config") {
|
|
8661
|
-
json(response, 200, configToPayload(
|
|
9597
|
+
json(response, 200, configToPayload(config));
|
|
8662
9598
|
return;
|
|
8663
9599
|
}
|
|
8664
9600
|
if (request.method === "GET" && url.pathname === "/api/desktop-sessions") {
|
|
@@ -8683,8 +9619,8 @@ var server = http.createServer(async (request, response) => {
|
|
|
8683
9619
|
}
|
|
8684
9620
|
if (request.method === "POST" && url.pathname === "/api/config") {
|
|
8685
9621
|
const payload = await readJsonBody(request);
|
|
8686
|
-
const
|
|
8687
|
-
saveConfig(
|
|
9622
|
+
const config2 = mergeConfig(payload);
|
|
9623
|
+
saveConfig(config2);
|
|
8688
9624
|
json(response, 200, { ok: true, config: configToPayload(loadConfig()) });
|
|
8689
9625
|
return;
|
|
8690
9626
|
}
|
|
@@ -8765,7 +9701,7 @@ async function startServer() {
|
|
|
8765
9701
|
port = await resolveUiPort(parsePreferredPort());
|
|
8766
9702
|
await new Promise((resolve, reject) => {
|
|
8767
9703
|
server.once("error", reject);
|
|
8768
|
-
server.listen(port, "
|
|
9704
|
+
server.listen(port, "0.0.0.0", () => {
|
|
8769
9705
|
server.removeListener("error", reject);
|
|
8770
9706
|
resolve();
|
|
8771
9707
|
});
|