agim-cli 1.4.8 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +415 -402
- package/README.md +4 -4
- package/bin/agim_rpc.py +12 -12
- package/dist/cli-ui/cmd-handlers.d.ts +3 -3
- package/dist/cli-ui/cmd-handlers.d.ts.map +1 -1
- package/dist/cli-ui/cmd-handlers.js +11 -19
- package/dist/cli-ui/cmd-handlers.js.map +1 -1
- package/dist/cli-ui/config-wizard.js +27 -27
- package/dist/cli-ui/config-wizard.js.map +1 -1
- package/dist/cli-ui/env-file.d.ts +4 -4
- package/dist/cli-ui/env-file.js +13 -13
- package/dist/cli-ui/env-file.js.map +1 -1
- package/dist/cli-ui/i18n.d.ts +2 -2
- package/dist/cli-ui/i18n.js +9 -9
- package/dist/cli-ui/i18n.js.map +1 -1
- package/dist/cli-ui/lang-picker.js +1 -1
- package/dist/cli-ui/lang-picker.js.map +1 -1
- package/dist/cli-ui/paths.d.ts.map +1 -1
- package/dist/cli-ui/paths.js +2 -4
- package/dist/cli-ui/paths.js.map +1 -1
- package/dist/cli-ui/service.d.ts +7 -7
- package/dist/cli-ui/service.d.ts.map +1 -1
- package/dist/cli-ui/service.js +57 -72
- package/dist/cli-ui/service.js.map +1 -1
- package/dist/cli-ui/tui/app.js +2 -2
- package/dist/cli-ui/tui/app.js.map +1 -1
- package/dist/cli-ui/tui/index.js +6 -6
- package/dist/cli-ui/tui/index.js.map +1 -1
- package/dist/cli-ui/tui/mouse-stdin.js +1 -1
- package/dist/cli-ui/tui/mouse-stdin.js.map +1 -1
- package/dist/cli-ui/tui/stream-reveal.d.ts +2 -2
- package/dist/cli-ui/tui/stream-reveal.d.ts.map +1 -1
- package/dist/cli-ui/tui/stream-reveal.js +4 -4
- package/dist/cli-ui/tui/stream-reveal.js.map +1 -1
- package/dist/cli.js +24 -45
- package/dist/cli.js.map +1 -1
- package/dist/core/a2a-notify.js +5 -5
- package/dist/core/a2a-notify.js.map +1 -1
- package/dist/core/a2a.d.ts +2 -2
- package/dist/core/a2a.d.ts.map +1 -1
- package/dist/core/a2a.js +12 -12
- package/dist/core/a2a.js.map +1 -1
- package/dist/core/access-token.d.ts +1 -1
- package/dist/core/access-token.js +7 -7
- package/dist/core/access-token.js.map +1 -1
- package/dist/core/acp-server.js +5 -5
- package/dist/core/acp-server.js.map +1 -1
- package/dist/core/admin-allowlist.js +5 -5
- package/dist/core/admin-allowlist.js.map +1 -1
- package/dist/core/agent-base.d.ts +1 -1
- package/dist/core/agent-base.js +3 -3
- package/dist/core/agent-base.js.map +1 -1
- package/dist/core/agent-cwd.d.ts +5 -6
- package/dist/core/agent-cwd.d.ts.map +1 -1
- package/dist/core/agent-cwd.js +15 -16
- package/dist/core/agent-cwd.js.map +1 -1
- package/dist/core/agim-paths.d.ts +1 -4
- package/dist/core/agim-paths.d.ts.map +1 -1
- package/dist/core/agim-paths.js +18 -35
- package/dist/core/agim-paths.js.map +1 -1
- package/dist/core/approval-bus.d.ts +4 -4
- package/dist/core/approval-bus.d.ts.map +1 -1
- package/dist/core/approval-bus.js +14 -14
- package/dist/core/approval-bus.js.map +1 -1
- package/dist/core/approval-router.js +2 -2
- package/dist/core/artifacts.js +3 -3
- package/dist/core/artifacts.js.map +1 -1
- package/dist/core/ask-user-rpc.js +1 -1
- package/dist/core/ask-user-rpc.js.map +1 -1
- package/dist/core/audit-log.js +2 -2
- package/dist/core/audit-log.js.map +1 -1
- package/dist/core/bgjob-reader.d.ts +1 -1
- package/dist/core/bgjob-reader.js +4 -4
- package/dist/core/bgjob-reader.js.map +1 -1
- package/dist/core/commands/approval.js +2 -2
- package/dist/core/commands/approval.js.map +1 -1
- package/dist/core/commands/heartbeat.js +2 -2
- package/dist/core/commands/heartbeat.js.map +1 -1
- package/dist/core/commands/memo.js +1 -1
- package/dist/core/commands/memo.js.map +1 -1
- package/dist/core/commands/model.js +1 -1
- package/dist/core/commands/model.js.map +1 -1
- package/dist/core/commands/plan.js +3 -3
- package/dist/core/commands/plan.js.map +1 -1
- package/dist/core/commands/router-compare.js +3 -3
- package/dist/core/commands/router-compare.js.map +1 -1
- package/dist/core/commands/service.d.ts.map +1 -1
- package/dist/core/commands/service.js +1 -3
- package/dist/core/commands/service.js.map +1 -1
- package/dist/core/commands/sessions.js +4 -4
- package/dist/core/commands/sessions.js.map +1 -1
- package/dist/core/commands/skill.js +1 -1
- package/dist/core/commands/skill.js.map +1 -1
- package/dist/core/commands/stats.js +1 -1
- package/dist/core/commands/stats.js.map +1 -1
- package/dist/core/commands/web.js +5 -5
- package/dist/core/commands/web.js.map +1 -1
- package/dist/core/config-schema.js +1 -1
- package/dist/core/coord-systems.d.ts +1 -1
- package/dist/core/coord-systems.js +4 -4
- package/dist/core/coord-systems.js.map +1 -1
- package/dist/core/event-bus.d.ts +5 -5
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +3 -3
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/feature-flags.d.ts +2 -2
- package/dist/core/feature-flags.js +4 -4
- package/dist/core/feature-flags.js.map +1 -1
- package/dist/core/goal-rpc.js +2 -2
- package/dist/core/goal-rpc.js.map +1 -1
- package/dist/core/goals.d.ts +1 -1
- package/dist/core/goals.js +3 -3
- package/dist/core/goals.js.map +1 -1
- package/dist/core/heartbeat-store.d.ts +1 -1
- package/dist/core/heartbeat-store.d.ts.map +1 -1
- package/dist/core/heartbeat-store.js +3 -3
- package/dist/core/heartbeat-store.js.map +1 -1
- package/dist/core/heartbeat.js +4 -4
- package/dist/core/heartbeat.js.map +1 -1
- package/dist/core/intent-llm.d.ts +2 -2
- package/dist/core/intent-llm.js +5 -5
- package/dist/core/intent-llm.js.map +1 -1
- package/dist/core/job-board.d.ts +5 -5
- package/dist/core/job-board.d.ts.map +1 -1
- package/dist/core/job-board.js +17 -17
- package/dist/core/job-board.js.map +1 -1
- package/dist/core/llm/agent-loop.d.ts +3 -3
- package/dist/core/llm/agent-loop.js +14 -14
- package/dist/core/llm/agent-loop.js.map +1 -1
- package/dist/core/llm/{imhub-dispatcher.d.ts → agim-dispatcher.d.ts} +4 -4
- package/dist/core/llm/agim-dispatcher.d.ts.map +1 -0
- package/dist/core/llm/{imhub-dispatcher.js → agim-dispatcher.js} +43 -43
- package/dist/core/llm/agim-dispatcher.js.map +1 -0
- package/dist/core/llm/agim-rpc-server.js +17 -17
- package/dist/core/llm/agim-rpc-server.js.map +1 -1
- package/dist/core/llm/auto-compact.d.ts +3 -3
- package/dist/core/llm/auto-compact.d.ts.map +1 -1
- package/dist/core/llm/auto-compact.js +5 -5
- package/dist/core/llm/auto-compact.js.map +1 -1
- package/dist/core/llm/builtin-dispatcher.js +3 -3
- package/dist/core/llm/builtin-dispatcher.js.map +1 -1
- package/dist/core/llm/exec-dispatcher.d.ts +2 -2
- package/dist/core/llm/exec-dispatcher.d.ts.map +1 -1
- package/dist/core/llm/exec-dispatcher.js +20 -22
- package/dist/core/llm/exec-dispatcher.js.map +1 -1
- package/dist/core/llm/fs-dispatcher.js +8 -8
- package/dist/core/llm/fs-dispatcher.js.map +1 -1
- package/dist/core/llm/goal-critic.js +4 -4
- package/dist/core/llm/goal-critic.js.map +1 -1
- package/dist/core/llm/hallucination-detector.js +2 -2
- package/dist/core/llm/hallucination-detector.js.map +1 -1
- package/dist/core/llm/mcp-client.d.ts +1 -1
- package/dist/core/llm/mcp-client.js +3 -3
- package/dist/core/llm/mcp-client.js.map +1 -1
- package/dist/core/llm/mcp-registry.js +3 -3
- package/dist/core/llm/mcp-registry.js.map +1 -1
- package/dist/core/llm/openai-compat-provider.d.ts +1 -1
- package/dist/core/llm/openai-compat-provider.js +2 -2
- package/dist/core/llm/openai-compat-provider.js.map +1 -1
- package/dist/core/llm/provider-base.d.ts +1 -1
- package/dist/core/llm/secrets.d.ts +2 -2
- package/dist/core/llm/secrets.d.ts.map +1 -1
- package/dist/core/llm/tool-dispatcher.d.ts +1 -1
- package/dist/core/llm/web-dispatcher.d.ts +1 -1
- package/dist/core/llm/web-dispatcher.js +15 -15
- package/dist/core/llm/web-dispatcher.js.map +1 -1
- package/dist/core/logger.d.ts +1 -1
- package/dist/core/logger.js +3 -3
- package/dist/core/logger.js.map +1 -1
- package/dist/core/memo-rpc.js +3 -3
- package/dist/core/memo-rpc.js.map +1 -1
- package/dist/core/memory-consolidate.js +4 -4
- package/dist/core/memory-consolidate.js.map +1 -1
- package/dist/core/memory-distill.js +4 -4
- package/dist/core/memory-distill.js.map +1 -1
- package/dist/core/memory-distiller.d.ts +10 -4
- package/dist/core/memory-distiller.d.ts.map +1 -1
- package/dist/core/memory-distiller.js +31 -17
- package/dist/core/memory-distiller.js.map +1 -1
- package/dist/core/memory-vector.js +9 -9
- package/dist/core/memory-vector.js.map +1 -1
- package/dist/core/memory.js +2 -2
- package/dist/core/memory.js.map +1 -1
- package/dist/core/memos.js +6 -6
- package/dist/core/memos.js.map +1 -1
- package/dist/core/message-sink.js +13 -13
- package/dist/core/message-sink.js.map +1 -1
- package/dist/core/notification-evaluator.d.ts +2 -2
- package/dist/core/notification-evaluator.js +4 -4
- package/dist/core/notification-evaluator.js.map +1 -1
- package/dist/core/onboarding.js +3 -3
- package/dist/core/onboarding.js.map +1 -1
- package/dist/core/outbox.js +2 -2
- package/dist/core/outbox.js.map +1 -1
- package/dist/core/persona.d.ts +1 -1
- package/dist/core/persona.d.ts.map +1 -1
- package/dist/core/persona.js +2 -2
- package/dist/core/persona.js.map +1 -1
- package/dist/core/plan-history.js +1 -1
- package/dist/core/plan-history.js.map +1 -1
- package/dist/core/plan-intent.js +5 -5
- package/dist/core/plan-intent.js.map +1 -1
- package/dist/core/plan-mode-state.d.ts +1 -1
- package/dist/core/plan-mode-state.js +4 -4
- package/dist/core/plan-mode-state.js.map +1 -1
- package/dist/core/push-rpc.d.ts +1 -1
- package/dist/core/push-rpc.js +6 -6
- package/dist/core/push-rpc.js.map +1 -1
- package/dist/core/registry.d.ts +4 -4
- package/dist/core/registry.js +10 -10
- package/dist/core/registry.js.map +1 -1
- package/dist/core/reminders.js +1 -1
- package/dist/core/reminders.js.map +1 -1
- package/dist/core/restart-flow.d.ts.map +1 -1
- package/dist/core/restart-flow.js +5 -7
- package/dist/core/restart-flow.js.map +1 -1
- package/dist/core/router.d.ts +1 -1
- package/dist/core/router.js +5 -5
- package/dist/core/router.js.map +1 -1
- package/dist/core/schedule.d.ts +2 -2
- package/dist/core/schedule.js +4 -4
- package/dist/core/schedule.js.map +1 -1
- package/dist/core/self-protect.js +3 -3
- package/dist/core/self-protect.js.map +1 -1
- package/dist/core/sender-allowlist.js +7 -7
- package/dist/core/sender-allowlist.js.map +1 -1
- package/dist/core/sensitive-paths.d.ts.map +1 -1
- package/dist/core/sensitive-paths.js +1 -2
- package/dist/core/sensitive-paths.js.map +1 -1
- package/dist/core/session.js +2 -2
- package/dist/core/session.js.map +1 -1
- package/dist/core/skills/builtin/ECC_NOTICE.md +1 -1
- package/dist/core/skills/builtin/agim-memory/SKILL.md +1 -1
- package/dist/core/skills/builtin/agim-reminders/SKILL.md +2 -2
- package/dist/core/skills/builtin/agim-self/SKILL.md +9 -9
- package/dist/core/skills/builtin/agim-skill-discovery/SKILL.md +5 -5
- package/dist/core/skills/builtin/image-generation/SKILL.md +2 -2
- package/dist/core/skills/builtin/long-goal/SKILL.md +7 -7
- package/dist/core/skills/builtin/my/SKILL.md +2 -2
- package/dist/core/skills/builtin/skill-creator/SKILL.md +2 -2
- package/dist/core/skills/loader.d.ts +4 -4
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/loader.js.map +1 -1
- package/dist/core/skills-rpc.js +1 -1
- package/dist/core/skills-rpc.js.map +1 -1
- package/dist/core/transcribe.js +13 -13
- package/dist/core/transcribe.js.map +1 -1
- package/dist/core/tunnel.js +1 -1
- package/dist/core/tunnel.js.map +1 -1
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/user-coord-prefs.js +1 -1
- package/dist/core/user-coord-prefs.js.map +1 -1
- package/dist/core/viewer-config.d.ts +8 -8
- package/dist/core/viewer-config.js +17 -17
- package/dist/core/viewer-config.js.map +1 -1
- package/dist/core/viewer-local.js +4 -4
- package/dist/core/viewer-local.js.map +1 -1
- package/dist/core/viewer-remote.js +1 -1
- package/dist/core/viewer-remote.js.map +1 -1
- package/dist/plugins/agents/acp/url-guard.d.ts +1 -1
- package/dist/plugins/agents/acp/url-guard.js +2 -2
- package/dist/plugins/agents/acp/url-guard.js.map +1 -1
- package/dist/plugins/agents/antigravity/ensure-mcp-config.d.ts +6 -6
- package/dist/plugins/agents/antigravity/ensure-mcp-config.d.ts.map +1 -1
- package/dist/plugins/agents/antigravity/ensure-mcp-config.js +12 -12
- package/dist/plugins/agents/antigravity/ensure-mcp-config.js.map +1 -1
- package/dist/plugins/agents/antigravity/index.js +10 -10
- package/dist/plugins/agents/antigravity/index.js.map +1 -1
- package/dist/plugins/agents/claude-code/index.d.ts +2 -2
- package/dist/plugins/agents/claude-code/index.js +16 -16
- package/dist/plugins/agents/claude-code/index.js.map +1 -1
- package/dist/plugins/agents/claude-code/mcp-approval-server.js +13 -13
- package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -1
- package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts +4 -4
- package/dist/plugins/agents/codex/build-mcp-cli-args.js +14 -14
- package/dist/plugins/agents/codex/build-mcp-cli-args.js.map +1 -1
- package/dist/plugins/agents/codex/index.d.ts +3 -3
- package/dist/plugins/agents/codex/index.js +14 -14
- package/dist/plugins/agents/codex/index.js.map +1 -1
- package/dist/plugins/agents/cursor/ensure-mcp-config.d.ts +5 -5
- package/dist/plugins/agents/cursor/ensure-mcp-config.d.ts.map +1 -1
- package/dist/plugins/agents/cursor/ensure-mcp-config.js +11 -11
- package/dist/plugins/agents/cursor/ensure-mcp-config.js.map +1 -1
- package/dist/plugins/agents/cursor/index.d.ts +1 -1
- package/dist/plugins/agents/cursor/index.js +12 -12
- package/dist/plugins/agents/cursor/index.js.map +1 -1
- package/dist/plugins/agents/native/index.js +14 -14
- package/dist/plugins/agents/native/index.js.map +1 -1
- package/dist/plugins/agents/native/tool-registry.d.ts +3 -3
- package/dist/plugins/agents/native/tool-registry.d.ts.map +1 -1
- package/dist/plugins/agents/native/tool-registry.js +5 -5
- package/dist/plugins/agents/native/tool-registry.js.map +1 -1
- package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts +1 -1
- package/dist/plugins/agents/opencode/ensure-mcp-config.js +9 -9
- package/dist/plugins/agents/opencode/ensure-mcp-config.js.map +1 -1
- package/dist/plugins/agents/opencode/index.js +3 -3
- package/dist/plugins/agents/opencode/index.js.map +1 -1
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +4 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -1
- package/dist/plugins/agents/opencode/opencode-http-adapter.js +16 -12
- package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -1
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +2 -2
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -1
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +7 -5
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js.map +1 -1
- package/dist/plugins/agents/opencode/serve-manager.d.ts +1 -1
- package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -1
- package/dist/plugins/agents/opencode/serve-manager.js +10 -10
- package/dist/plugins/agents/opencode/serve-manager.js.map +1 -1
- package/dist/plugins/agents/pi-native/factory.js +10 -10
- package/dist/plugins/agents/pi-native/factory.js.map +1 -1
- package/dist/plugins/agents/pi-native/index.d.ts +3 -3
- package/dist/plugins/agents/pi-native/index.d.ts.map +1 -1
- package/dist/plugins/agents/pi-native/index.js +2 -2
- package/dist/plugins/agents/pi-native/index.js.map +1 -1
- package/dist/plugins/agents/pi-native/tool-bridge.js +1 -1
- package/dist/plugins/agents/pi-native/tool-bridge.js.map +1 -1
- package/dist/plugins/agents/pi-native/tools.js +4 -4
- package/dist/plugins/agents/pi-native/tools.js.map +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +2 -2
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -1
- package/dist/plugins/messengers/email/email-adapter.js +15 -15
- package/dist/plugins/messengers/email/email-adapter.js.map +1 -1
- package/dist/plugins/messengers/telegram/media-download.d.ts +1 -1
- package/dist/plugins/messengers/telegram/media-download.js +4 -4
- package/dist/plugins/messengers/telegram/media-download.js.map +1 -1
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +1 -1
- package/dist/plugins/messengers/telegram/telegram-adapter.js +3 -3
- package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -1
- package/dist/plugins/messengers/wechat/context-store.js +1 -1
- package/dist/plugins/messengers/wechat/context-store.js.map +1 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.js +1 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -1
- package/dist/plugins/messengers/wechat/ilink-client.js +1 -1
- package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -1
- package/dist/plugins/messengers/wechat/media-download.js +1 -1
- package/dist/plugins/messengers/wechat/media-download.js.map +1 -1
- package/dist/scripts/migrate-gcj02-to-wgs84.js +1 -1
- package/dist/scripts/migrate-gcj02-to-wgs84.js.map +1 -1
- package/dist/web/public/assets/{a2a-Dnc-MHI-.js → a2a-D7MoJ1iT.js} +2 -2
- package/dist/web/public/assets/{a2a-Dnc-MHI-.js.map → a2a-D7MoJ1iT.js.map} +1 -1
- package/dist/web/public/assets/{activity-CKQwfSVC.js → activity-BAgb2WZC.js} +2 -2
- package/dist/web/public/assets/{activity-CKQwfSVC.js.map → activity-BAgb2WZC.js.map} +1 -1
- package/dist/web/public/assets/{admins-C7MdDEF0.js → admins-CZYANmhn.js} +2 -2
- package/dist/web/public/assets/{admins-C7MdDEF0.js.map → admins-CZYANmhn.js.map} +1 -1
- package/dist/web/public/assets/{agents-Be4IUCYz.js → agents-BXThDW6f.js} +2 -2
- package/dist/web/public/assets/agents-BXThDW6f.js.map +1 -0
- package/dist/web/public/assets/{approvals-KCd1BSvN.js → approvals-ByPXIYVl.js} +2 -2
- package/dist/web/public/assets/{approvals-KCd1BSvN.js.map → approvals-ByPXIYVl.js.map} +1 -1
- package/dist/web/public/assets/{arrow-down-NRUr_gzg.js → arrow-down-B8DkdbEY.js} +2 -2
- package/dist/web/public/assets/{arrow-down-NRUr_gzg.js.map → arrow-down-B8DkdbEY.js.map} +1 -1
- package/dist/web/public/assets/{arrow-up-4KyqPaSd.js → arrow-up-i_dEdXkz.js} +2 -2
- package/dist/web/public/assets/{arrow-up-4KyqPaSd.js.map → arrow-up-i_dEdXkz.js.map} +1 -1
- package/dist/web/public/assets/{asks-nKwuDJpD.js → asks-yD_inOnM.js} +2 -2
- package/dist/web/public/assets/{asks-nKwuDJpD.js.map → asks-yD_inOnM.js.map} +1 -1
- package/dist/web/public/assets/{audit-Bf4Yv1or.js → audit-teCIRtgN.js} +2 -2
- package/dist/web/public/assets/{audit-Bf4Yv1or.js.map → audit-teCIRtgN.js.map} +1 -1
- package/dist/web/public/assets/{bell--lSOhH-X.js → bell-CeWDMs8_.js} +2 -2
- package/dist/web/public/assets/{bell--lSOhH-X.js.map → bell-CeWDMs8_.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-Daya2BMh.js → bgjobs-Rc05aEy9.js} +2 -2
- package/dist/web/public/assets/bgjobs-Rc05aEy9.js.map +1 -0
- package/dist/web/public/assets/{brain-DF90t0yo.js → brain-BQqv0Zhc.js} +2 -2
- package/dist/web/public/assets/{brain-DF90t0yo.js.map → brain-BQqv0Zhc.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-aRM_fCrr.js → briefcase-DUXbR4xs.js} +2 -2
- package/dist/web/public/assets/{briefcase-aRM_fCrr.js.map → briefcase-DUXbR4xs.js.map} +1 -1
- package/dist/web/public/assets/{chat-BhnNXkIJ.js → chat-DQpQLW9j.js} +2 -2
- package/dist/web/public/assets/{chat-BhnNXkIJ.js.map → chat-DQpQLW9j.js.map} +1 -1
- package/dist/web/public/assets/{chevron-left-DK-fhgiL.js → chevron-left-RC6mMSiX.js} +2 -2
- package/dist/web/public/assets/{chevron-left-DK-fhgiL.js.map → chevron-left-RC6mMSiX.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-BGhMfCcE.js → chevron-right-DrkYVi19.js} +2 -2
- package/dist/web/public/assets/{chevron-right-BGhMfCcE.js.map → chevron-right-DrkYVi19.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-BWBI4Qhk.js → circle-check-DZnkaUdk.js} +2 -2
- package/dist/web/public/assets/{circle-check-BWBI4Qhk.js.map → circle-check-DZnkaUdk.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-BppjBT7j.js → circle-check-big-BC8ntMsz.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-BppjBT7j.js.map → circle-check-big-BC8ntMsz.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-BZ3UUhcm.js → circle-x-DHK7ypFY.js} +2 -2
- package/dist/web/public/assets/{circle-x-BZ3UUhcm.js.map → circle-x-DHK7ypFY.js.map} +1 -1
- package/dist/web/public/assets/{clock-ChP0IxI4.js → clock-DXHhWqJH.js} +2 -2
- package/dist/web/public/assets/{clock-ChP0IxI4.js.map → clock-DXHhWqJH.js.map} +1 -1
- package/dist/web/public/assets/{confirm-dialog-DrP5Lfwx.js → confirm-dialog-gPKJnvEW.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-DrP5Lfwx.js.map → confirm-dialog-gPKJnvEW.js.map} +1 -1
- package/dist/web/public/assets/{copy-CR2c0pyG.js → copy-DtQxgcR0.js} +2 -2
- package/dist/web/public/assets/{copy-CR2c0pyG.js.map → copy-DtQxgcR0.js.map} +1 -1
- package/dist/web/public/assets/{data-table-DElP7TJm.js → data-table-DOKUic1J.js} +2 -2
- package/dist/web/public/assets/{data-table-DElP7TJm.js.map → data-table-DOKUic1J.js.map} +1 -1
- package/dist/web/public/assets/distill-p6P7-1UR.js +7 -0
- package/dist/web/public/assets/distill-p6P7-1UR.js.map +1 -0
- package/dist/web/public/assets/{download-DO4Kw3Fi.js → download-CqNiIHa8.js} +2 -2
- package/dist/web/public/assets/{download-DO4Kw3Fi.js.map → download-CqNiIHa8.js.map} +1 -1
- package/dist/web/public/assets/email-DwbfTUlV.js +7 -0
- package/dist/web/public/assets/email-DwbfTUlV.js.map +1 -0
- package/dist/web/public/assets/{empty-state-DGH3i5i2.js → empty-state-CTwOQemt.js} +2 -2
- package/dist/web/public/assets/{empty-state-DGH3i5i2.js.map → empty-state-CTwOQemt.js.map} +1 -1
- package/dist/web/public/assets/{external-link-B6aOBfUG.js → external-link-BY7Ye8yi.js} +2 -2
- package/dist/web/public/assets/{external-link-B6aOBfUG.js.map → external-link-BY7Ye8yi.js.map} +1 -1
- package/dist/web/public/assets/{eye-BMxHZFil.js → eye-6RUADoDS.js} +2 -2
- package/dist/web/public/assets/{eye-BMxHZFil.js.map → eye-6RUADoDS.js.map} +1 -1
- package/dist/web/public/assets/{facts-B9PlO3xo.js → facts-DXE0aJmb.js} +2 -2
- package/dist/web/public/assets/{facts-B9PlO3xo.js.map → facts-DXE0aJmb.js.map} +1 -1
- package/dist/web/public/assets/{goals-DX_RjDAM.js → goals-C1LCm3qL.js} +2 -2
- package/dist/web/public/assets/{goals-DX_RjDAM.js.map → goals-C1LCm3qL.js.map} +1 -1
- package/dist/web/public/assets/{health-BAcwcy02.js → health-wqCp-K_o.js} +2 -2
- package/dist/web/public/assets/{health-BAcwcy02.js.map → health-wqCp-K_o.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-Cl-tJTJY.js → heart-pulse-DfqI4GF7.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-Cl-tJTJY.js.map → heart-pulse-DfqI4GF7.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-BF_rPcKb.js → heartbeat-Bumv4XtQ.js} +2 -2
- package/dist/web/public/assets/{heartbeat-BF_rPcKb.js.map → heartbeat-Bumv4XtQ.js.map} +1 -1
- package/dist/web/public/assets/{hot-XOCA1xAY.js → hot-B-CMjQIr.js} +2 -2
- package/dist/web/public/assets/{hot-XOCA1xAY.js.map → hot-B-CMjQIr.js.map} +1 -1
- package/dist/web/public/assets/{index-CzlhMSb2.js → index-DHh1LYlA.js} +29 -29
- package/dist/web/public/assets/{index-CzlhMSb2.js.map → index-DHh1LYlA.js.map} +1 -1
- package/dist/web/public/assets/{injection-ecvQ-6Ya.js → injection-Dn_XqgLG.js} +2 -2
- package/dist/web/public/assets/{injection-ecvQ-6Ya.js.map → injection-Dn_XqgLG.js.map} +1 -1
- package/dist/web/public/assets/{installed-D8VzYRBe.js → installed-Cet-1M2Q.js} +2 -2
- package/dist/web/public/assets/{installed-D8VzYRBe.js.map → installed-Cet-1M2Q.js.map} +1 -1
- package/dist/web/public/assets/{jobs-CpuY6G8D.js → jobs-CfEzOOAC.js} +2 -2
- package/dist/web/public/assets/{jobs-CpuY6G8D.js.map → jobs-CfEzOOAC.js.map} +1 -1
- package/dist/web/public/assets/{layout-BROGs5wv.js → layout-BX43KyXM.js} +2 -2
- package/dist/web/public/assets/{layout-BROGs5wv.js.map → layout-BX43KyXM.js.map} +1 -1
- package/dist/web/public/assets/{layout--XsfZzpI.js → layout-BcYZlaqf.js} +2 -2
- package/dist/web/public/assets/{layout--XsfZzpI.js.map → layout-BcYZlaqf.js.map} +1 -1
- package/dist/web/public/assets/{layout-DdbuRh8P.js → layout-Cb7looUv.js} +2 -2
- package/dist/web/public/assets/{layout-DdbuRh8P.js.map → layout-Cb7looUv.js.map} +1 -1
- package/dist/web/public/assets/{layout-BezPqRLV.js → layout-D7xH78OU.js} +2 -2
- package/dist/web/public/assets/{layout-BezPqRLV.js.map → layout-D7xH78OU.js.map} +1 -1
- package/dist/web/public/assets/{layout-Pxfmfh_2.js → layout-D_3ZcVG7.js} +2 -2
- package/dist/web/public/assets/{layout-Pxfmfh_2.js.map → layout-D_3ZcVG7.js.map} +1 -1
- package/dist/web/public/assets/llm-BZ9qqp-D.js +27 -0
- package/dist/web/public/assets/llm-BZ9qqp-D.js.map +1 -0
- package/dist/web/public/assets/{loader-circle-AgQ2XO06.js → loader-circle-DgdBWYl0.js} +2 -2
- package/dist/web/public/assets/{loader-circle-AgQ2XO06.js.map → loader-circle-DgdBWYl0.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-C6sGB9SZ.js → map-pin-3QS1A0-I.js} +2 -2
- package/dist/web/public/assets/{map-pin-C6sGB9SZ.js.map → map-pin-3QS1A0-I.js.map} +1 -1
- package/dist/web/public/assets/{mcp-jqsjSumH.js → mcp-DwKZULET.js} +2 -2
- package/dist/web/public/assets/{mcp-jqsjSumH.js.map → mcp-DwKZULET.js.map} +1 -1
- package/dist/web/public/assets/{memos-C38YN2Rf.js → memos-BBtqFcoH.js} +2 -2
- package/dist/web/public/assets/{memos-C38YN2Rf.js.map → memos-BBtqFcoH.js.map} +1 -1
- package/dist/web/public/assets/{messengers-l74nqYZF.js → messengers-i7WvNT3o.js} +2 -2
- package/dist/web/public/assets/messengers-i7WvNT3o.js.map +1 -0
- package/dist/web/public/assets/{mobile-CHhYS0Tw.js → mobile-Bq0FH9JV.js} +2 -2
- package/dist/web/public/assets/{mobile-CHhYS0Tw.js.map → mobile-Bq0FH9JV.js.map} +1 -1
- package/dist/web/public/assets/{network-CIrcKaZn.js → network--s113Jkm.js} +2 -2
- package/dist/web/public/assets/{network-CIrcKaZn.js.map → network--s113Jkm.js.map} +1 -1
- package/dist/web/public/assets/{outbox-O1lzMZPk.js → outbox-BbfC5kuG.js} +2 -2
- package/dist/web/public/assets/{outbox-O1lzMZPk.js.map → outbox-BbfC5kuG.js.map} +1 -1
- package/dist/web/public/assets/{pagination-CXBUSf6r.js → pagination-DkdCTctJ.js} +2 -2
- package/dist/web/public/assets/{pagination-CXBUSf6r.js.map → pagination-DkdCTctJ.js.map} +1 -1
- package/dist/web/public/assets/{persona-CI4tkm_n.js → persona-BvtcZh6G.js} +2 -2
- package/dist/web/public/assets/{persona-CI4tkm_n.js.map → persona-BvtcZh6G.js.map} +1 -1
- package/dist/web/public/assets/{plans-D8RZ9aXq.js → plans-i3a6lrqF.js} +2 -2
- package/dist/web/public/assets/{plans-D8RZ9aXq.js.map → plans-i3a6lrqF.js.map} +1 -1
- package/dist/web/public/assets/{play-DQ3P_XWl.js → play-CPoE_JnS.js} +2 -2
- package/dist/web/public/assets/{play-DQ3P_XWl.js.map → play-CPoE_JnS.js.map} +1 -1
- package/dist/web/public/assets/{plus-Zai0UXKL.js → plus-CfzKV_0u.js} +2 -2
- package/dist/web/public/assets/{plus-Zai0UXKL.js.map → plus-CfzKV_0u.js.map} +1 -1
- package/dist/web/public/assets/policy-Cm88P8LO.js +2 -0
- package/dist/web/public/assets/policy-Cm88P8LO.js.map +1 -0
- package/dist/web/public/assets/{qr-code-zcjicWRK.js → qr-code-DMkV8nv2.js} +2 -2
- package/dist/web/public/assets/{qr-code-zcjicWRK.js.map → qr-code-DMkV8nv2.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-CM-Cjwud.js → refresh-ccw-nBMm5Xal.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-CM-Cjwud.js.map → refresh-ccw-nBMm5Xal.js.map} +1 -1
- package/dist/web/public/assets/{reminders-BR6noe6I.js → reminders-DjEujanC.js} +2 -2
- package/dist/web/public/assets/{reminders-BR6noe6I.js.map → reminders-DjEujanC.js.map} +1 -1
- package/dist/web/public/assets/{save-xBMgs6Bd.js → save-DbrrCFDM.js} +2 -2
- package/dist/web/public/assets/{save-xBMgs6Bd.js.map → save-DbrrCFDM.js.map} +1 -1
- package/dist/web/public/assets/{schedules-Brp1Fomd.js → schedules-DzwDWykc.js} +2 -2
- package/dist/web/public/assets/{schedules-Brp1Fomd.js.map → schedules-DzwDWykc.js.map} +1 -1
- package/dist/web/public/assets/search-5q3dkINm.js +17 -0
- package/dist/web/public/assets/search-5q3dkINm.js.map +1 -0
- package/dist/web/public/assets/{search-CIc8bWW1.js → search-DbE4VEm9.js} +2 -2
- package/dist/web/public/assets/{search-CIc8bWW1.js.map → search-DbE4VEm9.js.map} +1 -1
- package/dist/web/public/assets/security-BIcnUrAs.js +2 -0
- package/dist/web/public/assets/security-BIcnUrAs.js.map +1 -0
- package/dist/web/public/assets/{service-Bo9rkfQX.js → service-CnorFHzZ.js} +2 -2
- package/dist/web/public/assets/{service-Bo9rkfQX.js.map → service-CnorFHzZ.js.map} +1 -1
- package/dist/web/public/assets/{shield-alert-bg0_ILjD.js → shield-alert-WOa69jy3.js} +2 -2
- package/dist/web/public/assets/{shield-alert-bg0_ILjD.js.map → shield-alert-WOa69jy3.js.map} +1 -1
- package/dist/web/public/assets/{status-badge-Bw4TDDCb.js → status-badge-D5xhwquL.js} +2 -2
- package/dist/web/public/assets/{status-badge-Bw4TDDCb.js.map → status-badge-D5xhwquL.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-D58R9C_Z.js → subtasks-DMRyk6YS.js} +2 -2
- package/dist/web/public/assets/{subtasks-D58R9C_Z.js.map → subtasks-DMRyk6YS.js.map} +1 -1
- package/dist/web/public/assets/{table-D4S5FCk_.js → table-Dx65w6V0.js} +2 -2
- package/dist/web/public/assets/{table-D4S5FCk_.js.map → table-Dx65w6V0.js.map} +1 -1
- package/dist/web/public/assets/{topn-DDxDNIZf.js → topn-L7Juczp3.js} +2 -2
- package/dist/web/public/assets/{topn-DDxDNIZf.js.map → topn-L7Juczp3.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-CB7X8tay.js → trash-2-7xrfqd-v.js} +2 -2
- package/dist/web/public/assets/{trash-2-CB7X8tay.js.map → trash-2-7xrfqd-v.js.map} +1 -1
- package/dist/web/public/assets/{use-agim-skills-BV2IJPlc.js → use-agim-skills-pFjfgqMF.js} +2 -2
- package/dist/web/public/assets/{use-agim-skills-BV2IJPlc.js.map → use-agim-skills-pFjfgqMF.js.map} +1 -1
- package/dist/web/public/assets/{use-background-tasks-Dk9S55ip.js → use-background-tasks-D1--hHjp.js} +2 -2
- package/dist/web/public/assets/{use-background-tasks-Dk9S55ip.js.map → use-background-tasks-D1--hHjp.js.map} +1 -1
- package/dist/web/public/assets/{use-memory-DncmZXGJ.js → use-memory-Bz1Zao7g.js} +2 -2
- package/dist/web/public/assets/{use-memory-DncmZXGJ.js.map → use-memory-Bz1Zao7g.js.map} +1 -1
- package/dist/web/public/assets/{use-observability-CcDO7PdN.js → use-observability-DtqSWVjM.js} +2 -2
- package/dist/web/public/assets/{use-observability-CcDO7PdN.js.map → use-observability-DtqSWVjM.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-DZhfMpNR.js → use-settings-DKbDqCEJ.js} +2 -2
- package/dist/web/public/assets/{use-settings-DZhfMpNR.js.map → use-settings-DKbDqCEJ.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-ywkrT7Aj.js → use-workspace-CConjEx0.js} +2 -2
- package/dist/web/public/assets/{use-workspace-ywkrT7Aj.js.map → use-workspace-CConjEx0.js.map} +1 -1
- package/dist/web/public/assets/vector-D8sEa2W-.js +2 -0
- package/dist/web/public/assets/vector-D8sEa2W-.js.map +1 -0
- package/dist/web/public/assets/viewer-aSIjAKVA.js +12 -0
- package/dist/web/public/assets/viewer-aSIjAKVA.js.map +1 -0
- package/dist/web/public/assets/{workspace-BvrXvliN.js → workspace-BqwWoinI.js} +2 -2
- package/dist/web/public/assets/{workspace-BvrXvliN.js.map → workspace-BqwWoinI.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-0H6Dzz6N.js → workspaces-ChsJcrav.js} +2 -2
- package/dist/web/public/assets/{workspaces-0H6Dzz6N.js.map → workspaces-ChsJcrav.js.map} +1 -1
- package/dist/web/public/index.html +1 -1
- package/dist/web/public/loc.html +1 -1
- package/dist/web/public/login.html +2 -2
- package/dist/web/server.d.ts +2 -2
- package/dist/web/server.js +121 -120
- package/dist/web/server.js.map +1 -1
- package/package.json +2 -3
- package/dist/core/llm/imhub-dispatcher.d.ts.map +0 -1
- package/dist/core/llm/imhub-dispatcher.js.map +0 -1
- package/dist/web/public/assets/agents-Be4IUCYz.js.map +0 -1
- package/dist/web/public/assets/bgjobs-Daya2BMh.js.map +0 -1
- package/dist/web/public/assets/distill-DxSq7g_8.js +0 -7
- package/dist/web/public/assets/distill-DxSq7g_8.js.map +0 -1
- package/dist/web/public/assets/email-Dkqwudqq.js +0 -7
- package/dist/web/public/assets/email-Dkqwudqq.js.map +0 -1
- package/dist/web/public/assets/llm-IXFv_MMM.js +0 -27
- package/dist/web/public/assets/llm-IXFv_MMM.js.map +0 -1
- package/dist/web/public/assets/messengers-l74nqYZF.js.map +0 -1
- package/dist/web/public/assets/policy-BodrOHl5.js +0 -2
- package/dist/web/public/assets/policy-BodrOHl5.js.map +0 -1
- package/dist/web/public/assets/search-nk8nyLFI.js +0 -17
- package/dist/web/public/assets/search-nk8nyLFI.js.map +0 -1
- package/dist/web/public/assets/security-DWxWfpuX.js +0 -2
- package/dist/web/public/assets/security-DWxWfpuX.js.map +0 -1
- package/dist/web/public/assets/vector-B3h4iyfn.js +0 -2
- package/dist/web/public/assets/vector-B3h4iyfn.js.map +0 -1
- package/dist/web/public/assets/viewer-Bz3wL-99.js +0 -12
- package/dist/web/public/assets/viewer-Bz3wL-99.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"security-DWxWfpuX.js","sources":["../../src/routes/settings/security.tsx"],"sourcesContent":["/**\n * /settings/security — central console for v1.2.66 security controls.\n *\n * Lays out:\n * • Diagnostics card (read-only) — uid 0? env file perms? bwrap? allowlists configured?\n * • Sender allowlist (IMHUB_ALLOWED_USERS)\n * • Native exec (IMHUB_EXEC_SANDBOX, IMHUB_EXEC_SANDBOX_NET, IMHUB_EXEC_TIMEOUT_MS, IMHUB_EXEC_MAX_OUTPUT)\n * • Native web (IMHUB_NATIVE_WEB_ALLOW_PRIVATE, IMHUB_NATIVE_WEB_SSRF_WHITELIST, IMHUB_NATIVE_WEB_TIMEOUT_MS)\n * • Native fs (IMHUB_NATIVE_FS_RESTRICT, IMHUB_NATIVE_FS_TIMEOUT_MS)\n * • Delegation (IMHUB_NATIVE_CALL_AGENT_MAX_PER_TURN)\n *\n * All writes go through PUT /api/env (admin-gated). Most knobs are\n * hot-reloaded (read process.env per tool call); the exec sandbox +\n * sender allowlist apply at boot — service restart required.\n */\n\nimport { useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { AlertTriangle, CheckCircle2, Loader2, RefreshCcw, ShieldAlert } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv } from '@/hooks/use-settings'\nimport { client } from '@/lib/api/client'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\ninterface Diagnostics {\n runningAsRoot: boolean | null\n envFile: { exists: boolean; mode: string | null; tooPermissive: boolean }\n bwrapAvailable: boolean\n senderAllowlistConfigured: boolean\n adminAllowlistConfigured: boolean\n platformBlacklist: string[]\n liveEnv: Record<string, string | null>\n}\n\nfunction envBool(v: string | undefined): boolean {\n if (v == null) return false\n const t = v.toLowerCase()\n return t === '1' || t === 'true' || t === 'yes' || t === 'on'\n}\n\nexport default function SettingsSecurityRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const envQuery = useEnv()\n const updateEnv = useUpdateEnv()\n const [diagnostics, setDiagnostics] = useState<Diagnostics | null>(null)\n const [diagLoading, setDiagLoading] = useState(false)\n\n async function loadDiagnostics(): Promise<void> {\n setDiagLoading(true)\n try {\n const res = await client.get<{ diagnostics: Diagnostics }>('/api/security/diagnostics')\n setDiagnostics(res.diagnostics)\n } catch (err) {\n toast.error(describeError(err, t).message)\n } finally {\n setDiagLoading(false)\n }\n }\n\n useEffect(() => { void loadDiagnostics() }, [])\n\n async function setValue(key: string, value: string | null): Promise<void> {\n try {\n await updateEnv.mutateAsync({ updates: { [key]: value } })\n toast.success(t('security.savingToast'))\n await loadDiagnostics()\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n const env = envQuery.data?.env ?? {}\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('security.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => { void envQuery.refetch(); void loadDiagnostics() }}\n disabled={envQuery.isFetching || diagLoading}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {envQuery.isFetching || diagLoading\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />\n }\n </Button>\n </div>\n <p className=\"text-sm text-muted\">{t('security.subtitle')}</p>\n </header>\n\n {/* Diagnostics card */}\n <section className=\"rounded-lg border border-border bg-card p-4\">\n <h2 className=\"mb-3 flex items-center gap-2 text-sm font-semibold\">\n <ShieldAlert className=\"h-4 w-4\" />\n {t('security.diagnostics.title')}\n </h2>\n {diagnostics ? (\n <ul className=\"grid gap-2 text-sm sm:grid-cols-2\">\n <DiagRow\n label={t('security.diagnostics.runningAsRoot')}\n ok={diagnostics.runningAsRoot === false}\n text={diagnostics.runningAsRoot === true ? t('security.diagnostics.runningAsRootHelp') : 'OK'}\n />\n <DiagRow\n label={t('security.diagnostics.envFilePerms')}\n ok={diagnostics.envFile.exists && !diagnostics.envFile.tooPermissive}\n text={\n !diagnostics.envFile.exists\n ? '—'\n : diagnostics.envFile.tooPermissive\n ? `${diagnostics.envFile.mode} — ${t('security.diagnostics.envFilePermsLax')}`\n : t('security.diagnostics.envFilePermsOk')\n }\n />\n <DiagRow\n label={t('security.diagnostics.bwrapAvailable')}\n ok={diagnostics.bwrapAvailable}\n text={diagnostics.bwrapAvailable ? '/usr/bin/bwrap' : t('security.diagnostics.bwrapMissing')}\n />\n <DiagRow\n label={t('security.diagnostics.senderAllowlist')}\n ok={diagnostics.senderAllowlistConfigured}\n text={diagnostics.senderAllowlistConfigured\n ? t('security.diagnostics.senderAllowlistOn')\n : t('security.diagnostics.senderAllowlistOff')\n }\n />\n <DiagRow\n label={t('security.diagnostics.adminAllowlist')}\n ok={diagnostics.adminAllowlistConfigured}\n text={diagnostics.adminAllowlistConfigured\n ? t('security.diagnostics.adminAllowlistOn')\n : t('security.diagnostics.adminAllowlistOff')\n }\n />\n <DiagRow\n label={t('security.diagnosticsPlatformBlacklist')}\n ok={diagnostics.platformBlacklist.length === 0}\n text={diagnostics.platformBlacklist.length === 0\n ? '—'\n : diagnostics.platformBlacklist.join(', ')\n }\n />\n </ul>\n ) : (\n <p className=\"text-sm text-muted\">…</p>\n )}\n </section>\n\n {/* Sender allowlist */}\n <ControlCard\n title={t('security.sender.title')}\n description={t('security.sender.description')}\n envKey=\"IMHUB_ALLOWED_USERS\"\n >\n <Input\n defaultValue={env.IMHUB_ALLOWED_USERS ?? ''}\n placeholder={t('security.sender.placeholder')}\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_ALLOWED_USERS', v === '' ? null : v)\n }}\n />\n </ControlCard>\n\n {/* Exec sandbox */}\n <ControlCard\n title={t('security.exec.title')}\n description={t('security.exec.description')}\n >\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <LabeledField label={t('security.exec.sandbox')}>\n <Select\n value={(env.IMHUB_EXEC_SANDBOX ?? '').toLowerCase() === 'bwrap' ? 'bwrap' : '__none__'}\n onValueChange={(v) => void setValue('IMHUB_EXEC_SANDBOX', v === '__none__' ? null : v)}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__none__\">{t('security.exec.sandboxNone')}</SelectItem>\n <SelectItem\n value=\"bwrap\"\n disabled={!diagnostics?.bwrapAvailable}\n >\n {t('security.exec.sandboxBwrap')}\n {!diagnostics?.bwrapAvailable && (\n <span className=\"ml-2 text-xs text-muted\">\n ({t('security.exec.sandboxBwrapMissing')})\n </span>\n )}\n </SelectItem>\n </SelectContent>\n </Select>\n </LabeledField>\n\n <LabeledField label={t('security.exec.sandboxNet')}>\n <Select\n value={(env.IMHUB_EXEC_SANDBOX_NET ?? '').toLowerCase() === 'off' ? 'off' : 'on'}\n onValueChange={(v) => void setValue('IMHUB_EXEC_SANDBOX_NET', v === 'off' ? 'off' : null)}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"on\">{t('security.exec.sandboxNetOn')}</SelectItem>\n <SelectItem value=\"off\">{t('security.exec.sandboxNetOff')}</SelectItem>\n </SelectContent>\n </Select>\n </LabeledField>\n\n <LabeledField label={t('security.exec.timeoutMs')}>\n <Input\n type=\"number\"\n defaultValue={env.IMHUB_EXEC_TIMEOUT_MS ?? ''}\n placeholder=\"60000\"\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_EXEC_TIMEOUT_MS', v === '' ? null : v)\n }}\n />\n </LabeledField>\n\n <LabeledField label={t('security.exec.maxOutput')}>\n <Input\n type=\"number\"\n defaultValue={env.IMHUB_EXEC_MAX_OUTPUT ?? ''}\n placeholder=\"32768\"\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_EXEC_MAX_OUTPUT', v === '' ? null : v)\n }}\n />\n </LabeledField>\n </div>\n </ControlCard>\n\n {/* Web SSRF */}\n <ControlCard\n title={t('security.web.title')}\n description={t('security.web.description')}\n >\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <LabeledField label={t('security.web.allowPrivate')} hint={t('security.web.allowPrivateHelp')}>\n <Select\n value={envBool(env.IMHUB_NATIVE_WEB_ALLOW_PRIVATE) ? '1' : '0'}\n onValueChange={(v) => void setValue('IMHUB_NATIVE_WEB_ALLOW_PRIVATE', v === '1' ? '1' : null)}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"0\">OFF</SelectItem>\n <SelectItem value=\"1\">ON</SelectItem>\n </SelectContent>\n </Select>\n </LabeledField>\n\n <LabeledField label={t('security.web.timeoutMs')}>\n <Input\n type=\"number\"\n defaultValue={env.IMHUB_NATIVE_WEB_TIMEOUT_MS ?? ''}\n placeholder=\"30000\"\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_NATIVE_WEB_TIMEOUT_MS', v === '' ? null : v)\n }}\n />\n </LabeledField>\n\n <div className=\"sm:col-span-2\">\n <LabeledField label={t('security.web.ssrfWhitelist')}>\n <Input\n defaultValue={env.IMHUB_NATIVE_WEB_SSRF_WHITELIST ?? ''}\n placeholder={t('security.web.ssrfWhitelistPlaceholder')}\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_NATIVE_WEB_SSRF_WHITELIST', v === '' ? null : v)\n }}\n />\n </LabeledField>\n </div>\n </div>\n </ControlCard>\n\n {/* FS */}\n <ControlCard\n title={t('security.fs.title')}\n description={t('security.fs.description')}\n >\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <LabeledField label={t('security.fs.restrict')}>\n <Select\n value={(env.IMHUB_NATIVE_FS_RESTRICT ?? '0') === '1' ? '1' : '0'}\n onValueChange={(v) => void setValue('IMHUB_NATIVE_FS_RESTRICT', v === '1' ? '1' : null)}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"1\">{t('security.fs.restrictOn')}</SelectItem>\n <SelectItem value=\"0\">{t('security.fs.restrictOff')}</SelectItem>\n </SelectContent>\n </Select>\n </LabeledField>\n\n <LabeledField label={t('security.fs.timeoutMs')}>\n <Input\n type=\"number\"\n defaultValue={env.IMHUB_NATIVE_FS_TIMEOUT_MS ?? ''}\n placeholder=\"60000\"\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_NATIVE_FS_TIMEOUT_MS', v === '' ? null : v)\n }}\n />\n </LabeledField>\n </div>\n </ControlCard>\n\n {/* Delegation cap */}\n <ControlCard\n title={t('security.delegation.title')}\n description={t('security.delegation.description')}\n envKey=\"IMHUB_NATIVE_CALL_AGENT_MAX_PER_TURN\"\n >\n <Input\n type=\"number\"\n defaultValue={env.IMHUB_NATIVE_CALL_AGENT_MAX_PER_TURN ?? ''}\n placeholder=\"2\"\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_NATIVE_CALL_AGENT_MAX_PER_TURN', v === '' ? null : v)\n }}\n />\n </ControlCard>\n\n {/* IM platform blacklist */}\n <ControlCard\n title={t('security.platformBlacklist.title')}\n description={t('security.platformBlacklist.description')}\n envKey=\"IMHUB_PLATFORM_BLACKLIST\"\n >\n <Input\n defaultValue={env.IMHUB_PLATFORM_BLACKLIST ?? ''}\n placeholder={t('security.platformBlacklist.placeholder')}\n onBlur={(e) => {\n const v = e.target.value.trim()\n void setValue('IMHUB_PLATFORM_BLACKLIST', v === '' ? null : v)\n }}\n />\n {diagnostics?.platformBlacklist && diagnostics.platformBlacklist.length > 0 && (\n <p className=\"mt-2 text-[10px] text-muted\">\n {t('security.platformBlacklist.currentLabel')}: {diagnostics.platformBlacklist.join(', ')}\n </p>\n )}\n </ControlCard>\n </div>\n )\n}\n\nfunction DiagRow({ label, ok, text }: { label: string; ok: boolean; text: string }): JSX.Element {\n return (\n <li className=\"flex items-start gap-2\">\n {ok\n ? <CheckCircle2 className=\"mt-0.5 h-4 w-4 shrink-0 text-success\" />\n : <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-warning\" />\n }\n <div className=\"flex-1\">\n <div className=\"font-medium\">{label}</div>\n <div className={cn('text-xs', ok ? 'text-muted' : 'text-warning')}>{text}</div>\n </div>\n </li>\n )\n}\n\nfunction ControlCard({\n title, description, envKey, children,\n}: { title: string; description: string; envKey?: string; children: React.ReactNode }): JSX.Element {\n return (\n <section className=\"rounded-lg border border-border bg-card p-4\">\n <div className=\"mb-2 flex flex-wrap items-baseline gap-2\">\n <h2 className=\"text-sm font-semibold\">{title}</h2>\n {envKey && <Badge variant=\"outline\" className=\"font-mono text-[10px]\">{envKey}</Badge>}\n </div>\n <p className=\"mb-3 text-xs text-muted\">{description}</p>\n {children}\n </section>\n )\n}\n\nfunction LabeledField({\n label, hint, children,\n}: { label: string; hint?: string; children: React.ReactNode }): JSX.Element {\n return (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs font-medium text-muted\">{label}</label>\n {children}\n {hint && <p className=\"text-[10px] text-muted\">{hint}</p>}\n </div>\n )\n}\n"],"names":["envBool","v","t","SettingsSecurityRoute","useTranslation","envQuery","useEnv","updateEnv","useUpdateEnv","diagnostics","setDiagnostics","useState","diagLoading","setDiagLoading","loadDiagnostics","res","client","err","toast","describeError","useEffect","setValue","key","value","env","jsxs","jsx","Button","Loader2","RefreshCcw","ShieldAlert","DiagRow","ControlCard","Input","e","LabeledField","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","label","ok","text","CheckCircle2","AlertTriangle","cn","title","description","envKey","children","Badge","hint"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{b as Q,d as O,e as S,a as V,u as L,j as e,l as k,B as p,S as G,g as X,h as Z,i as J,k as H,I as y,m as c,n as j,L as $,f as ee,c as Y}from"./index-CzlhMSb2.js";import{r as g}from"./react-DlP5eolq.js";import{u as te,b as se}from"./use-settings-DZhfMpNR.js";import{m as ae}from"./use-memory-DncmZXGJ.js";import{L as M}from"./loader-circle-AgQ2XO06.js";import{S as re}from"./save-xBMgs6Bd.js";import{E as oe,a as ne}from"./eye-BMxHZFil.js";import{C as ie}from"./confirm-dialog-DrP5Lfwx.js";import{E as ce}from"./empty-state-DGH3i5i2.js";import{C as F}from"./circle-x-BZ3UUhcm.js";import{R as le}from"./refresh-ccw-CM-Cjwud.js";import{P}from"./play-DQ3P_XWl.js";import{D as de}from"./download-DO4Kw3Fi.js";import{T as me}from"./trash-2-CB7X8tay.js";import{C as ue}from"./circle-check-big-BppjBT7j.js";const D={all:["memory","vector"],status:t=>["memory","vector","status",t??null]};function xe(t={}){return Q({queryKey:D.status(t.user_key),queryFn:()=>O.getMemoryVectorStatus(t),refetchInterval:3e3,refetchIntervalInBackground:!1})}function z(t){return()=>{t.invalidateQueries({queryKey:D.all}),t.invalidateQueries({queryKey:ae.all})}}function he(){const t=V(),s=z(t);return S({mutationFn:n=>O.backfillMemoryVector({user_key:n?.user_key},n?.max_rows?{max_rows:n.max_rows}:void 0),onSuccess:s})}function fe(){const t=V();return S({mutationFn:()=>O.downloadMemoryVector(),onSuccess:z(t)})}function pe(){const t=V();return S({mutationFn:s=>O.clearMemoryVector({user_key:s?.user_key}),onSuccess:z(t)})}function W(){return S({mutationFn:()=>O.testMemoryVector()})}const m={backend:"off",localModel:"Xenova/bge-base-zh-v1.5",openaiBaseUrl:"https://api.openai.com/v1",openaiModel:"text-embedding-3-small",openaiApiKey:"",batchSize:"32",hybridWeight:"0.5"};function ve(t){const s=(t.IMHUB_MEMORY_VECTOR_BACKEND||"").toLowerCase();return{backend:s==="local"||s==="openai"?s:"off",localModel:t.IMHUB_MEMORY_VECTOR_LOCAL_MODEL||"",openaiBaseUrl:t.IMHUB_MEMORY_VECTOR_OPENAI_BASE_URL||"",openaiModel:t.IMHUB_MEMORY_VECTOR_OPENAI_MODEL||"",openaiApiKey:"",batchSize:t.IMHUB_MEMORY_VECTOR_BATCH_SIZE||"",hybridWeight:t.IMHUB_MEMORY_VECTOR_HYBRID_WEIGHT||""}}function ge({onSaved:t}){const{t:s}=L(["memory","common"]),n=te({reveal:!1}),l=g.useMemo(()=>n.data?.env??{},[n.data?.env]),[r,h]=g.useState(m),[N,_]=g.useState(!1),f=g.useRef(m);g.useEffect(()=>{if(!n.data)return;const a=ve(l);h(a),f.current=a},[l,n.data]);const b=se(),E=W(),w=g.useMemo(()=>{const a=f.current;return Object.keys(r).some(d=>r[d]!==a[d])},[r]);function x(a,d){h(o=>({...o,[a]:d}))}function B(a){h(d=>{const o={...d,backend:a};return a==="local"&&!o.localModel.trim()&&(o.localModel=m.localModel),a==="openai"&&(o.openaiBaseUrl.trim()||(o.openaiBaseUrl=m.openaiBaseUrl),o.openaiModel.trim()||(o.openaiModel=m.openaiModel)),a!=="off"&&(o.batchSize.trim()||(o.batchSize=m.batchSize),o.hybridWeight.trim()||(o.hybridWeight=m.hybridWeight)),o})}function A(){if(r.backend==="openai"){if(!r.openaiBaseUrl.trim())return s("vector.form.errors.baseUrlRequired");try{new URL(r.openaiBaseUrl.trim())}catch{return s("vector.form.errors.baseUrlInvalid")}if(!r.openaiModel.trim())return s("vector.form.errors.openaiModelRequired");if(!!!l.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY&&!r.openaiApiKey.trim())return s("vector.form.errors.apiKeyRequired")}if(r.backend==="local"&&!r.localModel.trim())return s("vector.form.errors.localModelRequired");if(r.batchSize.trim()){const a=Number(r.batchSize);if(!Number.isFinite(a)||a<1||a>1024)return s("vector.form.errors.batchSizeRange")}if(r.hybridWeight.trim()){const a=Number(r.hybridWeight);if(!Number.isFinite(a)||a<0||a>1)return s("vector.form.errors.hybridWeightRange")}return null}function I(){const a=f.current,d={},o=(C,U,q)=>{U!==q&&(d[C]=U.trim()===""?null:U.trim())};return o("IMHUB_MEMORY_VECTOR_BACKEND",r.backend,a.backend),o("IMHUB_MEMORY_VECTOR_LOCAL_MODEL",r.localModel,a.localModel),o("IMHUB_MEMORY_VECTOR_OPENAI_BASE_URL",r.openaiBaseUrl,a.openaiBaseUrl),o("IMHUB_MEMORY_VECTOR_OPENAI_MODEL",r.openaiModel,a.openaiModel),o("IMHUB_MEMORY_VECTOR_BATCH_SIZE",r.batchSize,a.batchSize),o("IMHUB_MEMORY_VECTOR_HYBRID_WEIGHT",r.hybridWeight,a.hybridWeight),r.openaiApiKey.trim()&&(d.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY=r.openaiApiKey.trim()),d}async function T(){const a=A();if(a){c.error(a);return}const d=I();if(Object.keys(d).length===0){c.info(s("vector.form.nothingChanged"));return}try{await b.mutateAsync({updates:d}),c.success(s("vector.form.savedToast"));try{const o=await E.mutateAsync();o.ok?c.success(s("vector.actions.testOk")):c.error(s("vector.actions.testFail",{detail:o.error??""}))}catch(o){const{message:C}=j(o,s);c.error(s("vector.actions.testFail",{detail:C}))}t?.()}catch(o){const{message:C}=j(o,s);c.error(C)}}function R(){h(f.current)}const i=b.isPending||E.isPending,u=!!l.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY;return e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("h2",{className:"text-sm font-medium",children:s("vector.form.title")}),w&&e.jsx(k,{variant:"info",children:s("vector.form.dirty")}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[w&&e.jsx(p,{type:"button",variant:"secondary",size:"sm",onClick:R,disabled:i,children:s("vector.form.discard")}),e.jsxs(p,{type:"button",size:"sm",onClick:()=>void T(),disabled:!w||i,children:[i?e.jsx(M,{className:"h-4 w-4 animate-spin"}):e.jsx(re,{className:"h-4 w-4"}),s("vector.form.saveAndTest")]})]})]}),e.jsx("p",{className:"mt-1 text-xs text-text-dim",children:s("vector.form.hint")}),n.isLoading?e.jsx("div",{className:"mt-3 h-32 w-full rounded-md bg-surface-2 animate-pulse"}):e.jsxs("div",{className:"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(v,{label:s("vector.form.backend"),help:s("vector.form.backendHelp"),children:e.jsxs(G,{value:r.backend,onValueChange:a=>B(a),children:[e.jsx(X,{children:e.jsx(Z,{})}),e.jsxs(J,{children:[e.jsx(H,{value:"off",children:s("vector.form.backendOff")}),e.jsx(H,{value:"local",children:s("vector.form.backendLocal")}),e.jsx(H,{value:"openai",children:s("vector.form.backendOpenai")})]})]})}),r.backend==="local"&&e.jsx(v,{label:s("vector.form.localModel"),help:s("vector.form.localModelHelp"),children:e.jsx(y,{value:r.localModel,placeholder:m.localModel,onChange:a=>x("localModel",a.target.value),className:"font-mono text-xs"})}),r.backend==="openai"&&e.jsxs(e.Fragment,{children:[e.jsx(v,{label:s("vector.form.openaiBaseUrl"),help:s("vector.form.openaiBaseUrlHelp"),children:e.jsx(y,{value:r.openaiBaseUrl,placeholder:m.openaiBaseUrl,onChange:a=>x("openaiBaseUrl",a.target.value),className:"font-mono text-xs"})}),e.jsx(v,{label:s("vector.form.openaiModel"),help:s("vector.form.openaiModelHelp"),children:e.jsx(y,{value:r.openaiModel,placeholder:m.openaiModel,onChange:a=>x("openaiModel",a.target.value),className:"font-mono text-xs"})}),e.jsx(v,{label:s("vector.form.openaiApiKey"),help:s(u?"vector.form.apiKeyKeepHint":"vector.form.apiKeyNewHint"),children:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(y,{type:N?"text":"password",value:r.openaiApiKey,placeholder:u?l.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY||"••••":"sk-…",onChange:a=>x("openaiApiKey",a.target.value),className:"font-mono text-xs",autoComplete:"off"}),e.jsx(p,{type:"button",variant:"ghost",size:"icon",onClick:()=>_(a=>!a),"aria-label":s("vector.form.toggleApiKey"),children:N?e.jsx(oe,{className:"h-4 w-4"}):e.jsx(ne,{className:"h-4 w-4"})})]})})]}),r.backend!=="off"&&e.jsxs(e.Fragment,{children:[e.jsx(v,{label:s("vector.form.batchSize"),help:s("vector.form.batchSizeHelp"),children:e.jsx(y,{type:"number",min:1,max:1024,step:1,value:r.batchSize,placeholder:m.batchSize,onChange:a=>x("batchSize",a.target.value),className:"font-mono text-xs"})}),e.jsx(v,{label:s("vector.form.hybridWeight"),help:s("vector.form.hybridWeightHelp"),children:e.jsx(y,{type:"number",min:0,max:1,step:.05,value:r.hybridWeight,placeholder:m.hybridWeight,onChange:a=>x("hybridWeight",a.target.value),className:"font-mono text-xs"})})]})]})]})}function v({label:t,help:s,children:n}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx($,{className:"text-xs text-text-dim",children:t}),n,s&&e.jsx("p",{className:"text-[11px] text-text-muted",children:s})]})}function He(){const{t}=L(["memory","common"]),[s]=ee(),n=s.get("user")??"",l=xe(n?{user_key:n}:{}),r=l.data?.status,h=l.data?.coverage,N=l.data?.jobs??[],_=W(),f=fe(),b=he(),E=pe(),[w,x]=g.useState(!1);async function B(){try{const i=await _.mutateAsync();i.ok?c.success(t("vector.actions.testOk")):c.error(t("vector.actions.testFail",{detail:i.error??""}))}catch(i){const{message:u}=j(i,t);c.error(u)}}async function A(){try{const i=await f.mutateAsync();c.success(i.alreadyReady?t("vector.actions.downloadAlreadyReady"):t("vector.actions.downloadStarted"))}catch(i){const{message:u}=j(i,t);c.error(u)}}async function I(){try{await b.mutateAsync(n?{user_key:n}:void 0),c.success(t("vector.actions.backfillStarted"))}catch(i){const{message:u}=j(i,t);c.error(u)}}async function T(){try{const i=await E.mutateAsync(n?{user_key:n}:void 0);c.success(t("vector.actions.clearStarted",{count:i.cleared}))}catch(i){const{message:u}=j(i,t);throw c.error(u),i}}if(l.isLoading)return e.jsx("div",{className:"h-48 w-full rounded-md bg-surface-2 animate-pulse"});if(!r)return e.jsx(ce,{icon:e.jsx(F,{}),title:t("common:states.error"),description:l.error?.message??""});const R=n?t("vector.coverage.scope_user",{userKey:n}):t("vector.coverage.scope_global");return e.jsxs("div",{className:"mx-auto flex max-w-5xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:t("vector.title")}),e.jsxs(p,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>l.refetch(),disabled:l.isFetching,"aria-label":t("actions.refresh",{ns:"common"}),children:[l.isFetching?e.jsx(M,{className:"h-4 w-4 animate-spin"}):e.jsx(le,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:t("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:t("vector.subtitle")})]}),e.jsx(ge,{onSaved:()=>void l.refetch()}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-2",children:[e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsx("span",{className:"font-medium",children:t("vector.backendLabel")}),e.jsx(k,{variant:"secondary",children:r.backend}),e.jsx(k,{variant:r.ready?"success":"warning",children:r.ready?t("vector.readyTrue"):t("vector.readyFalse")}),r.downloaded&&e.jsx(k,{variant:"info",children:t("vector.downloadedTrue")})]}),e.jsxs("dl",{className:"mt-3 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-sm",children:[e.jsx("dt",{className:"text-text-dim",children:t("vector.modelLabel")}),e.jsx("dd",{className:"font-mono text-text",children:r.modelId||"—"}),e.jsx("dt",{className:"text-text-dim",children:t("vector.dimsLabel")}),e.jsx("dd",{className:"tabular-nums text-text",children:r.dims||"—"}),r.lastError&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-text-dim",children:t("vector.lastError")}),e.jsx("dd",{className:"text-danger text-xs break-all",children:r.lastError})]})]})]}),e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsx("div",{className:"text-sm font-medium",children:t("vector.coverage.title")}),e.jsx("div",{className:"mt-1 text-xs text-text-dim",children:R}),e.jsxs("div",{className:"mt-3 grid grid-cols-3 gap-2",children:[e.jsx(K,{label:t("vector.coverage.total"),value:h?.total??0,tone:"info"}),e.jsx(K,{label:t("vector.coverage.withEmbedding"),value:h?.withEmbedding??0,tone:"success"}),e.jsx(K,{label:t("vector.coverage.withDifferentModel"),value:h?.withDifferentModel??0,tone:"warning"})]})]})]}),e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsx("div",{className:"text-sm font-medium",children:t("vector.actions.title")}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsxs(p,{variant:"secondary",size:"sm",onClick:()=>void B(),disabled:_.isPending,children:[_.isPending?e.jsx(M,{className:"h-4 w-4 animate-spin"}):e.jsx(P,{className:"h-4 w-4"}),t("vector.actions.test")]}),r.backend==="local"&&e.jsxs(p,{variant:"secondary",size:"sm",onClick:()=>void A(),disabled:f.isPending,children:[f.isPending?e.jsx(M,{className:"h-4 w-4 animate-spin"}):e.jsx(de,{className:"h-4 w-4"}),t("vector.actions.download")]}),e.jsxs(p,{variant:"default",size:"sm",onClick:()=>void I(),disabled:b.isPending||!r.ready,children:[b.isPending?e.jsx(M,{className:"h-4 w-4 animate-spin"}):e.jsx(P,{className:"h-4 w-4"}),t("vector.actions.backfill")]}),e.jsxs(p,{variant:"destructive",size:"sm",onClick:()=>x(!0),disabled:E.isPending,children:[e.jsx(me,{className:"h-4 w-4"}),t("vector.actions.clear")]})]})]}),e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsx("div",{className:"text-sm font-medium",children:t("vector.jobs.title")}),N.length===0?e.jsx("div",{className:"mt-2 text-sm text-text-muted",children:t("vector.jobs.empty")}):e.jsx("ul",{className:"mt-2 flex flex-col gap-1.5 text-sm",children:N.map(i=>e.jsx("li",{children:e.jsx(ye,{job:i})},i.id))})]}),e.jsx(ie,{open:w,onOpenChange:x,title:t("vector.actions.confirmClear"),description:t("vector.actions.confirmClearDesc",{scope:R}),intent:"danger",confirmLabel:t("vector.actions.clear"),onConfirm:T})]})}const be={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function K({label:t,value:s,tone:n}){return e.jsxs("div",{className:Y("rounded-md border bg-bg px-2 py-2",be[n]),children:[e.jsx("div",{className:"text-[10px] uppercase tracking-wide text-text-dim",children:t}),e.jsx("div",{className:"text-xl font-semibold tabular-nums",children:s})]})}function ye({job:t}){const{t:s}=L("memory"),n=t.phase==="done"?"text-success":t.phase==="failed"?"text-danger":"text-info";return e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[e.jsx(k,{variant:"outline",children:t.kind}),e.jsxs("span",{className:Y("font-medium",n),children:[t.phase==="running"&&e.jsx(M,{className:"inline h-3 w-3 animate-spin"}),t.phase==="done"&&e.jsx(ue,{className:"inline h-3 w-3"}),t.phase==="failed"&&e.jsx(F,{className:"inline h-3 w-3"})," ",s(`vector.jobs.phase.${t.phase}`)]}),e.jsx("span",{className:"text-text-dim",children:t.message}),e.jsx("span",{className:"ml-auto text-text-muted tabular-nums",children:je(t.finishedAt??t.startedAt)})]})}function je(t){try{const s=new Date(t);return Number.isNaN(s.getTime())?String(t):s.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(t)}}export{He as default};
|
|
2
|
-
//# sourceMappingURL=vector-B3h4iyfn.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vector-B3h4iyfn.js","sources":["../../src/hooks/use-vector.ts","../../src/routes/memory/vector-backend-form.tsx","../../src/routes/memory/vector.tsx"],"sourcesContent":["/**\n * useVector — react-query wrappers for the embedding/vector backend.\n *\n * useVectorStatus({ user_key }) — status + coverage + jobs\n * (polls every 3s; jobs\n * are async)\n * useTriggerVectorBackfill()\n * useTriggerVectorDownload()\n * useTriggerVectorClear() — DESTRUCTIVE; route gates\n * with ConfirmDialog\n * useTriggerVectorTest()\n *\n * Status polling stops backgrounded (refetchIntervalInBackground:\n * false) so an idle tab on a phone doesn't drain battery.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport { memoryKeys } from './use-memory'\nimport type {\n VectorActionResponse,\n VectorClearResponse,\n VectorStatus,\n VectorTestResponse,\n} from '@/types/api'\n\nexport const vectorKeys = {\n all: ['memory', 'vector'] as const,\n status: (user_key?: string) => ['memory', 'vector', 'status', user_key ?? null] as const,\n}\n\nexport function useVectorStatus(query: { user_key?: string } = {}) {\n return useQuery<VectorStatus>({\n queryKey: vectorKeys.status(query.user_key),\n queryFn: () => api.getMemoryVectorStatus(query),\n refetchInterval: 3000,\n refetchIntervalInBackground: false,\n })\n}\n\nfunction invalidateAfter(qc: ReturnType<typeof useQueryClient>): () => void {\n return () => {\n qc.invalidateQueries({ queryKey: vectorKeys.all })\n qc.invalidateQueries({ queryKey: memoryKeys.all })\n }\n}\n\nexport function useTriggerVectorBackfill() {\n const qc = useQueryClient()\n const invalidate = invalidateAfter(qc)\n return useMutation<\n VectorActionResponse,\n Error,\n { user_key?: string; max_rows?: number } | undefined\n >({\n mutationFn: (vars) => api.backfillMemoryVector(\n { user_key: vars?.user_key },\n vars?.max_rows ? { max_rows: vars.max_rows } : undefined,\n ),\n onSuccess: invalidate,\n })\n}\n\nexport function useTriggerVectorDownload() {\n const qc = useQueryClient()\n return useMutation<VectorActionResponse, Error, void>({\n mutationFn: () => api.downloadMemoryVector(),\n onSuccess: invalidateAfter(qc),\n })\n}\n\nexport function useTriggerVectorClear() {\n const qc = useQueryClient()\n return useMutation<VectorClearResponse, Error, { user_key?: string } | undefined>({\n mutationFn: (vars) => api.clearMemoryVector({ user_key: vars?.user_key }),\n onSuccess: invalidateAfter(qc),\n })\n}\n\nexport function useTriggerVectorTest() {\n return useMutation<VectorTestResponse, Error, void>({\n mutationFn: () => api.testMemoryVector(),\n })\n}\n","/**\n * VectorBackendForm — inline, form-based editor for the seven\n * IMHUB_MEMORY_VECTOR_* keys that drive the embedding backend.\n *\n * Replaces the older \"Edit in env\" link path: operators no longer\n * have to know which env var maps to which knob, and the on-the-wire\n * format (numbers, OpenAI URL shape) is enforced by the widget.\n *\n * Save flow: PUT /api/env (backend-side allowlist filters to just\n * these keys), then auto-trigger a single `vector/test` so the user\n * sees in toast whether the new config produces an embedding.\n *\n * API key: the GET /api/env response returns secrets masked (e.g.\n * \"sk-1***...abcd\"). The widget shows the mask as placeholder and\n * leaves the input empty by default — typing a value sends it as a\n * real update, leaving it empty sends nothing for that key (the\n * server already rejects masked echoes as \"no change\").\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Eye, EyeOff, Loader2, Save } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv } from '@/hooks/use-settings'\nimport { useTriggerVectorTest } from '@/hooks/use-vector'\nimport { describeError } from '@/lib/api/errors'\n\ntype BackendName = 'off' | 'local' | 'openai'\n\ninterface FormState {\n backend: BackendName\n localModel: string\n openaiBaseUrl: string\n openaiModel: string\n openaiApiKey: string // empty = \"keep existing\"\n batchSize: string\n hybridWeight: string\n}\n\nconst DEFAULTS: FormState = {\n backend: 'off',\n localModel: 'Xenova/bge-base-zh-v1.5',\n openaiBaseUrl: 'https://api.openai.com/v1',\n openaiModel: 'text-embedding-3-small',\n openaiApiKey: '',\n batchSize: '32',\n hybridWeight: '0.5',\n}\n\nfunction readFormFromEnv(env: Record<string, string>): FormState {\n const raw = (env.IMHUB_MEMORY_VECTOR_BACKEND || '').toLowerCase()\n const backend: BackendName = raw === 'local' || raw === 'openai' ? raw : 'off'\n return {\n backend,\n localModel: env.IMHUB_MEMORY_VECTOR_LOCAL_MODEL || '',\n openaiBaseUrl: env.IMHUB_MEMORY_VECTOR_OPENAI_BASE_URL || '',\n openaiModel: env.IMHUB_MEMORY_VECTOR_OPENAI_MODEL || '',\n openaiApiKey: '',\n batchSize: env.IMHUB_MEMORY_VECTOR_BATCH_SIZE || '',\n hybridWeight: env.IMHUB_MEMORY_VECTOR_HYBRID_WEIGHT || '',\n }\n}\n\nexport interface VectorBackendFormProps {\n /** Called after a successful save + test cycle so the parent page can\n * refresh status + coverage. */\n onSaved?: () => void\n}\n\nexport function VectorBackendForm({ onSaved }: VectorBackendFormProps): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n\n // Pull masked env (we never need real key on the client; the masked\n // value is shown as placeholder so the operator can tell a value is\n // configured without revealing it).\n const envQuery = useEnv({ reveal: false })\n const env = useMemo(() => envQuery.data?.env ?? {}, [envQuery.data?.env])\n\n const [form, setForm] = useState<FormState>(DEFAULTS)\n const [showApiKey, setShowApiKey] = useState(false)\n const initialRef = useRef<FormState>(DEFAULTS)\n\n // Reset from server only when the underlying env object identity\n // changes (after refetch). useEffect avoids stomping on local edits\n // mid-typing.\n useEffect(() => {\n if (!envQuery.data) return\n const next = readFormFromEnv(env)\n setForm(next)\n initialRef.current = next\n }, [env, envQuery.data])\n\n const updateEnv = useUpdateEnv()\n const test = useTriggerVectorTest()\n\n const dirty = useMemo(() => {\n const initial = initialRef.current\n return (Object.keys(form) as Array<keyof FormState>).some((k) => form[k] !== initial[k])\n }, [form])\n\n function set<K extends keyof FormState>(k: K, v: FormState[K]): void {\n setForm((prev) => ({ ...prev, [k]: v }))\n }\n\n // v1.2.75 — when the operator switches backend off→local / off→openai\n // and the per-backend fields are still empty, auto-prefill defaults so\n // they don't have to look up the BGE model id by hand. They can still\n // edit afterwards. Also fills shared numeric knobs (batch / weight)\n // since those have well-known sensible defaults too.\n function selectBackend(next: BackendName): void {\n setForm((prev) => {\n const out = { ...prev, backend: next }\n if (next === 'local' && !out.localModel.trim()) {\n out.localModel = DEFAULTS.localModel\n }\n if (next === 'openai') {\n if (!out.openaiBaseUrl.trim()) out.openaiBaseUrl = DEFAULTS.openaiBaseUrl\n if (!out.openaiModel.trim()) out.openaiModel = DEFAULTS.openaiModel\n }\n if (next !== 'off') {\n if (!out.batchSize.trim()) out.batchSize = DEFAULTS.batchSize\n if (!out.hybridWeight.trim()) out.hybridWeight = DEFAULTS.hybridWeight\n }\n return out\n })\n }\n\n function validate(): string | null {\n if (form.backend === 'openai') {\n if (!form.openaiBaseUrl.trim()) return t('vector.form.errors.baseUrlRequired')\n try { new URL(form.openaiBaseUrl.trim()) } catch { return t('vector.form.errors.baseUrlInvalid') }\n if (!form.openaiModel.trim()) return t('vector.form.errors.openaiModelRequired')\n const hasExistingKey = !!env.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY\n if (!hasExistingKey && !form.openaiApiKey.trim()) {\n return t('vector.form.errors.apiKeyRequired')\n }\n }\n if (form.backend === 'local' && !form.localModel.trim()) {\n return t('vector.form.errors.localModelRequired')\n }\n if (form.batchSize.trim()) {\n const n = Number(form.batchSize)\n if (!Number.isFinite(n) || n < 1 || n > 1024) return t('vector.form.errors.batchSizeRange')\n }\n if (form.hybridWeight.trim()) {\n const n = Number(form.hybridWeight)\n if (!Number.isFinite(n) || n < 0 || n > 1) return t('vector.form.errors.hybridWeightRange')\n }\n return null\n }\n\n function buildUpdates(): Record<string, string | null> {\n const initial = initialRef.current\n const out: Record<string, string | null> = {}\n const diff = (key: string, current: string, prev: string): void => {\n if (current === prev) return\n out[key] = current.trim() === '' ? null : current.trim()\n }\n diff('IMHUB_MEMORY_VECTOR_BACKEND', form.backend, initial.backend)\n diff('IMHUB_MEMORY_VECTOR_LOCAL_MODEL', form.localModel, initial.localModel)\n diff('IMHUB_MEMORY_VECTOR_OPENAI_BASE_URL', form.openaiBaseUrl, initial.openaiBaseUrl)\n diff('IMHUB_MEMORY_VECTOR_OPENAI_MODEL', form.openaiModel, initial.openaiModel)\n diff('IMHUB_MEMORY_VECTOR_BATCH_SIZE', form.batchSize, initial.batchSize)\n diff('IMHUB_MEMORY_VECTOR_HYBRID_WEIGHT', form.hybridWeight, initial.hybridWeight)\n // API key: only send if the user actually typed a non-empty new value.\n // Empty input = keep current (which is the whole point of the placeholder UX).\n if (form.openaiApiKey.trim()) {\n out.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY = form.openaiApiKey.trim()\n }\n return out\n }\n\n async function onSave(): Promise<void> {\n const err = validate()\n if (err) {\n toast.error(err)\n return\n }\n const updates = buildUpdates()\n if (Object.keys(updates).length === 0) {\n toast.info(t('vector.form.nothingChanged'))\n return\n }\n try {\n await updateEnv.mutateAsync({ updates })\n toast.success(t('vector.form.savedToast'))\n // Auto-test against the freshly applied config. We don't await\n // the parent's refresh — the toast is the source of truth for the\n // operator; the status card behind it picks up dims / lastError\n // on its next 3s poll anyway.\n try {\n const r = await test.mutateAsync()\n if (r.ok) toast.success(t('vector.actions.testOk'))\n else toast.error(t('vector.actions.testFail', { detail: r.error ?? '' }))\n } catch (terr) {\n const { message } = describeError(terr, t)\n toast.error(t('vector.actions.testFail', { detail: message }))\n }\n onSaved?.()\n } catch (serr) {\n const { message } = describeError(serr, t)\n toast.error(message)\n }\n }\n\n function onDiscard(): void {\n setForm(initialRef.current)\n }\n\n const busy = updateEnv.isPending || test.isPending\n const hasExistingKey = !!env.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY\n\n return (\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-sm font-medium\">{t('vector.form.title')}</h2>\n {dirty && <Badge variant=\"info\">{t('vector.form.dirty')}</Badge>}\n <div className=\"ml-auto flex items-center gap-2\">\n {dirty && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={onDiscard}\n disabled={busy}\n >\n {t('vector.form.discard')}\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={!dirty || busy}\n >\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {t('vector.form.saveAndTest')}\n </Button>\n </div>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{t('vector.form.hint')}</p>\n\n {envQuery.isLoading ? (\n <div className=\"mt-3 h-32 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <div className=\"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {/* Backend selector — full row on mobile, half on desktop */}\n <Field label={t('vector.form.backend')} help={t('vector.form.backendHelp')}>\n <Select value={form.backend} onValueChange={(v) => selectBackend(v as BackendName)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"off\">{t('vector.form.backendOff')}</SelectItem>\n <SelectItem value=\"local\">{t('vector.form.backendLocal')}</SelectItem>\n <SelectItem value=\"openai\">{t('vector.form.backendOpenai')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n\n {/* Local-only field */}\n {form.backend === 'local' && (\n <Field label={t('vector.form.localModel')} help={t('vector.form.localModelHelp')}>\n <Input\n value={form.localModel}\n placeholder={DEFAULTS.localModel}\n onChange={(e) => set('localModel', e.target.value)}\n className=\"font-mono text-xs\"\n />\n </Field>\n )}\n\n {/* OpenAI-only fields */}\n {form.backend === 'openai' && (\n <>\n <Field label={t('vector.form.openaiBaseUrl')} help={t('vector.form.openaiBaseUrlHelp')}>\n <Input\n value={form.openaiBaseUrl}\n placeholder={DEFAULTS.openaiBaseUrl}\n onChange={(e) => set('openaiBaseUrl', e.target.value)}\n className=\"font-mono text-xs\"\n />\n </Field>\n <Field label={t('vector.form.openaiModel')} help={t('vector.form.openaiModelHelp')}>\n <Input\n value={form.openaiModel}\n placeholder={DEFAULTS.openaiModel}\n onChange={(e) => set('openaiModel', e.target.value)}\n className=\"font-mono text-xs\"\n />\n </Field>\n <Field\n label={t('vector.form.openaiApiKey')}\n help={hasExistingKey ? t('vector.form.apiKeyKeepHint') : t('vector.form.apiKeyNewHint')}\n >\n <div className=\"flex items-center gap-1\">\n <Input\n type={showApiKey ? 'text' : 'password'}\n value={form.openaiApiKey}\n placeholder={hasExistingKey\n ? (env.IMHUB_MEMORY_VECTOR_OPENAI_API_KEY || '••••')\n : 'sk-…'}\n onChange={(e) => set('openaiApiKey', e.target.value)}\n className=\"font-mono text-xs\"\n autoComplete=\"off\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setShowApiKey((v) => !v)}\n aria-label={t('vector.form.toggleApiKey')}\n >\n {showApiKey ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n </Button>\n </div>\n </Field>\n </>\n )}\n\n {/* Shared numeric knobs (hidden when off so they don't visually\n suggest the operator can tune anything without picking a\n backend first). */}\n {form.backend !== 'off' && (\n <>\n <Field label={t('vector.form.batchSize')} help={t('vector.form.batchSizeHelp')}>\n <Input\n type=\"number\"\n min={1}\n max={1024}\n step={1}\n value={form.batchSize}\n placeholder={DEFAULTS.batchSize}\n onChange={(e) => set('batchSize', e.target.value)}\n className=\"font-mono text-xs\"\n />\n </Field>\n <Field label={t('vector.form.hybridWeight')} help={t('vector.form.hybridWeightHelp')}>\n <Input\n type=\"number\"\n min={0}\n max={1}\n step={0.05}\n value={form.hybridWeight}\n placeholder={DEFAULTS.hybridWeight}\n onChange={(e) => set('hybridWeight', e.target.value)}\n className=\"font-mono text-xs\"\n />\n </Field>\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction Field({\n label,\n help,\n children,\n}: {\n label: string\n help?: string\n children: React.ReactNode\n}): JSX.Element {\n return (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs text-text-dim\">{label}</Label>\n {children}\n {help && <p className=\"text-[11px] text-text-muted\">{help}</p>}\n </div>\n )\n}\n","/**\n * /memory/vector — backend status + maintenance actions.\n *\n * Status (left): backend name + ready badge + model + dims + last\n * error. Coverage (right): three KPI tiles (total / embedded /\n * mismatched). Actions (bottom): test, download, backfill, clear\n * (destructive — ConfirmDialog). Recent-job strip pulls from the\n * shared in-memory tracker via the status endpoint.\n *\n * The clear action picks up the ?user= filter from the layout, so\n * clearing scoped to a single user is a one-click operation.\n */\n\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { CheckCircle, Download, Loader2, Play, RefreshCcw, Trash2, XCircle } from 'lucide-react'\n\nimport { VectorBackendForm } from './vector-backend-form'\n\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n useVectorStatus,\n useTriggerVectorBackfill,\n useTriggerVectorClear,\n useTriggerVectorDownload,\n useTriggerVectorTest,\n} from '@/hooks/use-vector'\nimport { describeError } from '@/lib/api/errors'\nimport type { VectorJob } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nexport default function MemoryVectorRoute(): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const [params] = useSearchParams()\n const userKey = params.get('user') ?? ''\n\n const statusQuery = useVectorStatus(userKey ? { user_key: userKey } : {})\n const status = statusQuery.data?.status\n const coverage = statusQuery.data?.coverage\n const jobs = statusQuery.data?.jobs ?? []\n\n const test = useTriggerVectorTest()\n const download = useTriggerVectorDownload()\n const backfill = useTriggerVectorBackfill()\n const clear = useTriggerVectorClear()\n const [confirmClear, setConfirmClear] = useState(false)\n\n async function onTest(): Promise<void> {\n try {\n const r = await test.mutateAsync()\n if (r.ok) toast.success(t('vector.actions.testOk'))\n else toast.error(t('vector.actions.testFail', { detail: r.error ?? '' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n async function onDownload(): Promise<void> {\n try {\n const r = await download.mutateAsync()\n toast.success(r.alreadyReady ? t('vector.actions.downloadAlreadyReady') : t('vector.actions.downloadStarted'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n async function onBackfill(): Promise<void> {\n try {\n await backfill.mutateAsync(userKey ? { user_key: userKey } : undefined)\n toast.success(t('vector.actions.backfillStarted'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n async function onConfirmClear(): Promise<void> {\n try {\n const r = await clear.mutateAsync(userKey ? { user_key: userKey } : undefined)\n toast.success(t('vector.actions.clearStarted', { count: r.cleared }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n if (statusQuery.isLoading) {\n return <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n }\n if (!status) {\n return (\n <EmptyState\n icon={<XCircle />}\n title={t('common:states.error')}\n description={statusQuery.error?.message ?? ''}\n />\n )\n }\n\n const coverageScope = userKey\n ? t('vector.coverage.scope_user', { userKey })\n : t('vector.coverage.scope_global')\n\n return (\n <div className=\"mx-auto flex max-w-5xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('vector.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => statusQuery.refetch()}\n disabled={statusQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {statusQuery.isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('vector.subtitle')}</p>\n </header>\n\n {/* Backend configuration — inline form replaces the older\n \"Edit in env\" link. Saving runs PUT /api/env + an auto\n vector test against the freshly applied config. */}\n <VectorBackendForm onSaved={() => void statusQuery.refetch()} />\n\n {/* Status + Coverage */}\n <div className=\"grid gap-3 md:grid-cols-2\">\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n <span className=\"font-medium\">{t('vector.backendLabel')}</span>\n <Badge variant=\"secondary\">{status.backend}</Badge>\n <Badge variant={status.ready ? 'success' : 'warning'}>\n {status.ready ? t('vector.readyTrue') : t('vector.readyFalse')}\n </Badge>\n {status.downloaded && <Badge variant=\"info\">{t('vector.downloadedTrue')}</Badge>}\n </div>\n <dl className=\"mt-3 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-sm\">\n <dt className=\"text-text-dim\">{t('vector.modelLabel')}</dt>\n <dd className=\"font-mono text-text\">{status.modelId || '—'}</dd>\n <dt className=\"text-text-dim\">{t('vector.dimsLabel')}</dt>\n <dd className=\"tabular-nums text-text\">{status.dims || '—'}</dd>\n {status.lastError && (\n <>\n <dt className=\"text-text-dim\">{t('vector.lastError')}</dt>\n <dd className=\"text-danger text-xs break-all\">{status.lastError}</dd>\n </>\n )}\n </dl>\n </div>\n\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"text-sm font-medium\">{t('vector.coverage.title')}</div>\n <div className=\"mt-1 text-xs text-text-dim\">{coverageScope}</div>\n <div className=\"mt-3 grid grid-cols-3 gap-2\">\n <CoverageTile label={t('vector.coverage.total')} value={coverage?.total ?? 0} tone=\"info\" />\n <CoverageTile label={t('vector.coverage.withEmbedding')} value={coverage?.withEmbedding ?? 0} tone=\"success\" />\n <CoverageTile label={t('vector.coverage.withDifferentModel')} value={coverage?.withDifferentModel ?? 0} tone=\"warning\" />\n </div>\n </div>\n </div>\n\n {/* Maintenance actions */}\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"text-sm font-medium\">{t('vector.actions.title')}</div>\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onTest()}\n disabled={test.isPending}\n >\n {test.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Play className=\"h-4 w-4\" />}\n {t('vector.actions.test')}\n </Button>\n {status.backend === 'local' && (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onDownload()}\n disabled={download.isPending}\n >\n {download.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Download className=\"h-4 w-4\" />}\n {t('vector.actions.download')}\n </Button>\n )}\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={() => void onBackfill()}\n disabled={backfill.isPending || !status.ready}\n >\n {backfill.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Play className=\"h-4 w-4\" />}\n {t('vector.actions.backfill')}\n </Button>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmClear(true)}\n disabled={clear.isPending}\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('vector.actions.clear')}\n </Button>\n </div>\n </div>\n\n {/* Jobs strip */}\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"text-sm font-medium\">{t('vector.jobs.title')}</div>\n {jobs.length === 0 ? (\n <div className=\"mt-2 text-sm text-text-muted\">{t('vector.jobs.empty')}</div>\n ) : (\n <ul className=\"mt-2 flex flex-col gap-1.5 text-sm\">\n {jobs.map((j) => <li key={j.id}><JobRow job={j} /></li>)}\n </ul>\n )}\n </div>\n\n <ConfirmDialog\n open={confirmClear}\n onOpenChange={setConfirmClear}\n title={t('vector.actions.confirmClear')}\n description={t('vector.actions.confirmClearDesc', { scope: coverageScope })}\n intent=\"danger\"\n confirmLabel={t('vector.actions.clear')}\n onConfirm={onConfirmClear}\n />\n </div>\n )\n}\n\ninterface CoverageTileProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<CoverageTileProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction CoverageTile({ label, value, tone }: CoverageTileProps): JSX.Element {\n return (\n <div className={cn('rounded-md border bg-bg px-2 py-2', TONE_STYLES[tone])}>\n <div className=\"text-[10px] uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction JobRow({ job }: { job: VectorJob }): JSX.Element {\n const { t } = useTranslation('memory')\n const phaseClass =\n job.phase === 'done' ? 'text-success' :\n job.phase === 'failed' ? 'text-danger' :\n 'text-info'\n return (\n <div className=\"flex flex-wrap items-center gap-2 text-xs\">\n <Badge variant=\"outline\">{job.kind}</Badge>\n <span className={cn('font-medium', phaseClass)}>\n {job.phase === 'running' && <Loader2 className=\"inline h-3 w-3 animate-spin\" />}\n {job.phase === 'done' && <CheckCircle className=\"inline h-3 w-3\" />}\n {job.phase === 'failed' && <XCircle className=\"inline h-3 w-3\" />}\n {' '}\n {t(`vector.jobs.phase.${job.phase}`)}\n </span>\n <span className=\"text-text-dim\">{job.message}</span>\n <span className=\"ml-auto text-text-muted tabular-nums\">{formatEpoch(job.finishedAt ?? job.startedAt)}</span>\n </div>\n )\n}\n\nfunction formatEpoch(ms: number): string {\n try {\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return String(ms)\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return String(ms)\n }\n}\n"],"names":["vectorKeys","user_key","useVectorStatus","query","useQuery","api","invalidateAfter","qc","memoryKeys","useTriggerVectorBackfill","useQueryClient","invalidate","useMutation","vars","useTriggerVectorDownload","useTriggerVectorClear","useTriggerVectorTest","DEFAULTS","readFormFromEnv","env","raw","VectorBackendForm","onSaved","t","useTranslation","envQuery","useEnv","useMemo","form","setForm","useState","showApiKey","setShowApiKey","initialRef","useRef","useEffect","next","updateEnv","useUpdateEnv","test","dirty","initial","k","set","v","prev","selectBackend","out","validate","n","buildUpdates","diff","key","current","onSave","err","toast","updates","r","terr","message","describeError","serr","onDiscard","busy","hasExistingKey","jsxs","jsx","Badge","Button","Loader2","Save","Field","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","e","Fragment","EyeOff","Eye","label","help","children","Label","MemoryVectorRoute","params","useSearchParams","userKey","statusQuery","status","coverage","jobs","download","backfill","clear","confirmClear","setConfirmClear","onTest","onDownload","onBackfill","onConfirmClear","EmptyState","XCircle","coverageScope","RefreshCcw","CoverageTile","Play","Download","Trash2","j","JobRow","ConfirmDialog","TONE_STYLES","value","tone","cn","job","phaseClass","CheckCircle","formatEpoch","ms","d"],"mappings":"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"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import{o as k,u as R,j as e,B as h,l as f,I as y,S as W,g as T,h as O,i as F,k as B,c as L,X as C,L as A,m as g,n as U}from"./index-CzlhMSb2.js";import{r as m}from"./react-DlP5eolq.js";import{u as z,b as D,g as q}from"./use-settings-DZhfMpNR.js";import{E as K,a as X}from"./eye-BMxHZFil.js";import{L as N}from"./loader-circle-AgQ2XO06.js";import{R as V}from"./refresh-ccw-CM-Cjwud.js";import{C as J}from"./circle-check-BWBI4Qhk.js";import{E as Q}from"./external-link-B6aOBfUG.js";import{S as P}from"./save-xBMgs6Bd.js";import{M as Z}from"./map-pin-C6sGB9SZ.js";/**
|
|
2
|
-
* @license lucide-react v0.469.0 - ISC
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the ISC license.
|
|
5
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/const G=k("Earth",[["path",{d:"M21.54 15H17a2 2 0 0 0-2 2v4.54",key:"1djwo0"}],["path",{d:"M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17",key:"1tzkfa"}],["path",{d:"M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05",key:"14pb5j"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);/**
|
|
7
|
-
* @license lucide-react v0.469.0 - ISC
|
|
8
|
-
*
|
|
9
|
-
* This source code is licensed under the ISC license.
|
|
10
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
-
*/const Y=k("FileText",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);function xe(){const{t:i}=R(["settings","common"]),[s,r]=m.useState(!1),a=z({reveal:s});return e.jsxs("div",{className:"mx-auto flex max-w-4xl flex-col gap-6",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:i("viewerSettings.title")}),e.jsxs(h,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>r(t=>!t),disabled:a.isFetching,"aria-label":i(s?"viewerSettings.hide":"viewerSettings.reveal"),children:[s?e.jsx(K,{className:"h-4 w-4"}):e.jsx(X,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:i(s?"viewerSettings.hide":"viewerSettings.reveal")})]}),e.jsxs(h,{variant:"ghost",size:"sm",onClick:()=>void a.refetch(),disabled:a.isFetching,"aria-label":i("actions.refresh",{ns:"common"}),children:[a.isFetching?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(V,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:i("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:i("viewerSettings.subtitle")})]}),a.isLoading?e.jsx("div",{className:"h-64 rounded-md bg-surface-2 animate-pulse"}):e.jsxs(e.Fragment,{children:[e.jsx($,{env:a.data?.env??{}}),e.jsx(ee,{env:a.data?.env??{}})]})]})}function M(i){return{enabled:i.IMHUB_VIEWER_ENABLED==="1"||i.IMHUB_VIEWER_ENABLED?.toLowerCase()==="true",publicUrl:i.IMHUB_VIEWER_PUBLIC_BASE_URL??"",tunnelMode:i.IMHUB_VIEWER_TUNNEL_MODE==="quick"?"quick":"off",noDefaultRemote:i.IMHUB_VIEWER_NO_DEFAULT_REMOTE==="1"||i.IMHUB_VIEWER_NO_DEFAULT_REMOTE?.toLowerCase()==="true",chars:i.IMHUB_VIEWER_CHARS??"",lines:i.IMHUB_VIEWER_LINES??"",codeLines:i.IMHUB_VIEWER_CODE_LINES??"",maxPastes:i.IMHUB_VIEWER_MAX_PASTES??""}}function $({env:i}){const{t:s}=R(["settings","common"]),r=D(),a=q(),[t,d]=m.useState(()=>M(i)),[w,S]=m.useState("");m.useEffect(()=>{const n=M(i),x=JSON.stringify(n);x!==w&&(d(n),S(x))},[i.IMHUB_VIEWER_ENABLED,i.IMHUB_VIEWER_PUBLIC_BASE_URL,i.IMHUB_VIEWER_TUNNEL_MODE,i.IMHUB_VIEWER_CHARS,i.IMHUB_VIEWER_LINES,i.IMHUB_VIEWER_CODE_LINES,i.IMHUB_VIEWER_MAX_PASTES,i.IMHUB_VIEWER_NO_DEFAULT_REMOTE]);const c=m.useMemo(()=>M(i),[i]),b=m.useMemo(()=>JSON.stringify(t)!==JSON.stringify(c),[t,c]);function o(n,x){d(j=>({...j,[n]:x}))}async function _(){const n={};if(t.enabled!==c.enabled&&(n.IMHUB_VIEWER_ENABLED=t.enabled?"1":"0"),t.publicUrl!==c.publicUrl&&(n.IMHUB_VIEWER_PUBLIC_BASE_URL=t.publicUrl.trim()||null),t.tunnelMode!==c.tunnelMode&&(n.IMHUB_VIEWER_TUNNEL_MODE=t.tunnelMode),t.chars!==c.chars&&(n.IMHUB_VIEWER_CHARS=t.chars.trim()||null),t.lines!==c.lines&&(n.IMHUB_VIEWER_LINES=t.lines.trim()||null),t.codeLines!==c.codeLines&&(n.IMHUB_VIEWER_CODE_LINES=t.codeLines.trim()||null),t.maxPastes!==c.maxPastes&&(n.IMHUB_VIEWER_MAX_PASTES=t.maxPastes.trim()||null),t.noDefaultRemote!==c.noDefaultRemote&&(n.IMHUB_VIEWER_NO_DEFAULT_REMOTE=t.noDefaultRemote?"1":null),Object.keys(n).length!==0)try{await r.mutateAsync({updates:n}),g.success(s("viewerSettings.toast.saved"))}catch(x){g.error(U(x,s).message)}}function I(){d(c)}const l=a.data,H=l?.effectivePublicUrl;return e.jsxs("section",{className:"rounded-md border border-border bg-surface",children:[e.jsxs("header",{className:"flex items-center gap-2 border-b border-border px-4 py-3",children:[e.jsx(Y,{className:"h-4 w-4 text-text-dim"}),e.jsx("h2",{className:"text-sm font-semibold",children:s("viewerSettings.viewer.title")}),t.enabled?e.jsx(f,{variant:"success",children:s("viewerSettings.viewer.on")}):e.jsx(f,{variant:"outline",children:s("viewerSettings.viewer.off")})]}),e.jsx("p",{className:"px-4 pt-2 text-xs text-text-dim",children:s("viewerSettings.viewer.subtitle")}),e.jsx("div",{className:"flex items-center gap-3 px-4 py-3",children:e.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",checked:t.enabled,onChange:n=>{const x=n.target.checked;d(j=>({...j,enabled:x,noDefaultRemote:x?j.noDefaultRemote:!1}))},className:"h-4 w-4 accent-accent cursor-pointer"}),e.jsx("span",{className:"font-medium",children:s("viewerSettings.viewer.enableLabel")})]})}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 px-4 pb-3 sm:grid-cols-2",children:[e.jsx(u,{label:s("viewerSettings.viewer.publicUrl"),hint:s("viewerSettings.viewer.publicUrlHint"),children:e.jsx(y,{value:t.publicUrl,onChange:n=>o("publicUrl",n.target.value),placeholder:"https://agim.example.com",className:"font-mono text-xs"})}),e.jsx(u,{label:s("viewerSettings.viewer.tunnelMode"),hint:s("viewerSettings.viewer.tunnelHint"),children:e.jsxs(W,{value:t.tunnelMode,onValueChange:n=>o("tunnelMode",n),children:[e.jsx(T,{children:e.jsx(O,{})}),e.jsxs(F,{children:[e.jsx(B,{value:"off",children:s("viewerSettings.viewer.tunnelOff")}),e.jsx(B,{value:"quick",children:s("viewerSettings.viewer.tunnelQuick")})]})]})}),e.jsx(u,{label:s("viewerSettings.viewer.noDefaultRemote"),hint:s("viewerSettings.viewer.noDefaultRemoteHint"),children:e.jsxs("label",{className:L("inline-flex items-center gap-2 text-xs",!t.enabled&&"opacity-50 cursor-not-allowed"),children:[e.jsx("input",{type:"checkbox",checked:t.noDefaultRemote,disabled:!t.enabled,onChange:n=>o("noDefaultRemote",n.target.checked),className:"h-4 w-4 accent-accent cursor-pointer disabled:cursor-not-allowed"}),e.jsx("span",{children:s("viewerSettings.viewer.noDefaultRemoteLabel")})]})})]}),t.tunnelMode==="quick"&&e.jsxs("div",{className:"mx-4 mb-3 rounded-md border border-border bg-surface-2 p-3",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-2",children:[e.jsx(G,{className:"h-4 w-4 text-text-dim"}),e.jsx("span",{className:"text-xs font-medium uppercase tracking-wide text-text-dim",children:s("viewerSettings.viewer.tunnelStatus")}),e.jsxs(h,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>void a.refetch(),disabled:a.isFetching,"aria-label":s("viewerSettings.viewer.refreshTunnel"),children:[a.isFetching?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(V,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("viewerSettings.viewer.refreshTunnel")})]})]}),l?e.jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[e.jsx(p,{label:s("viewerSettings.viewer.tunnelRunning"),children:l.tunnel.running?e.jsxs("span",{className:"inline-flex items-center gap-1 text-success",children:[e.jsx(J,{className:"h-3 w-3"}),s("viewerSettings.viewer.yes")]}):e.jsx("span",{className:"text-text-dim",children:s("viewerSettings.viewer.no")})}),e.jsx(p,{label:s("viewerSettings.viewer.tunnelUrl"),children:l.tunnel.url?e.jsxs("a",{href:l.tunnel.url,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 break-all font-mono text-info hover:underline",children:[l.tunnel.url,e.jsx(Q,{className:"h-3 w-3 shrink-0"})]}):e.jsx("span",{className:"text-text-muted",children:"—"})}),e.jsx(p,{label:s("viewerSettings.viewer.effectiveUrl"),children:H?e.jsx("span",{className:"break-all font-mono text-text",children:H}):e.jsx("span",{className:"text-text-muted",children:"—"})}),e.jsx(p,{label:s("viewerSettings.viewer.binary"),children:l.tunnel.binaryFound?e.jsx("span",{className:"font-mono text-text",children:l.tunnel.binaryPath}):e.jsx("span",{className:"text-warning",children:s("viewerSettings.viewer.binaryMissing")})}),l.tunnel.lastError&&e.jsx(p,{label:s("viewerSettings.viewer.lastError"),children:e.jsx("span",{className:"break-words text-danger",children:l.tunnel.lastError})})]}):e.jsx("p",{className:"text-xs text-text-dim",children:s("viewerSettings.viewer.tunnelLoading")})]}),e.jsx("h3",{className:"border-t border-border px-4 pt-3 text-xs font-semibold uppercase tracking-wide text-text-dim",children:s("viewerSettings.viewer.thresholds")}),e.jsxs("div",{className:"grid grid-cols-2 gap-3 px-4 py-3 sm:grid-cols-4",children:[e.jsx(u,{label:s("viewerSettings.viewer.chars"),hint:s("viewerSettings.viewer.charsHint"),children:e.jsx(E,{value:t.chars,onChange:n=>o("chars",n),min:100,max:1e4,placeholder:"500"})}),e.jsx(u,{label:s("viewerSettings.viewer.lines"),hint:s("viewerSettings.viewer.linesHint"),children:e.jsx(E,{value:t.lines,onChange:n=>o("lines",n),min:5,max:200,placeholder:"12"})}),e.jsx(u,{label:s("viewerSettings.viewer.codeLines"),hint:s("viewerSettings.viewer.codeLinesHint"),children:e.jsx(E,{value:t.codeLines,onChange:n=>o("codeLines",n),min:5,max:200,placeholder:"10"})}),e.jsx(u,{label:s("viewerSettings.viewer.maxPastes"),hint:s("viewerSettings.viewer.maxPastesHint"),children:e.jsx(E,{value:t.maxPastes,onChange:n=>o("maxPastes",n),min:100,max:1e6,placeholder:"10000"})})]}),b&&e.jsxs("div",{className:"flex items-center gap-2 border-t border-border px-4 py-3",children:[e.jsx(f,{variant:"info",children:s("viewerSettings.dirtyHint")}),e.jsxs(h,{variant:"ghost",size:"sm",className:"ml-auto",onClick:I,disabled:r.isPending,children:[e.jsx(C,{className:"h-4 w-4"}),s("viewerSettings.discard")]}),e.jsxs(h,{size:"sm",onClick:()=>void _(),disabled:r.isPending,children:[r.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(P,{className:"h-4 w-4"}),r.isPending?s("viewerSettings.saving"):s("viewerSettings.save")]})]})]})}function v(i){return/\*{3,}/.test(i)}function ee({env:i}){const{t:s}=R(["settings","common"]),r=D(),a=i.IMHUB_BAIDU_MAP_AK??"",[t,d]=m.useState(a),[w,S]=m.useState("");m.useEffect(()=>{a!==w&&(d(a),S(a))},[a,w]);const c=!!a,b=t!==a&&!(v(t)&&t===a),o=t.length>0&&!v(t)&&t.length!==32;async function _(){if(b&&!v(t))try{await r.mutateAsync({updates:{IMHUB_BAIDU_MAP_AK:t.trim()||null}}),g.success(s("viewerSettings.baidu.toast.saved"))}catch(l){g.error(U(l,s).message)}}async function I(){try{await r.mutateAsync({updates:{IMHUB_BAIDU_MAP_AK:null}}),d(""),g.success(s("viewerSettings.baidu.toast.cleared"))}catch(l){g.error(U(l,s).message)}}return e.jsxs("section",{className:"rounded-md border border-border bg-surface",children:[e.jsxs("header",{className:"flex items-center gap-2 border-b border-border px-4 py-3",children:[e.jsx(Z,{className:"h-4 w-4 text-text-dim"}),e.jsx("h2",{className:"text-sm font-semibold",children:s("viewerSettings.baidu.title")}),c?e.jsx(f,{variant:"success",children:s("viewerSettings.baidu.configured")}):e.jsx(f,{variant:"outline",children:s("viewerSettings.baidu.empty")})]}),e.jsx("p",{className:"px-4 pt-2 text-xs text-text-dim",children:s("viewerSettings.baidu.subtitle")}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx(A,{htmlFor:"baidu-ak",className:"text-xs font-medium",children:"IMHUB_BAIDU_MAP_AK"}),e.jsx(y,{id:"baidu-ak",value:t,onChange:l=>d(l.target.value),placeholder:s("viewerSettings.baidu.placeholder"),autoComplete:"off",className:L("mt-1 font-mono text-xs",v(t)&&"text-text-muted")}),o&&e.jsx("p",{className:"mt-1 text-[11px] text-warning",children:s("viewerSettings.baidu.suspicious",{length:t.length})}),e.jsx("p",{className:"mt-1 text-[11px] text-text-dim",children:s("viewerSettings.baidu.hint")})]}),e.jsxs("div",{className:"flex items-center gap-2 border-t border-border px-4 py-3",children:[e.jsxs(h,{variant:"ghost",size:"sm",onClick:()=>void I(),disabled:!c||r.isPending,className:"text-danger hover:text-danger",children:[e.jsx(C,{className:"h-4 w-4"}),s("viewerSettings.baidu.clear")]}),e.jsx("span",{className:"ml-auto"}),b&&e.jsxs(h,{size:"sm",onClick:()=>void _(),disabled:r.isPending||v(t),children:[r.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(P,{className:"h-4 w-4"}),r.isPending?s("viewerSettings.saving"):s("viewerSettings.save")]})]})]})}function u({label:i,hint:s,children:r}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(A,{className:"text-xs font-medium",children:i}),r,s&&e.jsx("p",{className:"text-[11px] text-text-dim",children:s})]})}function p({label:i,children:s}){return e.jsxs("div",{className:"flex flex-wrap items-baseline gap-2",children:[e.jsxs("span",{className:"shrink-0 font-medium text-text-dim",children:[i,":"]}),e.jsx("span",{className:"min-w-0 flex-1",children:s})]})}function E({value:i,onChange:s,min:r,max:a,placeholder:t}){return e.jsx(y,{type:"number",inputMode:"numeric",min:r,max:a,value:i,onChange:d=>s(d.target.value),placeholder:t})}export{xe as default};
|
|
12
|
-
//# sourceMappingURL=viewer-Bz3wL-99.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"viewer-Bz3wL-99.js","sources":["../../node_modules/lucide-react/dist/esm/icons/earth.js","../../node_modules/lucide-react/dist/esm/icons/file-text.js","../../src/routes/settings/viewer.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Earth = createLucideIcon(\"Earth\", [\n [\"path\", { d: \"M21.54 15H17a2 2 0 0 0-2 2v4.54\", key: \"1djwo0\" }],\n [\n \"path\",\n {\n d: \"M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17\",\n key: \"1tzkfa\"\n }\n ],\n [\"path\", { d: \"M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05\", key: \"14pb5j\" }],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }]\n]);\n\nexport { Earth as default };\n//# sourceMappingURL=earth.js.map\n","/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FileText = createLucideIcon(\"FileText\", [\n [\"path\", { d: \"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\", key: \"1rqfz7\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M10 9H8\", key: \"b1mrlr\" }],\n [\"path\", { d: \"M16 13H8\", key: \"t4e002\" }],\n [\"path\", { d: \"M16 17H8\", key: \"z1uh3a\" }]\n]);\n\nexport { FileText as default };\n//# sourceMappingURL=file-text.js.map\n","/**\n * /settings/viewer — long-message Viewer card + Baidu Maps AK card.\n *\n * Both cards are env-driven (~/.agim/.env), each with its own dirty /\n * Save / Discard state so a change to one doesn't force re-save of the\n * other. The Viewer card additionally surfaces cloudflared tunnel\n * status via `GET /api/viewer/tunnel`, with a manual Refresh button\n * since tunnel state is essentially static between operator actions.\n *\n * Env keys covered:\n * * Viewer: IMHUB_VIEWER_ENABLED / _PUBLIC_BASE_URL / _TUNNEL_MODE /\n * _CHARS / _LINES / _CODE_LINES / _MAX_PASTES\n * * Baidu: IMHUB_BAIDU_MAP_AK (in SECRET_KEYS — masked unless\n * reveal=1 is passed)\n *\n * AK validation: v1 mentioned \"32-char AK starting with non-digit\" as\n * a hint, but isn't strictly enforced (Baidu has refreshed AK formats\n * over the years). We surface a `pattern-looks-suspicious` warning\n * rather than blocking save.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n CheckCircle2, Eye, EyeOff, ExternalLink, FileText, Globe2, Loader2,\n MapPin, RefreshCcw, Save, X,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv, useViewerTunnel } from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\n/* ─────────────── Page wrapper ─────────────── */\n\nexport default function SettingsViewerRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const [reveal, setReveal] = useState(false)\n const envQuery = useEnv({ reveal })\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-6\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('viewerSettings.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => setReveal((v) => !v)}\n disabled={envQuery.isFetching}\n aria-label={reveal ? t('viewerSettings.hide') : t('viewerSettings.reveal')}\n >\n {reveal ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">\n {reveal ? t('viewerSettings.hide') : t('viewerSettings.reveal')}\n </span>\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => void envQuery.refetch()}\n disabled={envQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {envQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('viewerSettings.subtitle')}</p>\n </header>\n\n {envQuery.isLoading ? (\n <div className=\"h-64 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <>\n <ViewerCard env={envQuery.data?.env ?? {}} />\n <BaiduCard env={envQuery.data?.env ?? {}} />\n </>\n )}\n </div>\n )\n}\n\n/* ─────────────── Viewer card ─────────────── */\n\ninterface ViewerDraft {\n enabled: boolean\n publicUrl: string\n tunnelMode: 'off' | 'quick'\n // v1.2.45 — remote-paste URL/Token are env-only advanced knobs.\n // Only the opt-out toggle stays in the UI.\n noDefaultRemote: boolean\n chars: string\n lines: string\n codeLines: string\n maxPastes: string\n}\n\nfunction viewerDraftFromEnv(env: Record<string, string>): ViewerDraft {\n return {\n enabled: env.IMHUB_VIEWER_ENABLED === '1' || env.IMHUB_VIEWER_ENABLED?.toLowerCase() === 'true',\n publicUrl: env.IMHUB_VIEWER_PUBLIC_BASE_URL ?? '',\n tunnelMode: env.IMHUB_VIEWER_TUNNEL_MODE === 'quick' ? 'quick' : 'off',\n noDefaultRemote: env.IMHUB_VIEWER_NO_DEFAULT_REMOTE === '1' || env.IMHUB_VIEWER_NO_DEFAULT_REMOTE?.toLowerCase() === 'true',\n chars: env.IMHUB_VIEWER_CHARS ?? '',\n lines: env.IMHUB_VIEWER_LINES ?? '',\n codeLines: env.IMHUB_VIEWER_CODE_LINES ?? '',\n maxPastes: env.IMHUB_VIEWER_MAX_PASTES ?? '',\n }\n}\n\nfunction ViewerCard({ env }: { env: Record<string, string> }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const updateEnv = useUpdateEnv()\n const tunnelQuery = useViewerTunnel()\n\n const [draft, setDraft] = useState<ViewerDraft>(() => viewerDraftFromEnv(env))\n const [syncedHash, setSyncedHash] = useState('')\n\n // Sync draft when env changes (initial load + post-save refetch).\n useEffect(() => {\n const next = viewerDraftFromEnv(env)\n const hash = JSON.stringify(next)\n if (hash !== syncedHash) {\n setDraft(next)\n setSyncedHash(hash)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [env.IMHUB_VIEWER_ENABLED, env.IMHUB_VIEWER_PUBLIC_BASE_URL,\n env.IMHUB_VIEWER_TUNNEL_MODE, env.IMHUB_VIEWER_CHARS,\n env.IMHUB_VIEWER_LINES, env.IMHUB_VIEWER_CODE_LINES,\n env.IMHUB_VIEWER_MAX_PASTES, env.IMHUB_VIEWER_NO_DEFAULT_REMOTE])\n\n const current = useMemo(() => viewerDraftFromEnv(env), [env])\n const isDirty = useMemo(\n () => JSON.stringify(draft) !== JSON.stringify(current),\n [draft, current],\n )\n\n function setField<K extends keyof ViewerDraft>(k: K, v: ViewerDraft[K]): void {\n setDraft((d) => ({ ...d, [k]: v }))\n }\n\n async function onSave(): Promise<void> {\n const updates: Record<string, string | null> = {}\n if (draft.enabled !== current.enabled) {\n updates.IMHUB_VIEWER_ENABLED = draft.enabled ? '1' : '0'\n }\n if (draft.publicUrl !== current.publicUrl) {\n updates.IMHUB_VIEWER_PUBLIC_BASE_URL = draft.publicUrl.trim() || null\n }\n if (draft.tunnelMode !== current.tunnelMode) {\n updates.IMHUB_VIEWER_TUNNEL_MODE = draft.tunnelMode\n }\n if (draft.chars !== current.chars) {\n updates.IMHUB_VIEWER_CHARS = draft.chars.trim() || null\n }\n if (draft.lines !== current.lines) {\n updates.IMHUB_VIEWER_LINES = draft.lines.trim() || null\n }\n if (draft.codeLines !== current.codeLines) {\n updates.IMHUB_VIEWER_CODE_LINES = draft.codeLines.trim() || null\n }\n if (draft.maxPastes !== current.maxPastes) {\n updates.IMHUB_VIEWER_MAX_PASTES = draft.maxPastes.trim() || null\n }\n if (draft.noDefaultRemote !== current.noDefaultRemote) {\n updates.IMHUB_VIEWER_NO_DEFAULT_REMOTE = draft.noDefaultRemote ? '1' : null\n }\n if (Object.keys(updates).length === 0) return\n try {\n await updateEnv.mutateAsync({ updates })\n toast.success(t('viewerSettings.toast.saved'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n function onDiscard(): void {\n setDraft(current)\n }\n\n const tunnel = tunnelQuery.data\n const effectivePublicUrl = tunnel?.effectivePublicUrl\n\n return (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <FileText className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('viewerSettings.viewer.title')}</h2>\n {draft.enabled\n ? <Badge variant=\"success\">{t('viewerSettings.viewer.on')}</Badge>\n : <Badge variant=\"outline\">{t('viewerSettings.viewer.off')}</Badge>}\n </header>\n <p className=\"px-4 pt-2 text-xs text-text-dim\">{t('viewerSettings.viewer.subtitle')}</p>\n\n {/* Enable toggle */}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={draft.enabled}\n onChange={(e) => {\n const on = e.target.checked\n setDraft((d) => ({\n ...d,\n enabled: on,\n // Opt-out only applies when viewer is on; clear when disabling.\n noDefaultRemote: on ? d.noDefaultRemote : false,\n }))\n }}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n <span className=\"font-medium\">{t('viewerSettings.viewer.enableLabel')}</span>\n </label>\n </div>\n\n {/* Public URL + tunnel mode */}\n <div className=\"grid grid-cols-1 gap-3 px-4 pb-3 sm:grid-cols-2\">\n <Field label={t('viewerSettings.viewer.publicUrl')} hint={t('viewerSettings.viewer.publicUrlHint')}>\n <Input\n value={draft.publicUrl}\n onChange={(e) => setField('publicUrl', e.target.value)}\n placeholder=\"https://agim.example.com\"\n className=\"font-mono text-xs\"\n />\n </Field>\n <Field label={t('viewerSettings.viewer.tunnelMode')} hint={t('viewerSettings.viewer.tunnelHint')}>\n <Select\n value={draft.tunnelMode}\n onValueChange={(v) => setField('tunnelMode', v as 'off' | 'quick')}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"off\">{t('viewerSettings.viewer.tunnelOff')}</SelectItem>\n <SelectItem value=\"quick\">{t('viewerSettings.viewer.tunnelQuick')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n\n {/* v1.2.45 — only the opt-out toggle is in the UI. The\n community default endpoint (viewer.iclaw.host) is the\n implicit fallback when neither public base URL nor tunnel\n is set; operators who need to point at a different paste\n server use the IMHUB_VIEWER_REMOTE_PASTE_URL env var\n (documented in docs/viewer-modes.md). */}\n <Field\n label={t('viewerSettings.viewer.noDefaultRemote')}\n hint={t('viewerSettings.viewer.noDefaultRemoteHint')}\n >\n <label className={cn(\n 'inline-flex items-center gap-2 text-xs',\n !draft.enabled && 'opacity-50 cursor-not-allowed',\n )}>\n <input\n type=\"checkbox\"\n checked={draft.noDefaultRemote}\n disabled={!draft.enabled}\n onChange={(e) => setField('noDefaultRemote', e.target.checked)}\n className=\"h-4 w-4 accent-accent cursor-pointer disabled:cursor-not-allowed\"\n />\n <span>{t('viewerSettings.viewer.noDefaultRemoteLabel')}</span>\n </label>\n </Field>\n </div>\n\n {/* Tunnel status panel (only when quick mode is selected) */}\n {draft.tunnelMode === 'quick' && (\n <div className=\"mx-4 mb-3 rounded-md border border-border bg-surface-2 p-3\">\n <div className=\"mb-1 flex items-center gap-2\">\n <Globe2 className=\"h-4 w-4 text-text-dim\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-dim\">\n {t('viewerSettings.viewer.tunnelStatus')}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => void tunnelQuery.refetch()}\n disabled={tunnelQuery.isFetching}\n aria-label={t('viewerSettings.viewer.refreshTunnel')}\n >\n {tunnelQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('viewerSettings.viewer.refreshTunnel')}</span>\n </Button>\n </div>\n {tunnel ? (\n <div className=\"flex flex-col gap-1 text-xs\">\n <Row label={t('viewerSettings.viewer.tunnelRunning')}>\n {tunnel.tunnel.running ? (\n <span className=\"inline-flex items-center gap-1 text-success\">\n <CheckCircle2 className=\"h-3 w-3\" />\n {t('viewerSettings.viewer.yes')}\n </span>\n ) : (\n <span className=\"text-text-dim\">{t('viewerSettings.viewer.no')}</span>\n )}\n </Row>\n <Row label={t('viewerSettings.viewer.tunnelUrl')}>\n {tunnel.tunnel.url ? (\n <a\n href={tunnel.tunnel.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 break-all font-mono text-info hover:underline\"\n >\n {tunnel.tunnel.url}\n <ExternalLink className=\"h-3 w-3 shrink-0\" />\n </a>\n ) : <span className=\"text-text-muted\">—</span>}\n </Row>\n <Row label={t('viewerSettings.viewer.effectiveUrl')}>\n {effectivePublicUrl ? (\n <span className=\"break-all font-mono text-text\">{effectivePublicUrl}</span>\n ) : <span className=\"text-text-muted\">—</span>}\n </Row>\n <Row label={t('viewerSettings.viewer.binary')}>\n {tunnel.tunnel.binaryFound ? (\n <span className=\"font-mono text-text\">{tunnel.tunnel.binaryPath}</span>\n ) : (\n <span className=\"text-warning\">{t('viewerSettings.viewer.binaryMissing')}</span>\n )}\n </Row>\n {tunnel.tunnel.lastError && (\n <Row label={t('viewerSettings.viewer.lastError')}>\n <span className=\"break-words text-danger\">{tunnel.tunnel.lastError}</span>\n </Row>\n )}\n </div>\n ) : (\n <p className=\"text-xs text-text-dim\">{t('viewerSettings.viewer.tunnelLoading')}</p>\n )}\n </div>\n )}\n\n {/* Thresholds */}\n <h3 className=\"border-t border-border px-4 pt-3 text-xs font-semibold uppercase tracking-wide text-text-dim\">\n {t('viewerSettings.viewer.thresholds')}\n </h3>\n <div className=\"grid grid-cols-2 gap-3 px-4 py-3 sm:grid-cols-4\">\n <Field label={t('viewerSettings.viewer.chars')} hint={t('viewerSettings.viewer.charsHint')}>\n <NumberInput value={draft.chars} onChange={(v) => setField('chars', v)} min={100} max={10000} placeholder=\"500\" />\n </Field>\n <Field label={t('viewerSettings.viewer.lines')} hint={t('viewerSettings.viewer.linesHint')}>\n <NumberInput value={draft.lines} onChange={(v) => setField('lines', v)} min={5} max={200} placeholder=\"12\" />\n </Field>\n <Field label={t('viewerSettings.viewer.codeLines')} hint={t('viewerSettings.viewer.codeLinesHint')}>\n <NumberInput value={draft.codeLines} onChange={(v) => setField('codeLines', v)} min={5} max={200} placeholder=\"10\" />\n </Field>\n <Field label={t('viewerSettings.viewer.maxPastes')} hint={t('viewerSettings.viewer.maxPastesHint')}>\n <NumberInput value={draft.maxPastes} onChange={(v) => setField('maxPastes', v)} min={100} max={1000000} placeholder=\"10000\" />\n </Field>\n </div>\n\n {/* Save bar */}\n {isDirty && (\n <div className=\"flex items-center gap-2 border-t border-border px-4 py-3\">\n <Badge variant=\"info\">{t('viewerSettings.dirtyHint')}</Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={onDiscard}\n disabled={updateEnv.isPending}\n >\n <X className=\"h-4 w-4\" />\n {t('viewerSettings.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateEnv.isPending}\n >\n {updateEnv.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Save className=\"h-4 w-4\" />}\n {updateEnv.isPending ? t('viewerSettings.saving') : t('viewerSettings.save')}\n </Button>\n </div>\n )}\n </section>\n )\n}\n\n/* ─────────────── Baidu Maps card ─────────────── */\n\nfunction isMasked(s: string): boolean {\n return /\\*{3,}/.test(s)\n}\n\nfunction BaiduCard({ env }: { env: Record<string, string> }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const updateEnv = useUpdateEnv()\n\n const currentAk = env.IMHUB_BAIDU_MAP_AK ?? ''\n const [draftAk, setDraftAk] = useState(currentAk)\n const [syncedHash, setSyncedHash] = useState('')\n\n useEffect(() => {\n if (currentAk !== syncedHash) {\n setDraftAk(currentAk)\n setSyncedHash(currentAk)\n }\n }, [currentAk, syncedHash])\n\n const isConfigured = !!currentAk\n // Treat masked echo as no-change. Operator either typed something\n // new, or cleared. AK validity = looks-suspicious warning.\n const isDirty = draftAk !== currentAk && !(isMasked(draftAk) && draftAk === currentAk)\n const suspicious = draftAk.length > 0 && !isMasked(draftAk) && draftAk.length !== 32\n\n async function onSave(): Promise<void> {\n if (!isDirty) return\n if (isMasked(draftAk)) return // server would skip anyway; be explicit\n try {\n await updateEnv.mutateAsync({\n updates: { IMHUB_BAIDU_MAP_AK: draftAk.trim() || null },\n })\n toast.success(t('viewerSettings.baidu.toast.saved'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onClear(): Promise<void> {\n try {\n await updateEnv.mutateAsync({ updates: { IMHUB_BAIDU_MAP_AK: null } })\n setDraftAk('')\n toast.success(t('viewerSettings.baidu.toast.cleared'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n return (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <MapPin className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('viewerSettings.baidu.title')}</h2>\n {isConfigured\n ? <Badge variant=\"success\">{t('viewerSettings.baidu.configured')}</Badge>\n : <Badge variant=\"outline\">{t('viewerSettings.baidu.empty')}</Badge>}\n </header>\n <p className=\"px-4 pt-2 text-xs text-text-dim\">{t('viewerSettings.baidu.subtitle')}</p>\n\n <div className=\"px-4 py-3\">\n <Label htmlFor=\"baidu-ak\" className=\"text-xs font-medium\">IMHUB_BAIDU_MAP_AK</Label>\n <Input\n id=\"baidu-ak\"\n value={draftAk}\n onChange={(e) => setDraftAk(e.target.value)}\n placeholder={t('viewerSettings.baidu.placeholder')}\n autoComplete=\"off\"\n className={cn('mt-1 font-mono text-xs', isMasked(draftAk) && 'text-text-muted')}\n />\n {suspicious && (\n <p className=\"mt-1 text-[11px] text-warning\">\n {t('viewerSettings.baidu.suspicious', { length: draftAk.length })}\n </p>\n )}\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('viewerSettings.baidu.hint')}</p>\n </div>\n\n <div className=\"flex items-center gap-2 border-t border-border px-4 py-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => void onClear()}\n disabled={!isConfigured || updateEnv.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <X className=\"h-4 w-4\" />\n {t('viewerSettings.baidu.clear')}\n </Button>\n <span className=\"ml-auto\" />\n {isDirty && (\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateEnv.isPending || isMasked(draftAk)}\n >\n {updateEnv.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Save className=\"h-4 w-4\" />}\n {updateEnv.isPending ? t('viewerSettings.saving') : t('viewerSettings.save')}\n </Button>\n )}\n </div>\n </section>\n )\n}\n\n/* ─────────────── Helpers ─────────────── */\n\ninterface FieldProps {\n label: string\n hint?: string\n children: React.ReactNode\n}\n\nfunction Field({ label, hint, children }: FieldProps): JSX.Element {\n return (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs font-medium\">{label}</Label>\n {children}\n {hint && <p className=\"text-[11px] text-text-dim\">{hint}</p>}\n </div>\n )\n}\n\ninterface RowProps {\n label: string\n children: React.ReactNode\n}\n\nfunction Row({ label, children }: RowProps): JSX.Element {\n return (\n <div className=\"flex flex-wrap items-baseline gap-2\">\n <span className=\"shrink-0 font-medium text-text-dim\">{label}:</span>\n <span className=\"min-w-0 flex-1\">{children}</span>\n </div>\n )\n}\n\ninterface NumberInputProps {\n value: string\n onChange: (v: string) => void\n min?: number\n max?: number\n placeholder?: string\n}\n\nfunction NumberInput({ value, onChange, min, max, placeholder }: NumberInputProps): JSX.Element {\n return (\n <Input\n type=\"number\"\n inputMode=\"numeric\"\n min={min}\n max={max}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={placeholder}\n />\n )\n}\n"],"names":["Earth","createLucideIcon","FileText","SettingsViewerRoute","t","useTranslation","reveal","setReveal","useState","envQuery","useEnv","jsxs","jsx","Button","v","EyeOff","Eye","Loader2","RefreshCcw","Fragment","ViewerCard","BaiduCard","viewerDraftFromEnv","env","updateEnv","useUpdateEnv","tunnelQuery","useViewerTunnel","draft","setDraft","syncedHash","setSyncedHash","useEffect","next","hash","current","useMemo","isDirty","setField","k","d","onSave","updates","toast","err","describeError","onDiscard","tunnel","effectivePublicUrl","Badge","e","on","Field","Input","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","cn","Globe2","Row","CheckCircle2","ExternalLink","NumberInput","X","Save","isMasked","s","currentAk","draftAk","setDraftAk","isConfigured","suspicious","onClear","MapPin","Label","label","hint","children","value","onChange","min","max","placeholder"],"mappings":"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","x_google_ignoreList":[0,1]}
|