@wu529778790/open-im 1.6.5-beta.4 → 1.6.5
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 +0 -13
- package/README.zh-CN.md +0 -13
- package/dist/config-web-page-i18n.d.ts +0 -10
- package/dist/config-web-page-i18n.js +0 -10
- package/dist/config-web-page-script.js +0 -36
- package/dist/config-web-page-template.js +22 -71
- package/dist/config-web-page.test.js +0 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,19 +14,6 @@ Multi-platform IM bridge for AI CLI tools. Connect Telegram, Feishu, WeCom, Ding
|
|
|
14
14
|
- Isolated sessions: each user gets an independent local session, and `/new` resets it
|
|
15
15
|
- Built-in commands: `/help`, `/new`, `/cd`, `/pwd`, `/status`
|
|
16
16
|
|
|
17
|
-
## Coverage Matrix
|
|
18
|
-
|
|
19
|
-
Capability levels: `Native` = fully supported in-channel, `Fallback` = degraded behavior or text fallback, `None` = not currently supported.
|
|
20
|
-
|
|
21
|
-
| Platform | Text Inbound | Image Inbound | File Inbound | Voice Inbound | Video Inbound | Streaming Reply | Image Reply | Card Reply |
|
|
22
|
-
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
|
23
|
-
| Telegram | Native | Native | Native | Native | Native | Native | Native | Native |
|
|
24
|
-
| Feishu | Native | Native | Native | Fallback | Fallback | Native | Native | Native |
|
|
25
|
-
| QQ | Native | Fallback | Fallback | Fallback | Fallback | None | Fallback | Fallback |
|
|
26
|
-
| WeCom | Native | Fallback | Fallback | Fallback | Fallback | Native | Native | Native |
|
|
27
|
-
| DingTalk | Native | Fallback | Fallback | Fallback | Fallback | Native | Fallback | Native |
|
|
28
|
-
| WeChat (experimental) | Native | Fallback | Fallback | Fallback | Fallback | Native | Fallback | Native |
|
|
29
|
-
|
|
30
17
|
## Requirements
|
|
31
18
|
|
|
32
19
|
- Node.js >= 20
|
package/README.zh-CN.md
CHANGED
|
@@ -14,19 +14,6 @@
|
|
|
14
14
|
- 会话隔离:每个用户独立维护本地会话,`/new` 可重置
|
|
15
15
|
- 常用命令:支持 `/help`、`/new`、`/cd`、`/pwd`、`/status`
|
|
16
16
|
|
|
17
|
-
## 覆盖矩阵
|
|
18
|
-
|
|
19
|
-
能力等级说明:`Native` 表示平台内原生支持,`Fallback` 表示有降级方案或文本兜底,`None` 表示当前暂不支持。
|
|
20
|
-
|
|
21
|
-
| 平台 | 文本输入 | 图片输入 | 文件输入 | 语音输入 | 视频输入 | 流式回复 | 图片回复 | 卡片回复 |
|
|
22
|
-
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
|
23
|
-
| Telegram | Native | Native | Native | Native | Native | Native | Native | Native |
|
|
24
|
-
| 飞书 | Native | Native | Native | Fallback | Fallback | Native | Native | Native |
|
|
25
|
-
| QQ | Native | Fallback | Fallback | Fallback | Fallback | None | Fallback | Fallback |
|
|
26
|
-
| 企业微信 | Native | Fallback | Fallback | Fallback | Fallback | Native | Native | Native |
|
|
27
|
-
| 钉钉 | Native | Fallback | Fallback | Fallback | Fallback | Native | Fallback | Native |
|
|
28
|
-
| 微信(测试中) | Native | Fallback | Fallback | Fallback | Fallback | Native | Fallback | Native |
|
|
29
|
-
|
|
30
17
|
## 环境要求
|
|
31
18
|
|
|
32
19
|
- Node.js >= 20
|
|
@@ -65,11 +65,6 @@ export declare const PAGE_TEXTS: {
|
|
|
65
65
|
readonly aiTitle: "AI Tooling";
|
|
66
66
|
readonly aiHint: "";
|
|
67
67
|
readonly claudeNote: "Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.";
|
|
68
|
-
readonly aiCommonTitle: "Shared defaults";
|
|
69
|
-
readonly aiCommonHint: "Choose the default AI tool first. Tool-specific fields are shown below.";
|
|
70
|
-
readonly aiToolConfigTitle: "Tool-specific settings";
|
|
71
|
-
readonly aiToolConfigHint: "Only the selected tool's fields are shown.";
|
|
72
|
-
readonly aiConfigSummary: "Editing {tool} settings. Switch tools above if you need to configure another runtime.";
|
|
73
68
|
readonly aiTool: "Default AI tool";
|
|
74
69
|
readonly workDir: "Default work directory";
|
|
75
70
|
readonly claudeCli: "Claude CLI path";
|
|
@@ -169,11 +164,6 @@ export declare const PAGE_TEXTS: {
|
|
|
169
164
|
readonly aiTitle: "AI 工具配置";
|
|
170
165
|
readonly aiHint: "";
|
|
171
166
|
readonly claudeNote: "Claude 凭证仍然从环境变量或 ~/.claude/settings.json 读取。这个页面只管理本地桥接配置,不负责 Claude 账号登录。";
|
|
172
|
-
readonly aiCommonTitle: "公共默认配置";
|
|
173
|
-
readonly aiCommonHint: "先选择默认 AI 工具,下方再显示对应的工具专属配置。";
|
|
174
|
-
readonly aiToolConfigTitle: "工具专属配置";
|
|
175
|
-
readonly aiToolConfigHint: "只显示当前选中 AI 工具的字段。";
|
|
176
|
-
readonly aiConfigSummary: "正在编辑 {tool} 的配置,如需配置其他工具,可在上方切换。";
|
|
177
167
|
readonly aiTool: "默认 AI 工具";
|
|
178
168
|
readonly workDir: "默认工作目录";
|
|
179
169
|
readonly claudeCli: "Claude CLI 路径";
|
|
@@ -65,11 +65,6 @@ export const PAGE_TEXTS = {
|
|
|
65
65
|
aiTitle: "AI Tooling",
|
|
66
66
|
aiHint: "",
|
|
67
67
|
claudeNote: "Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.",
|
|
68
|
-
aiCommonTitle: "Shared defaults",
|
|
69
|
-
aiCommonHint: "Choose the default AI tool first. Tool-specific fields are shown below.",
|
|
70
|
-
aiToolConfigTitle: "Tool-specific settings",
|
|
71
|
-
aiToolConfigHint: "Only the selected tool's fields are shown.",
|
|
72
|
-
aiConfigSummary: "Editing {tool} settings. Switch tools above if you need to configure another runtime.",
|
|
73
68
|
aiTool: "Default AI tool",
|
|
74
69
|
workDir: "Default work directory",
|
|
75
70
|
claudeCli: "Claude CLI path",
|
|
@@ -169,11 +164,6 @@ export const PAGE_TEXTS = {
|
|
|
169
164
|
aiTitle: "AI \u5de5\u5177\u914d\u7f6e",
|
|
170
165
|
aiHint: "",
|
|
171
166
|
claudeNote: "Claude \u51ed\u8bc1\u4ecd\u7136\u4ece\u73af\u5883\u53d8\u91cf\u6216 ~/.claude/settings.json \u8bfb\u53d6\u3002\u8fd9\u4e2a\u9875\u9762\u53ea\u7ba1\u7406\u672c\u5730\u6865\u63a5\u914d\u7f6e\uff0c\u4e0d\u8d1f\u8d23 Claude \u8d26\u53f7\u767b\u5f55\u3002",
|
|
172
|
-
aiCommonTitle: "\u516c\u5171\u9ed8\u8ba4\u914d\u7f6e",
|
|
173
|
-
aiCommonHint: "\u5148\u9009\u62e9\u9ed8\u8ba4 AI \u5de5\u5177\uff0c\u4e0b\u65b9\u518d\u663e\u793a\u5bf9\u5e94\u7684\u5de5\u5177\u4e13\u5c5e\u914d\u7f6e\u3002",
|
|
174
|
-
aiToolConfigTitle: "\u5de5\u5177\u4e13\u5c5e\u914d\u7f6e",
|
|
175
|
-
aiToolConfigHint: "\u53ea\u663e\u793a\u5f53\u524d\u9009\u4e2d AI \u5de5\u5177\u7684\u5b57\u6bb5\u3002",
|
|
176
|
-
aiConfigSummary: "\u6b63\u5728\u7f16\u8f91 {tool} \u7684\u914d\u7f6e\uff0c\u5982\u9700\u914d\u7f6e\u5176\u4ed6\u5de5\u5177\uff0c\u53ef\u5728\u4e0a\u65b9\u5207\u6362\u3002",
|
|
177
167
|
aiTool: "\u9ed8\u8ba4 AI \u5de5\u5177",
|
|
178
168
|
workDir: "\u9ed8\u8ba4\u5de5\u4f5c\u76ee\u5f55",
|
|
179
169
|
claudeCli: "Claude CLI \u8def\u5f84",
|
|
@@ -6,7 +6,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
6
6
|
{ key: "dingtalk", label: "DingTalk", fields: ["aiCommand", "clientId", "clientSecret", "cardTemplateId", "allowedUserIds"], testFields: ["clientId", "clientSecret"] },
|
|
7
7
|
];
|
|
8
8
|
const platformKeys = platformDefinitions.map((platform) => platform.key);
|
|
9
|
-
const aiTools = ["claude", "codex", "cursor", "codebuddy"];
|
|
10
9
|
const ids = platformDefinitions.flatMap((platform) => ["enabled", ...platform.fields].map((field) => platform.key + "-" + field)).concat(["ai-aiCommand","ai-claudeCliPath","ai-claudeWorkDir","ai-claudeSkipPermissions","ai-claudeTimeoutMs","ai-codexTimeoutMs","ai-codebuddyTimeoutMs","ai-claudeModel","ai-cursorCliPath","ai-codexCliPath","ai-codebuddyCliPath","ai-codexProxy","ai-hookPort","ai-logLevel","ai-useSdkMode"]);
|
|
11
10
|
const el = (id) => document.getElementById(id);
|
|
12
11
|
const storageKey = "open-im-web-lang";
|
|
@@ -26,7 +25,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
26
25
|
const setChecked = (id, value) => { const node = el(id); if (node) node.checked = Boolean(value); };
|
|
27
26
|
const setMessage = (text, type="") => { const node = el("message"); node.textContent = text; node.className = ("message " + type).trim(); };
|
|
28
27
|
const setBusy = (busy) => ["validateButton","saveButton","startButton","stopButton","langButton"].forEach((id) => { el(id).disabled = busy; });
|
|
29
|
-
const getActiveAiTool = () => el("ai-aiCommand").value || "claude";
|
|
30
28
|
const readPlatformConfig = (platform) => platform.testFields.reduce((config, field) => {
|
|
31
29
|
config[field] = getValue(platform.key + "-" + field);
|
|
32
30
|
return config;
|
|
@@ -56,14 +54,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
56
54
|
el("aiHint").textContent = t("aiHint");
|
|
57
55
|
el("aiHint").style.display = t("aiHint") ? "block" : "none";
|
|
58
56
|
el("claudeNote").textContent = t("claudeNote");
|
|
59
|
-
setText("aiCommonTitle", t("aiCommonTitle"));
|
|
60
|
-
setText("aiCommonHint", t("aiCommonHint"));
|
|
61
|
-
setText("aiToolConfigTitle", t("aiToolConfigTitle"));
|
|
62
|
-
setText("aiToolConfigHint", t("aiToolConfigHint"));
|
|
63
|
-
setText("ai-claudeSectionLabel", "Claude");
|
|
64
|
-
setText("ai-codexSectionLabel", "Codex");
|
|
65
|
-
setText("ai-cursorSectionLabel", "Cursor");
|
|
66
|
-
setText("ai-codebuddySectionLabel", "CodeBuddy");
|
|
67
57
|
setText("telegram-enabled-label", t("enabled"));
|
|
68
58
|
setText("feishu-enabled-label", t("enabled"));
|
|
69
59
|
setText("qq-enabled-label", t("enabled"));
|
|
@@ -133,9 +123,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
133
123
|
el("ai-claudeModel").placeholder = t("optional");
|
|
134
124
|
setText("ai-claudeSkipPermissions-label", t("autoApprove"));
|
|
135
125
|
setText("ai-useSdkMode-label", t("sdkMode"));
|
|
136
|
-
document.querySelectorAll("[data-tool]").forEach((button) => {
|
|
137
|
-
button.textContent = button.getAttribute("data-tool");
|
|
138
|
-
});
|
|
139
126
|
el("validateButton").textContent = t("validate");
|
|
140
127
|
el("saveButton").textContent = t("save");
|
|
141
128
|
el("startButton").textContent = t("start");
|
|
@@ -169,20 +156,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
169
156
|
el("navAiBtn").textContent = t("aiTitle");
|
|
170
157
|
el("navServiceBtn").textContent = t("serviceTitle");
|
|
171
158
|
}
|
|
172
|
-
function updateAiToolVisibility() {
|
|
173
|
-
const activeTool = getActiveAiTool();
|
|
174
|
-
aiTools.forEach((tool) => {
|
|
175
|
-
const panel = document.querySelector('[data-tool-panel="' + tool + '"]');
|
|
176
|
-
if (panel) {
|
|
177
|
-
panel.hidden = tool !== activeTool;
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
document.querySelectorAll("[data-tool]").forEach((button) => {
|
|
181
|
-
button.classList.toggle("active", button.getAttribute("data-tool") === activeTool);
|
|
182
|
-
});
|
|
183
|
-
const toolLabels = { claude: "Claude", codex: "Codex", cursor: "Cursor", codebuddy: "CodeBuddy" };
|
|
184
|
-
el("aiConfigSummary").textContent = t("aiConfigSummary", { tool: toolLabels[activeTool] || activeTool });
|
|
185
|
-
}
|
|
186
159
|
function updateVisualState() {
|
|
187
160
|
const enabled = [];
|
|
188
161
|
platformDefinitions.forEach((platform) => {
|
|
@@ -194,7 +167,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
194
167
|
el("liveSummary").textContent = enabled.length
|
|
195
168
|
? t("summaryEnabled", { platforms: enabled.join(t("listSeparator")), tool: aiTool })
|
|
196
169
|
: t("summaryEmpty", { tool: aiTool });
|
|
197
|
-
updateAiToolVisibility();
|
|
198
170
|
}
|
|
199
171
|
async function updateDashboard() {
|
|
200
172
|
try {
|
|
@@ -356,14 +328,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
356
328
|
node.addEventListener("change", updateVisualState);
|
|
357
329
|
}
|
|
358
330
|
});
|
|
359
|
-
document.querySelectorAll("[data-tool]").forEach((button) => {
|
|
360
|
-
button.addEventListener("click", () => {
|
|
361
|
-
const tool = button.getAttribute("data-tool");
|
|
362
|
-
if (!tool) return;
|
|
363
|
-
setValue("ai-aiCommand", tool);
|
|
364
|
-
updateVisualState();
|
|
365
|
-
});
|
|
366
|
-
});
|
|
367
331
|
}
|
|
368
332
|
async function validate() { setBusy(true); try { await request("/api/config/validate", { method: "POST", body: JSON.stringify(payload()) }); setMessage(t("validationOk"), "success"); } catch (error) { setMessage(error.message || String(error), "error"); } finally { setBusy(false); } }
|
|
369
333
|
async function save() { setBusy(true); try { await request("/api/config/save?final=1", { method: "POST", body: JSON.stringify(payload()) }); setMessage(t("saveOk"), "success"); } catch (error) { setMessage(error.message || String(error), "error"); } finally { setBusy(false); } }
|
|
@@ -47,16 +47,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
47
47
|
#configSection .panel,#aiSection .panel,#serviceSection{background:rgba(255,253,247,.82)}
|
|
48
48
|
#configSection .panel-head,#aiSection .panel-head,#serviceSection .panel-head{margin-bottom:14px}
|
|
49
49
|
#configSection .panel .summary,#aiSection .panel .summary{line-height:1.58}
|
|
50
|
-
.ai-layout{display:grid;gap:16px}
|
|
51
|
-
.ai-switcher{display:flex;flex-wrap:wrap;gap:10px}
|
|
52
|
-
.tool-switch{padding:10px 14px;background:rgba(19,35,26,.06);color:var(--ink);border:1px solid var(--line);box-shadow:none}
|
|
53
|
-
.tool-switch:hover{box-shadow:none}
|
|
54
|
-
.tool-switch.active{background:var(--green);border-color:var(--green);color:#fff7eb}
|
|
55
|
-
.ai-card{display:grid;gap:14px}
|
|
56
|
-
.ai-card[hidden]{display:none}
|
|
57
|
-
.ai-section-label{font-size:.75rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
|
|
58
|
-
.ai-summary-bar{padding:14px 16px;border:1px dashed var(--line-strong);background:rgba(255,255,255,.5);color:var(--muted)}
|
|
59
|
-
.toggle-grid{display:grid;gap:12px}
|
|
60
50
|
#serviceSection .actions{grid-template-columns:repeat(auto-fit,minmax(170px,1fr));align-items:stretch}
|
|
61
51
|
#startButton{background:var(--green);box-shadow:0 12px 22px rgba(26,106,68,.18)}
|
|
62
52
|
#saveButton{background:rgba(19,35,26,.88)}
|
|
@@ -216,67 +206,28 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
216
206
|
</section>
|
|
217
207
|
<section class="section" id="aiSection">
|
|
218
208
|
<div class="panel-head"><h2 id="aiTitle">AI Tooling</h2><div id="aiHint">WeChat is intentionally excluded from this first version.</div></div>
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
<
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
</
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
</
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
</
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
<button type="button" class="tool-switch" data-tool="codex">codex</button>
|
|
242
|
-
<button type="button" class="tool-switch" data-tool="cursor">cursor</button>
|
|
243
|
-
<button type="button" class="tool-switch" data-tool="codebuddy">codebuddy</button>
|
|
244
|
-
</div>
|
|
245
|
-
<section class="ai-card" id="ai-tool-claude" data-tool-panel="claude">
|
|
246
|
-
<div class="ai-section-label" id="ai-claudeSectionLabel">Claude</div>
|
|
247
|
-
<div class="two-col">
|
|
248
|
-
<label><span id="ai-claudeCliPath-label">Claude CLI path</span><input id="ai-claudeCliPath" class="mono" /></label>
|
|
249
|
-
<label><span id="ai-claudeTimeoutMs-label">Claude timeout (ms)</span><input id="ai-claudeTimeoutMs" type="number" min="1" /></label>
|
|
250
|
-
<label><span id="ai-claudeModel-label">Claude model</span><input id="ai-claudeModel" placeholder="Optional" /></label>
|
|
251
|
-
</div>
|
|
252
|
-
<div class="toggle-grid">
|
|
253
|
-
<label class="toggle"><input id="ai-claudeSkipPermissions" type="checkbox" /> <span id="ai-claudeSkipPermissions-label">Auto-approve tool permissions</span></label>
|
|
254
|
-
<label class="toggle"><input id="ai-useSdkMode" type="checkbox" /> <span id="ai-useSdkMode-label">Use Claude SDK mode</span></label>
|
|
255
|
-
</div>
|
|
256
|
-
</section>
|
|
257
|
-
<section class="ai-card" id="ai-tool-codex" data-tool-panel="codex" hidden>
|
|
258
|
-
<div class="ai-section-label" id="ai-codexSectionLabel">Codex</div>
|
|
259
|
-
<div class="two-col">
|
|
260
|
-
<label><span id="ai-codexCliPath-label">Codex CLI path</span><input id="ai-codexCliPath" class="mono" /></label>
|
|
261
|
-
<label><span id="ai-codexTimeoutMs-label">Codex timeout (ms)</span><input id="ai-codexTimeoutMs" type="number" min="1" /></label>
|
|
262
|
-
<label><span id="ai-codexProxy-label">Codex proxy</span><input id="ai-codexProxy" class="mono" placeholder="Optional" /></label>
|
|
263
|
-
</div>
|
|
264
|
-
</section>
|
|
265
|
-
<section class="ai-card" id="ai-tool-cursor" data-tool-panel="cursor" hidden>
|
|
266
|
-
<div class="ai-section-label" id="ai-cursorSectionLabel">Cursor</div>
|
|
267
|
-
<div class="two-col">
|
|
268
|
-
<label><span id="ai-cursorCliPath-label">Cursor CLI path</span><input id="ai-cursorCliPath" class="mono" /></label>
|
|
269
|
-
</div>
|
|
270
|
-
</section>
|
|
271
|
-
<section class="ai-card" id="ai-tool-codebuddy" data-tool-panel="codebuddy" hidden>
|
|
272
|
-
<div class="ai-section-label" id="ai-codebuddySectionLabel">CodeBuddy</div>
|
|
273
|
-
<div class="two-col">
|
|
274
|
-
<label><span id="ai-codebuddyCliPath-label">CodeBuddy CLI path</span><input id="ai-codebuddyCliPath" class="mono" /></label>
|
|
275
|
-
<label><span id="ai-codebuddyTimeoutMs-label">CodeBuddy timeout (ms)</span><input id="ai-codebuddyTimeoutMs" type="number" min="1" /></label>
|
|
276
|
-
</div>
|
|
277
|
-
</section>
|
|
278
|
-
</article>
|
|
279
|
-
</div>
|
|
209
|
+
<article class="panel note" id="claudeNote">Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.</article>
|
|
210
|
+
<article class="panel">
|
|
211
|
+
<div class="two-col">
|
|
212
|
+
<label><span id="ai-aiCommand-label">Default AI tool</span><select id="ai-aiCommand"><option value="claude">claude</option><option value="codex">codex</option><option value="cursor">cursor</option><option value="codebuddy">codebuddy</option></select></label>
|
|
213
|
+
<label><span id="ai-claudeWorkDir-label">Default work directory</span><input id="ai-claudeWorkDir" class="mono" /></label>
|
|
214
|
+
<label><span id="ai-claudeCliPath-label">Claude CLI path</span><input id="ai-claudeCliPath" class="mono" /></label>
|
|
215
|
+
<label><span id="ai-cursorCliPath-label">Cursor CLI path</span><input id="ai-cursorCliPath" class="mono" /></label>
|
|
216
|
+
<label><span id="ai-codexCliPath-label">Codex CLI path</span><input id="ai-codexCliPath" class="mono" /></label>
|
|
217
|
+
<label><span id="ai-codebuddyCliPath-label">CodeBuddy CLI path</span><input id="ai-codebuddyCliPath" class="mono" /></label>
|
|
218
|
+
<label><span id="ai-codexProxy-label">Codex proxy</span><input id="ai-codexProxy" class="mono" placeholder="Optional" /></label>
|
|
219
|
+
<label><span id="ai-claudeTimeoutMs-label">Claude timeout (ms)</span><input id="ai-claudeTimeoutMs" type="number" min="1" /></label>
|
|
220
|
+
<label><span id="ai-codexTimeoutMs-label">Codex timeout (ms)</span><input id="ai-codexTimeoutMs" type="number" min="1" /></label>
|
|
221
|
+
<label><span id="ai-codebuddyTimeoutMs-label">CodeBuddy timeout (ms)</span><input id="ai-codebuddyTimeoutMs" type="number" min="1" /></label>
|
|
222
|
+
<label><span id="ai-claudeModel-label">Claude model</span><input id="ai-claudeModel" placeholder="Optional" /></label>
|
|
223
|
+
<label><span id="ai-hookPort-label">Hook port</span><input id="ai-hookPort" type="number" min="1" /></label>
|
|
224
|
+
<label><span id="ai-logLevel-label">Log level</span><select id="ai-logLevel"><option value="default">default</option><option value="DEBUG">DEBUG</option><option value="INFO">INFO</option><option value="WARN">WARN</option><option value="ERROR">ERROR</option></select></label>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="actions" style="margin-top:14px">
|
|
227
|
+
<label class="toggle"><input id="ai-claudeSkipPermissions" type="checkbox" /> <span id="ai-claudeSkipPermissions-label">Auto-approve tool permissions</span></label>
|
|
228
|
+
<label class="toggle"><input id="ai-useSdkMode" type="checkbox" /> <span id="ai-useSdkMode-label">Use Claude SDK mode</span></label>
|
|
229
|
+
</div>
|
|
230
|
+
</article>
|
|
280
231
|
</section>
|
|
281
232
|
<section class="footer" id="serviceSection">
|
|
282
233
|
<div class="panel-head"><h2 id="serviceTitle">Service Control</h2><div id="serviceHint">Validate, save, start, and stop the local bridge from one place.</div></div>
|
|
@@ -30,14 +30,4 @@ describe("config web page assembly", () => {
|
|
|
30
30
|
expect(PAGE_HTML).toContain(`id="${id}"`);
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
-
it("keeps AI tool switch buttons and tool panels aligned", () => {
|
|
34
|
-
const toolListMatch = PAGE_SCRIPT.match(/const aiTools = \[([^\]]+)\]/);
|
|
35
|
-
expect(toolListMatch).toBeTruthy();
|
|
36
|
-
const tools = Array.from((toolListMatch?.[1] ?? "").matchAll(/"([^"]+)"/g), (match) => match[1]);
|
|
37
|
-
expect(tools).toEqual(["claude", "codex", "cursor", "codebuddy"]);
|
|
38
|
-
for (const tool of tools) {
|
|
39
|
-
expect(PAGE_HTML).toContain(`data-tool="${tool}"`);
|
|
40
|
-
expect(PAGE_HTML).toContain(`data-tool-panel="${tool}"`);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
33
|
});
|