@wu529778790/open-im 1.8.1-beta.0 → 1.8.1-beta.1

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.
@@ -120,10 +120,12 @@ export declare const PAGE_TEXTS: {
120
120
  readonly stopOk: "Bridge stopped.";
121
121
  readonly configEditorTitle: "Config Editor";
122
122
  readonly configEditorHint: "Edit ~/.open-im/config.json directly";
123
- readonly configJson: "Configuration (JSON)";
123
+ readonly claudeSettingsLabel: "~/.claude/settings.json";
124
+ readonly configJson: "~/.open-im/config.json";
124
125
  readonly configJsonHint: "Edit the configuration JSON. Changes will be saved when you click \"Save Config\" in the Service section.";
125
126
  readonly formatJson: "Format";
126
127
  readonly resetJson: "Reset";
128
+ readonly saveBtn: "Save";
127
129
  readonly jsonValid: "Valid JSON";
128
130
  readonly jsonInvalid: "Invalid JSON: {error}";
129
131
  };
@@ -242,10 +244,12 @@ export declare const PAGE_TEXTS: {
242
244
  readonly stopOk: "桥接已停止。";
243
245
  readonly configEditorTitle: "JSON 配置编辑器";
244
246
  readonly configEditorHint: "直接编辑 ~/.open-im/config.json";
245
- readonly configJson: "配置文件 (JSON)";
246
- readonly configJsonHint: "编辑配置 JSON。点击服务区的“保存配置”按钮后保存更改。";
247
+ readonly claudeSettingsLabel: "~/.claude/settings.json";
248
+ readonly configJson: "~/.open-im/config.json";
249
+ readonly configJsonHint: "编辑配置 JSON。点击服务区的“保存配置”按钮后侘存更改。";
247
250
  readonly formatJson: "格式化";
248
251
  readonly resetJson: "重置";
252
+ readonly saveBtn: "保存";
249
253
  readonly jsonValid: "JSON 有效";
250
254
  readonly jsonInvalid: "JSON 无效:{error}";
251
255
  };
@@ -120,10 +120,12 @@ export const PAGE_TEXTS = {
120
120
  stopOk: "Bridge stopped.",
121
121
  configEditorTitle: "Config Editor",
122
122
  configEditorHint: "Edit ~/.open-im/config.json directly",
123
- configJson: "Configuration (JSON)",
123
+ claudeSettingsLabel: "~/.claude/settings.json",
124
+ configJson: "~/.open-im/config.json",
124
125
  configJsonHint: "Edit the configuration JSON. Changes will be saved when you click \"Save Config\" in the Service section.",
125
126
  formatJson: "Format",
126
127
  resetJson: "Reset",
128
+ saveBtn: "Save",
127
129
  jsonValid: "Valid JSON",
128
130
  jsonInvalid: "Invalid JSON: {error}",
129
131
  },
@@ -242,10 +244,12 @@ export const PAGE_TEXTS = {
242
244
  stopOk: "\u6865\u63a5\u5df2\u505c\u6b62\u3002",
243
245
  configEditorTitle: "JSON \u914d\u7f6e\u7f16\u8f91\u5668",
244
246
  configEditorHint: "\u76f4\u63a5\u7f16\u8f91 ~/.open-im/config.json",
245
- configJson: "\u914d\u7f6e\u6587\u4ef6 (JSON)",
246
- configJsonHint: "\u7f16\u8f91\u914d\u7f6e JSON\u3002\u70b9\u51fb\u670d\u52a1\u533a\u7684\u201c\u4fdd\u5b58\u914d\u7f6e\u201d\u6309\u94ae\u540e\u4fdd\u5b58\u66f4\u6539\u3002",
247
+ claudeSettingsLabel: "~/.claude/settings.json",
248
+ configJson: "~/.open-im/config.json",
249
+ configJsonHint: "\u7f16\u8f91\u914d\u7f6e JSON\u3002\u70b9\u51fb\u670d\u52a1\u533a\u7684\u201c\u4fdd\u5b58\u914d\u7f6e\u201d\u6309\u94ae\u540e\u4f98\u5b58\u66f4\u6539\u3002",
247
250
  formatJson: "\u683c\u5f0f\u5316",
248
251
  resetJson: "\u91cd\u7f6e",
252
+ saveBtn: "\u4fdd\u5b58",
249
253
  jsonValid: "JSON \u6709\u6548",
250
254
  jsonInvalid: "JSON \u65e0\u6548\uff1a{error}",
251
255
  }
@@ -159,6 +159,12 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
159
159
  { id: "statConfiguredLabel", key: "statConfiguredLabel" },
160
160
  { id: "statEnabledLabel", key: "statEnabledLabel" },
161
161
  { id: "statServiceLabel", key: "statServiceLabel" },
162
+ { id: "openImConfigSummary", key: "configJson" },
163
+ { id: "claudeSettingsSummary", key: "claudeSettingsLabel" },
164
+ { id: "formatJsonButtonText", key: "formatJson" },
165
+ { id: "resetJsonButtonText", key: "resetJson" },
166
+ { id: "saveClaudeSettingsBtnText", key: "saveBtn" },
167
+ { id: "saveOpenImConfigBtnText", key: "saveBtn" },
162
168
  ],
163
169
  platformLabels: {
164
170
  enabled: { suffix: "-label", key: "enabled" },
@@ -380,7 +386,7 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
380
386
 
381
387
  // Navigation
382
388
  function setActiveNav(targetId) {
383
- ["navOverviewBtn","navPlatformsBtn","navAiBtn","navServiceBtn","navConfigEditorBtn"].forEach((id) => {
389
+ ["navOverviewBtn","navPlatformsBtn","navAiBtn","navServiceBtn"].forEach((id) => {
384
390
  const btn = el(id);
385
391
  if (btn) btn.classList.toggle("active", id === targetId);
386
392
  });
@@ -604,16 +610,37 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
604
610
  }
605
611
  });
606
612
 
607
- // Claude settings.json editor (advanced, inline & collapsible)
613
+ // Open-im config.json: load when expanded
614
+ const openImConfigContainer = document.getElementById("openImConfigContainer");
615
+ if (openImConfigContainer && openImConfigContainer instanceof HTMLDetailsElement) {
616
+ openImConfigContainer.addEventListener("toggle", () => {
617
+ if (openImConfigContainer.open) void loadOpenImConfig();
618
+ });
619
+ }
620
+ // Claude settings.json: load when expanded
608
621
  const claudeSettingsContainer = document.getElementById("claudeSettingsContainer");
609
622
  if (claudeSettingsContainer && claudeSettingsContainer instanceof HTMLDetailsElement) {
610
623
  claudeSettingsContainer.addEventListener("toggle", () => {
611
- if (claudeSettingsContainer.open) {
612
- void loadClaudeSettings();
613
- }
624
+ if (claudeSettingsContainer.open) void loadClaudeSettings();
614
625
  });
615
626
  }
616
627
 
628
+ el("saveClaudeSettingsBtn").onclick = async () => {
629
+ try {
630
+ await saveClaudeSettings();
631
+ } catch (e) {
632
+ setMessage(e && e.message ? e.message : String(e), "error");
633
+ }
634
+ };
635
+ el("saveOpenImConfigBtn").onclick = async () => {
636
+ try {
637
+ await saveOpenImConfig();
638
+ setMessage(t("saveOk"), "success");
639
+ } catch (e) {
640
+ setMessage(e && e.message ? e.message : String(e), "error");
641
+ }
642
+ };
643
+
617
644
  // AI tool switcher
618
645
  document.querySelectorAll(".tab[data-tool]").forEach((tab) => {
619
646
  tab.addEventListener("click", () => {
@@ -648,7 +675,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
648
675
  el("navPlatformsBtn").onclick = () => scrollToSection("configSection", "navPlatformsBtn");
649
676
  el("navAiBtn").onclick = () => scrollToSection("aiSection", "navAiBtn");
650
677
  el("navServiceBtn").onclick = () => scrollToSection("serviceSection", "navServiceBtn");
651
- el("navConfigEditorBtn").onclick = () => scrollToSection("configEditorSection", "navConfigEditorBtn");
652
678
 
653
679
  // Language toggle
654
680
  el("langButton").onclick = () => {
@@ -718,7 +744,8 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
718
744
  async function saveOpenImConfig() {
719
745
  const textarea = document.getElementById("configJson");
720
746
  if (!(textarea instanceof HTMLTextAreaElement)) return;
721
- const json = textarea.value;
747
+ const json = textarea.value.trim();
748
+ if (!json) return;
722
749
 
723
750
  // Validate JSON
724
751
  try {
@@ -781,16 +781,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
781
781
  </svg>
782
782
  <span id="navServiceText">Service</span>
783
783
  </button>
784
- <button class="nav-item" id="navConfigEditorBtn">
785
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
786
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
787
- <polyline points="14 2 14 8 20 8"/>
788
- <line x1="16" y1="13" x2="8" y2="13"/>
789
- <line x1="16" y1="17" x2="8" y2="17"/>
790
- <polyline points="10 9 9 9 8 9"/>
791
- </svg>
792
- <span id="navConfigEditorText">Config Editor</span>
793
- </button>
794
784
  </nav>
795
785
  </aside>
796
786
 
@@ -1138,18 +1128,31 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
1138
1128
  <div class="form-hint" id="ai-claudeConfigPath-hint">Environment variables are saved to ~/.claude/settings.json</div>
1139
1129
  </div>
1140
1130
  <div class="form-group">
1141
- <details id="claudeSettingsContainer">
1142
- <summary class="form-label" style="cursor: pointer;">Edit ~/.claude/settings.json (advanced)</summary>
1143
- <div class="form-hint" style="margin-top: 8px; margin-bottom: 8px;">
1144
- JSON will be auto-formatted; invalid JSON 会提示错误。
1131
+ <details id="openImConfigContainer">
1132
+ <summary class="form-label" style="cursor: pointer;" id="openImConfigSummary">~/.open-im/config.json</summary>
1133
+ <div style="margin-top: 12px;">
1134
+ <div style="display:flex; justify-content:flex-end; gap:8px; margin-bottom:8px;">
1135
+ <button type="button" id="formatJsonButton" class="btn btn-sm btn-ghost"><span id="formatJsonButtonText">Format</span></button>
1136
+ <button type="button" id="resetJsonButton" class="btn btn-sm btn-ghost"><span id="resetJsonButtonText">Reset</span></button>
1137
+ </div>
1138
+ <textarea id="configJson" class="form-input mono" rows="16" style="font-family:monospace; font-size:13px; line-height:1.5; min-height:320px; resize:vertical; white-space:pre;" spellcheck="false"></textarea>
1139
+ <div id="jsonValidationMessage" class="message hidden" style="margin-top:6px;" aria-live="polite"></div>
1140
+ <div style="margin-top: 8px;">
1141
+ <button type="button" id="saveOpenImConfigBtn" class="btn btn-secondary btn-sm"><span id="saveOpenImConfigBtnText">Save</span></button>
1142
+ </div>
1145
1143
  </div>
1146
- <textarea
1147
- id="claudeSettingsEditor"
1148
- class="form-input mono"
1149
- style="min-height: 200px; white-space: pre; font-family: var(--font-mono);"
1150
- ></textarea>
1151
- <div class="form-hint" style="margin-top: 4px;">
1152
- 折叠/展开以隐藏或查看完整配置。
1144
+ </details>
1145
+ <details id="claudeSettingsContainer" style="margin-top: 12px;">
1146
+ <summary class="form-label" style="cursor: pointer;" id="claudeSettingsSummary">~/.claude/settings.json</summary>
1147
+ <div style="margin-top: 12px;">
1148
+ <textarea
1149
+ id="claudeSettingsEditor"
1150
+ class="form-input mono"
1151
+ style="min-height: 180px; white-space: pre; font-family: var(--font-mono);"
1152
+ ></textarea>
1153
+ <div style="margin-top: 8px;">
1154
+ <button type="button" id="saveClaudeSettingsBtn" class="btn btn-secondary btn-sm"><span id="saveClaudeSettingsBtnText">Save</span></button>
1155
+ </div>
1153
1156
  </div>
1154
1157
  </details>
1155
1158
  </div>
@@ -1207,32 +1210,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
1207
1210
  </div>
1208
1211
  </section>
1209
1212
 
1210
- <!-- Config Editor Section -->
1211
- <section class="section" id="configEditorSection" style="display:none">
1212
- <div class="section-header">
1213
- <h2 class="section-title" id="configEditorTitle">Config Editor</h2>
1214
- <p class="section-description" id="configEditorHint">Edit ~/.open-im/config.json directly</p>
1215
- </div>
1216
-
1217
- <div class="card">
1218
- <div class="card-body">
1219
- <div class="form-group">
1220
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:12px;">
1221
- <label class="form-label" id="configJson-label">Configuration (JSON)</label>
1222
- <div style="display:flex; gap:8px;">
1223
- <button id="formatJsonButton" class="btn btn-sm btn-ghost">Format</button>
1224
- <button id="resetJsonButton" class="btn btn-sm btn-ghost">Reset</button>
1225
- </div>
1226
- </div>
1227
- <textarea id="configJson" class="form-input mono" rows="20" style="font-family:monospace; font-size:13px; line-height:1.5; min-height:400px; resize:vertical;" spellcheck="false"></textarea>
1228
- <p class="form-hint" id="configJson-hint">Edit the configuration JSON. Changes will be saved when you click "Save Config" in the Service section.</p>
1229
- </div>
1230
- <div class="form-group">
1231
- <div id="jsonValidationMessage" class="message hidden" aria-live="polite"></div>
1232
- </div>
1233
- </div>
1234
- </div>
1235
- </section>
1236
1213
  </div>
1237
1214
  </main>
1238
1215
  </div>
@@ -673,6 +673,47 @@ export async function startWebConfigServer(options) {
673
673
  });
674
674
  return;
675
675
  }
676
+ if (request.method === "GET" && requestUrl.pathname === "/api/config/file") {
677
+ try {
678
+ let contents = "{}";
679
+ if (existsSync(CONFIG_PATH)) {
680
+ contents = readFileSync(CONFIG_PATH, "utf-8");
681
+ }
682
+ json(response, 200, { path: CONFIG_PATH, contents });
683
+ }
684
+ catch (error) {
685
+ json(response, 500, { error: error instanceof Error ? error.message : String(error) });
686
+ }
687
+ return;
688
+ }
689
+ if (request.method === "POST" && requestUrl.pathname === "/api/config/file") {
690
+ try {
691
+ const body = await readJson(request);
692
+ const raw = body.contents ?? "";
693
+ if (!raw.trim()) {
694
+ json(response, 400, { error: "contents is required" });
695
+ return;
696
+ }
697
+ try {
698
+ JSON.parse(raw);
699
+ }
700
+ catch {
701
+ json(response, 400, { error: "Invalid JSON" });
702
+ return;
703
+ }
704
+ const dir = dirname(CONFIG_PATH);
705
+ if (!existsSync(dir)) {
706
+ mkdirSync(dir, { recursive: true });
707
+ }
708
+ writeFileSync(CONFIG_PATH, raw, "utf-8");
709
+ loadConfig();
710
+ json(response, 200, { message: "Config file saved.", path: CONFIG_PATH });
711
+ }
712
+ catch (error) {
713
+ json(response, 500, { error: error instanceof Error ? error.message : String(error) });
714
+ }
715
+ return;
716
+ }
676
717
  if (request.method === "POST" && requestUrl.pathname === "/api/config/validate") {
677
718
  try {
678
719
  const body = await readJson(request);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wu529778790/open-im",
3
- "version": "1.8.1-beta.0",
3
+ "version": "1.8.1-beta.1",
4
4
  "description": "Multi-platform IM bridge for AI CLI tools (Claude, Codex, CodeBuddy)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",