jishushell 0.4.24 → 0.4.30

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 (167) hide show
  1. package/INSTALL-NOTICE +11 -0
  2. package/apps/browserless-chromium-container.yaml +78 -0
  3. package/apps/hermes-container.yaml +36 -2
  4. package/apps/ollama-binary.yaml +91 -90
  5. package/apps/ollama-cpu-container.yaml +8 -1
  6. package/apps/ollama-with-hollama-binary.yaml +91 -90
  7. package/apps/openclaw-binary.yaml +30 -1
  8. package/apps/openclaw-container.yaml +37 -2
  9. package/apps/openclaw-with-ollama-container.yaml +11 -2
  10. package/apps/openclaw-with-searxng-container.yaml +22 -2
  11. package/apps/openwebui-container.yaml +45 -1
  12. package/apps/playwright-container.yaml +7 -1
  13. package/apps/searxng-container.yaml +54 -4
  14. package/dist/cli/app.js +79 -9
  15. package/dist/cli/app.js.map +1 -1
  16. package/dist/cli/doctor.d.ts +12 -12
  17. package/dist/cli/doctor.js +242 -55
  18. package/dist/cli/doctor.js.map +1 -1
  19. package/dist/cli/llm.d.ts +4 -3
  20. package/dist/cli/llm.js +4 -3
  21. package/dist/cli/llm.js.map +1 -1
  22. package/dist/cli/panel.d.ts +6 -5
  23. package/dist/cli/panel.js +10 -9
  24. package/dist/cli/panel.js.map +1 -1
  25. package/dist/control.d.ts +7 -6
  26. package/dist/control.js +7 -6
  27. package/dist/control.js.map +1 -1
  28. package/dist/routes/agent-apps.d.ts +1 -1
  29. package/dist/routes/agent-apps.js +1 -1
  30. package/dist/routes/apps.js +44 -11
  31. package/dist/routes/apps.js.map +1 -1
  32. package/dist/routes/auth.js +3 -0
  33. package/dist/routes/auth.js.map +1 -1
  34. package/dist/routes/instances.js +787 -16
  35. package/dist/routes/instances.js.map +1 -1
  36. package/dist/routes/llm.js +24 -35
  37. package/dist/routes/llm.js.map +1 -1
  38. package/dist/routes/setup.js +1 -1
  39. package/dist/routes/setup.js.map +1 -1
  40. package/dist/server.d.ts +9 -0
  41. package/dist/server.js +410 -17
  42. package/dist/server.js.map +1 -1
  43. package/dist/services/agent-apps/catalog.js +4 -3
  44. package/dist/services/agent-apps/catalog.js.map +1 -1
  45. package/dist/services/agent-apps/index.d.ts +1 -1
  46. package/dist/services/agent-apps/index.js +1 -1
  47. package/dist/services/agent-apps/installers/adapter.d.ts +1 -1
  48. package/dist/services/agent-apps/installers/adapter.js +1 -1
  49. package/dist/services/agent-apps/installers/shell-script.d.ts +1 -1
  50. package/dist/services/agent-apps/installers/shell-script.js +3 -3
  51. package/dist/services/agent-apps/installers/shell-script.js.map +1 -1
  52. package/dist/services/agent-apps/types.d.ts +2 -2
  53. package/dist/services/agent-apps/types.js +1 -1
  54. package/dist/services/app/app-manager.d.ts +24 -1
  55. package/dist/services/app/app-manager.js +664 -116
  56. package/dist/services/app/app-manager.js.map +1 -1
  57. package/dist/services/app/hermes-agent-manager.js +6 -4
  58. package/dist/services/app/hermes-agent-manager.js.map +1 -1
  59. package/dist/services/app/provide-resolver.d.ts +29 -0
  60. package/dist/services/app/provide-resolver.js +112 -0
  61. package/dist/services/app/provide-resolver.js.map +1 -0
  62. package/dist/services/capability-endpoint-validator.d.ts +41 -0
  63. package/dist/services/capability-endpoint-validator.js +104 -0
  64. package/dist/services/capability-endpoint-validator.js.map +1 -0
  65. package/dist/services/capability-health.d.ts +16 -0
  66. package/dist/services/capability-health.js +121 -0
  67. package/dist/services/capability-health.js.map +1 -0
  68. package/dist/services/capability-registry.d.ts +106 -0
  69. package/dist/services/capability-registry.js +313 -0
  70. package/dist/services/capability-registry.js.map +1 -0
  71. package/dist/services/connection-apply.d.ts +89 -0
  72. package/dist/services/connection-apply.js +421 -0
  73. package/dist/services/connection-apply.js.map +1 -0
  74. package/dist/services/connection-resolver.d.ts +65 -0
  75. package/dist/services/connection-resolver.js +281 -0
  76. package/dist/services/connection-resolver.js.map +1 -0
  77. package/dist/services/connection-transactor.d.ts +37 -0
  78. package/dist/services/connection-transactor.js +341 -0
  79. package/dist/services/connection-transactor.js.map +1 -0
  80. package/dist/services/instance-manager.d.ts +13 -0
  81. package/dist/services/instance-manager.js +137 -23
  82. package/dist/services/instance-manager.js.map +1 -1
  83. package/dist/services/llm-proxy/index.d.ts +16 -2
  84. package/dist/services/llm-proxy/index.js +48 -44
  85. package/dist/services/llm-proxy/index.js.map +1 -1
  86. package/dist/services/llm-proxy/probe.d.ts +6 -0
  87. package/dist/services/llm-proxy/probe.js +85 -0
  88. package/dist/services/llm-proxy/probe.js.map +1 -0
  89. package/dist/services/llm-proxy/ssrf.d.ts +1 -0
  90. package/dist/services/llm-proxy/ssrf.js +18 -7
  91. package/dist/services/llm-proxy/ssrf.js.map +1 -1
  92. package/dist/services/nomad-manager.js +375 -16
  93. package/dist/services/nomad-manager.js.map +1 -1
  94. package/dist/services/process-manager.js +1 -1
  95. package/dist/services/process-manager.js.map +1 -1
  96. package/dist/services/runtime/adapters/hermes.d.ts +30 -1
  97. package/dist/services/runtime/adapters/hermes.js +218 -5
  98. package/dist/services/runtime/adapters/hermes.js.map +1 -1
  99. package/dist/services/runtime/adapters/openclaw-mcporter.d.ts +45 -0
  100. package/dist/services/runtime/adapters/openclaw-mcporter.js +108 -0
  101. package/dist/services/runtime/adapters/openclaw-mcporter.js.map +1 -0
  102. package/dist/services/runtime/adapters/openclaw.d.ts +87 -0
  103. package/dist/services/runtime/adapters/openclaw.js +250 -2
  104. package/dist/services/runtime/adapters/openclaw.js.map +1 -1
  105. package/dist/services/runtime/mcp-shims/firewall.d.ts +26 -0
  106. package/dist/services/runtime/mcp-shims/firewall.js +129 -0
  107. package/dist/services/runtime/mcp-shims/firewall.js.map +1 -0
  108. package/dist/services/runtime/mcp-shims/searxng-shim.d.ts +27 -0
  109. package/dist/services/runtime/mcp-shims/searxng-shim.js +125 -0
  110. package/dist/services/runtime/mcp-shims/searxng-shim.js.map +1 -0
  111. package/dist/services/runtime/mcp-shims/write-mcp-entry.d.ts +83 -0
  112. package/dist/services/runtime/mcp-shims/write-mcp-entry.js +127 -0
  113. package/dist/services/runtime/mcp-shims/write-mcp-entry.js.map +1 -0
  114. package/dist/services/runtime/migrations.d.ts +8 -0
  115. package/dist/services/runtime/migrations.js +100 -0
  116. package/dist/services/runtime/migrations.js.map +1 -1
  117. package/dist/services/runtime/types.d.ts +15 -0
  118. package/dist/services/setup-manager.js +6 -6
  119. package/dist/services/setup-manager.js.map +1 -1
  120. package/dist/services/suggestions.d.ts +27 -0
  121. package/dist/services/suggestions.js +133 -0
  122. package/dist/services/suggestions.js.map +1 -0
  123. package/dist/services/task-registry.js +4 -2
  124. package/dist/services/task-registry.js.map +1 -1
  125. package/dist/services/telemetry/device-fingerprint.d.ts +1 -1
  126. package/dist/services/telemetry/device-fingerprint.js +1 -1
  127. package/dist/services/types-shim.d.ts +16 -0
  128. package/dist/services/types-shim.js +2 -0
  129. package/dist/services/types-shim.js.map +1 -0
  130. package/dist/types.d.ts +171 -1
  131. package/dist/utils/instance-lock.d.ts +22 -0
  132. package/dist/utils/instance-lock.js +48 -0
  133. package/dist/utils/instance-lock.js.map +1 -0
  134. package/dist/utils/safe-json.js +55 -22
  135. package/dist/utils/safe-json.js.map +1 -1
  136. package/install/jishu-install.sh +323 -27
  137. package/install/jishu-uninstall.sh +353 -20
  138. package/package.json +3 -1
  139. package/public/assets/Dashboard-rkWp-CXd.js +1 -0
  140. package/public/assets/{HermesChatPanel-mFSureyc.js → HermesChatPanel-_GHoklgo.js} +1 -1
  141. package/public/assets/HermesConfigForm-anDnwUp_.js +4 -0
  142. package/public/assets/{InitPassword-CVA8wQA6.js → InitPassword-ZU9_-hDr.js} +1 -1
  143. package/public/assets/InstanceDetail-CN0FH1aw.js +92 -0
  144. package/public/assets/{Login-BWsZH2mu.js → Login-BItXqYAJ.js} +1 -1
  145. package/public/assets/NewInstance-BousE6kY.js +1 -0
  146. package/public/assets/ProviderRecommendations-DFYj7Fb6.js +1 -0
  147. package/public/assets/Settings-Bttc6QmM.js +1 -0
  148. package/public/assets/Setup-Bsxx1zgj.js +1 -0
  149. package/public/assets/{WeixinLoginPanel-CnjR8xMu.js → WeixinLoginPanel-DPZpAKgO.js} +2 -2
  150. package/public/assets/index-8xZy1z5k.css +1 -0
  151. package/public/assets/index-Dw3HhUYE.js +19 -0
  152. package/public/assets/providers-DtNXh9JD.js +1 -0
  153. package/public/assets/registry-5s2UB6is.js +2 -0
  154. package/public/index.html +2 -2
  155. package/scripts/check-app-spec.mjs +443 -0
  156. package/scripts/check-i18n.mjs +154 -0
  157. package/scripts/run.sh +4 -4
  158. package/public/assets/Dashboard-B-JoOjBQ.js +0 -1
  159. package/public/assets/HermesConfigForm-DvR05LK1.js +0 -4
  160. package/public/assets/InstanceDetail-DcZW2QGO.js +0 -91
  161. package/public/assets/NewInstance-BCIrAd86.js +0 -1
  162. package/public/assets/Settings-xkDcduFz.js +0 -1
  163. package/public/assets/Setup-Cfuwj4gV.js +0 -1
  164. package/public/assets/index-CPhVFEsx.css +0 -1
  165. package/public/assets/index-DQsM6Joa.js +0 -19
  166. package/public/assets/providers-V-vwrExZ.js +0 -1
  167. package/public/assets/registry-B4UFJdpA.js +0 -2
@@ -2,27 +2,274 @@
2
2
  set -euo pipefail
3
3
 
4
4
  JISHU_SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
- # shellcheck source=jishu-install.sh
6
- source "${JISHU_SCRIPT_DIR}/jishu-install.sh"
7
5
 
6
+ _get_user_home() {
7
+ local user="$1"
8
+ local user_home=""
9
+
10
+ if [[ -z "$user" ]]; then
11
+ return 1
12
+ fi
13
+
14
+ if command -v getent >/dev/null 2>&1; then
15
+ user_home="$(getent passwd "$user" 2>/dev/null | cut -d: -f6 || true)"
16
+ elif command -v dscl >/dev/null 2>&1; then
17
+ user_home="$(dscl . -read "/Users/${user}" NFSHomeDirectory 2>/dev/null | awk '/NFSHomeDirectory:/{print $2; exit}')"
18
+ fi
19
+
20
+ if [[ -z "$user_home" ]]; then
21
+ user_home="$(eval "printf '%s' ~${user}" 2>/dev/null || true)"
22
+ fi
23
+
24
+ [[ -n "$user_home" ]] && printf '%s' "$user_home"
25
+ }
26
+
27
+ if [[ $EUID -eq 0 && -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then
28
+ REAL_USER="${SUDO_USER}"
29
+ REAL_HOME="$(_get_user_home "${SUDO_USER}")"
30
+ else
31
+ REAL_USER="$(id -un)"
32
+ REAL_HOME="${HOME}"
33
+ fi
34
+
35
+ [[ -z "${REAL_HOME}" ]] && REAL_HOME="${HOME}"
36
+ USER_HOME="${REAL_HOME}"
37
+ JISHUSHELL_HOME="${JISHUSHELL_HOME:-${USER_HOME}/.jishushell}"
38
+ _COLIMA_HOME="${JISHUSHELL_HOME}/colima"
39
+ _COLIMA_PROFILE="jishushell"
40
+
41
+ BOLD='\033[1m'
42
+ ACCENT='\033[38;2;66;135;245m'
43
+ INFO='\033[38;2;136;146;176m'
44
+ SUCCESS='\033[38;2;0;229;204m'
45
+ WARN='\033[38;2;255;176;32m'
46
+ ERROR='\033[38;2;230;57;70m'
47
+ MUTED='\033[38;2;90;100;128m'
48
+ NC='\033[0m'
49
+
50
+ DRY_RUN="${DRY_RUN:-0}"
8
51
  DO_DOCKER=0
9
52
  DO_NOMAD=0
53
+ DO_XCODE_CLT=0
54
+ DO_BREW=0
10
55
  AUTO_YES=0
56
+ SUDO=""
57
+ PKG_MANAGER="none"
58
+ OS=""
59
+ OS_ID=""
60
+ OS_VERSION=""
61
+ OS_NAME=""
62
+
63
+ ui_info() {
64
+ echo -e "${MUTED}·${NC} $*"
65
+ }
66
+
67
+ ui_success() {
68
+ echo -e "${SUCCESS}✓${NC} $*"
69
+ }
70
+
71
+ ui_warn() {
72
+ echo -e "${WARN}!${NC} $*"
73
+ }
74
+
75
+ ui_error() {
76
+ echo -e "${ERROR}✗${NC} $*" >&2
77
+ }
78
+
79
+ ui_section() {
80
+ echo -e "\n${ACCENT}${BOLD}── $* ──${NC}"
81
+ }
82
+
83
+ confirm() {
84
+ local prompt="$1"
85
+
86
+ if [[ "${NO_PROMPT:-0}" == "1" ]]; then
87
+ ui_info "$prompt → auto-confirmed (NO_PROMPT=1)"
88
+ return 0
89
+ fi
90
+
91
+ if [[ "${AUTO_YES:-0}" == "1" ]]; then
92
+ ui_info "$prompt → auto-confirmed (--yes)"
93
+ return 0
94
+ fi
95
+
96
+ local answer answer_lc
97
+ read -r -p "$(echo -e "${WARN} ${prompt} [y/N]: ${NC}")" answer </dev/tty || answer="n"
98
+ answer_lc="$(echo "$answer" | tr '[:upper:]' '[:lower:]')"
99
+ case "$answer_lc" in
100
+ y|yes) return 0 ;;
101
+ *) return 1 ;;
102
+ esac
103
+ }
104
+
105
+ _run_as_real_user() {
106
+ if [[ $EUID -eq 0 && -n "${REAL_USER:-}" && "${REAL_USER}" != "root" ]]; then
107
+ sudo -u "${REAL_USER}" -H env HOME="${USER_HOME}" "$@"
108
+ return $?
109
+ fi
110
+ "$@"
111
+ }
112
+
113
+ _load_homebrew_shellenv() {
114
+ local brew_bin=""
115
+
116
+ if command -v brew >/dev/null 2>&1; then
117
+ brew_bin="$(command -v brew)"
118
+ elif [[ -x "/opt/homebrew/bin/brew" ]]; then
119
+ brew_bin="/opt/homebrew/bin/brew"
120
+ elif [[ -x "/usr/local/bin/brew" ]]; then
121
+ brew_bin="/usr/local/bin/brew"
122
+ fi
123
+
124
+ if [[ -z "$brew_bin" ]]; then
125
+ return 1
126
+ fi
127
+
128
+ eval "$(${brew_bin} shellenv 2>/dev/null)"
129
+ command -v brew >/dev/null 2>&1
130
+ }
131
+
132
+ detect_os() {
133
+ if [[ "$(uname -s)" == "Darwin" ]]; then
134
+ OS="macos"
135
+ OS_ID="macos"
136
+ OS_VERSION="$(sw_vers -productVersion 2>/dev/null || echo "unknown")"
137
+ OS_NAME="macOS ${OS_VERSION}"
138
+ if _load_homebrew_shellenv; then
139
+ PKG_MANAGER="brew"
140
+ else
141
+ PKG_MANAGER="none"
142
+ fi
143
+ ui_success "OS: ${OS_NAME}"
144
+ return 0
145
+ fi
146
+
147
+ if [[ ! -f /etc/os-release ]]; then
148
+ ui_error "Cannot detect OS: /etc/os-release not found"
149
+ ui_error "This uninstaller supports Linux and macOS"
150
+ exit 1
151
+ fi
152
+
153
+ # shellcheck source=/dev/null
154
+ . /etc/os-release
155
+
156
+ OS="linux"
157
+ OS_ID="${ID:-unknown}"
158
+ OS_VERSION="${VERSION_ID:-unknown}"
159
+ OS_NAME="${PRETTY_NAME:-$OS_ID $OS_VERSION}"
160
+
161
+ case "$OS_ID" in
162
+ ubuntu|debian|linuxmint|pop)
163
+ PKG_MANAGER="apt"
164
+ ;;
165
+ centos|rhel|rocky|almalinux|fedora|amzn)
166
+ if command -v dnf >/dev/null 2>&1; then
167
+ PKG_MANAGER="dnf"
168
+ else
169
+ PKG_MANAGER="yum"
170
+ fi
171
+ ;;
172
+ *)
173
+ if command -v apt-get >/dev/null 2>&1; then
174
+ PKG_MANAGER="apt"
175
+ elif command -v dnf >/dev/null 2>&1; then
176
+ PKG_MANAGER="dnf"
177
+ elif command -v yum >/dev/null 2>&1; then
178
+ PKG_MANAGER="yum"
179
+ fi
180
+ ;;
181
+ esac
182
+
183
+ ui_success "OS: ${OS_NAME} (package manager: ${PKG_MANAGER})"
184
+ }
185
+
186
+ check_sudo() {
187
+ if [[ "$DRY_RUN" == "1" ]]; then
188
+ if [[ $EUID -eq 0 ]]; then
189
+ SUDO=""
190
+ else
191
+ SUDO="sudo"
192
+ fi
193
+ return 0
194
+ fi
195
+
196
+ if [[ $EUID -eq 0 ]]; then
197
+ SUDO=""
198
+ return 0
199
+ fi
200
+
201
+ if ! command -v sudo >/dev/null 2>&1; then
202
+ ui_error "Not running as root and sudo is not installed. Re-run as root."
203
+ exit 1
204
+ fi
205
+
206
+ if ! sudo -n true 2>/dev/null; then
207
+ ui_info "Some steps require sudo — you may be prompted for your password."
208
+ if [[ ! -t 0 || ! -t 1 ]]; then
209
+ ui_error "Failed to obtain sudo privileges (no interactive TTY available)"
210
+ exit 1
211
+ fi
212
+ if ! sudo -v; then
213
+ ui_error "Failed to obtain sudo privileges"
214
+ exit 1
215
+ fi
216
+ fi
217
+
218
+ SUDO="sudo"
219
+ ui_success "sudo privileges confirmed"
220
+ }
221
+
222
+ run_sudo() {
223
+ if [[ "$DRY_RUN" == "1" ]]; then
224
+ ui_info "[dry-run] ${SUDO:+sudo }$*"
225
+ return 0
226
+ fi
227
+ ${SUDO} "$@"
228
+ }
229
+
230
+ wait_for_apt_lock() {
231
+ if [[ "${PKG_MANAGER:-}" != "apt" ]]; then
232
+ return 0
233
+ fi
234
+
235
+ local max_wait=60
236
+ local waited=0
237
+
238
+ while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || \
239
+ fuser /var/lib/apt/lists/lock >/dev/null 2>&1; do
240
+ if [[ $waited -eq 0 ]]; then
241
+ ui_info "Waiting for apt lock to be released..."
242
+ fi
243
+ sleep 2
244
+ waited=$((waited + 2))
245
+ if [[ $waited -ge $max_wait ]]; then
246
+ ui_error "Timed out waiting for apt lock (${max_wait}s). Check for other running package managers."
247
+ exit 1
248
+ fi
249
+ done
250
+ }
251
+
252
+ _colima() {
253
+ COLIMA_HOME="${_COLIMA_HOME}" command colima "$@"
254
+ }
11
255
 
12
256
  # ─── Argument parsing ─────────────────────────────────────────────────────────
13
257
  usage() {
14
258
  cat <<EOF
15
259
  Usage: bash jishu-uninstall.sh [options]
16
260
 
17
- Run without options to stop all JishuShell services, clean up runtime
18
- artifacts, and optionally delete the data directory (~/.jishushell).
261
+ Run without options to remove only JishuShell-owned files and runtime data:
262
+ stop JishuShell services, remove the jishushell package, and optionally
263
+ delete the data directory (~/.jishushell).
19
264
 
20
- System-installed tools (colima, docker, nomad, Node.js) are never removed
21
- unless you explicitly pass --docker or --nomad.
265
+ System-installed tools (colima, docker, nomad, Homebrew, Xcode Command Line
266
+ Tools, Node.js) are never removed unless you explicitly pass extra flags.
22
267
 
23
268
  Options:
24
269
  --docker Also uninstall Docker/Colima system packages (brew/apt/dnf)
25
270
  --nomad Also uninstall Nomad system package (brew/apt/dnf)
271
+ --xcode-clt Also delete macOS Xcode Command Line Tools
272
+ --brew Also run the official Homebrew uninstall script (macOS)
26
273
  --all Full uninstall: default cleanup + --docker + --nomad + --yes
27
274
  --dry-run Print the removal plan only, do not execute anything
28
275
  --yes, -y Skip all confirmation prompts (auto-yes)
@@ -36,6 +283,8 @@ parse_args() {
36
283
  case "$1" in
37
284
  --docker) DO_DOCKER=1 ;;
38
285
  --nomad) DO_NOMAD=1 ;;
286
+ --xcode-clt) DO_XCODE_CLT=1 ;;
287
+ --brew) DO_BREW=1 ;;
39
288
  --all) DO_DOCKER=1; DO_NOMAD=1; AUTO_YES=1 ;;
40
289
  --dry-run) DRY_RUN=1 ;;
41
290
  --yes|-y) AUTO_YES=1 ;;
@@ -99,8 +348,8 @@ stop_services() {
99
348
  fi
100
349
 
101
350
  if [[ "$(uname -s)" == "Darwin" ]]; then
102
- local panel_plist="${HOME}/Library/LaunchAgents/com.jishushell.panel.plist"
103
- local nomad_plist="${HOME}/Library/LaunchAgents/com.jishushell.nomad.plist"
351
+ local panel_plist="${USER_HOME}/Library/LaunchAgents/com.jishushell.panel.plist"
352
+ local nomad_plist="${USER_HOME}/Library/LaunchAgents/com.jishushell.nomad.plist"
104
353
 
105
354
  if launchctl list 2>/dev/null | grep -q "com.jishushell.panel"; then
106
355
  ui_info "Stopping JishuShell panel..."
@@ -160,7 +409,7 @@ stop_services() {
160
409
  local _cmd
161
410
  _cmd="$(ps -p "$_pid" -o args= 2>/dev/null || true)"
162
411
  # Only kill nomad agents that reference our config directory
163
- if [[ "$_cmd" == *"${JISHUSHELL_HOME:-${HOME}/.jishushell}"* ]]; then
412
+ if [[ "$_cmd" == *"${JISHUSHELL_HOME}"* ]]; then
164
413
  kill "$_pid" 2>/dev/null || true
165
414
  ((_killed_nomad++)) || true
166
415
  fi
@@ -173,7 +422,7 @@ stop_services() {
173
422
  if kill -0 "$_pid" 2>/dev/null; then
174
423
  local _cmd
175
424
  _cmd="$(ps -p "$_pid" -o args= 2>/dev/null || true)"
176
- if [[ "$_cmd" == *"${JISHUSHELL_HOME:-${HOME}/.jishushell}"* ]]; then
425
+ if [[ "$_cmd" == *"${JISHUSHELL_HOME}"* ]]; then
177
426
  kill -9 "$_pid" 2>/dev/null || true
178
427
  fi
179
428
  fi
@@ -211,7 +460,7 @@ stop_services() {
211
460
  fi
212
461
 
213
462
  # Clean leaked ~/.colima directory (Colima stat-guard artifact)
214
- local default_colima_home="${HOME}/.colima"
463
+ local default_colima_home="${USER_HOME}/.colima"
215
464
  if [[ -d "$default_colima_home" ]]; then
216
465
  local real_files
217
466
  real_files="$(find "$default_colima_home" -type f 2>/dev/null | head -1 || true)"
@@ -226,7 +475,7 @@ stop_services() {
226
475
  fi
227
476
  fi
228
477
 
229
- local wrapper="${HOME}/.jishushell/bin/jishushell-panel-start"
478
+ local wrapper="${JISHUSHELL_HOME}/bin/jishushell-panel-start"
230
479
  if [[ -f "$wrapper" ]]; then
231
480
  rm -f "$wrapper"
232
481
  ui_success "Removed wrapper: ${wrapper}"
@@ -234,7 +483,7 @@ stop_services() {
234
483
 
235
484
  # Clean JishuShell PATH entries from shell RC files.
236
485
  local marker="# jishushell-bin-path"
237
- local shell_configs=("$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.profile" "$HOME/.zshrc")
486
+ local shell_configs=("${USER_HOME}/.bashrc" "${USER_HOME}/.bash_profile" "${USER_HOME}/.profile" "${USER_HOME}/.zshrc")
238
487
  for cfg in "${shell_configs[@]}"; do
239
488
  if [[ -f "$cfg" ]] && grep -qF "$marker" "$cfg" 2>/dev/null; then
240
489
  ui_info "Cleaning JishuShell PATH from ${cfg}..."
@@ -255,7 +504,7 @@ stop_services() {
255
504
 
256
505
  # ─── Delete ~/.jishushell data directory ──────────────────────────────────────
257
506
  delete_data_dir() {
258
- local jishu_home="${JISHUSHELL_HOME:-${HOME}/.jishushell}"
507
+ local jishu_home="${JISHUSHELL_HOME}"
259
508
  if [[ ! -d "$jishu_home" ]]; then
260
509
  ui_info "Data directory does not exist: ${jishu_home}"
261
510
  return 0
@@ -337,6 +586,86 @@ uninstall_colima() {
337
586
  fi
338
587
  }
339
588
 
589
+ # ─── macOS Xcode Command Line Tools (--xcode-clt flag) ───────────────────────
590
+ uninstall_xcode_clt() {
591
+ ui_section "Removing Xcode Command Line Tools"
592
+
593
+ if [[ "$OS" != "macos" ]]; then
594
+ ui_info "Xcode Command Line Tools removal is only supported on macOS"
595
+ return 0
596
+ fi
597
+
598
+ if [[ ! -d /Library/Developer/CommandLineTools ]]; then
599
+ ui_info "Xcode Command Line Tools are not installed, skipping"
600
+ return 0
601
+ fi
602
+
603
+ if [[ "$DRY_RUN" == "1" ]]; then
604
+ ui_info "[dry-run] Would: sudo rm -rf /Library/Developer/CommandLineTools"
605
+ return 0
606
+ fi
607
+
608
+ ui_warn "This will delete /Library/Developer/CommandLineTools from this Mac."
609
+ if ! confirm "Delete Xcode Command Line Tools?"; then
610
+ ui_info "Xcode Command Line Tools kept"
611
+ return 0
612
+ fi
613
+
614
+ run_sudo rm -rf /Library/Developer/CommandLineTools
615
+ if [[ ! -d /Library/Developer/CommandLineTools ]]; then
616
+ ui_success "Xcode Command Line Tools removed"
617
+ return 0
618
+ fi
619
+
620
+ ui_warn "Could not fully remove /Library/Developer/CommandLineTools"
621
+ return 1
622
+ }
623
+
624
+ # ─── Homebrew uninstall (--brew flag) ────────────────────────────────────────
625
+ uninstall_homebrew() {
626
+ ui_section "Removing Homebrew"
627
+
628
+ if [[ "$OS" != "macos" ]]; then
629
+ ui_info "Homebrew removal is only supported on macOS"
630
+ return 0
631
+ fi
632
+
633
+ if [[ ! -x /opt/homebrew/bin/brew && ! -x /usr/local/bin/brew && ! -d /opt/homebrew && ! -d /usr/local/Homebrew ]]; then
634
+ ui_info "Homebrew not found — skipping"
635
+ return 0
636
+ fi
637
+
638
+ if [[ "$DRY_RUN" == "1" ]]; then
639
+ ui_info '[dry-run] Would: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"'
640
+ return 0
641
+ fi
642
+
643
+ ui_warn "This will run the official Homebrew uninstall script and may remove all Homebrew packages on this Mac."
644
+ if ! confirm "Run Homebrew uninstall script?"; then
645
+ ui_info "Homebrew kept"
646
+ return 0
647
+ fi
648
+
649
+ local uninstall_script=""
650
+ if ! uninstall_script="$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"; then
651
+ ui_warn "Failed to download the Homebrew uninstall script"
652
+ return 1
653
+ fi
654
+
655
+ if ! _run_as_real_user /bin/bash -c "$uninstall_script"; then
656
+ ui_warn "Homebrew uninstall script failed"
657
+ return 1
658
+ fi
659
+
660
+ hash -r 2>/dev/null || true
661
+ if [[ -x /opt/homebrew/bin/brew || -x /usr/local/bin/brew || -d /opt/homebrew || -d /usr/local/Homebrew ]]; then
662
+ ui_warn "Homebrew may still be present after uninstall"
663
+ return 1
664
+ fi
665
+
666
+ ui_success "Homebrew removed"
667
+ }
668
+
340
669
  # ─── Docker (Linux, --docker flag) ───────────────────────────────────────────
341
670
  uninstall_docker() {
342
671
  ui_section "Removing Docker"
@@ -362,7 +691,7 @@ uninstall_docker() {
362
691
  fi
363
692
  ui_info "[dry-run] Would groupdel docker"
364
693
  ui_info "[dry-run] Would remove /var/lib/docker /var/lib/containerd /etc/docker"
365
- ui_info "[dry-run] Would remove ~/.docker"
694
+ ui_info "[dry-run] Would remove ${USER_HOME}/.docker"
366
695
  ui_info "[dry-run] Would: systemctl daemon-reload"
367
696
  return 0
368
697
  fi
@@ -483,12 +812,12 @@ uninstall_docker() {
483
812
  done
484
813
 
485
814
  # Remove user Docker config directory (~/.docker contains credentials and config)
486
- if [[ -d "${HOME}/.docker" ]]; then
815
+ if [[ -d "${USER_HOME}/.docker" ]]; then
487
816
  if confirm "Delete user Docker config directory (~/.docker)?"; then
488
- rm -rf "${HOME}/.docker" 2>/dev/null || true
489
- ui_success "Removed: ${HOME}/.docker"
817
+ rm -rf "${USER_HOME}/.docker" 2>/dev/null || true
818
+ ui_success "Removed: ${USER_HOME}/.docker"
490
819
  else
491
- ui_info "Kept: ${HOME}/.docker"
820
+ ui_info "Kept: ${USER_HOME}/.docker"
492
821
  fi
493
822
  fi
494
823
 
@@ -515,7 +844,7 @@ uninstall_nomad() {
515
844
 
516
845
  local system_nomad
517
846
  system_nomad="$(command -v nomad 2>/dev/null || true)"
518
- local local_bin="${JISHUSHELL_HOME:-${HOME}/.jishushell}/bin/nomad"
847
+ local local_bin="${JISHUSHELL_HOME}/bin/nomad"
519
848
  # Ignore if system PATH resolves to our local bin (that gets cleaned with ~/.jishushell)
520
849
  [[ "$system_nomad" == "$local_bin" ]] && system_nomad=""
521
850
 
@@ -636,6 +965,8 @@ show_plan() {
636
965
  echo -e " ${WARN}·${NC} Data directory (~/.jishushell) — will ask"
637
966
  [[ $DO_DOCKER -eq 1 ]] && echo -e " ${WARN}·${NC} Uninstall Docker/Colima system packages (brew/apt/dnf)"
638
967
  [[ $DO_NOMAD -eq 1 ]] && echo -e " ${WARN}·${NC} Uninstall Nomad system package (brew/apt/dnf)"
968
+ [[ $DO_BREW -eq 1 ]] && echo -e " ${WARN}·${NC} Run the official Homebrew uninstall script (macOS)"
969
+ [[ $DO_XCODE_CLT -eq 1 ]] && echo -e " ${WARN}·${NC} Delete /Library/Developer/CommandLineTools (macOS)"
639
970
  if [[ "$DRY_RUN" == "1" ]]; then
640
971
  echo ""
641
972
  echo -e "${WARN} Dry-run mode: no changes will be made${NC}"
@@ -683,6 +1014,8 @@ main() {
683
1014
  fi
684
1015
 
685
1016
  [[ $DO_NOMAD -eq 1 ]] && { uninstall_nomad || uninstall_errors=1; }
1017
+ [[ $DO_BREW -eq 1 ]] && { uninstall_homebrew || uninstall_errors=1; }
1018
+ [[ $DO_XCODE_CLT -eq 1 ]] && { uninstall_xcode_clt || uninstall_errors=1; }
686
1019
 
687
1020
  echo ""
688
1021
  if [[ $uninstall_errors -eq 0 ]]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jishushell",
3
- "version": "0.4.24",
3
+ "version": "0.4.30",
4
4
  "description": "JishuShell - Multi-Agent Framework Management",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,6 +40,8 @@
40
40
  "prepare": "git config core.hooksPath .githooks 2>/dev/null || true",
41
41
  "build:pack": "npm run build && npm pack",
42
42
  "check:contracts": "node --experimental-strip-types scripts/check-adapter-isolation.ts",
43
+ "check:i18n": "node scripts/check-i18n.mjs",
44
+ "check:app-spec": "node scripts/check-app-spec.mjs",
43
45
  "version": "node -e \"const fs=require('fs'),v=JSON.parse(fs.readFileSync('./package.json','utf8')).version,fp='./frontend/package.json',p=JSON.parse(fs.readFileSync(fp,'utf8'));p.version=v;fs.writeFileSync(fp,JSON.stringify(p,null,2)+'\\n')\" && git add frontend/package.json"
44
46
  },
45
47
  "engines": {
@@ -0,0 +1 @@
1
+ import{k as B,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-Dw3HhUYE.js";import{r as u,u as D}from"./vendor-react-Bk1hRGiY.js";import{u as P}from"./usePolling-Do5Erqm_.js";import{u as _}from"./vendor-i18n-ucpM0OR0.js";function G(t){if(!t)return"-";const l=Math.floor(t/86400),o=Math.floor(t%86400/3600),r=Math.floor(t%3600/60);return l>0?`${l}d ${o}h`:o>0?`${o}h ${r}m`:`${r}m`}function q({status:t}){const{t:l}=_(),r={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 ${r.cls}`,children:l(r.labelKey)})}const O=[{key:"localInference",labelKey:"capability.localInference",cls:"bg-emerald-500/10 text-emerald-400 border-emerald-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 l=new Set((Array.isArray(t==null?void 0:t.provides)?t.provides:[]).map(a=>String((a==null?void 0:a.capability)??"").toLowerCase()).filter(Boolean));if(l.has("llm-agent"))return[];const o=a=>{for(const m of l)if(a(m))return!0;return!1},r=new Set;return o(a=>a==="llm-ollama"||a==="ollama-api")&&r.add("localInference"),o(a=>a==="search"||a.startsWith("search-"))&&r.add("search"),o(a=>a==="browser"||a.startsWith("browser-")||a.startsWith("web-browserless")||a.startsWith("playwright"))&&r.add("browser"),o(a=>a.includes("openwebui"))&&r.add("aiWebUi"),!r.size&&o(a=>a.startsWith("web-")||a.endsWith("-web")||a.endsWith("-dashboard"))&&r.add("webUi"),O.filter(a=>r.has(a.key))}function Q(){const{t}=_(["dashboard","common"]),[l,o]=u.useState([]),[r,a]=u.useState(null),[m,v]=u.useState(""),[j,w]=u.useState(""),[g,N]=u.useState(!1),y=D(),{showToast:b}=B(),h=()=>{I().then(s=>{o(s),w("")}).catch(s=>w(s.message||t("common:error.loadFailed"))),T().then(a).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)}}},f=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=l.filter(s=>{var n;return((n=s.service)==null?void 0:n.status)==="running"}).length,p=!!r&&r.disk.percent>90,W=r?[{label:t("stats.runningInstances"),value:`${S} / ${l.length}`,sub:r.nomad_running?t("stats.engineRunning"):t("stats.engineStopped"),subColor:r.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:`${r.cpu_percent}%`,sub:r.temperature?`${r.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:r.cpu_percent>90},{label:t("stats.memory"),value:`${r.memory.percent}%`,sub:`${r.memory.used_mb}MB / ${r.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:`${r.disk.percent}%`,sub:`${r.disk.used_gb}GB / ${r.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 max-w-5xl 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,{})]}),r&&e.jsx("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-3 mb-4",children:W.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:()=>y("/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:()=>y("/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")})]}):l.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:l.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:()=>y(`/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=>f(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=>f(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=>f(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 +1 @@
1
- import{j as r,ax as J}from"./index-DQsM6Joa.js";import{r as a}from"./vendor-react-Bk1hRGiY.js";import"./vendor-i18n-ucpM0OR0.js";const h="hermes-chat:",I="hermes-chat-epoch:",Y=500,u=10,L=10;function q(s,l){if(!l)return null;try{const t=localStorage.getItem(I+s),c=localStorage.getItem(h+s)!=null;(t!==null&&t!==l||t===null&&c)&&localStorage.removeItem(h+s),t!==l&&localStorage.setItem(I+s,l)}catch{}return l}function P(s,l){q(s,l);try{const t=localStorage.getItem(h+s);if(!t)return[];const c=JSON.parse(t);return Array.isArray(c)?c.filter(n=>n&&(n.role==="user"||n.role==="assistant"||n.role==="system")).map(n=>({role:n.role,content:String(n.content??""),error:!!n.error})):[]}catch{return[]}}function X({instanceId:s,instanceEpoch:l=null}){const[t,c]=a.useState(()=>P(s,l)),[n,m]=a.useState(()=>Math.min(u,t.length||u)),[v,S]=a.useState(""),[d,N]=a.useState(!1),[g,w]=a.useState(!1),x=a.useRef(null),M=a.useRef(t.length),f=a.useRef(null),F=t.slice(-n),j=n<t.length;a.useEffect(()=>{try{const e=t.filter(i=>!i.pending).slice(-Y);e.length===0?localStorage.removeItem(h+s):localStorage.setItem(h+s,JSON.stringify(e))}catch{}},[s,t]),a.useEffect(()=>{const e=P(s,l);c(e),m(Math.min(u,e.length||u))},[s,l]),a.useEffect(()=>{const e=x.current;if(e){if(f.current){const i=f.current.prevScrollHeight;e.scrollTop=e.scrollHeight-i,f.current=null;return}t.length>=M.current&&(e.scrollTop=e.scrollHeight),M.current=t.length}},[t,n]);const C=()=>{if(!j||g)return;w(!0);const e=x.current;e&&(f.current={prevScrollHeight:e.scrollHeight}),m(i=>Math.min(i+L,t.length)),requestAnimationFrame(()=>w(!1))},T=()=>{const e=x.current;!e||!j||g||e.scrollTop<40&&C()},E=async()=>{var H,R,k,A;const e=v.trim();if(!e||d)return;S(""),N(!0);const i={role:"user",content:e},K={role:"assistant",content:"",pending:!0},_=[...t,i,K];c(_);const $=_.slice(0,-1).slice(-20).map(o=>({role:o.role,content:o.content}));try{const o=await J(s,{model:"hermes-agent",messages:$,max_tokens:512}),p=((k=(R=(H=o==null?void 0:o.choices)==null?void 0:H[0])==null?void 0:R.message)==null?void 0:k.content)??((A=o==null?void 0:o.error)==null?void 0:A.message)??"(empty response)";c(b=>b.map((y,B)=>B===b.length-1?{role:"assistant",content:String(p)}:y))}catch(o){c(p=>p.map((b,y)=>y===p.length-1?{role:"assistant",content:(o==null?void 0:o.message)||"(request failed)",error:!0}:b))}finally{N(!1)}},O=e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),E())};return r.jsxs("div",{className:"overflow-hidden rounded-[22px] border border-[var(--border)] bg-[var(--card)] shadow-[0_18px_48px_rgba(15,23,42,0.06)] flex flex-col",style:{height:"calc(100vh - 160px)",minHeight:"500px"},children:[r.jsxs("div",{className:"px-5 py-3 border-b border-[var(--border)] flex items-center justify-between",children:[r.jsxs("div",{className:"flex items-center gap-2",children:[r.jsx("span",{className:"inline-block w-2 h-2 rounded-full bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.7)]"}),r.jsx("span",{className:"text-sm font-medium text-foreground",children:"Chat"}),r.jsx("span",{className:"text-[10px] text-muted font-mono",children:"inline → /v1/chat/completions"})]}),t.length>0&&r.jsx("button",{onClick:()=>{c([]),m(u)},className:"text-xs text-muted hover:text-foreground transition-colors",disabled:d,children:"清空对话"})]}),r.jsxs("div",{ref:x,onScroll:T,className:"flex-1 overflow-y-auto p-5 space-y-3",children:[j&&r.jsx("div",{className:"flex justify-center py-1",children:r.jsx("button",{onClick:C,disabled:g,className:"text-xs text-muted hover:text-foreground transition-colors",children:g?"加载中...":`向上滚动或点击加载更早的 ${Math.min(L,t.length-n)} 条 (共 ${t.length} 条)`})}),t.length===0?r.jsxs("div",{className:"h-full flex flex-col items-center justify-center text-center",children:[r.jsx("div",{className:"text-4xl mb-3 opacity-40",children:"⚕"}),r.jsx("div",{className:"text-sm text-foreground/70 font-medium mb-1",children:"和 Hermes agent 开始对话"}),r.jsx("div",{className:"text-xs text-muted max-w-md",children:"消息会走完整的 agent loop(skills + tools + memory), 经 JishuShell LLM 代理转发到上游模型。首次请求因冷启动约 20-30 秒。"})]}):F.map((e,i)=>r.jsx("div",{className:`flex ${e.role==="user"?"justify-end":"justify-start"}`,children:r.jsx("div",{className:`max-w-[80%] rounded-2xl px-4 py-2.5 text-sm whitespace-pre-wrap break-words ${e.role==="user"?"bg-[#0066FF] text-white":e.error?"bg-red-500/10 border border-red-500/20 text-red-400":"bg-[var(--input-bg)] border border-[var(--border)] text-foreground"}`,children:e.pending?r.jsxs("span",{className:"inline-flex items-center gap-2 text-muted",children:[r.jsx("span",{className:"w-3 h-3 border-2 border-[#0066FF]/30 border-t-[#0066FF] rounded-full animate-spin"}),"agent 正在思考..."]}):e.content})},t.length-F.length+i))]}),r.jsx("div",{className:"p-4 border-t border-[var(--border)]",children:r.jsxs("div",{className:"flex gap-2",children:[r.jsx("textarea",{value:v,onChange:e=>S(e.target.value),onKeyDown:O,placeholder:"输入消息 (Enter 发送,Shift+Enter 换行)",rows:2,disabled:d,className:"flex-1 bg-[var(--input-bg)] border border-[var(--border)] rounded-lg px-3 py-2 text-sm text-foreground placeholder-[var(--muted)] focus:outline-none focus:ring-1 focus:ring-[#0066FF]/60 focus:border-[#0066FF]/60 resize-none"}),r.jsx("button",{onClick:E,disabled:!v.trim()||d,className:"self-end px-4 py-2 bg-[#0066FF] text-white rounded-lg text-sm font-medium hover:bg-[#0066FF]/90 disabled:opacity-40 transition-all duration-200",children:d?r.jsxs("span",{className:"inline-flex items-center gap-2",children:[r.jsx("span",{className:"w-3 h-3 border-2 border-white/30 border-t-white rounded-full animate-spin"}),"发送中"]}):"发送"})]})})]})}export{X as HermesChatPanel};
1
+ import{j as r,aC as J}from"./index-Dw3HhUYE.js";import{r as a}from"./vendor-react-Bk1hRGiY.js";import"./vendor-i18n-ucpM0OR0.js";const h="hermes-chat:",I="hermes-chat-epoch:",Y=500,u=10,L=10;function q(s,l){if(!l)return null;try{const t=localStorage.getItem(I+s),c=localStorage.getItem(h+s)!=null;(t!==null&&t!==l||t===null&&c)&&localStorage.removeItem(h+s),t!==l&&localStorage.setItem(I+s,l)}catch{}return l}function P(s,l){q(s,l);try{const t=localStorage.getItem(h+s);if(!t)return[];const c=JSON.parse(t);return Array.isArray(c)?c.filter(n=>n&&(n.role==="user"||n.role==="assistant"||n.role==="system")).map(n=>({role:n.role,content:String(n.content??""),error:!!n.error})):[]}catch{return[]}}function X({instanceId:s,instanceEpoch:l=null}){const[t,c]=a.useState(()=>P(s,l)),[n,m]=a.useState(()=>Math.min(u,t.length||u)),[v,S]=a.useState(""),[d,N]=a.useState(!1),[g,w]=a.useState(!1),x=a.useRef(null),M=a.useRef(t.length),f=a.useRef(null),F=t.slice(-n),j=n<t.length;a.useEffect(()=>{try{const e=t.filter(i=>!i.pending).slice(-Y);e.length===0?localStorage.removeItem(h+s):localStorage.setItem(h+s,JSON.stringify(e))}catch{}},[s,t]),a.useEffect(()=>{const e=P(s,l);c(e),m(Math.min(u,e.length||u))},[s,l]),a.useEffect(()=>{const e=x.current;if(e){if(f.current){const i=f.current.prevScrollHeight;e.scrollTop=e.scrollHeight-i,f.current=null;return}t.length>=M.current&&(e.scrollTop=e.scrollHeight),M.current=t.length}},[t,n]);const C=()=>{if(!j||g)return;w(!0);const e=x.current;e&&(f.current={prevScrollHeight:e.scrollHeight}),m(i=>Math.min(i+L,t.length)),requestAnimationFrame(()=>w(!1))},T=()=>{const e=x.current;!e||!j||g||e.scrollTop<40&&C()},E=async()=>{var H,R,k,A;const e=v.trim();if(!e||d)return;S(""),N(!0);const i={role:"user",content:e},K={role:"assistant",content:"",pending:!0},_=[...t,i,K];c(_);const $=_.slice(0,-1).slice(-20).map(o=>({role:o.role,content:o.content}));try{const o=await J(s,{model:"hermes-agent",messages:$,max_tokens:512}),p=((k=(R=(H=o==null?void 0:o.choices)==null?void 0:H[0])==null?void 0:R.message)==null?void 0:k.content)??((A=o==null?void 0:o.error)==null?void 0:A.message)??"(empty response)";c(b=>b.map((y,B)=>B===b.length-1?{role:"assistant",content:String(p)}:y))}catch(o){c(p=>p.map((b,y)=>y===p.length-1?{role:"assistant",content:(o==null?void 0:o.message)||"(request failed)",error:!0}:b))}finally{N(!1)}},O=e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),E())};return r.jsxs("div",{className:"overflow-hidden rounded-[22px] border border-[var(--border)] bg-[var(--card)] shadow-[0_18px_48px_rgba(15,23,42,0.06)] flex flex-col",style:{height:"calc(100vh - 160px)",minHeight:"500px"},children:[r.jsxs("div",{className:"px-5 py-3 border-b border-[var(--border)] flex items-center justify-between",children:[r.jsxs("div",{className:"flex items-center gap-2",children:[r.jsx("span",{className:"inline-block w-2 h-2 rounded-full bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.7)]"}),r.jsx("span",{className:"text-sm font-medium text-foreground",children:"Chat"}),r.jsx("span",{className:"text-[10px] text-muted font-mono",children:"inline → /v1/chat/completions"})]}),t.length>0&&r.jsx("button",{onClick:()=>{c([]),m(u)},className:"text-xs text-muted hover:text-foreground transition-colors",disabled:d,children:"清空对话"})]}),r.jsxs("div",{ref:x,onScroll:T,className:"flex-1 overflow-y-auto p-5 space-y-3",children:[j&&r.jsx("div",{className:"flex justify-center py-1",children:r.jsx("button",{onClick:C,disabled:g,className:"text-xs text-muted hover:text-foreground transition-colors",children:g?"加载中...":`向上滚动或点击加载更早的 ${Math.min(L,t.length-n)} 条 (共 ${t.length} 条)`})}),t.length===0?r.jsxs("div",{className:"h-full flex flex-col items-center justify-center text-center",children:[r.jsx("div",{className:"text-4xl mb-3 opacity-40",children:"⚕"}),r.jsx("div",{className:"text-sm text-foreground/70 font-medium mb-1",children:"和 Hermes agent 开始对话"}),r.jsx("div",{className:"text-xs text-muted max-w-md",children:"消息会走完整的 agent loop(skills + tools + memory), 经 JishuShell LLM 代理转发到上游模型。首次请求因冷启动约 20-30 秒。"})]}):F.map((e,i)=>r.jsx("div",{className:`flex ${e.role==="user"?"justify-end":"justify-start"}`,children:r.jsx("div",{className:`max-w-[80%] rounded-2xl px-4 py-2.5 text-sm whitespace-pre-wrap break-words ${e.role==="user"?"bg-[#0066FF] text-white":e.error?"bg-red-500/10 border border-red-500/20 text-red-400":"bg-[var(--input-bg)] border border-[var(--border)] text-foreground"}`,children:e.pending?r.jsxs("span",{className:"inline-flex items-center gap-2 text-muted",children:[r.jsx("span",{className:"w-3 h-3 border-2 border-[#0066FF]/30 border-t-[#0066FF] rounded-full animate-spin"}),"agent 正在思考..."]}):e.content})},t.length-F.length+i))]}),r.jsx("div",{className:"p-4 border-t border-[var(--border)]",children:r.jsxs("div",{className:"flex gap-2",children:[r.jsx("textarea",{value:v,onChange:e=>S(e.target.value),onKeyDown:O,placeholder:"输入消息 (Enter 发送,Shift+Enter 换行)",rows:2,disabled:d,className:"flex-1 bg-[var(--input-bg)] border border-[var(--border)] rounded-lg px-3 py-2 text-sm text-foreground placeholder-[var(--muted)] focus:outline-none focus:ring-1 focus:ring-[#0066FF]/60 focus:border-[#0066FF]/60 resize-none"}),r.jsx("button",{onClick:E,disabled:!v.trim()||d,className:"self-end px-4 py-2 bg-[#0066FF] text-white rounded-lg text-sm font-medium hover:bg-[#0066FF]/90 disabled:opacity-40 transition-all duration-200",children:d?r.jsxs("span",{className:"inline-flex items-center gap-2",children:[r.jsx("span",{className:"w-3 h-3 border-2 border-white/30 border-t-white rounded-full animate-spin"}),"发送中"]}):"发送"})]})})]})}export{X as HermesChatPanel};
@@ -0,0 +1,4 @@
1
+ import{aD as pe,j as s,p as ve,$ as fe}from"./index-Dw3HhUYE.js";import{r as u,L as Z}from"./vendor-react-Bk1hRGiY.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-DPZpAKgO.js";import{u as je}from"./vendor-i18n-ucpM0OR0.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)||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 +1 @@
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-DQsM6Joa.js";import{r}from"./vendor-react-Bk1hRGiY.js";import{u as S}from"./vendor-i18n-ucpM0OR0.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(""),[n,h]=r.useState(""),[o,f]=r.useState(!1),[l,d]=r.useState(""),[c,m]=r.useState(!1),u=s.length>=8&&s===n,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:o?"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(!o),className:"absolute right-3 top-1/2 -translate-y-1/2 text-muted hover:text-foreground transition-colors duration-200",children:o?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:o?"text":"password",value:n,onChange:a=>h(a.target.value),placeholder:t("init.confirmPlaceholder"),className:x}),s&&n&&s!==n&&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};
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-Dw3HhUYE.js";import{r}from"./vendor-react-Bk1hRGiY.js";import{u as S}from"./vendor-i18n-ucpM0OR0.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(""),[n,h]=r.useState(""),[o,f]=r.useState(!1),[l,d]=r.useState(""),[c,m]=r.useState(!1),u=s.length>=8&&s===n,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:o?"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(!o),className:"absolute right-3 top-1/2 -translate-y-1/2 text-muted hover:text-foreground transition-colors duration-200",children:o?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:o?"text":"password",value:n,onChange:a=>h(a.target.value),placeholder:t("init.confirmPlaceholder"),className:x}),s&&n&&s!==n&&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};