jishushell 0.5.15 → 0.5.22

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.
Files changed (97) hide show
  1. package/Dockerfile.hermes-slim +2 -5
  2. package/apps/filebrowser-container.yaml +1 -0
  3. package/apps/ollama-binary.yaml +44 -0
  4. package/apps/ollama-with-hollama-binary.yaml +45 -1
  5. package/dist/cli/doctor.js +144 -16
  6. package/dist/cli/doctor.js.map +1 -1
  7. package/dist/install.js +1 -1
  8. package/dist/install.js.map +1 -1
  9. package/dist/routes/instances.js +42 -5
  10. package/dist/routes/instances.js.map +1 -1
  11. package/dist/routes/llm.js +29 -0
  12. package/dist/routes/llm.js.map +1 -1
  13. package/dist/server.js +18 -4
  14. package/dist/server.js.map +1 -1
  15. package/dist/services/agent-apps/catalog.d.ts +3 -0
  16. package/dist/services/agent-apps/catalog.js +40 -13
  17. package/dist/services/agent-apps/catalog.js.map +1 -1
  18. package/dist/services/agent-apps/installers/shell-script.d.ts +1 -1
  19. package/dist/services/agent-apps/installers/shell-script.js +19 -2
  20. package/dist/services/agent-apps/installers/shell-script.js.map +1 -1
  21. package/dist/services/agent-apps/types.d.ts +3 -0
  22. package/dist/services/app/app-manager.d.ts +8 -0
  23. package/dist/services/app/app-manager.js +77 -3
  24. package/dist/services/app/app-manager.js.map +1 -1
  25. package/dist/services/app/openclaw-manager.js +17 -2
  26. package/dist/services/app/openclaw-manager.js.map +1 -1
  27. package/dist/services/backup-manager.js +43 -4
  28. package/dist/services/backup-manager.js.map +1 -1
  29. package/dist/services/capability-endpoint-validator.js +26 -7
  30. package/dist/services/capability-endpoint-validator.js.map +1 -1
  31. package/dist/services/instance-manager.js +89 -9
  32. package/dist/services/instance-manager.js.map +1 -1
  33. package/dist/services/llm-proxy/index.d.ts +28 -0
  34. package/dist/services/llm-proxy/index.js +76 -3
  35. package/dist/services/llm-proxy/index.js.map +1 -1
  36. package/dist/services/llm-proxy/validate-key.d.ts +41 -0
  37. package/dist/services/llm-proxy/validate-key.js +672 -0
  38. package/dist/services/llm-proxy/validate-key.js.map +1 -0
  39. package/dist/services/macos-launchd.d.ts +89 -0
  40. package/dist/services/macos-launchd.js +273 -0
  41. package/dist/services/macos-launchd.js.map +1 -0
  42. package/dist/services/nomad-manager.d.ts +7 -0
  43. package/dist/services/nomad-manager.js +290 -79
  44. package/dist/services/nomad-manager.js.map +1 -1
  45. package/dist/services/panel-manager.js +20 -10
  46. package/dist/services/panel-manager.js.map +1 -1
  47. package/dist/services/runtime/adapters/custom.js +56 -0
  48. package/dist/services/runtime/adapters/custom.js.map +1 -1
  49. package/dist/services/runtime/adapters/hermes.d.ts +4 -3
  50. package/dist/services/runtime/adapters/hermes.js +165 -63
  51. package/dist/services/runtime/adapters/hermes.js.map +1 -1
  52. package/dist/services/runtime/adapters/openclaw.d.ts +28 -0
  53. package/dist/services/runtime/adapters/openclaw.js +502 -4
  54. package/dist/services/runtime/adapters/openclaw.js.map +1 -1
  55. package/dist/services/setup-manager.js +97 -50
  56. package/dist/services/setup-manager.js.map +1 -1
  57. package/dist/services/update-manager.js +32 -14
  58. package/dist/services/update-manager.js.map +1 -1
  59. package/dist/types.d.ts +1 -0
  60. package/install/jishu-install.sh +247 -35
  61. package/install/jishu-uninstall.sh +45 -5
  62. package/package.json +5 -2
  63. package/public/assets/ApiKeyField-CvyAOcJS.js +1 -0
  64. package/public/assets/Dashboard-AuJESBlJ.js +1 -0
  65. package/public/assets/{HermesChatPanel-B_2HlVBQ.js → HermesChatPanel-CByPREwb.js} +1 -1
  66. package/public/assets/HermesConfigForm-DRda8FKX.js +4 -0
  67. package/public/assets/InitPassword-ka4wNpM5.js +1 -0
  68. package/public/assets/InstanceDetail-Cg1nS8HX.js +92 -0
  69. package/public/assets/Login-aPajuQzf.js +1 -0
  70. package/public/assets/NewInstance-Dd1ebNIx.js +1 -0
  71. package/public/assets/ProviderRecommendations-DFmADQ7V.js +1 -0
  72. package/public/assets/Settings-BYQnbLYL.js +1 -0
  73. package/public/assets/Setup-D05lwDOV.js +1 -0
  74. package/public/assets/WeixinLoginPanel-D89kdhP4.js +9 -0
  75. package/public/assets/index-HSXCsceK.css +1 -0
  76. package/public/assets/{index-BZc5zH7u.js → index-bnBu0nlQ.js} +7 -7
  77. package/public/assets/registry-C_qeFTkZ.js +2 -0
  78. package/public/assets/usePolling-Bn93fe7M.js +1 -0
  79. package/public/assets/{vendor-i18n-y9V7Sfuu.js → vendor-i18n-flxcMVeP.js} +2 -2
  80. package/public/assets/{vendor-react-BWrEVJVb.js → vendor-react-ZC5T_huj.js} +1 -1
  81. package/public/index.html +4 -4
  82. package/scripts/check-colima-launchd.mjs +230 -0
  83. package/public/assets/Dashboard-BdWPtroF.js +0 -1
  84. package/public/assets/HermesConfigForm-DVlhg3WV.js +0 -4
  85. package/public/assets/InitPassword-D7glTExX.js +0 -1
  86. package/public/assets/InstanceDetail-CxSy2cpe.js +0 -92
  87. package/public/assets/Login-Cfr5c2sv.js +0 -1
  88. package/public/assets/NewInstance-BIYDmJis.js +0 -1
  89. package/public/assets/ProviderRecommendations-BuRnvRcI.js +0 -1
  90. package/public/assets/Settings-Cc-tYBil.js +0 -1
  91. package/public/assets/Setup-lGZEk5jq.js +0 -1
  92. package/public/assets/WeixinLoginPanel-CoGqzxeV.js +0 -9
  93. package/public/assets/index-87IJXG-w.css +0 -1
  94. package/public/assets/input-paste-CrNVAyOy.js +0 -1
  95. package/public/assets/providers-DtNXh9JD.js +0 -1
  96. package/public/assets/registry-BWnkJgZ1.js +0 -2
  97. package/public/assets/usePolling-CwwT9KrC.js +0 -1
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Static validator for the macOS Colima/Nomad/Panel launchd artifacts
4
+ * produced by install/jishu-install.sh and the doctor self-heal checks.
5
+ * Mirrors the text-assertion style of scripts/check-app-spec.mjs — runs
6
+ * in CI without a Mac. Exits non-zero on any failed assertion.
7
+ */
8
+ import { readFileSync } from "fs";
9
+ import { join, dirname } from "path";
10
+ import { fileURLToPath } from "url";
11
+
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const ROOT = join(__dirname, "..");
14
+ const installer = readFileSync(join(ROOT, "install/jishu-install.sh"), "utf8");
15
+ const doctor = readFileSync(join(ROOT, "src/cli/doctor.ts"), "utf8");
16
+
17
+ const failures = [];
18
+ const must = (cond, msg) => { if (!cond) failures.push(msg); };
19
+
20
+ // Task 2 (ARM-only) — macOS is Apple Silicon only: constant arch/vm-type,
21
+ // fail-fast on non-arm64 Darwin, no Intel/qemu derivation.
22
+ must(/COLIMA_ARCH="aarch64"/.test(installer),
23
+ 'installer must set COLIMA_ARCH="aarch64" (Apple Silicon only)');
24
+ must(/COLIMA_VM_TYPE="vz"/.test(installer),
25
+ 'installer must set COLIMA_VM_TYPE="vz" (Apple Silicon only)');
26
+ must(!/<string>--arch<\/string><string>aarch64<\/string>/.test(installer),
27
+ "colima plist must not hardcode --arch aarch64 (use ${COLIMA_ARCH})");
28
+ must(!/COLIMA_VM_TYPE="?qemu/.test(installer),
29
+ "no qemu COLIMA_VM_TYPE (macOS is Apple Silicon only)");
30
+ must(/Apple Silicon \(arm64\) only/.test(installer),
31
+ "installer must fail fast on non-arm64 macOS with an Apple-Silicon-only message");
32
+
33
+ // Task 3 — colima wait/start wrapper + hardened plist
34
+ must(/_install_colima_wait_start_wrapper\(\)/.test(installer),
35
+ "installer must define _install_colima_wait_start_wrapper()");
36
+ must(/colima-launchd-wrapper\.sh/.test(installer),
37
+ "installer must generate colima-launchd-wrapper.sh");
38
+ must(!/colima"?\s+delete/.test(installer.replace(/#.*$/gm, "")),
39
+ "colima wrapper must never run `colima delete` (destroys the openclaw image)");
40
+ must(/SuccessfulExit<\/key>\s*<false\/>/.test(installer),
41
+ "colima plist must use KeepAlive={SuccessfulExit:false}");
42
+ must(/<key>ThrottleInterval<\/key>\s*<integer>30<\/integer>/.test(installer),
43
+ "colima plist must set ThrottleInterval=30");
44
+
45
+ // Task 4 — panel 60s docker gate
46
+ must(/panel-launchd-wrapper\.sh/.test(installer),
47
+ "installer must generate panel-launchd-wrapper.sh (60s docker gate)");
48
+ must(/PANEL_DOCKER_WAIT_DEADLINE=60\b/.test(installer),
49
+ "panel gate deadline must be 60s");
50
+
51
+ // Task 5 — autologin opt-in + FileVault guard + flags
52
+ must(/_enable_autologin\(\)/.test(installer),
53
+ "installer must define _enable_autologin()");
54
+ must(/ENABLE_AUTOLOGIN="?\$\{ENABLE_AUTOLOGIN:-0\}"?/.test(installer),
55
+ "ENABLE_AUTOLOGIN must default to 0 (opt-in)");
56
+ must(/--enable-autologin/.test(installer) && /--no-autologin/.test(installer)
57
+ && /--autologin-password/.test(installer),
58
+ "installer must accept --enable-autologin / --no-autologin / --autologin-password");
59
+ must(/fdesetup status/.test(installer),
60
+ "_enable_autologin must check FileVault via `fdesetup status`");
61
+ must(/0x7D 0x89 0x52 0x23 0xD2 0xBC 0xDD 0xEA 0xA3 0xB9 0x1F/.test(installer),
62
+ "kcpassword cipher key bytes must be present");
63
+
64
+ // Task 6 — doctor self-heal checks registered
65
+ for (const id of ["colima-launchd", "colima-wrapper", "macos-autologin"]) {
66
+ must(new RegExp(`id:\\s*"${id}"`).test(doctor),
67
+ `doctor must define a check with id "${id}"`);
68
+ }
69
+ must(/checkColimaLaunchd[,\s]/.test(doctor) && /ALL_CHECKS/.test(doctor),
70
+ "doctor must register the new checks in ALL_CHECKS");
71
+
72
+ // ─────────────────────────────────────────────────────────────────────
73
+ // Follow-up #14 — TypeScript install path parity. `jishushell install`
74
+ // and the Setup wizard go through src/services/setup-manager.ts, which
75
+ // must produce the SAME hardened launchd artifacts as the bash installer
76
+ // (otherwise any reinstall/update reverts the headless-reboot fix).
77
+ // These assertions read the canonical TS builders in macos-launchd.ts.
78
+ const tsLaunchd = readFileSync(join(ROOT, "src/services/macos-launchd.ts"), "utf8");
79
+ const setupMgr = readFileSync(join(ROOT, "src/services/setup-manager.ts"), "utf8");
80
+ const tsLaunchdNoComments = tsLaunchd.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
81
+
82
+ // setup-manager must import + use the canonical builders.
83
+ must(/from\s+"\.\/macos-launchd\.js"/.test(setupMgr),
84
+ "setup-manager.ts must import the canonical builders from ./macos-launchd.js");
85
+ must(/buildColimaWrapperScript\(/.test(setupMgr) && /buildColimaPlist\(/.test(setupMgr)
86
+ && /buildNomadWaitWrapper\(/.test(setupMgr) && /buildNomadPlist\(/.test(setupMgr)
87
+ && /buildPanelGateWrapper\(/.test(setupMgr) && /buildPanelPlist\(/.test(setupMgr),
88
+ "setup-manager.ts must call all six macos-launchd builders");
89
+ must(/appleSiliconGuard\(/.test(setupMgr),
90
+ "setup-manager.ts must gate the macOS branch with appleSiliconGuard()");
91
+
92
+ // Colima wrapper: atomic mkdir single-flight lock, no flock, never delete.
93
+ must(/mkdir\s+-p\s+"\\\$COLIMA_HOME"/.test(tsLaunchd),
94
+ 'TS colima wrapper must mkdir -p "$COLIMA_HOME"');
95
+ must(/mkdir\s+"\\\$LOCKDIR"/.test(tsLaunchd),
96
+ 'TS colima wrapper must use an atomic `mkdir "$LOCKDIR"` single-flight lock');
97
+ must(/trap '.*rmdir "\\\$LOCKDIR".*' EXIT/.test(tsLaunchd),
98
+ "TS colima wrapper must rmdir the lockdir on EXIT");
99
+ must(!/\bflock\b/.test(tsLaunchd),
100
+ "TS launchd builders must not use flock (macOS lacks it; mkdir-lock only)");
101
+ must(!/colima"?\s+delete/.test(tsLaunchdNoComments) && !/"delete"/.test(tsLaunchdNoComments),
102
+ "TS colima wrapper must never run `colima delete` (destroys the openclaw image)");
103
+ must(/--vm-type \$\{COLIMA_VM_TYPE\}/.test(tsLaunchd) && /--arch \$\{COLIMA_ARCH\}/.test(tsLaunchd),
104
+ "TS colima wrapper must use the COLIMA_VM_TYPE / COLIMA_ARCH consts for start flags");
105
+
106
+ // Apple-Silicon-only constants — no qemu / x86_64 derivation.
107
+ must(/COLIMA_ARCH\s*=\s*"aarch64"/.test(tsLaunchd),
108
+ 'macos-launchd.ts must export COLIMA_ARCH = "aarch64"');
109
+ must(/COLIMA_VM_TYPE\s*=\s*"vz"/.test(tsLaunchd),
110
+ 'macos-launchd.ts must export COLIMA_VM_TYPE = "vz"');
111
+ must(!/qemu/.test(tsLaunchdNoComments) && !/x86_64/.test(tsLaunchdNoComments),
112
+ "macos-launchd.ts must not reference qemu / x86_64 (Apple Silicon only)");
113
+ must(/Apple Silicon \(arm64\) only/.test(tsLaunchd) && /appleSiliconGuard/.test(tsLaunchd),
114
+ "macos-launchd.ts must define appleSiliconGuard with an Apple-Silicon-only message");
115
+
116
+ // Colima plist: KeepAlive={SuccessfulExit:false} + ThrottleInterval 30.
117
+ must(/<key>SuccessfulExit<\/key>\s*<false\/>/.test(tsLaunchd),
118
+ "TS colima plist must use KeepAlive={SuccessfulExit:false}");
119
+ must(/<key>ThrottleInterval<\/key>\s*<integer>30<\/integer>/.test(tsLaunchd),
120
+ "TS colima plist must set ThrottleInterval=30");
121
+
122
+ // Panel 60s docker gate; nomad waits for docker before exec.
123
+ must(/PANEL_DOCKER_WAIT_DEADLINE=60\b/.test(tsLaunchd),
124
+ "TS panel gate deadline must be 60s");
125
+ must(/docker info/.test(tsLaunchd) && /exec "\$\{nomadBin\}" agent/.test(tsLaunchd),
126
+ "TS nomad wait wrapper must poll docker then exec nomad");
127
+
128
+ // ─────────────────────────────────────────────────────────────────────
129
+ // Follow-up #14 nit — bash↔TS budget cross-link. The retry/timeout budgets
130
+ // (60/180/throttle-30/retry-5/sleep-10) are duplicated between the bash
131
+ // installer and the TS builders. The assertions above only check each side
132
+ // in isolation, so a lockstep edit (60→90 in both) or a bash-only edit
133
+ // would pass vacuously and silently drift the two install paths apart.
134
+ // Extract the SAME budget literal from BOTH sources and assert equality so
135
+ // any divergence fails loudly with both values named.
136
+ const extract = (src, re, label, side) => {
137
+ const m = re.exec(src);
138
+ if (!m) { failures.push(`${side} source missing budget literal: ${label}`); return null; }
139
+ return m[1];
140
+ };
141
+ const crossLink = (label, bashRe, tsRe) => {
142
+ const b = extract(installer, bashRe, label, "bash");
143
+ const t = extract(tsLaunchd, tsRe, label, "TS");
144
+ if (b !== null && t !== null) {
145
+ must(b === t,
146
+ `${label} budget drift: bash=${b} != TS=${t} ` +
147
+ `(install/jishu-install.sh vs src/services/macos-launchd.ts must stay lockstep)`);
148
+ }
149
+ };
150
+
151
+ // panel docker-wait deadline (PANEL_DOCKER_WAIT_DEADLINE=60).
152
+ crossLink("PANEL_DOCKER_WAIT_DEADLINE",
153
+ /PANEL_DOCKER_WAIT_DEADLINE=(\d+)\b/,
154
+ /PANEL_DOCKER_WAIT_DEADLINE=(\d+)\b/);
155
+
156
+ // nomad docker-wait budget (deadline = now + 180, echoed "after 180s").
157
+ crossLink("nomad docker-wait seconds",
158
+ /deadline=\\?\$\(\(\s*\\?\$\(date \+%s\)\s*\+\s*(\d+)\s*\)\)[\s\S]{0,160}?\[nomad-launchd-wrapper\]/,
159
+ /deadline=\\?\$\(\(\s*\\?\$\(date \+%s\)\s*\+\s*(\d+)\s*\)\)[\s\S]{0,160}?\[nomad-launchd-wrapper\]/);
160
+ crossLink("nomad timeout message seconds",
161
+ /\[nomad-launchd-wrapper\][\s\S]{0,80}?after (\d+)s/,
162
+ /\[nomad-launchd-wrapper\][\s\S]{0,80}?after (\d+)s/);
163
+
164
+ // colima network-wait deadline (net_deadline = now + 60).
165
+ crossLink("colima net-wait seconds",
166
+ /net_deadline=\\?\$\(\(\s*\\?\$\(date \+%s\)\s*\+\s*(\d+)\s*\)\)/,
167
+ /net_deadline=\\?\$\(\(\s*\\?\$\(date \+%s\)\s*\+\s*(\d+)\s*\)\)/);
168
+
169
+ // colima plist ThrottleInterval.
170
+ crossLink("colima ThrottleInterval",
171
+ /<key>ThrottleInterval<\/key>\s*<integer>(\d+)<\/integer>/,
172
+ /<key>ThrottleInterval<\/key>\s*<integer>(\d+)<\/integer>/);
173
+
174
+ // colima retry attempt bound ([ $attempt -lt 5 ]).
175
+ crossLink("colima retry attempts",
176
+ /\[\s*\\?\$attempt\s+-lt\s+(\d+)\s*\]/,
177
+ /\[\s*\\?\$attempt\s+-lt\s+(\d+)\s*\]/);
178
+
179
+ // colima per-attempt backoff multiplier (sleep $(( attempt * 10 ))).
180
+ crossLink("colima backoff multiplier",
181
+ /sleep\s+\\?\$\(\(\s*attempt\s*\*\s*(\d+)\s*\)\)/,
182
+ /sleep\s+\\?\$\(\(\s*attempt\s*\*\s*(\d+)\s*\)\)/);
183
+
184
+ // ─────────────────────────────────────────────────────────────────────
185
+ // M1 — stale mkdir-lock reclamation. If the wrapper is SIGKILLed/power-cut
186
+ // before the `trap rmdir EXIT` is installed, $LOCKDIR is orphaned and every
187
+ // subsequent launchd fire dead-ends at "another start in progress" → colima
188
+ // never recovers. The wrapper reclaims a $LOCKDIR older than the staleness
189
+ // budget (rmdir only removes it while still empty — safe). Assert the line is
190
+ // present on BOTH install paths and the budget literal stays lockstep.
191
+ const staleReclaimRe =
192
+ /\[\s*-d\s+"\\?\$LOCKDIR"\s*\]\s*&&\s*find\s+"\\?\$LOCKDIR"\s+-maxdepth\s+0\s+-type\s+d\s+-mmin\s+\+\d+\s+-exec\s+rmdir\s+\{\}\s+\\\\;\s+2>\/dev\/null\s+\|\|\s+true/;
193
+ must(staleReclaimRe.test(installer),
194
+ "bash colima-wrapper heredoc (install/jishu-install.sh) must reclaim a stale mkdir-lock " +
195
+ 'before acquiring it ([ -d "$LOCKDIR" ] && find ... -mmin +N -exec rmdir {} \\;)');
196
+ must(staleReclaimRe.test(tsLaunchd),
197
+ "TS buildColimaWrapperScript (src/services/macos-launchd.ts) must reclaim a stale " +
198
+ 'mkdir-lock before acquiring it ([ -d "$LOCKDIR" ] && find ... -mmin +N -exec rmdir {} \\;)');
199
+
200
+ // staleness budget literal (-mmin +10) must match bash↔TS.
201
+ crossLink("colima stale-lock mmin budget",
202
+ /find\s+"\\?\$LOCKDIR"\s+-maxdepth\s+0\s+-type\s+d\s+-mmin\s+\+(\d+)\s+-exec\s+rmdir/,
203
+ /find\s+"\\?\$LOCKDIR"\s+-maxdepth\s+0\s+-type\s+d\s+-mmin\s+\+(\d+)\s+-exec\s+rmdir/);
204
+
205
+ // ─────────────────────────────────────────────────────────────────────
206
+ // M1+ — per-retry lock-mtime refresh. The mkdir-lock's mtime is stamped
207
+ // ONCE at acquire and never refreshed, so a single legit `colima start`
208
+ // invocation whose total wall-time exceeds the staleness budget (cold VM
209
+ // init + ≤5 attempts + cumulative backoff) is seen as `-mmin +N` stale by
210
+ // the next launchd fire, which then reclaims the still-held lock and starts
211
+ // colima concurrently. The wrapper re-stamps $LOCKDIR at the top of every
212
+ // retry attempt so an actively-progressing start is never reclaimed. Assert
213
+ // the line is present on BOTH install paths (no numeric budget to crossLink
214
+ // — presence-on-both-sides is the guard).
215
+ const lockRefreshRe = /touch\s+"\\?\$LOCKDIR"\s+2>\/dev\/null\s+\|\|\s+true/;
216
+ must(lockRefreshRe.test(installer),
217
+ "bash colima-wrapper heredoc (install/jishu-install.sh) must refresh its own " +
218
+ 'lock mtime each retry attempt (touch "$LOCKDIR" 2>/dev/null || true) so a ' +
219
+ "long in-progress start is never reclaimed as stale");
220
+ must(lockRefreshRe.test(tsLaunchd),
221
+ "TS buildColimaWrapperScript (src/services/macos-launchd.ts) must refresh its own " +
222
+ 'lock mtime each retry attempt (touch "$LOCKDIR" 2>/dev/null || true) so a ' +
223
+ "long in-progress start is never reclaimed as stale");
224
+
225
+ if (failures.length) {
226
+ console.error("check-colima-launchd FAILED:");
227
+ for (const f of failures) console.error(" ✗ " + f);
228
+ process.exit(1);
229
+ }
230
+ console.log("check-colima-launchd OK");
@@ -1 +0,0 @@
1
- import{k as W,j as e,L as K,l as $,m as A,n as L,o as I,q as T,t as E,v as M,w as R,x as U}from"./index-BZc5zH7u.js";import{r as u,u as D}from"./vendor-react-BWrEVJVb.js";import{u as P}from"./usePolling-CwwT9KrC.js";import{u as _}from"./vendor-i18n-y9V7Sfuu.js";function G(t){if(!t)return"-";const o=Math.floor(t/86400),l=Math.floor(t%86400/3600),a=Math.floor(t%3600/60);return o>0?`${o}d ${l}h`:l>0?`${l}h ${a}m`:`${a}m`}function q({status:t}){const{t:o}=_(),a={running:{cls:"bg-emerald-500/10 text-emerald-400 border border-emerald-500/20",labelKey:"status.running"},pending:{cls:"bg-amber-500/10 text-amber-400 border border-amber-500/20",labelKey:"status.starting"},failed:{cls:"bg-red-500/10 text-red-400 border border-red-500/20",labelKey:"status.failed"},dead:{cls:"bg-red-500/10 text-red-400 border border-red-500/20",labelKey:"status.crashed"}}[t]||{cls:"bg-[var(--card)] text-muted border border-[var(--border)]",labelKey:"status.stopped"};return e.jsx("span",{className:`inline-flex items-center text-xs px-2 py-0.5 rounded-full font-medium ${a.cls}`,children:o(a.labelKey)})}const O=[{key:"localInference",labelKey:"capability.localInference",cls:"bg-emerald-500/10 text-emerald-400 border-emerald-500/20"},{key:"knowledgeBase",labelKey:"capability.knowledgeBase",cls:"bg-indigo-500/10 text-indigo-400 border-indigo-500/20"},{key:"files",labelKey:"capability.files",cls:"bg-amber-500/10 text-amber-400 border-amber-500/20"},{key:"search",labelKey:"capability.search",cls:"bg-sky-500/10 text-sky-400 border-sky-500/20"},{key:"browser",labelKey:"capability.browser",cls:"bg-violet-500/10 text-violet-400 border-violet-500/20"},{key:"aiWebUi",labelKey:"capability.aiWebUi",cls:"bg-cyan-500/10 text-cyan-400 border-cyan-500/20"},{key:"webUi",labelKey:"capability.webUi",cls:"bg-slate-500/10 text-muted border-[var(--border)]"}];function V(t){const o=new Set((Array.isArray(t==null?void 0:t.provides)?t.provides:[]).map(r=>String((r==null?void 0:r.capability)??"").toLowerCase()).filter(Boolean));if(o.has("llm-agent"))return[];const l=r=>{for(const m of o)if(r(m))return!0;return!1},a=new Set;return l(r=>r==="llm-ollama"||r==="ollama-api")&&a.add("localInference"),l(r=>r.startsWith("knowledge-")||r.includes("anythingllm")||r.includes("weknora"))&&a.add("knowledgeBase"),l(r=>r.startsWith("files-")||r.includes("filebrowser"))&&a.add("files"),l(r=>r==="search"||r.startsWith("search-"))&&a.add("search"),l(r=>r==="browser"||r.startsWith("browser-")||r.startsWith("web-browserless")||r.startsWith("playwright"))&&a.add("browser"),l(r=>r.includes("openwebui"))&&a.add("aiWebUi"),!a.size&&l(r=>r.startsWith("web-")||r.endsWith("-web")||r.endsWith("-dashboard"))&&a.add("webUi"),O.filter(r=>a.has(r.key))}function Q(){const{t}=_(["dashboard","common"]),[o,l]=u.useState([]),[a,r]=u.useState(null),[m,v]=u.useState(""),[j,w]=u.useState(""),[g,N]=u.useState(!1),f=D(),{showToast:b}=W(),h=()=>{I().then(s=>{l(s),w("")}).catch(s=>w(s.message||t("common:error.loadFailed"))),T().then(r).catch(()=>{})};P(h,1e4);const F=async()=>{if(window.confirm(t("engine.restartConfirm"))){N(!0);try{await E(),b(t("engine.restarted"),"success"),setTimeout(h,2e3)}catch(s){b(s.message||t("engine.restartFailed"),"error")}finally{N(!1)}}},y=async(s,n,x)=>{s.stopPropagation(),v(`${x}-${n}`);try{let i=null;n==="start"&&(i=await M(x)),n==="stop"&&(i=await R(x)),n==="restart"&&(i=await U(x)),b(t(`common:action.${n}Done`),"success");const d=i==null?void 0:i.port_allocation;d&&typeof d.from=="number"&&typeof d.to=="number"&&d.from!==d.to&&b(t("common:toast.portReallocated",{defaultValue:"端口 {{from}} 被占用,已自动切换到 {{to}}",from:d.from,to:d.to}),"info"),setTimeout(h,1e3)}catch(i){b(i.message||t("common:error.operationFailed"),"error")}finally{v("")}},S=o.filter(s=>{var n;return((n=s.service)==null?void 0:n.status)==="running"}).length,p=!!a&&a.disk.percent>90,B=a?[{label:t("stats.runningInstances"),value:`${S} / ${o.length}`,sub:a.nomad_running?t("stats.engineRunning"):t("stats.engineStopped"),subColor:a.nomad_running?"text-emerald-400":"text-red-400",icon:e.jsxs("svg",{className:"w-4 h-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.5,children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2"}),e.jsx("line",{x1:"8",y1:"21",x2:"16",y2:"21"}),e.jsx("line",{x1:"12",y1:"17",x2:"12",y2:"21"})]}),iconColor:"text-[#0066FF]",glowColor:"rgba(0,102,255,0.12)",accent:"border-l-2 border-l-[#0066FF]"},{label:t("stats.cpu"),value:`${a.cpu_percent}%`,sub:a.temperature?`${a.temperature}°C`:null,icon:e.jsxs("svg",{className:"w-4 h-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.5,children:[e.jsx("rect",{x:"4",y:"4",width:"16",height:"16",rx:"2"}),e.jsx("rect",{x:"9",y:"9",width:"6",height:"6"}),e.jsx("line",{x1:"9",y1:"2",x2:"9",y2:"4"}),e.jsx("line",{x1:"15",y1:"2",x2:"15",y2:"4"}),e.jsx("line",{x1:"9",y1:"20",x2:"9",y2:"22"}),e.jsx("line",{x1:"15",y1:"20",x2:"15",y2:"22"}),e.jsx("line",{x1:"20",y1:"9",x2:"22",y2:"9"}),e.jsx("line",{x1:"20",y1:"15",x2:"22",y2:"15"}),e.jsx("line",{x1:"2",y1:"9",x2:"4",y2:"9"}),e.jsx("line",{x1:"2",y1:"15",x2:"4",y2:"15"})]}),iconColor:"text-[#0066FF]",glowColor:"rgba(0,102,255,0.12)",accent:"border-l-2 border-l-[#0066FF]",warn:a.cpu_percent>90},{label:t("stats.memory"),value:`${a.memory.percent}%`,sub:`${a.memory.used_mb}MB / ${a.memory.total_mb}MB`,icon:e.jsx("svg",{className:"w-4 h-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{d:"M6 19v-8m4 8v-4m4 4v-6m4 6v-2"})}),iconColor:"text-[#00D4AA]",glowColor:"rgba(0,212,170,0.12)",accent:"border-l-2 border-l-[#00D4AA]"},{label:t("stats.disk"),value:`${a.disk.percent}%`,sub:`${a.disk.used_gb}GB / ${a.disk.total_gb}GB`,icon:e.jsxs("svg",{className:"w-4 h-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.5,children:[e.jsx("ellipse",{cx:"12",cy:"5",rx:"9",ry:"3"}),e.jsx("path",{d:"M3 5v14a9 3 0 0018 0V5"}),e.jsx("line",{x1:"12",y1:"8",x2:"12",y2:"22"})]}),iconColor:p?"text-red-400":"text-[#0066FF]",glowColor:p?"rgba(239,68,68,0.12)":"rgba(0,102,255,0.12)",accent:p?"border-l-2 border-l-red-400":"border-l-2 border-l-[#0066FF]",warn:p}]:[];return e.jsxs("div",{className:"p-4 2xl:px-6 2xl:py-3 max-w-5xl xl:max-w-6xl 2xl:max-w-none mx-auto",children:[e.jsxs("div",{className:"mb-4 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-base font-semibold text-foreground",children:t("title")}),e.jsx("p",{className:"text-xs text-muted mt-0.5",children:t("subtitle")})]}),e.jsx(K,{})]}),a&&e.jsx("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-3 mb-4",children:B.map(s=>e.jsxs("div",{className:`bg-[var(--card)] border border-[var(--border)] rounded-lg p-3 relative overflow-hidden hover:border-[var(--border-hover)] hover:bg-[var(--card-hover)] transition-all duration-200 ${s.accent}`,children:[e.jsx("div",{className:"absolute top-0 right-0 w-16 h-16 rounded-full opacity-60 pointer-events-none",style:{background:`radial-gradient(circle, ${s.glowColor} 0%, transparent 70%)`}}),e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("span",{className:"text-[11px] text-muted",children:s.label}),e.jsx("span",{className:`${s.iconColor} opacity-80`,children:s.icon})]}),e.jsx("div",{className:`text-lg font-semibold ${s.warn?"text-red-400":"text-foreground"}`,children:s.value}),s.sub&&e.jsx("div",{className:`text-[11px] mt-0.5 truncate ${s.subColor??"text-muted"}`,children:s.sub})]},s.label))}),e.jsxs("div",{className:"bg-[var(--card)] border border-[var(--border)] rounded-xl overflow-hidden",children:[e.jsxs("div",{className:"px-4 py-2.5 border-b border-[var(--border)] flex items-center justify-between",children:[e.jsx("h2",{className:"text-sm font-medium text-foreground",children:t("instances.title")}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:()=>f("/instances/new"),className:"bg-[#0066FF] text-white px-3 py-1.5 rounded-md text-xs font-medium hover:bg-[#0066FF]/90 transition-all duration-200 shadow-[0_0_12px_rgba(0,102,255,0.3)]",children:t("instances.new")}),e.jsx("button",{onClick:()=>f("/instances/new?import=true"),className:"px-3 py-1.5 rounded-md text-xs font-medium text-muted border border-[var(--border)] bg-[var(--card)] hover:bg-[var(--card-hover)] hover:text-foreground transition-all duration-200",children:t("instances.import")}),e.jsxs("button",{onClick:F,disabled:g,title:t("instances.restartEngineTitle"),className:"flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs font-medium text-red-400 border border-red-500/20 bg-red-500/5 hover:bg-red-500/15 disabled:opacity-40 disabled:cursor-not-allowed transition-all duration-200",children:[e.jsx($,{className:`w-3 h-3 ${g?"animate-spin":""}`}),t(g?"instances.restarting":"instances.restartEngine")]})]})]}),j?e.jsxs("div",{className:"text-center py-12 px-4",children:[e.jsx("p",{className:"text-sm text-red-400 mb-2",children:t("instances.loadError",{error:j})}),e.jsx("button",{onClick:h,className:"text-xs text-muted hover:text-foreground underline",children:t("common:action.retry")})]}):o.length===0?e.jsxs("div",{className:"text-center py-12 px-4",children:[e.jsx("div",{className:"text-muted opacity-40 mb-3",children:e.jsxs("svg",{className:"w-8 h-8 mx-auto",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1,strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2"}),e.jsx("line",{x1:"8",y1:"21",x2:"16",y2:"21"}),e.jsx("line",{x1:"12",y1:"17",x2:"12",y2:"21"})]})}),e.jsx("p",{className:"text-sm text-muted mb-1",children:t("instances.empty")}),e.jsx("p",{className:"text-xs text-muted opacity-60",children:t("instances.emptyHint")})]}):e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-xs text-muted border-b border-[var(--border)]",children:[e.jsx("th",{className:"text-left font-medium px-4 py-2",children:t("table.name")}),e.jsx("th",{className:"text-left font-medium px-4 py-2",children:t("table.status")}),e.jsx("th",{className:"text-left font-medium px-4 py-2 hidden sm:table-cell",children:t("table.uptime")}),e.jsx("th",{className:"text-left font-medium px-4 py-2 hidden md:table-cell",children:t("table.memory")}),e.jsx("th",{className:"text-left font-medium px-4 py-2 hidden lg:table-cell",children:t("table.localCapability")}),e.jsx("th",{className:"text-right font-medium px-4 py-2",children:t("table.actions")})]})}),e.jsx("tbody",{className:"divide-y divide-[var(--border)]",children:o.map(s=>{var d,k,C;const n=((d=s.service)==null?void 0:d.status)||"stopped",x=n==="running",i=V(s);return e.jsxs("tr",{className:"hover:bg-[var(--card-hover)] cursor-pointer transition-colors duration-150",onClick:()=>f(`/instances/${s.id}`),children:[e.jsxs("td",{className:"px-4 py-2.5",children:[e.jsx("div",{className:"font-medium text-foreground",children:s.name}),e.jsx("div",{className:"text-xs text-muted font-mono",children:s.id})]}),e.jsx("td",{className:"px-4 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(q,{status:n}),((k=s.auto_backup)==null?void 0:k.enabled)&&e.jsx("span",{className:`text-xs leading-none ${s.auto_backup.last_backup_ok===!1?"text-red-400":"text-green-400"}`,title:s.auto_backup.last_backup_ok===!1?"Backup failed":"Backup OK",children:s.auto_backup.last_backup_ok===!1?"⚠":"●"})]})}),e.jsx("td",{className:"px-4 py-2.5 text-muted hidden sm:table-cell font-mono text-xs",children:x?G(s.service.uptime):"-"}),e.jsx("td",{className:"px-4 py-2.5 text-muted hidden md:table-cell font-mono text-xs",children:(C=s.service)!=null&&C.memory_mb?`${s.service.memory_mb} MB`:"-"}),e.jsx("td",{className:"px-4 py-2.5 hidden lg:table-cell",children:i.length?e.jsx("div",{className:"flex flex-wrap gap-1.5",children:i.map(c=>e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[11px] font-medium ${c.cls}`,children:t(c.labelKey)},c.key))}):e.jsx("span",{className:"text-muted text-xs",children:"-"})}),e.jsx("td",{className:"px-4 py-2.5 text-right",children:e.jsx("div",{className:"inline-flex items-center gap-1",children:x||n==="pending"?e.jsxs(e.Fragment,{children:[e.jsx("button",{title:t("common:action.restart"),onClick:c=>y(c,"restart",s.id),disabled:!!m,className:"p-1.5 rounded-md text-muted hover:text-foreground hover:bg-[var(--card-hover)] disabled:opacity-30 transition-colors duration-150",children:e.jsx($,{className:"w-3.5 h-3.5"})}),e.jsx("button",{title:t("common:action.stop"),onClick:c=>y(c,"stop",s.id),disabled:!!m,className:"p-1.5 rounded-md text-muted hover:text-red-400 hover:bg-red-500/10 disabled:opacity-30 transition-colors duration-150",children:e.jsx(A,{className:"w-3.5 h-3.5"})})]}):e.jsx("button",{title:t("common:action.start"),onClick:c=>y(c,"start",s.id),disabled:!!m,className:"p-1.5 rounded-md text-muted hover:text-emerald-400 hover:bg-emerald-500/10 disabled:opacity-30 transition-colors duration-150",children:e.jsx(L,{className:"w-3.5 h-3.5"})})})})]},s.id)})})]})]})]})}export{Q as default};
@@ -1,4 +0,0 @@
1
- import{aD as pe,j as s,p as ve,$ as fe}from"./index-BZc5zH7u.js";import{r as u,L as Z}from"./vendor-react-BWrEVJVb.js";import{g as ge}from"./input-paste-CrNVAyOy.js";import{P as S}from"./providers-DtNXh9JD.js";import{S as U,F as v,a as R,b as ee,I as K,c as ye,W as be}from"./WeixinLoginPanel-CoGqzxeV.js";import{u as je}from"./vendor-i18n-y9V7Sfuu.js";const Ne=new Set(["feishu","weixin"]),F={telegram:{label:"Telegram",fields:[{key:"token",envKey:"TELEGRAM_BOT_TOKEN",label:"Bot Token",secret:!0,hint:"从 @BotFather 获取"},{key:"allowed",envKey:"TELEGRAM_ALLOWED_USERS",label:"Allowed Users",hint:"逗号分隔 user id,留空=所有人"}]},discord:{label:"Discord",fields:[{key:"token",envKey:"DISCORD_BOT_TOKEN",label:"Bot Token",secret:!0,hint:"从 Discord Developer Portal"}]},slack:{label:"Slack",fields:[{key:"bot",envKey:"SLACK_BOT_TOKEN",label:"Bot Token (xoxb-…)",secret:!0,placeholder:"xoxb-..."},{key:"app",envKey:"SLACK_APP_TOKEN",label:"App Token (xapp-…)",secret:!0,placeholder:"xapp-..."}]},whatsapp:{label:"WhatsApp",fields:[{key:"token",envKey:"WHATSAPP_TOKEN",label:"Access Token",secret:!0}]},signal:{label:"Signal",fields:[{key:"account",envKey:"SIGNAL_ACCOUNT",label:"Phone (E.164)",placeholder:"+8613800138000"}]},email:{label:"Email (SMTP)",fields:[{key:"host",envKey:"SMTP_HOST",label:"SMTP Host",placeholder:"smtp.gmail.com"},{key:"port",envKey:"SMTP_PORT",label:"SMTP Port",placeholder:"587"},{key:"user",envKey:"SMTP_USER",label:"SMTP User"},{key:"pass",envKey:"SMTP_PASSWORD",label:"SMTP Password",secret:!0}]}};function Ae(l){const m=new Map;for(const f of l.split(`
2
- `)){const x=f.trim();if(!x||x.startsWith("#"))continue;const o=x.indexOf("=");if(o<0)continue;const c=x.slice(0,o).trim();let r=x.slice(o+1).trim();(r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'"))&&(r=r.slice(1,-1)),m.set(c,r)}return m}function se(l,m){const f=l.split(`
3
- `),x=new Set,o=[];for(const c of f){const r=c.trim();if(!r||r.startsWith("#")){o.push(c);continue}const g=r.indexOf("=");if(g<0){o.push(c);continue}const N=r.slice(0,g).trim();if(N in m){x.add(N);const C=m[N];if(C==="")continue;o.push(`${N}=${C}`)}else o.push(c)}for(const[c,r]of Object.entries(m))!x.has(c)&&r!==""&&o.push(`${c}=${r}`);return o.join(`
4
- `)}function Ce({config:l,onChange:m,instanceId:f,capabilities:x}){var X;const{t:o}=je(["instance","common"]),c=String((l==null?void 0:l.yaml)||""),r=String((l==null?void 0:l.env)||""),g=u.useMemo(()=>Ae(r),[r]),a=(((l==null?void 0:l["x-jishushell"])||{}).proxy||{}).upstream||{},h=a.providerId||"",k=S.find(e=>e.id===h),E=a.models||[],M=k?k.models.map(e=>({id:e.id,name:e.name,contextWindow:e.contextWindow})):E.map(e=>({id:e.id,name:e.name||e.id,contextWindow:e.contextWindow||0})),y=a.selectedModelId||((X=M[0])==null?void 0:X.id)||"",w=E.find(e=>e.id===y)||M.find(e=>e.id===y)||{id:"",name:"",contextWindow:0},[j,te]=u.useState(null),[T,oe]=u.useState(!1),[I,ne]=u.useState(!(a.hasApiKey&&h)),[D,H]=u.useState([]),[re,le]=u.useState([]),[O,V]=u.useState(!1);u.useEffect(()=>{pe().then(te).catch(()=>{})},[]);const P=e=>{var n;const t=JSON.parse(JSON.stringify(l));t["x-jishushell"]||(t["x-jishushell"]={}),(n=t["x-jishushell"]).proxy||(n.proxy={}),t["x-jishushell"].proxy.upstream={...t["x-jishushell"].proxy.upstream||{},...e},m(t)},W=(e,t)=>P({[e]:t}),ae=e=>{var d,i;const t=S.find(p=>p.id===e);if(!t){P({providerId:""});return}if(a.apiKey&&!window.confirm(o("configForm.switchProviderConfirm",{defaultValue:"切换 provider 会清空当前 API key,确定继续?"})))return;const n=JSON.parse(JSON.stringify(l));n["x-jishushell"]||(n["x-jishushell"]={}),(d=n["x-jishushell"]).proxy||(d.proxy={}),n["x-jishushell"].proxy.upstream={providerId:t.id,baseUrl:t.baseUrl,api:t.api,authHeader:t.authHeader===!0,headers:t.headers||{},models:t.models.map(p=>({id:p.id,name:p.name,contextWindow:p.contextWindow})),selectedModelId:((i=t.models[0])==null?void 0:i.id)||"",apiKey:"",hasApiKey:!1,clearApiKey:!1},m(n)},$=e=>W("selectedModelId",e),_=e=>{var p;const t=[...E],n=t.findIndex(b=>b.id===y),d={...w,...e};n>=0?t[n]=d:t.push(d);const i=JSON.parse(JSON.stringify(l));i["x-jishushell"]||(i["x-jishushell"]={}),(p=i["x-jishushell"]).proxy||(p.proxy={}),i["x-jishushell"].proxy.upstream={...i["x-jishushell"].proxy.upstream||{},models:t,selectedModelId:typeof e.id=="string"&&e.id?e.id:y},m(i)},B=async e=>{if(!h)return;const t=S.find(b=>b.id===h);if(!t)return;const d=["ollama","vllm","sglang"].includes(h)&&a.baseUrl?String(a.baseUrl):t.baseUrl,i=t.authHeader?"x-api-key":"Authorization",p=e??(a.apiKey||"");V(!0);try{const{models:b}=await ve(d,p,i,t.id,t.api);le(b),b.length&&!y&&$(b[0].id)}catch{}finally{V(!1)}},ie=e=>{if(!h||O)return;const t=ge(a.apiKey||"",e).trim();t&&B(t)},A=Array.isArray(x==null?void 0:x.messagingPlatforms)?x.messagingPlatforms:[],L=u.useMemo(()=>A.filter(e=>!Ne.has(e)),[A]),J=u.useMemo(()=>{const e=[];for(const t of L){const n=F[t];n&&n.fields.some(d=>(g.get(d.envKey)||"").trim()!=="")&&e.push(t)}return e},[L,g]),G=u.useMemo(()=>Array.from(new Set([...J,...D])),[J,D]),z=L.filter(e=>!G.includes(e)&&F[e]),Y=g.get("FEISHU_APP_ID")||"",de=u.useMemo(()=>{const e=c.match(/platforms:\s*[\s\S]*?feishu:\s*[\s\S]*?domain_name:\s*["']?(\w+)["']?/);return(e==null?void 0:e[1])==="lark"?"lark":"feishu"},[c]),q=()=>{f&&fe(f).then(e=>{e&&m(e)}).catch(()=>{})},Q=(e,t)=>{m({...l,format:"yaml+env",yaml:c,env:se(r,{[e]:t})})},ce=e=>{H(t=>t.includes(e)?t:[...t,e])},me=e=>{const t=F[e];if(!t)return;const n={};t.fields.forEach(d=>{n[d.envKey]=""}),m({...l,format:"yaml+env",yaml:c,env:se(r,n)}),H(d=>d.filter(i=>i!==e))},xe=e=>m({...l,format:"yaml+env",yaml:e,env:r}),he=e=>m({...l,format:"yaml+env",yaml:c,env:e}),ue=[...new Set(S.map(e=>e.group))];return s.jsxs("div",{className:"space-y-4",children:[s.jsxs(U,{title:o("configForm.modelConfig"),children:[s.jsxs("div",{className:"bg-[var(--card)] border border-[var(--border)] rounded-lg p-3 text-sm text-muted",children:[s.jsx("div",{className:"font-medium text-foreground mb-1",children:o("configForm.proxyChain")}),s.jsx("p",{children:o("configForm.proxyChainDesc")}),s.jsxs("div",{className:"mt-2 text-xs text-muted opacity-60 space-y-1",children:[s.jsxs("div",{children:["面板全局 provider:"," ",j!=null&&j.configured?s.jsxs("span",{className:"font-mono",children:[j.providerId,j.selectedModelId?` · ${j.selectedModelId}`:""]}):s.jsx(Z,{to:"/settings",className:"text-amber-400 underline hover:text-amber-300",children:"未配置"})," ",s.jsx(Z,{to:"/settings",className:"text-[#0066FF] hover:text-[#0066FF]/80",children:"(修改)"})]}),s.jsx("div",{className:"opacity-70",children:"本实例 API key 留空 → 自动回退全局 key (src/services/llm-proxy/index.ts:137)"})]})]}),!I&&s.jsx("button",{type:"button",onClick:()=>ne(!0),className:"text-xs text-[#0066FF] hover:text-[#0066FF]/80 transition-colors",children:o("configForm.editModelConfig")}),I&&s.jsx(v,{label:o("configForm.upstreamProvider"),hint:o("configForm.upstreamProviderHint"),children:s.jsxs(R,{value:h,onChange:ae,children:[s.jsx("option",{value:"",children:o("configForm.selectProvider")}),!k&&h&&s.jsxs("option",{value:h,children:[h," ",o("configForm.custom")]}),ue.map(e=>s.jsx("optgroup",{label:o(`configForm.providerGroup.${e}`,{defaultValue:e}),children:S.filter(t=>t.group===e).map(t=>s.jsx("option",{value:t.id,children:o(`configForm.providerLabel.${t.id}`,{defaultValue:t.label})},t.id))},e))]})}),I&&!["ollama","vllm","sglang"].includes(h)&&h&&s.jsxs(s.Fragment,{children:[s.jsxs(v,{label:o("configForm.upstreamApiKey"),hint:a.hasApiKey&&!a.clearApiKey?o("configForm.apiKeyHintSaved"):o("configForm.apiKeyHintNew"),children:[s.jsx(ee,{value:a.apiKey||"",saved:a.hasApiKey&&!a.clearApiKey,onChange:e=>P({apiKey:e,clearApiKey:!1}),onPaste:ie,placeholder:o("configForm.enterApiKey")}),a.hasApiKey&&s.jsx("button",{type:"button",onClick:()=>P({apiKey:"",clearApiKey:!a.clearApiKey}),className:"text-xs text-muted hover:text-foreground transition-colors mt-2",children:a.clearApiKey?o("configForm.restoreApiKey"):o("configForm.clearApiKey")})]}),s.jsx(v,{label:o("configForm.selectedModel"),children:s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("div",{className:"flex-1",children:s.jsxs(R,{value:y,onChange:$,children:[s.jsx("option",{value:"",children:o("configForm.selectModel")}),M.map(e=>s.jsxs("option",{value:e.id,children:[e.name||e.id,e.contextWindow?` (${Math.round(e.contextWindow/1e3)}K)`:""]},e.id)),re.filter(e=>!M.some(t=>t.id===e.id)).map(e=>s.jsx("option",{value:e.id,children:e.name||e.id},e.id))]})}),s.jsx("button",{type:"button",onClick:()=>{B()},disabled:O||!h,className:"px-3 py-2 border border-[var(--border)] text-muted rounded-md text-xs hover:bg-[var(--card-hover)] hover:text-foreground disabled:opacity-40 transition-colors",children:O?o("common:label.loading",{defaultValue:"加载中"}):o("configForm.fetchModels",{defaultValue:"拉取模型"})})]})}),s.jsx("button",{type:"button",onClick:()=>oe(!T),className:"text-xs text-muted hover:text-foreground transition-colors",children:o(T?"configForm.collapseAdvanced":"configForm.advancedOptions")}),T&&s.jsxs("div",{className:"space-y-4 border-t border-[var(--border)] pt-4",children:[s.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:[s.jsx(v,{label:o("configForm.upstreamBaseUrl"),children:s.jsx(K,{value:a.baseUrl||"",onChange:e=>W("baseUrl",e),placeholder:o("configForm.baseUrlPlaceholder"),mono:!0})}),s.jsx(v,{label:o("configForm.upstreamApiProtocol"),children:s.jsxs(R,{value:a.api||"openai-completions",onChange:e=>W("api",e),children:[s.jsx("option",{value:"openai-completions",children:"OpenAI Compatible"}),s.jsx("option",{value:"openai-responses",children:"OpenAI Responses"}),s.jsx("option",{value:"anthropic-messages",children:"Anthropic Messages"}),s.jsx("option",{value:"google-generative-ai",children:"Google Generative AI"}),s.jsx("option",{value:"ollama",children:"Ollama"})]})})]}),y&&s.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-4",children:[s.jsx(v,{label:o("configForm.modelId"),children:s.jsx(K,{value:w.id||"",onChange:e=>_({id:e}),placeholder:"model-id",mono:!0})}),s.jsx(v,{label:o("configForm.modelName"),children:s.jsx(K,{value:w.name||"",onChange:e=>_({name:e}),placeholder:"Model Name"})}),s.jsx(v,{label:o("configForm.contextWindow"),children:s.jsx(K,{value:String(w.contextWindow||""),onChange:e=>_({contextWindow:parseInt(e,10)||0}),placeholder:"200000",mono:!0})})]}),s.jsx("div",{className:"text-xs text-muted bg-[var(--card)] border border-[var(--border)] rounded-md p-3",children:o("configForm.proxyNote")})]})]})]}),A.length>0&&s.jsxs(U,{title:o("configForm.imChannelConfig"),children:[s.jsxs("p",{className:"text-xs text-muted",children:["Hermes 通过 ",s.jsx("code",{className:"font-mono text-[11px]",children:".env"})," 环境变量读取消息平台凭证。 保存后重启实例生效。"]}),A.includes("feishu")&&s.jsxs("div",{className:"border border-[var(--border)] rounded-lg p-4 space-y-3 bg-[var(--card)]",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("span",{className:"text-sm font-medium text-foreground",children:o("configForm.channel.feishu",{defaultValue:"飞书 / Lark"})}),s.jsx("span",{className:"text-[11px] text-muted font-mono",children:"feishu"})]}),s.jsx(ye,{instanceId:f,channelKey:"feishu",existingAppId:Y||void 0,existingDomain:Y?de:void 0,onConfigured:q})]}),A.includes("weixin")&&s.jsxs("div",{className:"border border-[var(--border)] rounded-lg p-4 space-y-3 bg-[var(--card)]",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("span",{className:"text-sm font-medium text-foreground",children:o("configForm.channel.weixin",{defaultValue:"个人微信"})}),s.jsx("span",{className:"text-[11px] text-muted font-mono",children:"weixin"})]}),s.jsx(be,{instanceId:f,onConfigured:q})]}),s.jsx("div",{className:"space-y-3",children:G.map(e=>{const t=F[e];return t?s.jsxs("div",{className:"border border-[var(--border)] rounded-lg p-4 space-y-3 bg-[var(--card)]",children:[s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("span",{className:"text-sm font-medium text-foreground",children:t.label}),s.jsx("span",{className:"text-[11px] text-muted font-mono",children:e})]}),s.jsx("button",{onClick:()=>me(e),className:"text-xs text-red-400 hover:text-red-300 transition-colors",children:o("configForm.remove")})]}),s.jsx("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:t.fields.map(n=>{const d=g.get(n.envKey)||"";return s.jsx(v,{label:n.label,hint:n.hint||`.env: ${n.envKey}`,children:n.secret?s.jsx(ee,{value:d,saved:!!d,onChange:i=>Q(n.envKey,i),placeholder:n.placeholder}):s.jsx(K,{value:d,onChange:i=>Q(n.envKey,i),placeholder:n.placeholder,mono:!0})},n.key)})})]},e):null})}),z.length>0&&s.jsxs("div",{className:"pt-2",children:[s.jsx("p",{className:"text-xs text-muted mb-2",children:o("configForm.addImChannel")}),s.jsx("div",{className:"flex flex-wrap gap-2",children:z.map(e=>{var t;return s.jsxs("button",{onClick:()=>ce(e),className:"px-3 py-1.5 text-xs border border-dashed rounded-md transition-colors duration-150 border-[var(--border)] text-muted hover:border-[var(--border-hover)] hover:text-foreground",children:["+ ",((t=F[e])==null?void 0:t.label)||e]},e)})})]})]}),s.jsxs(U,{title:"高级 (原始 YAML + .env)",defaultOpen:!1,children:[s.jsx("p",{className:"text-xs text-muted",children:"直接编辑 YAML / .env。上方 Channels 字段与此处同步 — 任一侧修改都会反映到另一侧。"}),s.jsxs("div",{className:"bg-[var(--card)] border border-[var(--border)] rounded-xl overflow-hidden",children:[s.jsx("div",{className:"border-b border-[var(--border)] px-4 py-2",children:s.jsx("span",{className:"text-xs font-medium text-muted",children:"config.yaml"})}),s.jsx("textarea",{value:c,onChange:e=>xe(e.target.value),className:"w-full font-mono text-[13px] p-4 min-h-[240px] focus:outline-none resize-y text-foreground bg-transparent",spellCheck:!1})]}),s.jsxs("div",{className:"bg-[var(--card)] border border-[var(--border)] rounded-xl overflow-hidden",children:[s.jsx("div",{className:"border-b border-[var(--border)] px-4 py-2",children:s.jsx("span",{className:"text-xs font-medium text-muted",children:".env"})}),s.jsx("textarea",{value:r,onChange:e=>he(e.target.value),className:"w-full font-mono text-[13px] p-4 min-h-[220px] focus:outline-none resize-y text-foreground bg-transparent",spellCheck:!1})]})]})]})}export{Ce as HermesConfigForm};
@@ -1 +0,0 @@
1
- import{j as e,L as j,T as v,I as w,a as N,c as y,s as F}from"./index-BZc5zH7u.js";import{r}from"./vendor-react-BWrEVJVb.js";import{u as S}from"./vendor-i18n-y9V7Sfuu.js";const x="w-full bg-[var(--input-bg)] border border-[var(--border)] rounded-md px-3 py-2.5 text-sm text-foreground placeholder-[var(--muted)] focus:outline-none focus:ring-1 focus:ring-[#0066FF]/60 focus:border-[#0066FF]/60 transition-colors duration-200";function C({onDone:b}){const{t}=S("auth"),[s,p]=r.useState(""),[o,h]=r.useState(""),[n,f]=r.useState(!1),[l,d]=r.useState(""),[c,m]=r.useState(!1),u=s.length>=8&&s===o,g=async a=>{if(a.preventDefault(),!!u){d(""),m(!0);try{const i=await y(s);F(i.token),b()}catch(i){d(i.message||t("init.failed"))}finally{m(!1)}}};return e.jsxs("div",{className:"min-h-screen flex items-center justify-center p-4 bg-background relative overflow-hidden",children:[e.jsx("div",{className:"grid-bg absolute inset-0 pointer-events-none"}),e.jsx("div",{className:"absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[300px] rounded-full bg-[#0066FF]/[0.07] blur-[90px] pointer-events-none"}),e.jsx("div",{className:"absolute left-4 bottom-4 z-20",children:e.jsx(j,{className:"bg-card/80 backdrop-blur-sm"})}),e.jsxs("div",{className:"w-full max-w-sm relative z-10",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx(v,{className:"w-40 h-40 mx-auto mb-4 object-contain"}),e.jsx("p",{className:"text-sm text-muted mt-1",children:t("init.title")})]}),e.jsxs("form",{onSubmit:g,className:"space-y-4",children:[l&&e.jsx("div",{className:"bg-red-500/10 border border-red-500/20 text-red-400 text-sm rounded-lg px-3 py-2.5",children:l}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-muted mb-1.5",children:t("init.password")}),e.jsxs("div",{className:"relative",children:[e.jsx("input",{type:n?"text":"password",value:s,onChange:a=>p(a.target.value),placeholder:t("init.passwordPlaceholder"),className:`${x} pr-10`,autoFocus:!0}),e.jsx("button",{type:"button",onClick:()=>f(!n),"aria-label":t("common:action.togglePassword"),className:"absolute right-3 top-1/2 -translate-y-1/2 text-muted hover:text-foreground transition-colors duration-200",children:n?e.jsx(w,{}):e.jsx(N,{})})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-muted mb-1.5",children:t("init.confirm")}),e.jsx("input",{type:n?"text":"password",value:o,onChange:a=>h(a.target.value),placeholder:t("init.confirmPlaceholder"),className:x}),s&&o&&s!==o&&e.jsx("p",{className:"text-red-400 text-xs mt-1.5",children:t("init.mismatch")})]}),e.jsx("button",{type:"submit",disabled:c||!u,className:"w-full bg-[#0066FF] text-white rounded-md py-2.5 text-sm font-medium hover:bg-[#0066FF]/90 disabled:opacity-40 disabled:cursor-not-allowed transition-all duration-200 shadow-[0_0_20px_rgba(0,102,255,0.3)] hover:shadow-[0_0_28px_rgba(0,102,255,0.45)]",children:c?e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx("span",{className:"w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin"}),t("init.loading")]}):t("init.submit")})]})]})]})}export{C as default};