@konbakuyomu/smart-search-linux-x64 0.0.0 → 0.1.26
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/LICENSE +21 -0
- package/package.json +18 -3
- package/runtime/smart-search/_internal/base_library.zip +0 -0
- package/runtime/smart-search/_internal/certifi/cacert.pem +3959 -0
- package/runtime/smart-search/_internal/certifi/py.typed +0 -0
- package/runtime/smart-search/_internal/libpython3.13.so.1.0 +0 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/INSTALLER +1 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/METADATA +171 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/RECORD +298 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/WHEEL +5 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/licenses/AUTHORS.rst +11 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/licenses/LICENSE +27 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/top_level.txt +1 -0
- package/runtime/smart-search/_internal/smart_search/__init__.py +1 -0
- package/runtime/smart-search/_internal/smart_search/activity.py +279 -0
- package/runtime/smart-search/_internal/smart_search/assets/i18n/messages.json +17858 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/SKILL.md +69 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/agents/openai.yaml +3 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/cli-contract.md +21 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/cli-core.md +99 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/command-patterns.md +166 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/deep-research-mode.md +204 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/provider-routing.md +178 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/regression-release.md +46 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/setup-config.md +133 -0
- package/runtime/smart-search/_internal/smart_search/assets/ui/index.html +955 -0
- package/runtime/smart-search/_internal/smart_search/cli.py +3651 -0
- package/runtime/smart-search/_internal/smart_search/config.py +1302 -0
- package/runtime/smart-search/_internal/smart_search/desktop_backend.py +709 -0
- package/runtime/smart-search/_internal/smart_search/desktop_catalog.py +166 -0
- package/runtime/smart-search/_internal/smart_search/desktop_cli.py +209 -0
- package/runtime/smart-search/_internal/smart_search/desktop_entry.py +19 -0
- package/runtime/smart-search/_internal/smart_search/desktop_environment.py +629 -0
- package/runtime/smart-search/_internal/smart_search/desktop_skills.py +129 -0
- package/runtime/smart-search/_internal/smart_search/desktop_updates.py +160 -0
- package/runtime/smart-search/_internal/smart_search/desktop_worker.py +117 -0
- package/runtime/smart-search/_internal/smart_search/i18n.py +135 -0
- package/runtime/smart-search/_internal/smart_search/intent_router.py +253 -0
- package/runtime/smart-search/_internal/smart_search/jev.py +473 -0
- package/runtime/smart-search/_internal/smart_search/jev_search.py +719 -0
- package/runtime/smart-search/_internal/smart_search/logger.py +43 -0
- package/runtime/smart-search/_internal/smart_search/provider_descriptions.py +140 -0
- package/runtime/smart-search/_internal/smart_search/provider_errors.py +137 -0
- package/runtime/smart-search/_internal/smart_search/provider_health.py +277 -0
- package/runtime/smart-search/_internal/smart_search/providers/__init__.py +27 -0
- package/runtime/smart-search/_internal/smart_search/providers/anysearch.py +336 -0
- package/runtime/smart-search/_internal/smart_search/providers/base.py +41 -0
- package/runtime/smart-search/_internal/smart_search/providers/context7.py +153 -0
- package/runtime/smart-search/_internal/smart_search/providers/exa.py +191 -0
- package/runtime/smart-search/_internal/smart_search/providers/jina.py +124 -0
- package/runtime/smart-search/_internal/smart_search/providers/openai_compatible.py +977 -0
- package/runtime/smart-search/_internal/smart_search/providers/sciverse.py +351 -0
- package/runtime/smart-search/_internal/smart_search/providers/tinyfish.py +213 -0
- package/runtime/smart-search/_internal/smart_search/providers/xai_responses.py +242 -0
- package/runtime/smart-search/_internal/smart_search/providers/zhipu.py +172 -0
- package/runtime/smart-search/_internal/smart_search/providers/zhipu_mcp.py +287 -0
- package/runtime/smart-search/_internal/smart_search/sciverse_schema.py +437 -0
- package/runtime/smart-search/_internal/smart_search/service.py +4302 -0
- package/runtime/smart-search/_internal/smart_search/skill_installer.py +549 -0
- package/runtime/smart-search/_internal/smart_search/skill_maintenance.py +181 -0
- package/runtime/smart-search/_internal/smart_search/sources.py +429 -0
- package/runtime/smart-search/_internal/smart_search/state_files.py +53 -0
- package/runtime/smart-search/_internal/smart_search/ui_api.py +246 -0
- package/runtime/smart-search/_internal/smart_search/ui_metadata.py +698 -0
- package/runtime/smart-search/_internal/smart_search/ui_server.py +506 -0
- package/runtime/smart-search/_internal/smart_search/utils.py +220 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/INSTALLER +1 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/METADATA +97 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/RECORD +105 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/REQUESTED +0 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/WHEEL +5 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/direct_url.json +1 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/entry_points.txt +2 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/licenses/LICENSE +21 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/top_level.txt +1 -0
- package/runtime/smart-search/_internal/wcwidth/_wcwidth_c.abi3.so +0 -0
- package/runtime/smart-search/_internal/wcwidth/_wcwidth_c.pyi +77 -0
- package/runtime/smart-search/_internal/wcwidth/py.typed +0 -0
- package/runtime/smart-search/package.json +49 -0
- package/runtime/smart-search/smart-search +0 -0
- package/README.md +0 -3
|
@@ -0,0 +1,955 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>smart-search</title>
|
|
7
|
+
<link rel="icon" type="image/png" data-smart-search-icon href="data:image/png;base64,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">
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
--bg: #f6f7f9; --panel: #ffffff; --ink: #1b1f24; --muted: #646e7a;
|
|
11
|
+
--line: #e2e6ea; --accent: #2f6feb; --ok: #1a7f46; --warn: #a3671a; --bad: #c0392b;
|
|
12
|
+
--chip: #eef1f5; --shadow: 0 1px 2px rgba(16,22,26,.06), 0 4px 16px rgba(16,22,26,.05);
|
|
13
|
+
}
|
|
14
|
+
@media (prefers-color-scheme: dark) {
|
|
15
|
+
:root {
|
|
16
|
+
--bg: #14171a; --panel: #1c2025; --ink: #e7eaee; --muted: #98a2ad;
|
|
17
|
+
--line: #2a3039; --accent: #6ea0ff; --ok: #4ec27f; --warn: #d7a34a; --bad: #f0776a;
|
|
18
|
+
--chip: #252b33; --shadow: none;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
* { box-sizing: border-box; }
|
|
22
|
+
body {
|
|
23
|
+
margin: 0; background: var(--bg); color: var(--ink);
|
|
24
|
+
font: 15px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
|
25
|
+
"Hiragino Sans GB", "Microsoft YaHei", Roboto, Helvetica, Arial, sans-serif;
|
|
26
|
+
}
|
|
27
|
+
code, pre, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
28
|
+
.layout { display: grid; grid-template-columns: 232px 1fr; min-height: 100vh; }
|
|
29
|
+
nav {
|
|
30
|
+
background: var(--panel); border-right: 1px solid var(--line);
|
|
31
|
+
padding: 20px 12px; position: sticky; top: 0; height: 100vh; overflow-y: auto;
|
|
32
|
+
}
|
|
33
|
+
nav h1 { font-size: 15px; margin: 0 0 4px 8px; letter-spacing: .2px; display: flex; align-items: center; gap: 8px; }
|
|
34
|
+
nav h1 img { width: 36px; height: 36px; padding: 2px; background: white; border-radius: 6px; }
|
|
35
|
+
nav .sub { font-size: 12px; color: var(--muted); margin: 0 0 18px 8px; }
|
|
36
|
+
nav button {
|
|
37
|
+
display: block; width: 100%; text-align: left; background: none; border: 0;
|
|
38
|
+
padding: 8px 10px; border-radius: 7px; color: var(--ink); cursor: pointer;
|
|
39
|
+
font: inherit; font-size: 14px; margin-bottom: 2px;
|
|
40
|
+
}
|
|
41
|
+
nav button:hover { background: var(--chip); }
|
|
42
|
+
nav button[aria-current="true"] { background: var(--accent); color: #fff; }
|
|
43
|
+
main { padding: 28px 32px 80px; max-width: 900px; }
|
|
44
|
+
h2 { font-size: 20px; margin: 0 0 6px; }
|
|
45
|
+
.blurb { color: var(--muted); margin: 0 0 22px; font-size: 14px; }
|
|
46
|
+
.card {
|
|
47
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
|
|
48
|
+
padding: 16px 18px; margin-bottom: 14px; box-shadow: var(--shadow);
|
|
49
|
+
}
|
|
50
|
+
.card h3 { margin: 0 0 2px; font-size: 15px; display: flex; align-items: center; gap: 8px; }
|
|
51
|
+
.card .note { color: var(--muted); font-size: 13px; margin: 0 0 12px; }
|
|
52
|
+
.card .provider-guidance {
|
|
53
|
+
color: var(--muted); font-size: 12px; margin: 0 0 12px; padding: 8px 10px;
|
|
54
|
+
border-left: 2px solid var(--accent); background: var(--bg); border-radius: 4px;
|
|
55
|
+
}
|
|
56
|
+
.banner { border-left: 3px solid var(--accent); }
|
|
57
|
+
.banner.ok { border-left-color: var(--ok); }
|
|
58
|
+
.banner.bad { border-left-color: var(--bad); }
|
|
59
|
+
.pill {
|
|
60
|
+
display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 12px;
|
|
61
|
+
background: var(--chip); color: var(--muted); white-space: nowrap;
|
|
62
|
+
}
|
|
63
|
+
.pill:empty { display: none; }
|
|
64
|
+
.pill.ok { background: rgba(26,127,70,.14); color: var(--ok); }
|
|
65
|
+
.pill.bad { background: rgba(192,57,43,.14); color: var(--bad); }
|
|
66
|
+
.pill.warn { background: rgba(163,103,26,.16); color: var(--warn); }
|
|
67
|
+
.row {
|
|
68
|
+
display: grid; grid-template-columns: 200px 1fr auto; gap: 10px;
|
|
69
|
+
align-items: start; padding: 9px 0; border-top: 1px solid var(--line);
|
|
70
|
+
}
|
|
71
|
+
.row:first-of-type { border-top: 0; }
|
|
72
|
+
.row label { font-size: 14px; }
|
|
73
|
+
.row .help { display: block; color: var(--muted); font-size: 12px; margin-top: 2px; }
|
|
74
|
+
.row .val { font-size: 13px; word-break: break-all; }
|
|
75
|
+
.row .val .unset { color: var(--muted); }
|
|
76
|
+
button.act {
|
|
77
|
+
background: var(--accent); color: #fff; border: 0; border-radius: 7px;
|
|
78
|
+
padding: 6px 13px; font: inherit; font-size: 13px; cursor: pointer;
|
|
79
|
+
}
|
|
80
|
+
button.act.ghost { background: var(--chip); color: var(--ink); }
|
|
81
|
+
button.act[disabled] { opacity: .5; cursor: not-allowed; }
|
|
82
|
+
table { border-collapse: collapse; width: 100%; font-size: 13px; }
|
|
83
|
+
th, td { text-align: left; padding: 7px 10px 7px 0; border-top: 1px solid var(--line); vertical-align: top; }
|
|
84
|
+
th { color: var(--muted); font-weight: 600; border-top: 0; }
|
|
85
|
+
input[type="text"], input[type="password"], select {
|
|
86
|
+
width: 100%; padding: 6px 9px; border: 1px solid var(--line); border-radius: 6px;
|
|
87
|
+
background: var(--bg); color: var(--ink); font: inherit; font-size: 13px;
|
|
88
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
89
|
+
}
|
|
90
|
+
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
|
|
91
|
+
input[disabled], select[disabled] { opacity: .6; cursor: not-allowed; }
|
|
92
|
+
input.dirty, select.dirty { border-color: var(--accent); }
|
|
93
|
+
.savebar {
|
|
94
|
+
position: sticky; bottom: 0; margin: 20px -32px -80px; padding: 12px 32px;
|
|
95
|
+
background: var(--panel); border-top: 1px solid var(--line);
|
|
96
|
+
display: flex; align-items: center; gap: 12px; z-index: 5;
|
|
97
|
+
}
|
|
98
|
+
.savebar .grow { flex: 1; font-size: 13px; color: var(--muted); }
|
|
99
|
+
.steps { counter-reset: step; }
|
|
100
|
+
.step > h3::before {
|
|
101
|
+
counter-increment: step; content: counter(step);
|
|
102
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
103
|
+
width: 20px; height: 20px; border-radius: 50%; background: var(--accent);
|
|
104
|
+
color: #fff; font-size: 12px; margin-right: 2px;
|
|
105
|
+
}
|
|
106
|
+
.step.done > h3::before { background: var(--ok); content: "✓"; }
|
|
107
|
+
details.more { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
|
|
108
|
+
details.more > summary {
|
|
109
|
+
cursor: pointer; color: var(--muted); font-size: 13px; list-style: none;
|
|
110
|
+
padding: 2px 0; user-select: none;
|
|
111
|
+
}
|
|
112
|
+
details.more > summary::-webkit-details-marker { display: none; }
|
|
113
|
+
details.more > summary::before { content: "▸ "; }
|
|
114
|
+
details.more[open] > summary::before { content: "▾ "; }
|
|
115
|
+
.links { display: flex; gap: 10px; margin-top: 4px; flex-wrap: wrap; }
|
|
116
|
+
.links a {
|
|
117
|
+
color: var(--accent); font-size: 12px; text-decoration: none;
|
|
118
|
+
border-bottom: 1px dotted var(--accent);
|
|
119
|
+
}
|
|
120
|
+
.links a:hover { border-bottom-style: solid; }
|
|
121
|
+
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
122
|
+
.chip {
|
|
123
|
+
border: 1px solid var(--line); background: var(--bg); color: var(--muted);
|
|
124
|
+
border-radius: 999px; padding: 3px 11px; font: inherit; font-size: 12px; cursor: pointer;
|
|
125
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
126
|
+
}
|
|
127
|
+
.chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
128
|
+
.chip[disabled] { cursor: not-allowed; opacity: .5; }
|
|
129
|
+
.chips.dirty .chip.on { outline: 1px solid var(--accent); }
|
|
130
|
+
.chain { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
|
|
131
|
+
.chain .arrow { color: var(--muted); font-size: 12px; }
|
|
132
|
+
.cost {
|
|
133
|
+
font-size: 12px; color: var(--warn); background: rgba(163,103,26,.1);
|
|
134
|
+
border-radius: 6px; padding: 7px 10px; margin-bottom: 12px;
|
|
135
|
+
}
|
|
136
|
+
.toast {
|
|
137
|
+
position: fixed; right: 20px; bottom: 20px; background: var(--panel);
|
|
138
|
+
border: 1px solid var(--line); border-left: 3px solid var(--accent);
|
|
139
|
+
border-radius: 8px; padding: 10px 14px; box-shadow: var(--shadow);
|
|
140
|
+
font-size: 13px; max-width: 380px; opacity: 0; transition: opacity .15s; pointer-events: none;
|
|
141
|
+
}
|
|
142
|
+
.toast.show { opacity: 1; }
|
|
143
|
+
.toast.bad { border-left-color: var(--bad); }
|
|
144
|
+
.lang { float: right; }
|
|
145
|
+
.lang button { display: inline; width: auto; padding: 2px 8px; font-size: 12px; }
|
|
146
|
+
@media (max-width: 720px) {
|
|
147
|
+
.layout { grid-template-columns: 1fr; }
|
|
148
|
+
nav { position: static; height: auto; }
|
|
149
|
+
main { padding: 20px 16px 60px; }
|
|
150
|
+
.row { grid-template-columns: 1fr; }
|
|
151
|
+
.savebar { margin: 20px -16px -60px; padding: 12px 16px; flex-wrap: wrap; }
|
|
152
|
+
}
|
|
153
|
+
</style>
|
|
154
|
+
</head>
|
|
155
|
+
<body>
|
|
156
|
+
<div class="layout">
|
|
157
|
+
<nav>
|
|
158
|
+
<h1><img data-smart-search-icon src="data:image/png;base64,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" alt="">smart-search</h1>
|
|
159
|
+
<p class="sub" id="subtitle"></p>
|
|
160
|
+
<div id="nav"></div>
|
|
161
|
+
<p class="sub" style="margin-top:18px">
|
|
162
|
+
<span class="lang">
|
|
163
|
+
<button class="act ghost" id="langToggle" type="button">EN / 中文</button>
|
|
164
|
+
</span>
|
|
165
|
+
</p>
|
|
166
|
+
</nav>
|
|
167
|
+
<main id="main"></main>
|
|
168
|
+
</div>
|
|
169
|
+
<div class="toast" id="toast"></div>
|
|
170
|
+
|
|
171
|
+
<script nonce="__SS_UI_NONCE__">
|
|
172
|
+
(function () {
|
|
173
|
+
"use strict";
|
|
174
|
+
var TOKEN = "__SS_UI_TOKEN__";
|
|
175
|
+
var lang = "__SS_UI_LANG__" === "en" ? "en" : "zh";
|
|
176
|
+
var state = null;
|
|
177
|
+
var current = "status";
|
|
178
|
+
var testing = {};
|
|
179
|
+
|
|
180
|
+
var T = {
|
|
181
|
+
zh: {
|
|
182
|
+
sub: "本地配置页", ready: "最低配置已满足", notReady: "最低配置还差一点",
|
|
183
|
+
missing: "还缺", configFile: "配置文件", source: "来源",
|
|
184
|
+
env: "环境变量", file: "配置文件", def: "默认值",
|
|
185
|
+
unset: "未配置", test: "测试", testing: "测试中…", testAll: "全部测试",
|
|
186
|
+
cost: "每点一次「测试」都会向对应服务商发一次真实请求,可能计费。",
|
|
187
|
+
capabilities: "能力", chain: "兜底顺序", configured: "已配置",
|
|
188
|
+
cooldown: "冷却中", provider: "数据源", status: "状态", message: "说明",
|
|
189
|
+
remaining: "剩余", reset: "解除冷却", resetAll: "全部解除",
|
|
190
|
+
noCooldown: "当前没有数据源在冷却。", envLocked: "由环境变量接管,改这里不生效",
|
|
191
|
+
doctor: "运行完整体检", doctorCost: "体检会一次性调用所有已配置的服务商。",
|
|
192
|
+
confirmAll: "这会对所有已配置的数据源各发一次真实请求,继续?",
|
|
193
|
+
skills: "已安装", skillsNot: "未安装", refresh: "刷新",
|
|
194
|
+
skillsCurrent: "已是当前版本", skillsStale: "可更新", skillsExtra: "已安装(含额外文件)",
|
|
195
|
+
required: "必需", optional: "可选", routingConnection: "路由与连接", jevMode: "Jev 自动选路", localMode: "本地选路",
|
|
196
|
+
missingOne: "缺", optionalOne: "未配置", more: "更多设置",
|
|
197
|
+
save: "保存", discard: "放弃修改", clear: "清除", saved: "已保存",
|
|
198
|
+
unsaved: "有 {n} 处未保存", envHint: "想改的话先在终端执行",
|
|
199
|
+
keepSecret: "留空表示不改动", getKey: "去申请 key", readDocs: "文档",
|
|
200
|
+
stepMain: "模型联网检索",
|
|
201
|
+
stepDocs: "文档与网页检索", stepFetch: "网页读取(深入搜索推荐)",
|
|
202
|
+
pickOne: "按用途选择渠道,不要求三类全部配置。", installSkill: "安装 / 更新",
|
|
203
|
+
runRoute: "看它走哪些能力(免费)", runSearch: "跑一次真实搜索",
|
|
204
|
+
queryPlaceholder: "比如:React useEffect 清理函数怎么写",
|
|
205
|
+
running: "运行中…", searchCost: "真实搜索会调用选中的检索渠道,配置 Jev 时还会进行一次选路判断,可能计费。确定继续?",
|
|
206
|
+
needQuery: "先输入一个问题。", result: "结果", chain: "兜底顺序",
|
|
207
|
+
chainNote: "Jev 按问题选择渠道;这里列出各类能力的本地回退顺序,绿色表示已配置。",
|
|
208
|
+
},
|
|
209
|
+
en: {
|
|
210
|
+
sub: "local config", ready: "Minimum profile met", notReady: "Minimum profile not met",
|
|
211
|
+
missing: "Missing", configFile: "Config file", source: "Source",
|
|
212
|
+
env: "environment", file: "config file", def: "default",
|
|
213
|
+
unset: "not set", test: "Test", testing: "Testing…", testAll: "Test all",
|
|
214
|
+
cost: "Every Test makes one real request to that provider and may cost money.",
|
|
215
|
+
capabilities: "Capabilities", chain: "Fallback order", configured: "Configured",
|
|
216
|
+
cooldown: "Cooling down", provider: "Provider", status: "Status", message: "Message",
|
|
217
|
+
remaining: "Remaining", reset: "Clear cooldown", resetAll: "Clear all",
|
|
218
|
+
noCooldown: "No provider is cooling down.", envLocked: "Taken over by an environment variable",
|
|
219
|
+
doctor: "Run full doctor", doctorCost: "Doctor calls every configured provider at once.",
|
|
220
|
+
confirmAll: "This makes one real request to every configured provider. Continue?",
|
|
221
|
+
skills: "installed", skillsNot: "not installed", refresh: "Refresh",
|
|
222
|
+
skillsCurrent: "up to date", skillsStale: "update available", skillsExtra: "installed (extra files)",
|
|
223
|
+
required: "required", optional: "optional", routingConnection: "Routing and connection", jevMode: "Jev routing", localMode: "Local routing",
|
|
224
|
+
missingOne: "missing", optionalOne: "not set", more: "More settings",
|
|
225
|
+
save: "Save", discard: "Discard", clear: "Clear", saved: "Saved",
|
|
226
|
+
unsaved: "{n} unsaved change(s)", envHint: "To change it, first run",
|
|
227
|
+
keepSecret: "Leave empty to keep the current value", getKey: "Get a key", readDocs: "Docs",
|
|
228
|
+
stepMain: "Model-backed retrieval",
|
|
229
|
+
stepDocs: "Documentation and web retrieval", stepFetch: "Page reading (recommended for research)",
|
|
230
|
+
pickOne: "Choose channels for your task; all three groups are not required.", installSkill: "Install / update",
|
|
231
|
+
runRoute: "Show which capabilities (free)", runSearch: "Run a real search",
|
|
232
|
+
queryPlaceholder: "e.g. how do I write a React useEffect cleanup function",
|
|
233
|
+
running: "Running…", searchCost: "A real search calls the selected channel and, when configured, Jev once for routing. Charges may apply. Continue?",
|
|
234
|
+
needQuery: "Type a question first.", result: "Result", chain: "Fallback order",
|
|
235
|
+
chainNote: "Jev selects for the question. These are local fallback orders; green channels are configured.",
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
function t(key) { return T[lang][key] || key; }
|
|
239
|
+
function L(obj, base) { return obj[base + "_" + lang] || obj[base + "_en"] || ""; }
|
|
240
|
+
|
|
241
|
+
function el(tag, attrs, kids) {
|
|
242
|
+
var node = document.createElement(tag);
|
|
243
|
+
attrs = attrs || {};
|
|
244
|
+
Object.keys(attrs).forEach(function (name) {
|
|
245
|
+
if (name === "class") node.className = attrs[name];
|
|
246
|
+
else if (name === "text") node.textContent = attrs[name];
|
|
247
|
+
else if (name.indexOf("on") === 0) node.addEventListener(name.slice(2), attrs[name]);
|
|
248
|
+
else if (attrs[name] !== null && attrs[name] !== undefined) node.setAttribute(name, attrs[name]);
|
|
249
|
+
});
|
|
250
|
+
(kids || []).forEach(function (kid) { if (kid) node.appendChild(kid); });
|
|
251
|
+
return node;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
var toastTimer = null;
|
|
255
|
+
function toast(message, bad) {
|
|
256
|
+
var node = document.getElementById("toast");
|
|
257
|
+
node.textContent = message;
|
|
258
|
+
node.className = "toast show" + (bad ? " bad" : "");
|
|
259
|
+
clearTimeout(toastTimer);
|
|
260
|
+
toastTimer = setTimeout(function () { node.className = "toast"; }, 4200);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function api(method, path, body) {
|
|
264
|
+
return fetch(path, {
|
|
265
|
+
method: method,
|
|
266
|
+
headers: body
|
|
267
|
+
? { "X-Smart-Search-Token": TOKEN, "Content-Type": "application/json" }
|
|
268
|
+
: { "X-Smart-Search-Token": TOKEN },
|
|
269
|
+
body: body ? JSON.stringify(body) : undefined
|
|
270
|
+
}).then(function (response) {
|
|
271
|
+
return response.json().catch(function () { return { ok: false, error: "HTTP " + response.status }; });
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function sourceLabel(source) {
|
|
276
|
+
if (source === "environment") return t("env");
|
|
277
|
+
if (source === "config_file") return t("file");
|
|
278
|
+
return t("def");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function seconds(value) {
|
|
282
|
+
var n = Number(value || 0);
|
|
283
|
+
if (n <= 0) return "-";
|
|
284
|
+
if (n < 60) return Math.round(n) + "s";
|
|
285
|
+
if (n < 3600) return Math.round(n / 60) + "m";
|
|
286
|
+
return (n / 3600).toFixed(1) + "h";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ---- views ------------------------------------------------------------
|
|
290
|
+
function viewStatus() {
|
|
291
|
+
var main = document.getElementById("main");
|
|
292
|
+
var minimum = state.minimum_profile || {};
|
|
293
|
+
var ok = !!minimum.ok;
|
|
294
|
+
main.appendChild(el("h2", { text: L(sectionById("status"), "label") }));
|
|
295
|
+
main.appendChild(el("p", { class: "blurb", text: L(sectionById("status"), "blurb") }));
|
|
296
|
+
|
|
297
|
+
var missing = (minimum.missing || []).join(", ");
|
|
298
|
+
main.appendChild(el("div", { class: "card banner " + (ok ? "ok" : "bad") }, [
|
|
299
|
+
el("h3", {}, [
|
|
300
|
+
el("span", { text: ok ? t("ready") : t("notReady") }),
|
|
301
|
+
el("span", { class: "pill " + (ok ? "ok" : "bad"), text: ok ? "OK" : "FAIL" })
|
|
302
|
+
]),
|
|
303
|
+
missing ? el("p", { class: "note", text: t("missing") + ": " + missing }) : null,
|
|
304
|
+
el("p", { class: "note mono", text: t("configFile") + ": " + (state.config_path || {}).config_file })
|
|
305
|
+
]));
|
|
306
|
+
|
|
307
|
+
var caps = state.capability_status || {};
|
|
308
|
+
var requiredCaps = minimum.required || [];
|
|
309
|
+
var rows = Object.keys(caps).map(function (name) {
|
|
310
|
+
var item = caps[name] || {};
|
|
311
|
+
var configured = (item.configured || []).join(", ") || "-";
|
|
312
|
+
var needed = requiredCaps.indexOf(name) >= 0;
|
|
313
|
+
var cls = item.ok ? "ok" : (needed ? "bad" : "");
|
|
314
|
+
var label = item.ok ? "OK" : (needed ? t("missingOne") : t("optionalOne"));
|
|
315
|
+
return el("tr", {}, [
|
|
316
|
+
el("td", {}, [
|
|
317
|
+
el("span", { class: "mono", text: name }),
|
|
318
|
+
needed ? el("span", { class: "pill", text: t("required") }) : null
|
|
319
|
+
]),
|
|
320
|
+
el("td", {}, [el("span", { class: "pill " + cls, text: label })]),
|
|
321
|
+
el("td", { class: "mono", text: configured }),
|
|
322
|
+
el("td", { class: "mono", text: (item.fallback_chain || []).join(" → ") })
|
|
323
|
+
]);
|
|
324
|
+
});
|
|
325
|
+
main.appendChild(el("div", { class: "card" }, [
|
|
326
|
+
el("h3", { text: t("capabilities") }),
|
|
327
|
+
el("table", {}, [
|
|
328
|
+
el("thead", {}, [el("tr", {}, [
|
|
329
|
+
el("th", { text: t("capabilities") }), el("th", { text: t("status") }),
|
|
330
|
+
el("th", { text: t("configured") }), el("th", { text: t("chain") })
|
|
331
|
+
])]),
|
|
332
|
+
el("tbody", {}, rows)
|
|
333
|
+
])
|
|
334
|
+
]));
|
|
335
|
+
|
|
336
|
+
main.appendChild(chainCard());
|
|
337
|
+
main.appendChild(cooldownCard());
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function cooldownCard() {
|
|
341
|
+
var health = state.provider_health || {};
|
|
342
|
+
var cooling = (health.providers || []).filter(function (item) { return item.state === "cooldown"; });
|
|
343
|
+
var kids = [el("h3", { text: t("cooldown") })];
|
|
344
|
+
if (!cooling.length) {
|
|
345
|
+
kids.push(el("p", { class: "note", text: t("noCooldown") }));
|
|
346
|
+
return el("div", { class: "card" }, kids);
|
|
347
|
+
}
|
|
348
|
+
kids.push(el("table", {}, [
|
|
349
|
+
el("thead", {}, [el("tr", {}, [
|
|
350
|
+
el("th", { text: t("provider") }), el("th", { text: t("remaining") }),
|
|
351
|
+
el("th", { text: t("message") }), el("th", {})
|
|
352
|
+
])]),
|
|
353
|
+
el("tbody", {}, cooling.map(function (item) {
|
|
354
|
+
return el("tr", {}, [
|
|
355
|
+
el("td", { class: "mono", text: item.provider }),
|
|
356
|
+
el("td", { text: seconds(item.cooldown_remaining_seconds) }),
|
|
357
|
+
el("td", { text: item.error || item.error_type || "-" }),
|
|
358
|
+
el("td", {}, [el("button", {
|
|
359
|
+
class: "act ghost", type: "button", text: t("reset"),
|
|
360
|
+
onclick: function () { resetCooldown([item.provider]); }
|
|
361
|
+
})])
|
|
362
|
+
]);
|
|
363
|
+
}))
|
|
364
|
+
]));
|
|
365
|
+
kids.push(el("p", { class: "note", style: "margin-top:12px" }, [
|
|
366
|
+
el("button", {
|
|
367
|
+
class: "act ghost", type: "button", text: t("resetAll"),
|
|
368
|
+
onclick: function () { resetCooldown(null); }
|
|
369
|
+
})
|
|
370
|
+
]));
|
|
371
|
+
return el("div", { class: "card" }, kids);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function resetCooldown(providers) {
|
|
375
|
+
api("POST", "/api/providers/reset", { providers: providers }).then(function (data) {
|
|
376
|
+
if (!data.ok) { toast(data.error || "failed", true); return; }
|
|
377
|
+
toast((data.cleared || []).join(", ") || t("noCooldown"));
|
|
378
|
+
refresh();
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function viewProviders() {
|
|
383
|
+
var main = document.getElementById("main");
|
|
384
|
+
var section = sectionById("providers");
|
|
385
|
+
main.appendChild(el("h2", { text: L(section, "label") }));
|
|
386
|
+
main.appendChild(el("p", { class: "blurb", text: L(section, "blurb") }));
|
|
387
|
+
main.appendChild(el("div", { class: "cost", text: t("cost") }));
|
|
388
|
+
|
|
389
|
+
var groups = {};
|
|
390
|
+
var order = [];
|
|
391
|
+
state.metadata.fields.forEach(function (field) {
|
|
392
|
+
if (field.section !== "providers") return;
|
|
393
|
+
var name = field.provider || "other";
|
|
394
|
+
if (!groups[name]) { groups[name] = []; order.push(name); }
|
|
395
|
+
groups[name].push(field);
|
|
396
|
+
});
|
|
397
|
+
order.forEach(function (provider) {
|
|
398
|
+
main.appendChild(providerCard(provider, groups[provider]));
|
|
399
|
+
});
|
|
400
|
+
main.appendChild(el("div", { class: "card" }, [
|
|
401
|
+
el("h3", { text: t("doctor") }),
|
|
402
|
+
el("p", { class: "note", text: t("doctorCost") }),
|
|
403
|
+
el("button", { class: "act ghost", type: "button", text: t("doctor"), onclick: runDoctor })
|
|
404
|
+
]));
|
|
405
|
+
main.appendChild(saveBar());
|
|
406
|
+
updateSaveBar();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function providerCard(provider, fields) {
|
|
410
|
+
var health = ((state.provider_health || {}).providers || []).filter(function (item) {
|
|
411
|
+
return item.provider === provider;
|
|
412
|
+
})[0];
|
|
413
|
+
var probe = (state.probe_kinds || {})[provider] || "";
|
|
414
|
+
var testable = !!probe;
|
|
415
|
+
var badge = null;
|
|
416
|
+
if (health && health.state === "cooldown") badge = el("span", { class: "pill bad", text: t("cooldown") });
|
|
417
|
+
else if (probe === "presence") badge = el("span", { class: "pill warn", text: "presence" });
|
|
418
|
+
|
|
419
|
+
var kids = [
|
|
420
|
+
el("h3", {}, [
|
|
421
|
+
el("span", { class: "mono", text: provider }),
|
|
422
|
+
badge,
|
|
423
|
+
el("span", { class: "pill", id: "res-" + provider, text: "" })
|
|
424
|
+
])
|
|
425
|
+
];
|
|
426
|
+
var profile = (state.provider_profiles || {})[provider] || {};
|
|
427
|
+
var descriptions = profile.descriptions || {};
|
|
428
|
+
function localizedDescriptions(prefix) {
|
|
429
|
+
return ["search", "fetch", "site_map", "synthesis"].map(function (operation) {
|
|
430
|
+
var translations = descriptions[operation] || {};
|
|
431
|
+
return translations[prefix + lang] || translations[prefix + "en"] || "";
|
|
432
|
+
}).filter(Boolean).join(" ");
|
|
433
|
+
}
|
|
434
|
+
var intro = localizedDescriptions("");
|
|
435
|
+
var guidance = localizedDescriptions("guidance_");
|
|
436
|
+
if (intro) kids.push(el("p", { class: "note", text: intro }));
|
|
437
|
+
if (guidance) kids.push(el("p", { class: "provider-guidance", text: guidance }));
|
|
438
|
+
var upfront = fields.filter(function (f) { return f.tier !== "advanced"; });
|
|
439
|
+
var advanced = fields.filter(function (f) { return f.tier === "advanced"; });
|
|
440
|
+
if (!upfront.length) { upfront = advanced; advanced = []; }
|
|
441
|
+
upfront.forEach(function (field) { kids.push(editableRow(field)); });
|
|
442
|
+
if (advanced.length) {
|
|
443
|
+
kids.push(el("details", { class: "more" }, [
|
|
444
|
+
el("summary", { text: t("more") + " (" + advanced.length + ")" })
|
|
445
|
+
].concat(advanced.map(editableRow))));
|
|
446
|
+
}
|
|
447
|
+
if (testable) {
|
|
448
|
+
kids.push(el("p", { class: "note", style: "margin-top:12px;margin-bottom:0" }, [
|
|
449
|
+
el("button", {
|
|
450
|
+
class: "act", type: "button", id: "btn-" + provider, text: t("test"),
|
|
451
|
+
onclick: function () { runTest(provider); }
|
|
452
|
+
})
|
|
453
|
+
]));
|
|
454
|
+
}
|
|
455
|
+
return el("div", { class: "card" }, kids);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
var pending = {}; // KEY -> new string value ("" means clear)
|
|
459
|
+
var previewTimer = null;
|
|
460
|
+
|
|
461
|
+
function isDirty() { return Object.keys(pending).length > 0; }
|
|
462
|
+
|
|
463
|
+
function effectiveValues() {
|
|
464
|
+
// Truthiness is all capability_status_from_values looks at, so a masked
|
|
465
|
+
// placeholder stands in fine for a secret we are not allowed to read back.
|
|
466
|
+
var merged = {};
|
|
467
|
+
Object.keys(state.values || {}).forEach(function (key) { merged[key] = state.values[key]; });
|
|
468
|
+
Object.keys(pending).forEach(function (key) { merged[key] = pending[key]; });
|
|
469
|
+
return merged;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function markDirty(field, input, value) {
|
|
473
|
+
var saved = (state.values || {})[field.key] || "";
|
|
474
|
+
if (value === saved || (value === "" && (!saved || field.kind === "secret"))) delete pending[field.key];
|
|
475
|
+
else pending[field.key] = value;
|
|
476
|
+
input.className = pending.hasOwnProperty(field.key) ? "dirty" : "";
|
|
477
|
+
updateSaveBar();
|
|
478
|
+
clearTimeout(previewTimer);
|
|
479
|
+
previewTimer = setTimeout(runPreview, 350);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function runPreview() {
|
|
483
|
+
api("POST", "/api/preview", { values: effectiveValues() }).then(function (data) {
|
|
484
|
+
if (!data || !data.ok) return;
|
|
485
|
+
var node = document.getElementById("previewMeter");
|
|
486
|
+
if (!node) return;
|
|
487
|
+
node.className = "pill " + (data.minimum_profile_ok ? "ok" : "bad");
|
|
488
|
+
node.textContent = data.minimum_profile_ok
|
|
489
|
+
? t("ready")
|
|
490
|
+
: t("notReady") + (data.missing.length ? " · " + data.missing.join(", ") : "");
|
|
491
|
+
document.querySelectorAll("[data-step]").forEach(function (card) {
|
|
492
|
+
var name = card.getAttribute("data-step");
|
|
493
|
+
var ok = (data.capability_status[name] || {}).ok;
|
|
494
|
+
card.className = "card step" + (ok ? " done" : "");
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function updateSaveBar() {
|
|
500
|
+
var bar = document.getElementById("saveBar");
|
|
501
|
+
if (!bar) return;
|
|
502
|
+
var count = Object.keys(pending).length;
|
|
503
|
+
bar.style.display = count ? "flex" : "none";
|
|
504
|
+
var label = document.getElementById("saveCount");
|
|
505
|
+
if (label) label.textContent = count ? t("unsaved").replace("{n}", count) : "";
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function saveChanges() {
|
|
509
|
+
if (!isDirty()) return;
|
|
510
|
+
var setValues = {}, unsetKeys = [];
|
|
511
|
+
Object.keys(pending).forEach(function (key) {
|
|
512
|
+
if (pending[key] === "") unsetKeys.push(key);
|
|
513
|
+
else setValues[key] = pending[key];
|
|
514
|
+
});
|
|
515
|
+
var button = document.getElementById("saveBtn");
|
|
516
|
+
if (button) button.disabled = true;
|
|
517
|
+
api("POST", "/api/config", { set: setValues, unset: unsetKeys, revision: state.revision }).then(function (data) {
|
|
518
|
+
if (!data.ok) { toast(data.error || "failed", true); return; }
|
|
519
|
+
pending = {};
|
|
520
|
+
if (data.status) { Object.keys(data.status).forEach(function (k) { state[k] = data.status[k]; }); }
|
|
521
|
+
toast(t("saved"));
|
|
522
|
+
render();
|
|
523
|
+
}).catch(function (e) {
|
|
524
|
+
toast(String(e), true);
|
|
525
|
+
}).then(function () {
|
|
526
|
+
if (button) button.disabled = false;
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function saveBar() {
|
|
531
|
+
return el("div", { class: "savebar", id: "saveBar", style: "display:none" }, [
|
|
532
|
+
el("span", { class: "grow", id: "saveCount" }),
|
|
533
|
+
el("button", {
|
|
534
|
+
class: "act ghost", type: "button", text: t("discard"),
|
|
535
|
+
onclick: function () { pending = {}; render(); }
|
|
536
|
+
}),
|
|
537
|
+
el("button", { class: "act", type: "button", id: "saveBtn", text: t("save"), onclick: saveChanges })
|
|
538
|
+
]);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function fieldInput(field) {
|
|
542
|
+
var source = (state.sources || {})[field.key] || "default";
|
|
543
|
+
var saved = (state.values || {})[field.key] || "";
|
|
544
|
+
var locked = source === "environment";
|
|
545
|
+
var value = pending.hasOwnProperty(field.key) ? pending[field.key] : saved;
|
|
546
|
+
|
|
547
|
+
if (field.kind === "enum" || field.kind === "bool") {
|
|
548
|
+
var options = field.kind === "bool" ? ["true", "false"] : field.choices;
|
|
549
|
+
var select = el("select", locked ? { disabled: "disabled" } : {});
|
|
550
|
+
select.appendChild(el("option", { value: "", text: "(" + t("def") + (field.default ? " " + field.default : "") + ")" }));
|
|
551
|
+
options.forEach(function (option) {
|
|
552
|
+
var label = field.key === "SMART_SEARCH_INTENT_ROUTER" ? t(option === "jev" ? "jevMode" : "localMode") : option;
|
|
553
|
+
select.appendChild(el("option", { value: option, text: label }));
|
|
554
|
+
});
|
|
555
|
+
select.value = value;
|
|
556
|
+
if (!locked) select.addEventListener("change", function () {
|
|
557
|
+
markDirty(field, select, select.value);
|
|
558
|
+
if (field.key === "SMART_SEARCH_INTENT_ROUTER") render();
|
|
559
|
+
});
|
|
560
|
+
if (pending.hasOwnProperty(field.key)) select.className = "dirty";
|
|
561
|
+
return select;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (field.kind === "csv" && field.key.indexOf("RESEARCH_") >= 0) {
|
|
565
|
+
var chosen = {};
|
|
566
|
+
value.split(",").forEach(function (item) {
|
|
567
|
+
item = item.trim();
|
|
568
|
+
if (item) chosen[item] = true;
|
|
569
|
+
});
|
|
570
|
+
var wrap = el("div", { class: "chips" });
|
|
571
|
+
Object.keys(state.provider_profiles || {}).sort().forEach(function (provider) {
|
|
572
|
+
var on = !!chosen[provider];
|
|
573
|
+
var chip = el("button", {
|
|
574
|
+
type: "button", class: "chip" + (on ? " on" : ""), text: provider,
|
|
575
|
+
disabled: locked ? "disabled" : null
|
|
576
|
+
});
|
|
577
|
+
chip.addEventListener("click", function () {
|
|
578
|
+
if (locked) return;
|
|
579
|
+
if (chosen[provider]) delete chosen[provider]; else chosen[provider] = true;
|
|
580
|
+
chip.className = "chip" + (chosen[provider] ? " on" : "");
|
|
581
|
+
markDirty(field, wrap, Object.keys(chosen).sort().join(","));
|
|
582
|
+
});
|
|
583
|
+
wrap.appendChild(chip);
|
|
584
|
+
});
|
|
585
|
+
return wrap;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
var secret = field.kind === "secret";
|
|
589
|
+
var input = el("input", {
|
|
590
|
+
type: secret ? "password" : "text",
|
|
591
|
+
autocomplete: secret ? "new-password" : "off",
|
|
592
|
+
spellcheck: "false",
|
|
593
|
+
placeholder: secret && saved ? saved : (field.placeholder || field.default || "")
|
|
594
|
+
});
|
|
595
|
+
// A saved secret is only ever shown masked; leaving the box empty keeps it.
|
|
596
|
+
input.value = secret ? (pending.hasOwnProperty(field.key) ? pending[field.key] : "") : value;
|
|
597
|
+
if (locked) { input.disabled = true; input.value = secret ? "" : saved; }
|
|
598
|
+
else input.addEventListener("input", function () { markDirty(field, input, input.value); });
|
|
599
|
+
if (pending.hasOwnProperty(field.key)) input.className = "dirty";
|
|
600
|
+
return input;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function editableRow(field) {
|
|
604
|
+
var source = (state.sources || {})[field.key] || "default";
|
|
605
|
+
var saved = (state.values || {})[field.key] || "";
|
|
606
|
+
var locked = source === "environment";
|
|
607
|
+
var input = fieldInput(field);
|
|
608
|
+
input.setAttribute("aria-label", L(field, "label"));
|
|
609
|
+
var side = [el("span", { class: "pill", text: sourceLabel(source) })];
|
|
610
|
+
if (locked) side.push(el("span", { class: "pill warn", text: t("envLocked") }));
|
|
611
|
+
else if (saved) side.push(el("button", {
|
|
612
|
+
class: "act ghost", type: "button", text: t("clear"),
|
|
613
|
+
onclick: function () {
|
|
614
|
+
pending[field.key] = "";
|
|
615
|
+
render();
|
|
616
|
+
clearTimeout(previewTimer);
|
|
617
|
+
previewTimer = setTimeout(runPreview, 50);
|
|
618
|
+
}
|
|
619
|
+
}));
|
|
620
|
+
var links = null;
|
|
621
|
+
if (field.key_url || field.docs_url) {
|
|
622
|
+
links = el("div", { class: "links" }, [
|
|
623
|
+
field.key_url ? el("a", {
|
|
624
|
+
href: field.key_url, target: "_blank", rel: "noopener noreferrer",
|
|
625
|
+
text: t("getKey") + " ↗"
|
|
626
|
+
}) : null,
|
|
627
|
+
field.docs_url ? el("a", {
|
|
628
|
+
href: field.docs_url, target: "_blank", rel: "noopener noreferrer",
|
|
629
|
+
text: t("readDocs") + " ↗"
|
|
630
|
+
}) : null
|
|
631
|
+
]);
|
|
632
|
+
}
|
|
633
|
+
return el("div", { class: "row" }, [
|
|
634
|
+
el("div", {}, [
|
|
635
|
+
el("label", { text: L(field, "label") }),
|
|
636
|
+
el("span", { class: "help mono", text: field.key }),
|
|
637
|
+
L(field, "help") ? el("span", { class: "help", text: L(field, "help") }) : null,
|
|
638
|
+
locked ? el("span", { class: "help", text: t("envHint") + " unset " + field.key }) : null,
|
|
639
|
+
links
|
|
640
|
+
]),
|
|
641
|
+
el("div", {}, [input]),
|
|
642
|
+
el("div", {}, side)
|
|
643
|
+
]);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function runTest(provider) {
|
|
647
|
+
if (testing[provider]) return;
|
|
648
|
+
testing[provider] = true;
|
|
649
|
+
var button = document.getElementById("btn-" + provider);
|
|
650
|
+
var result = document.getElementById("res-" + provider);
|
|
651
|
+
if (button) { button.disabled = true; button.textContent = t("testing"); }
|
|
652
|
+
if (result) { result.className = "pill"; result.textContent = "…"; }
|
|
653
|
+
var shared = (state.probe_kinds[provider] || "").replace(/^shared:/, "");
|
|
654
|
+
var overrides = {};
|
|
655
|
+
state.metadata.fields.forEach(function (field) {
|
|
656
|
+
if ((field.provider === provider || field.provider === shared) && pending.hasOwnProperty(field.key)) {
|
|
657
|
+
overrides[field.key] = pending[field.key];
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
api("POST", "/api/test", { provider: provider, overrides: overrides }).then(function (data) {
|
|
661
|
+
var good = data.status === "ok";
|
|
662
|
+
var neutral = data.status === "configured" || data.status === "not_configured";
|
|
663
|
+
if (result) {
|
|
664
|
+
result.className = "pill " + (good ? "ok" : (neutral ? "warn" : "bad"));
|
|
665
|
+
result.textContent = data.status + (data.response_time_ms ? " · " + Math.round(data.response_time_ms) + "ms" : "");
|
|
666
|
+
}
|
|
667
|
+
toast(provider + ": " + (data.message || data.status), !good && !neutral);
|
|
668
|
+
return api("GET", "/api/status");
|
|
669
|
+
}).then(function (fresh) {
|
|
670
|
+
if (fresh && fresh.ok) { Object.keys(fresh).forEach(function (k) { state[k] = fresh[k]; }); }
|
|
671
|
+
}).catch(function (e) {
|
|
672
|
+
toast(String(e), true);
|
|
673
|
+
}).then(function () {
|
|
674
|
+
testing[provider] = false;
|
|
675
|
+
if (button) { button.disabled = false; button.textContent = t("test"); }
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function runDoctor() {
|
|
680
|
+
if (!window.confirm(t("confirmAll"))) return;
|
|
681
|
+
toast(t("testing"));
|
|
682
|
+
api("POST", "/api/doctor").then(function (data) {
|
|
683
|
+
toast(data.ok ? "doctor: OK" : "doctor: " + (data.error || "FAIL"), !data.ok);
|
|
684
|
+
refresh();
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
var STEPS = [
|
|
689
|
+
{ capability: "main_search", title: "stepMain",
|
|
690
|
+
providers: ["xai-responses", "openai-compatible"] },
|
|
691
|
+
{ capability: "docs_search", title: "stepDocs",
|
|
692
|
+
providers: ["context7", "exa"] },
|
|
693
|
+
{ capability: "web_fetch", title: "stepFetch",
|
|
694
|
+
providers: ["tavily", "jina", "zhipu-mcp-reader", "zhipu-mcp", "firecrawl"] }
|
|
695
|
+
];
|
|
696
|
+
|
|
697
|
+
function viewGettingStarted() {
|
|
698
|
+
var main = document.getElementById("main");
|
|
699
|
+
var section = sectionById("getting_started");
|
|
700
|
+
main.appendChild(el("h2", {}, [
|
|
701
|
+
el("span", { text: L(section, "label") + " " }),
|
|
702
|
+
el("span", { class: "pill", id: "previewMeter", text: "" })
|
|
703
|
+
]));
|
|
704
|
+
main.appendChild(el("p", { class: "blurb", text: L(section, "blurb") }));
|
|
705
|
+
|
|
706
|
+
var wrap = el("div", { class: "steps" });
|
|
707
|
+
STEPS.forEach(function (step) {
|
|
708
|
+
var fields = state.metadata.fields.filter(function (field) {
|
|
709
|
+
return step.providers.indexOf(field.provider) >= 0
|
|
710
|
+
&& field.capabilities.indexOf(step.capability) >= 0;
|
|
711
|
+
}).sort(function (a, b) {
|
|
712
|
+
return step.providers.indexOf(a.provider) - step.providers.indexOf(b.provider);
|
|
713
|
+
});
|
|
714
|
+
var essential = fields.filter(function (f) { return f.tier !== "advanced"; });
|
|
715
|
+
var advanced = fields.filter(function (f) { return f.tier === "advanced"; });
|
|
716
|
+
var ok = ((state.capability_status || {})[step.capability] || {}).ok;
|
|
717
|
+
var kids = [
|
|
718
|
+
el("h3", {}, [
|
|
719
|
+
el("span", { text: " " + t(step.title) }),
|
|
720
|
+
el("span", { class: "mono pill", text: step.capability })
|
|
721
|
+
]),
|
|
722
|
+
el("p", { class: "note", text: t("pickOne") })
|
|
723
|
+
];
|
|
724
|
+
essential.forEach(function (field) { kids.push(editableRow(field)); });
|
|
725
|
+
if (advanced.length) {
|
|
726
|
+
kids.push(el("details", { class: "more" }, [
|
|
727
|
+
el("summary", { text: t("more") + " (" + advanced.length + ")" })
|
|
728
|
+
].concat(advanced.map(editableRow))));
|
|
729
|
+
}
|
|
730
|
+
step.providers.filter(function (provider) { return state.probe_kinds[provider]; }).forEach(function (provider) {
|
|
731
|
+
kids.push(el("p", { class: "note" }, [
|
|
732
|
+
el("button", { class: "act ghost", type: "button", id: "btn-" + provider,
|
|
733
|
+
text: t("test") + " " + provider, onclick: function () { runTest(provider); } }),
|
|
734
|
+
el("span", { class: "pill", id: "res-" + provider })
|
|
735
|
+
]));
|
|
736
|
+
});
|
|
737
|
+
wrap.appendChild(el("div", { class: "card step" + (ok ? " done" : ""), "data-step": step.capability }, kids));
|
|
738
|
+
});
|
|
739
|
+
main.appendChild(wrap);
|
|
740
|
+
main.appendChild(saveBar());
|
|
741
|
+
updateSaveBar();
|
|
742
|
+
runPreview();
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function viewSection(id) {
|
|
746
|
+
var main = document.getElementById("main");
|
|
747
|
+
var section = sectionById(id);
|
|
748
|
+
main.appendChild(el("h2", { text: L(section, "label") }));
|
|
749
|
+
main.appendChild(el("p", { class: "blurb", text: L(section, "blurb") }));
|
|
750
|
+
var fields = state.metadata.fields.filter(function (field) { return field.section === id; });
|
|
751
|
+
if (id === "routing" && effectiveValues().SMART_SEARCH_INTENT_ROUTER === "local") {
|
|
752
|
+
fields = fields.filter(function (field) {
|
|
753
|
+
return field.key.indexOf("TYPESAFE_") !== 0 && field.key.indexOf("SMART_SEARCH_JEV_") !== 0;
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
var essential = fields.filter(function (f) { return f.tier === "essential"; });
|
|
757
|
+
var rest = fields.filter(function (f) { return f.tier !== "essential"; });
|
|
758
|
+
if (essential.length) {
|
|
759
|
+
main.appendChild(el("div", { class: "card" }, [el("h3", { text: t(id === "routing" ? "routingConnection" : "required") })].concat(
|
|
760
|
+
essential.map(editableRow))));
|
|
761
|
+
}
|
|
762
|
+
if (rest.length) {
|
|
763
|
+
main.appendChild(el("div", { class: "card" }, [
|
|
764
|
+
el("h3", { text: t("optional") }),
|
|
765
|
+
el("details", { class: "more", open: essential.length ? null : "open" }, [
|
|
766
|
+
el("summary", { text: t("more") + " (" + rest.length + ")" })
|
|
767
|
+
].concat(rest.map(editableRow)))
|
|
768
|
+
]));
|
|
769
|
+
}
|
|
770
|
+
main.appendChild(saveBar());
|
|
771
|
+
updateSaveBar();
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function viewSkills() {
|
|
775
|
+
var main = document.getElementById("main");
|
|
776
|
+
var section = sectionById("skills");
|
|
777
|
+
main.appendChild(el("h2", { text: L(section, "label") }));
|
|
778
|
+
main.appendChild(el("p", { class: "blurb", text: L(section, "blurb") }));
|
|
779
|
+
var card = el("div", { class: "card" }, [el("p", { class: "note", text: "…" })]);
|
|
780
|
+
main.appendChild(card);
|
|
781
|
+
api("GET", "/api/skills?targets=" + encodeURIComponent(
|
|
782
|
+
state.skill_targets.map(function (item) { return item.id; }).join(",")
|
|
783
|
+
)).then(function (data) {
|
|
784
|
+
card.textContent = "";
|
|
785
|
+
if (!data.ok) { card.appendChild(el("p", { class: "note", text: data.error || "failed" })); return; }
|
|
786
|
+
card.appendChild(el("table", {}, [
|
|
787
|
+
el("thead", {}, [el("tr", {}, [
|
|
788
|
+
el("th", { text: t("provider") }), el("th", { text: t("status") }), el("th", { text: t("message") })
|
|
789
|
+
])]),
|
|
790
|
+
el("tbody", {}, (data.targets || []).map(function (item) {
|
|
791
|
+
var installed = ["up_to_date", "stale", "extra_files"].indexOf(item.status) >= 0;
|
|
792
|
+
var statusLabel = { up_to_date: "skillsCurrent", stale: "skillsStale", extra_files: "skillsExtra" }[item.status];
|
|
793
|
+
return el("tr", {}, [
|
|
794
|
+
el("td", { text: item.label || item.target }),
|
|
795
|
+
el("td", {}, [el("span", {
|
|
796
|
+
class: "pill " + (installed ? "ok" : ""), text: statusLabel ? t(statusLabel) : t("skillsNot")
|
|
797
|
+
})]),
|
|
798
|
+
el("td", { class: "mono", text: item.status || "" })
|
|
799
|
+
]);
|
|
800
|
+
}))
|
|
801
|
+
]));
|
|
802
|
+
card.appendChild(el("p", { class: "note", style: "margin-top:12px;margin-bottom:0" }, [
|
|
803
|
+
el("button", {
|
|
804
|
+
class: "act", type: "button", text: t("installSkill"),
|
|
805
|
+
onclick: function (event) {
|
|
806
|
+
var button = event.target;
|
|
807
|
+
button.disabled = true;
|
|
808
|
+
api("POST", "/api/skills/install", {
|
|
809
|
+
targets: (data.targets || []).map(function (item) { return item.target; })
|
|
810
|
+
}).then(function (result) {
|
|
811
|
+
toast(result.ok ? t("saved") + " (" + (result.installed_count || 0) + ")"
|
|
812
|
+
: (result.error || "failed"), !result.ok);
|
|
813
|
+
render();
|
|
814
|
+
}).then(function () { button.disabled = false; });
|
|
815
|
+
}
|
|
816
|
+
})
|
|
817
|
+
]));
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function viewTryIt() {
|
|
822
|
+
var main = document.getElementById("main");
|
|
823
|
+
var section = sectionById("tryit");
|
|
824
|
+
main.appendChild(el("h2", { text: L(section, "label") }));
|
|
825
|
+
main.appendChild(el("p", { class: "blurb", text: L(section, "blurb") }));
|
|
826
|
+
|
|
827
|
+
var box = el("input", { type: "text", placeholder: t("queryPlaceholder"), spellcheck: "false" });
|
|
828
|
+
var output = el("pre", {
|
|
829
|
+
class: "mono", style: "white-space:pre-wrap;word-break:break-word;margin:0;font-size:12px"
|
|
830
|
+
});
|
|
831
|
+
var outputCard = el("div", { class: "card", style: "display:none" }, [
|
|
832
|
+
el("h3", { text: t("result") }), output
|
|
833
|
+
]);
|
|
834
|
+
|
|
835
|
+
function run(command) {
|
|
836
|
+
var query = box.value.trim();
|
|
837
|
+
if (!query) { toast(t("needQuery"), true); return; }
|
|
838
|
+
if (command === "search" && !window.confirm(t("searchCost"))) return;
|
|
839
|
+
outputCard.style.display = "";
|
|
840
|
+
output.textContent = t("running");
|
|
841
|
+
api("POST", "/api/run", { command: command, query: query }).then(function (data) {
|
|
842
|
+
output.textContent = JSON.stringify(data, null, 2);
|
|
843
|
+
if (!data.ok) toast(data.error || "failed", true);
|
|
844
|
+
}).catch(function (e) { output.textContent = String(e); });
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
main.appendChild(el("div", { class: "card" }, [
|
|
848
|
+
el("div", { class: "row", style: "grid-template-columns:1fr" }, [el("div", {}, [box])]),
|
|
849
|
+
el("p", { class: "note", style: "margin:12px 0 0;display:flex;gap:8px;flex-wrap:wrap" }, [
|
|
850
|
+
el("button", { class: "act", type: "button", text: t("runRoute"), onclick: function () { run("route"); } }),
|
|
851
|
+
el("button", { class: "act ghost", type: "button", text: t("runSearch"), onclick: function () { run("search"); } })
|
|
852
|
+
])
|
|
853
|
+
]));
|
|
854
|
+
main.appendChild(outputCard);
|
|
855
|
+
box.addEventListener("keydown", function (event) { if (event.key === "Enter") run("route"); });
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function chainCard() {
|
|
859
|
+
var chains = state.capability_chains || {};
|
|
860
|
+
var caps = state.capability_status || {};
|
|
861
|
+
var cooling = {};
|
|
862
|
+
((state.provider_health || {}).providers || []).forEach(function (item) {
|
|
863
|
+
if (item.state === "cooldown") cooling[item.provider] = true;
|
|
864
|
+
});
|
|
865
|
+
var rows = Object.keys(chains).filter(function (name) { return caps[name]; }).map(function (name) {
|
|
866
|
+
var configured = (caps[name] || {}).configured || [];
|
|
867
|
+
var steps = [];
|
|
868
|
+
chains[name].forEach(function (provider, index) {
|
|
869
|
+
if (index) steps.push(el("span", { class: "arrow", text: "→" }));
|
|
870
|
+
var cls = cooling[provider] ? "bad" : (configured.indexOf(provider) >= 0 ? "ok" : "");
|
|
871
|
+
steps.push(el("span", {
|
|
872
|
+
class: "pill " + cls,
|
|
873
|
+
title: cooling[provider] ? t("cooldown") : "",
|
|
874
|
+
text: provider + (cooling[provider] ? " ✕" : "")
|
|
875
|
+
}));
|
|
876
|
+
});
|
|
877
|
+
return el("tr", {}, [
|
|
878
|
+
el("td", { class: "mono", text: name }),
|
|
879
|
+
el("td", { class: "chain" }, steps)
|
|
880
|
+
]);
|
|
881
|
+
});
|
|
882
|
+
return el("div", { class: "card" }, [
|
|
883
|
+
el("h3", { text: t("chain") }),
|
|
884
|
+
el("p", { class: "note", text: t("chainNote") }),
|
|
885
|
+
el("table", {}, [el("tbody", {}, rows)])
|
|
886
|
+
]);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
function sectionById(id) {
|
|
890
|
+
var found = state.metadata.sections.filter(function (item) { return item.id === id; })[0];
|
|
891
|
+
return found || { label_zh: id, label_en: id, blurb_zh: "", blurb_en: "" };
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// ---- shell ------------------------------------------------------------
|
|
895
|
+
function renderNav() {
|
|
896
|
+
var nav = document.getElementById("nav");
|
|
897
|
+
nav.textContent = "";
|
|
898
|
+
document.getElementById("subtitle").textContent = t("sub");
|
|
899
|
+
state.metadata.sections.forEach(function (section) {
|
|
900
|
+
nav.appendChild(el("button", {
|
|
901
|
+
type: "button", text: L(section, "label"),
|
|
902
|
+
"aria-current": section.id === current ? "true" : "false",
|
|
903
|
+
onclick: function () {
|
|
904
|
+
if (isDirty() && !window.confirm(t("discard") + "?")) return;
|
|
905
|
+
pending = {};
|
|
906
|
+
current = section.id;
|
|
907
|
+
render();
|
|
908
|
+
}
|
|
909
|
+
}));
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
function render() {
|
|
914
|
+
renderNav();
|
|
915
|
+
var main = document.getElementById("main");
|
|
916
|
+
main.textContent = "";
|
|
917
|
+
if (current === "status") viewStatus();
|
|
918
|
+
else if (current === "getting_started") viewGettingStarted();
|
|
919
|
+
else if (current === "providers") viewProviders();
|
|
920
|
+
else if (current === "skills") viewSkills();
|
|
921
|
+
else if (current === "tryit") viewTryIt();
|
|
922
|
+
else viewSection(current);
|
|
923
|
+
window.scrollTo(0, 0);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
function refresh() {
|
|
927
|
+
return api("GET", "/api/status").then(function (data) {
|
|
928
|
+
if (data && data.ok) {
|
|
929
|
+
Object.keys(data).forEach(function (key) { state[key] = data[key]; });
|
|
930
|
+
render();
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
document.getElementById("langToggle").addEventListener("click", function () {
|
|
936
|
+
lang = lang === "zh" ? "en" : "zh";
|
|
937
|
+
document.documentElement.lang = lang === "zh" ? "zh-CN" : "en";
|
|
938
|
+
render();
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
window.setInterval(function () { api("POST", "/api/heartbeat", {}); }, 30000);
|
|
942
|
+
|
|
943
|
+
api("GET", "/api/state").then(function (data) {
|
|
944
|
+
if (!data || !data.ok) {
|
|
945
|
+
document.getElementById("main").textContent = (data && data.error) || "failed to load";
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
state = data;
|
|
949
|
+
current = "status";
|
|
950
|
+
render();
|
|
951
|
+
});
|
|
952
|
+
})();
|
|
953
|
+
</script>
|
|
954
|
+
</body>
|
|
955
|
+
</html>
|