@dipertq/dsh-openviking-status 0.1.8 → 0.2.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/README.md +5 -13
- package/lib/client.cjs +724 -6
- package/lib/client.cjs.map +1 -1
- package/lib/client.d.cts +39 -11
- package/lib/client.js +724 -6
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +32 -4
- package/lib/index.js +1206 -5
- package/lib/index.js.map +1 -1
- package/package.json +5 -2
package/lib/client.cjs
CHANGED
|
@@ -38,6 +38,7 @@ __export(client_exports, {
|
|
|
38
38
|
COMMIT_THRESHOLD: () => COMMIT_THRESHOLD,
|
|
39
39
|
DEFAULT_OPENVIKING_ENDPOINT: () => DEFAULT_OPENVIKING_ENDPOINT,
|
|
40
40
|
OpenVikingClient: () => OpenVikingClient,
|
|
41
|
+
OpenVikingSettingsSection: () => OpenVikingSettingsSection,
|
|
41
42
|
OpenVikingStatusChip: () => OpenVikingStatusChip,
|
|
42
43
|
OpenVikingStatusPopover: () => OpenVikingStatusPopover,
|
|
43
44
|
THEME: () => THEME,
|
|
@@ -73,6 +74,7 @@ module.exports = __toCommonJS(client_exports);
|
|
|
73
74
|
|
|
74
75
|
// src/client/OpenVikingStatusChip.tsx
|
|
75
76
|
var import_react2 = __toESM(require("react"), 1);
|
|
77
|
+
var import_react_dom = __toESM(require("react-dom"), 1);
|
|
76
78
|
|
|
77
79
|
// src/client/api.ts
|
|
78
80
|
var DEFAULT_OPENVIKING_ENDPOINT = "http://127.0.0.1:1933";
|
|
@@ -126,6 +128,30 @@ var OpenVikingClient = class {
|
|
|
126
128
|
this.endpoint = resolveEndpoint(endpoint);
|
|
127
129
|
this.apiKey = resolveApiKey(apiKey);
|
|
128
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Обновление конфигурации клиента на лету (например, после сохранения настроек в UI).
|
|
133
|
+
*/
|
|
134
|
+
updateConfig(config) {
|
|
135
|
+
if (config.endpoint && config.endpoint.trim()) {
|
|
136
|
+
this.endpoint = resolveEndpoint(config.endpoint);
|
|
137
|
+
}
|
|
138
|
+
if (config.apiKey !== void 0) {
|
|
139
|
+
this.apiKey = resolveApiKey(config.apiKey);
|
|
140
|
+
}
|
|
141
|
+
this.resolvedSessionIds.clear();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Очистить кэш разрешенных идентификаторов сессий.
|
|
145
|
+
*/
|
|
146
|
+
clearResolvedSessions() {
|
|
147
|
+
this.resolvedSessionIds.clear();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Проверка, работает ли клиент через DSH Web Server proxy.
|
|
151
|
+
*/
|
|
152
|
+
isProxy() {
|
|
153
|
+
return this.endpoint.startsWith("/") || this.endpoint.includes("/openviking-status/api");
|
|
154
|
+
}
|
|
129
155
|
/**
|
|
130
156
|
* Формирование заголовков запроса, включая опциональный заголовок авторизации
|
|
131
157
|
*/
|
|
@@ -167,6 +193,32 @@ var OpenVikingClient = class {
|
|
|
167
193
|
* Проверка доступности и состояния сервиса OpenViking
|
|
168
194
|
*/
|
|
169
195
|
async checkHealth() {
|
|
196
|
+
if (this.isProxy()) {
|
|
197
|
+
try {
|
|
198
|
+
const res = await fetch(`${this.endpoint}/health`, {
|
|
199
|
+
method: "GET",
|
|
200
|
+
headers: this.getHeaders()
|
|
201
|
+
});
|
|
202
|
+
if (!res.ok) {
|
|
203
|
+
return {
|
|
204
|
+
ok: false,
|
|
205
|
+
error: `HTTP ${res.status}: ${res.statusText}`
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const body = await res.json().catch(() => ({}));
|
|
209
|
+
const isOk = body.ok !== false && body.status !== "error" && (body.ok === true || body.status === "ok" || body.status === "healthy" || res.ok);
|
|
210
|
+
return {
|
|
211
|
+
ok: isOk,
|
|
212
|
+
version: typeof body.version === "string" ? body.version : void 0,
|
|
213
|
+
storage: typeof body.storage === "string" ? body.storage : void 0
|
|
214
|
+
};
|
|
215
|
+
} catch (err) {
|
|
216
|
+
return {
|
|
217
|
+
ok: false,
|
|
218
|
+
error: err instanceof Error ? err.message : String(err)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
170
222
|
try {
|
|
171
223
|
const res = await fetch(`${this.endpoint}/health`, {
|
|
172
224
|
method: "GET",
|
|
@@ -204,6 +256,48 @@ var OpenVikingClient = class {
|
|
|
204
256
|
if (!sessionId || !sessionId.trim()) {
|
|
205
257
|
return { status: "missing" };
|
|
206
258
|
}
|
|
259
|
+
if (this.isProxy()) {
|
|
260
|
+
try {
|
|
261
|
+
const res = await fetch(
|
|
262
|
+
`${this.endpoint}/session?id=${encodeURIComponent(sessionId.trim())}`,
|
|
263
|
+
{
|
|
264
|
+
method: "GET",
|
|
265
|
+
headers: this.getHeaders()
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
if (res.status === 401 || res.status === 403) {
|
|
269
|
+
return { status: "unauthorized" };
|
|
270
|
+
}
|
|
271
|
+
if (!res.ok) {
|
|
272
|
+
return { status: "error", detail: `HTTP ${res.status}` };
|
|
273
|
+
}
|
|
274
|
+
const data = await res.json();
|
|
275
|
+
if (data.status === "unauthorized") return { status: "unauthorized" };
|
|
276
|
+
if (data.status === "missing") return { status: "missing" };
|
|
277
|
+
if (data.status === "unreachable")
|
|
278
|
+
return {
|
|
279
|
+
status: "unreachable",
|
|
280
|
+
detail: typeof data.detail === "string" ? data.detail : void 0
|
|
281
|
+
};
|
|
282
|
+
if (data.status === "error")
|
|
283
|
+
return {
|
|
284
|
+
status: "error",
|
|
285
|
+
detail: typeof data.detail === "string" ? data.detail : void 0
|
|
286
|
+
};
|
|
287
|
+
if (data.status === "ok" && data.session) {
|
|
288
|
+
return {
|
|
289
|
+
status: "ok",
|
|
290
|
+
session: data.session
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
return { status: "error", detail: "malformed response from proxy" };
|
|
294
|
+
} catch (err) {
|
|
295
|
+
return {
|
|
296
|
+
status: "unreachable",
|
|
297
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
207
301
|
const candidates = this.getCandidateSessionIds(sessionId);
|
|
208
302
|
for (const candidateId of candidates) {
|
|
209
303
|
try {
|
|
@@ -273,6 +367,31 @@ var OpenVikingClient = class {
|
|
|
273
367
|
if (!sessionId || !sessionId.trim()) {
|
|
274
368
|
return { ok: false, error: "Missing sessionId" };
|
|
275
369
|
}
|
|
370
|
+
if (this.isProxy()) {
|
|
371
|
+
try {
|
|
372
|
+
const res = await fetch(`${this.endpoint}/session/commit`, {
|
|
373
|
+
method: "POST",
|
|
374
|
+
headers: this.getHeaders(),
|
|
375
|
+
body: JSON.stringify({
|
|
376
|
+
sessionId: sessionId.trim(),
|
|
377
|
+
...options ?? { keep_recent_count: 10 }
|
|
378
|
+
})
|
|
379
|
+
});
|
|
380
|
+
if (!res.ok) {
|
|
381
|
+
return { ok: false, error: `HTTP ${res.status}` };
|
|
382
|
+
}
|
|
383
|
+
const data = await res.json().catch(() => ({}));
|
|
384
|
+
return {
|
|
385
|
+
ok: data.ok === true,
|
|
386
|
+
error: typeof data.error === "string" ? data.error : void 0
|
|
387
|
+
};
|
|
388
|
+
} catch (err) {
|
|
389
|
+
return {
|
|
390
|
+
ok: false,
|
|
391
|
+
error: err instanceof Error ? err.message : String(err)
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
}
|
|
276
395
|
const candidates = this.getCandidateSessionIds(sessionId);
|
|
277
396
|
const bodyPayload = JSON.stringify(options ?? { keep_recent_count: 10 });
|
|
278
397
|
let lastError = "Session commit failed";
|
|
@@ -352,6 +471,10 @@ var THEME = {
|
|
|
352
471
|
stateWarning: "--dsw-alias-state-warn-primary",
|
|
353
472
|
/** Утопленная поверхность: дорожка прогресс-бара. */
|
|
354
473
|
insetSurface: "--dsw-alias-bg-layer-2",
|
|
474
|
+
/** Заливка основной кнопки действий. */
|
|
475
|
+
buttonPrimaryFill: "--dsw-alias-button-primary-fill",
|
|
476
|
+
/** Цвет текста на основной кнопке действий. */
|
|
477
|
+
buttonPrimaryText: "--dsw-alias-label-primary-inverted",
|
|
355
478
|
/** Моноширинный шрифт для идентификаторов и путей. */
|
|
356
479
|
fontMono: "--dsw-font-markdown-code-font-family"
|
|
357
480
|
};
|
|
@@ -1285,8 +1408,22 @@ function StatusChipView({
|
|
|
1285
1408
|
const [isCommitting, setIsCommitting] = (0, import_react2.useState)(false);
|
|
1286
1409
|
const [commitError, setCommitError] = (0, import_react2.useState)(null);
|
|
1287
1410
|
const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
|
|
1411
|
+
const [statsHost, setStatsHost] = (0, import_react2.useState)(null);
|
|
1288
1412
|
const popoverRef = (0, import_react2.useRef)(null);
|
|
1289
1413
|
const apiClient = client ?? defaultOpenVikingClient;
|
|
1414
|
+
(0, import_react2.useEffect)(() => {
|
|
1415
|
+
if (typeof document === "undefined") return;
|
|
1416
|
+
function findHost() {
|
|
1417
|
+
const el = document.querySelector("[data-composer-stats]");
|
|
1418
|
+
setStatsHost((prev) => prev !== el ? el : prev);
|
|
1419
|
+
}
|
|
1420
|
+
findHost();
|
|
1421
|
+
const observer = new MutationObserver(() => {
|
|
1422
|
+
findHost();
|
|
1423
|
+
});
|
|
1424
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1425
|
+
return () => observer.disconnect();
|
|
1426
|
+
}, []);
|
|
1290
1427
|
const conversationText = (0, import_react2.useMemo)(() => {
|
|
1291
1428
|
if (typeof contextText === "string") return contextText;
|
|
1292
1429
|
return chatNodesToText(messages);
|
|
@@ -1372,10 +1509,11 @@ function StatusChipView({
|
|
|
1372
1509
|
sessionUnreadable
|
|
1373
1510
|
});
|
|
1374
1511
|
const label = !isOnline ? "OV offline" : sessionUnreadable ? `OV: ${recalledCount} rec \xB7 no access` : `OV: ${recalledCount} rec \xB7 ${Math.round(pendingTokens / 1e3)}k pend`;
|
|
1375
|
-
|
|
1512
|
+
const chipElement = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1376
1513
|
"span",
|
|
1377
1514
|
{
|
|
1378
1515
|
className,
|
|
1516
|
+
"data-openviking-status": "true",
|
|
1379
1517
|
style: { minWidth: 0, display: "inline-flex", position: "relative" },
|
|
1380
1518
|
ref: popoverRef,
|
|
1381
1519
|
children: [
|
|
@@ -1389,14 +1527,13 @@ function StatusChipView({
|
|
|
1389
1527
|
"aria-expanded": isOpen,
|
|
1390
1528
|
"aria-haspopup": "dialog",
|
|
1391
1529
|
style: {
|
|
1392
|
-
// Геометрия и типографика повторяют штатный чип статистики DSH:
|
|
1393
|
-
// прозрачный фон, без рамки, шрифт и кегль наследуются от строки.
|
|
1394
1530
|
boxSizing: "border-box",
|
|
1395
1531
|
maxWidth: "100%",
|
|
1396
|
-
color: themeVar("labelTertiary"),
|
|
1397
|
-
|
|
1532
|
+
color: isHovered ? themeVar("labelSecondary") : themeVar("labelTertiary"),
|
|
1533
|
+
fontFamily: "var(--dsw-font-family, system-ui)",
|
|
1534
|
+
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
1535
|
+
lineHeight: "calc(20px + var(--dsh-content-font-delta-secondary, 0px))",
|
|
1398
1536
|
fontVariantNumeric: "tabular-nums",
|
|
1399
|
-
lineHeight: "inherit",
|
|
1400
1537
|
whiteSpace: "nowrap",
|
|
1401
1538
|
background: isHovered ? themeVar("hoverBackground") : "transparent",
|
|
1402
1539
|
border: "none",
|
|
@@ -1446,6 +1583,572 @@ function StatusChipView({
|
|
|
1446
1583
|
]
|
|
1447
1584
|
}
|
|
1448
1585
|
);
|
|
1586
|
+
if (statsHost && typeof document !== "undefined") {
|
|
1587
|
+
return import_react_dom.default.createPortal(chipElement, statsHost);
|
|
1588
|
+
}
|
|
1589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1590
|
+
"div",
|
|
1591
|
+
{
|
|
1592
|
+
style: {
|
|
1593
|
+
maxWidth: "var(--dsh-chat-content-width, 748px)",
|
|
1594
|
+
boxSizing: "border-box",
|
|
1595
|
+
width: "100%",
|
|
1596
|
+
padding: "4px calc(var(--dsh-composer-side-clearance, 0px) + 16px) 0px",
|
|
1597
|
+
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
1598
|
+
lineHeight: "calc(20px + var(--dsh-content-font-delta-secondary, 0px))",
|
|
1599
|
+
justifyContent: "center",
|
|
1600
|
+
gap: "12px",
|
|
1601
|
+
margin: "0 auto",
|
|
1602
|
+
display: "flex"
|
|
1603
|
+
},
|
|
1604
|
+
children: chipElement
|
|
1605
|
+
}
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
// src/client/OpenVikingSettingsSection.tsx
|
|
1610
|
+
var import_react3 = require("react");
|
|
1611
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1612
|
+
var API_CONFIG = "/openviking-status/api/config";
|
|
1613
|
+
var API_TEST = "/openviking-status/api/test-connection";
|
|
1614
|
+
var SOURCE_LABELS = {
|
|
1615
|
+
ovcli: "Auto-detected from ~/.openviking/ovcli.conf",
|
|
1616
|
+
env: "Auto-detected from environment variables",
|
|
1617
|
+
ov: "Auto-detected from ~/.openviking/ov.conf",
|
|
1618
|
+
settings: "Custom override in DSH settings.yaml",
|
|
1619
|
+
default: "Default local configuration"
|
|
1620
|
+
};
|
|
1621
|
+
function OpenVikingSettingsSection({
|
|
1622
|
+
initialConfig,
|
|
1623
|
+
onConfigSaved,
|
|
1624
|
+
className,
|
|
1625
|
+
style
|
|
1626
|
+
}) {
|
|
1627
|
+
const [endpoint, setEndpoint] = (0, import_react3.useState)(
|
|
1628
|
+
initialConfig?.endpoint || "http://127.0.0.1:1933"
|
|
1629
|
+
);
|
|
1630
|
+
const [apiKey, setApiKey] = (0, import_react3.useState)("");
|
|
1631
|
+
const [showKey, setShowKey] = (0, import_react3.useState)(false);
|
|
1632
|
+
const [source, setSource] = (0, import_react3.useState)(
|
|
1633
|
+
initialConfig?.source || "default"
|
|
1634
|
+
);
|
|
1635
|
+
const [hasStoredKey, setHasStoredKey] = (0, import_react3.useState)(
|
|
1636
|
+
initialConfig?.hasApiKey || false
|
|
1637
|
+
);
|
|
1638
|
+
const [loading, setLoading] = (0, import_react3.useState)(!initialConfig);
|
|
1639
|
+
const [testing, setTesting] = (0, import_react3.useState)(false);
|
|
1640
|
+
const [saving, setSaving] = (0, import_react3.useState)(false);
|
|
1641
|
+
const [testResult, setTestResult] = (0, import_react3.useState)(null);
|
|
1642
|
+
const [flash, setFlash] = (0, import_react3.useState)(null);
|
|
1643
|
+
(0, import_react3.useEffect)(() => {
|
|
1644
|
+
if (initialConfig) return;
|
|
1645
|
+
let active = true;
|
|
1646
|
+
async function fetchConfig() {
|
|
1647
|
+
try {
|
|
1648
|
+
setLoading(true);
|
|
1649
|
+
const res = await fetch(API_CONFIG, { cache: "no-store" });
|
|
1650
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1651
|
+
const data = await res.json();
|
|
1652
|
+
if (!active) return;
|
|
1653
|
+
const newEp = data.endpoint || "http://127.0.0.1:1933";
|
|
1654
|
+
setEndpoint(newEp);
|
|
1655
|
+
setSource(data.source || "default");
|
|
1656
|
+
setHasStoredKey(data.hasApiKey);
|
|
1657
|
+
defaultOpenVikingClient.clearResolvedSessions();
|
|
1658
|
+
} catch {
|
|
1659
|
+
} finally {
|
|
1660
|
+
if (active) setLoading(false);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
void fetchConfig();
|
|
1664
|
+
return () => {
|
|
1665
|
+
active = false;
|
|
1666
|
+
};
|
|
1667
|
+
}, [initialConfig]);
|
|
1668
|
+
async function handleTestConnection() {
|
|
1669
|
+
setTesting(true);
|
|
1670
|
+
setTestResult(null);
|
|
1671
|
+
setFlash(null);
|
|
1672
|
+
try {
|
|
1673
|
+
const res = await fetch(API_TEST, {
|
|
1674
|
+
method: "POST",
|
|
1675
|
+
headers: { "Content-Type": "application/json" },
|
|
1676
|
+
body: JSON.stringify({
|
|
1677
|
+
endpoint: endpoint.trim(),
|
|
1678
|
+
apiKey: apiKey.trim() || void 0
|
|
1679
|
+
})
|
|
1680
|
+
});
|
|
1681
|
+
const data = await res.json();
|
|
1682
|
+
setTestResult(data);
|
|
1683
|
+
} catch (err) {
|
|
1684
|
+
setTestResult({
|
|
1685
|
+
ok: false,
|
|
1686
|
+
authenticated: false,
|
|
1687
|
+
error: String(err instanceof Error ? err.message : err)
|
|
1688
|
+
});
|
|
1689
|
+
} finally {
|
|
1690
|
+
setTesting(false);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
async function handleSave() {
|
|
1694
|
+
setSaving(true);
|
|
1695
|
+
setFlash(null);
|
|
1696
|
+
try {
|
|
1697
|
+
const res = await fetch(API_CONFIG, {
|
|
1698
|
+
method: "POST",
|
|
1699
|
+
headers: { "Content-Type": "application/json" },
|
|
1700
|
+
body: JSON.stringify({
|
|
1701
|
+
endpoint: endpoint.trim(),
|
|
1702
|
+
apiKey: apiKey.trim() || void 0
|
|
1703
|
+
})
|
|
1704
|
+
});
|
|
1705
|
+
const data = await res.json();
|
|
1706
|
+
if (!res.ok || data.error) {
|
|
1707
|
+
throw new Error(data.error || `HTTP ${res.status}`);
|
|
1708
|
+
}
|
|
1709
|
+
setFlash({ kind: "ok", message: "Settings saved successfully" });
|
|
1710
|
+
setSource("settings");
|
|
1711
|
+
defaultOpenVikingClient.clearResolvedSessions();
|
|
1712
|
+
if (apiKey.trim()) {
|
|
1713
|
+
setHasStoredKey(true);
|
|
1714
|
+
setApiKey("");
|
|
1715
|
+
}
|
|
1716
|
+
onConfigSaved?.(
|
|
1717
|
+
data.config || {
|
|
1718
|
+
endpoint,
|
|
1719
|
+
hasApiKey: hasStoredKey || Boolean(apiKey.trim()),
|
|
1720
|
+
source: "settings"
|
|
1721
|
+
}
|
|
1722
|
+
);
|
|
1723
|
+
} catch (err) {
|
|
1724
|
+
setFlash({
|
|
1725
|
+
kind: "err",
|
|
1726
|
+
message: `Failed to save: ${err instanceof Error ? err.message : String(err)}`
|
|
1727
|
+
});
|
|
1728
|
+
} finally {
|
|
1729
|
+
setSaving(false);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
async function handleReset() {
|
|
1733
|
+
setSaving(true);
|
|
1734
|
+
setFlash(null);
|
|
1735
|
+
setTestResult(null);
|
|
1736
|
+
try {
|
|
1737
|
+
const res = await fetch(API_CONFIG, {
|
|
1738
|
+
method: "POST",
|
|
1739
|
+
headers: { "Content-Type": "application/json" },
|
|
1740
|
+
body: JSON.stringify({ reset: true })
|
|
1741
|
+
});
|
|
1742
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1743
|
+
const cfgRes = await fetch(API_CONFIG, { cache: "no-store" });
|
|
1744
|
+
if (cfgRes.ok) {
|
|
1745
|
+
const data = await cfgRes.json();
|
|
1746
|
+
const newEp = data.endpoint || "http://127.0.0.1:1933";
|
|
1747
|
+
setEndpoint(newEp);
|
|
1748
|
+
setSource(data.source || "default");
|
|
1749
|
+
setHasStoredKey(data.hasApiKey);
|
|
1750
|
+
setApiKey("");
|
|
1751
|
+
defaultOpenVikingClient.clearResolvedSessions();
|
|
1752
|
+
setFlash({
|
|
1753
|
+
kind: "ok",
|
|
1754
|
+
message: "Reset to auto-detected local settings"
|
|
1755
|
+
});
|
|
1756
|
+
onConfigSaved?.(data);
|
|
1757
|
+
}
|
|
1758
|
+
} catch (err) {
|
|
1759
|
+
setFlash({
|
|
1760
|
+
kind: "err",
|
|
1761
|
+
message: `Failed to reset: ${err instanceof Error ? err.message : String(err)}`
|
|
1762
|
+
});
|
|
1763
|
+
} finally {
|
|
1764
|
+
setSaving(false);
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
const sourceBadgeText = SOURCE_LABELS[source] || SOURCE_LABELS["default"];
|
|
1768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1769
|
+
"div",
|
|
1770
|
+
{
|
|
1771
|
+
className: `ov-settings-root ${className || ""}`,
|
|
1772
|
+
style: {
|
|
1773
|
+
display: "flex",
|
|
1774
|
+
flexDirection: "column",
|
|
1775
|
+
gap: 20,
|
|
1776
|
+
maxWidth: 720,
|
|
1777
|
+
padding: "24px 28px",
|
|
1778
|
+
color: themeVar("labelPrimary"),
|
|
1779
|
+
fontSize: 14,
|
|
1780
|
+
lineHeight: 1.6,
|
|
1781
|
+
...style
|
|
1782
|
+
},
|
|
1783
|
+
children: [
|
|
1784
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1785
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1786
|
+
"div",
|
|
1787
|
+
{
|
|
1788
|
+
style: {
|
|
1789
|
+
display: "flex",
|
|
1790
|
+
alignItems: "baseline",
|
|
1791
|
+
gap: 12,
|
|
1792
|
+
marginBottom: 6
|
|
1793
|
+
},
|
|
1794
|
+
children: [
|
|
1795
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1796
|
+
"h2",
|
|
1797
|
+
{
|
|
1798
|
+
style: {
|
|
1799
|
+
fontSize: 20,
|
|
1800
|
+
fontWeight: 600,
|
|
1801
|
+
margin: 0,
|
|
1802
|
+
color: themeVar("labelPrimary")
|
|
1803
|
+
},
|
|
1804
|
+
children: "OpenViking Status"
|
|
1805
|
+
}
|
|
1806
|
+
),
|
|
1807
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1808
|
+
"span",
|
|
1809
|
+
{
|
|
1810
|
+
style: {
|
|
1811
|
+
fontSize: 12,
|
|
1812
|
+
fontWeight: 500,
|
|
1813
|
+
padding: "2px 8px",
|
|
1814
|
+
borderRadius: 6,
|
|
1815
|
+
background: themeVar("insetSurface"),
|
|
1816
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
1817
|
+
color: themeVar("labelSecondary")
|
|
1818
|
+
},
|
|
1819
|
+
children: sourceBadgeText
|
|
1820
|
+
}
|
|
1821
|
+
)
|
|
1822
|
+
]
|
|
1823
|
+
}
|
|
1824
|
+
),
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1826
|
+
"p",
|
|
1827
|
+
{
|
|
1828
|
+
style: { margin: 0, color: themeVar("labelSecondary"), fontSize: 13 },
|
|
1829
|
+
children: "Configure connection credentials for monitoring OpenViking persistent memory and session status."
|
|
1830
|
+
}
|
|
1831
|
+
)
|
|
1832
|
+
] }),
|
|
1833
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1834
|
+
"div",
|
|
1835
|
+
{
|
|
1836
|
+
style: {
|
|
1837
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
1838
|
+
borderRadius: 12,
|
|
1839
|
+
padding: 20,
|
|
1840
|
+
background: themeVar("insetSurface"),
|
|
1841
|
+
display: "flex",
|
|
1842
|
+
flexDirection: "column",
|
|
1843
|
+
gap: 16
|
|
1844
|
+
},
|
|
1845
|
+
children: [
|
|
1846
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1847
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1848
|
+
"label",
|
|
1849
|
+
{
|
|
1850
|
+
style: {
|
|
1851
|
+
display: "block",
|
|
1852
|
+
fontSize: 13,
|
|
1853
|
+
fontWeight: 600,
|
|
1854
|
+
marginBottom: 6,
|
|
1855
|
+
color: themeVar("labelPrimary")
|
|
1856
|
+
},
|
|
1857
|
+
children: "Daemon Endpoint"
|
|
1858
|
+
}
|
|
1859
|
+
),
|
|
1860
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1861
|
+
"input",
|
|
1862
|
+
{
|
|
1863
|
+
type: "text",
|
|
1864
|
+
value: endpoint,
|
|
1865
|
+
onChange: (e) => setEndpoint(e.target.value),
|
|
1866
|
+
placeholder: "http://127.0.0.1:1933",
|
|
1867
|
+
style: {
|
|
1868
|
+
width: "100%",
|
|
1869
|
+
boxSizing: "border-box",
|
|
1870
|
+
padding: "9px 12px",
|
|
1871
|
+
fontSize: 14,
|
|
1872
|
+
fontFamily: themeVar("fontMono"),
|
|
1873
|
+
borderRadius: 8,
|
|
1874
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
1875
|
+
background: themeVar("panelSurface"),
|
|
1876
|
+
color: themeVar("labelPrimary"),
|
|
1877
|
+
outline: "none"
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
),
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1882
|
+
"span",
|
|
1883
|
+
{
|
|
1884
|
+
style: {
|
|
1885
|
+
fontSize: 12,
|
|
1886
|
+
color: themeVar("labelTertiary"),
|
|
1887
|
+
marginTop: 4,
|
|
1888
|
+
display: "block"
|
|
1889
|
+
},
|
|
1890
|
+
children: "The URL of the local or remote OpenViking HTTP server. Resolved from the DSH host."
|
|
1891
|
+
}
|
|
1892
|
+
)
|
|
1893
|
+
] }),
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1896
|
+
"div",
|
|
1897
|
+
{
|
|
1898
|
+
style: {
|
|
1899
|
+
display: "flex",
|
|
1900
|
+
justifyContent: "space-between",
|
|
1901
|
+
alignItems: "center",
|
|
1902
|
+
marginBottom: 6
|
|
1903
|
+
},
|
|
1904
|
+
children: [
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1906
|
+
"label",
|
|
1907
|
+
{
|
|
1908
|
+
style: {
|
|
1909
|
+
fontSize: 13,
|
|
1910
|
+
fontWeight: 600,
|
|
1911
|
+
color: themeVar("labelPrimary")
|
|
1912
|
+
},
|
|
1913
|
+
children: "API Token (Authentication)"
|
|
1914
|
+
}
|
|
1915
|
+
),
|
|
1916
|
+
hasStoredKey && !apiKey && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1917
|
+
"span",
|
|
1918
|
+
{
|
|
1919
|
+
style: {
|
|
1920
|
+
fontSize: 12,
|
|
1921
|
+
color: themeVar("stateSuccess"),
|
|
1922
|
+
fontWeight: 500
|
|
1923
|
+
},
|
|
1924
|
+
children: "\u25CF Active token configured"
|
|
1925
|
+
}
|
|
1926
|
+
)
|
|
1927
|
+
]
|
|
1928
|
+
}
|
|
1929
|
+
),
|
|
1930
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
|
|
1931
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1932
|
+
"input",
|
|
1933
|
+
{
|
|
1934
|
+
type: showKey ? "text" : "password",
|
|
1935
|
+
value: apiKey,
|
|
1936
|
+
onChange: (e) => setApiKey(e.target.value),
|
|
1937
|
+
placeholder: hasStoredKey ? "(Token stored \u2014 leave blank to keep unchanged)" : "Optional or required if daemon uses auth_mode: api_key",
|
|
1938
|
+
style: {
|
|
1939
|
+
flex: 1,
|
|
1940
|
+
padding: "9px 12px",
|
|
1941
|
+
fontSize: 14,
|
|
1942
|
+
fontFamily: themeVar("fontMono"),
|
|
1943
|
+
borderRadius: 8,
|
|
1944
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
1945
|
+
background: themeVar("panelSurface"),
|
|
1946
|
+
color: themeVar("labelPrimary"),
|
|
1947
|
+
outline: "none"
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
),
|
|
1951
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1952
|
+
"button",
|
|
1953
|
+
{
|
|
1954
|
+
type: "button",
|
|
1955
|
+
onClick: () => setShowKey((v) => !v),
|
|
1956
|
+
style: {
|
|
1957
|
+
padding: "0 14px",
|
|
1958
|
+
fontSize: 13,
|
|
1959
|
+
fontWeight: 500,
|
|
1960
|
+
borderRadius: 8,
|
|
1961
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
1962
|
+
background: themeVar("panelSurface"),
|
|
1963
|
+
color: themeVar("labelSecondary"),
|
|
1964
|
+
cursor: "pointer"
|
|
1965
|
+
},
|
|
1966
|
+
children: showKey ? "Hide" : "Show"
|
|
1967
|
+
}
|
|
1968
|
+
)
|
|
1969
|
+
] }),
|
|
1970
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1971
|
+
"span",
|
|
1972
|
+
{
|
|
1973
|
+
style: {
|
|
1974
|
+
fontSize: 12,
|
|
1975
|
+
color: themeVar("labelTertiary"),
|
|
1976
|
+
marginTop: 4,
|
|
1977
|
+
display: "block"
|
|
1978
|
+
},
|
|
1979
|
+
children: "Required when the daemon runs with auth_mode: api_key. Local tokens are typically found in ~/.openviking/ovcli.conf."
|
|
1980
|
+
}
|
|
1981
|
+
)
|
|
1982
|
+
] }),
|
|
1983
|
+
testResult && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1984
|
+
"div",
|
|
1985
|
+
{
|
|
1986
|
+
style: {
|
|
1987
|
+
padding: "10px 14px",
|
|
1988
|
+
borderRadius: 8,
|
|
1989
|
+
fontSize: 13,
|
|
1990
|
+
display: "flex",
|
|
1991
|
+
alignItems: "center",
|
|
1992
|
+
gap: 8,
|
|
1993
|
+
border: `1px solid ${testResult.ok && testResult.authenticated ? themeVar("stateSuccess") : themeVar("stateError")}`,
|
|
1994
|
+
background: themeVar("panelSurface"),
|
|
1995
|
+
color: testResult.ok && testResult.authenticated ? themeVar("stateSuccess") : themeVar("stateError")
|
|
1996
|
+
},
|
|
1997
|
+
children: [
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: testResult.ok && testResult.authenticated ? "\u25CF" : "\u2715" }),
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 }, children: testResult.ok && testResult.authenticated ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
2000
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Connected successfully" }),
|
|
2001
|
+
testResult.version && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
|
|
2002
|
+
" \xB7 ",
|
|
2003
|
+
testResult.version
|
|
2004
|
+
] }),
|
|
2005
|
+
testResult.storage && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
|
|
2006
|
+
" (storage: ",
|
|
2007
|
+
testResult.storage,
|
|
2008
|
+
")"
|
|
2009
|
+
] })
|
|
2010
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Connection failed: " }),
|
|
2012
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: testResult.error || "Unable to reach daemon or token unauthorized" })
|
|
2013
|
+
] }) })
|
|
2014
|
+
]
|
|
2015
|
+
}
|
|
2016
|
+
),
|
|
2017
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2018
|
+
"div",
|
|
2019
|
+
{
|
|
2020
|
+
style: {
|
|
2021
|
+
display: "flex",
|
|
2022
|
+
flexWrap: "wrap",
|
|
2023
|
+
alignItems: "center",
|
|
2024
|
+
gap: 10,
|
|
2025
|
+
paddingTop: 4
|
|
2026
|
+
},
|
|
2027
|
+
children: [
|
|
2028
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2029
|
+
"button",
|
|
2030
|
+
{
|
|
2031
|
+
type: "button",
|
|
2032
|
+
disabled: testing || loading,
|
|
2033
|
+
onClick: () => void handleTestConnection(),
|
|
2034
|
+
style: {
|
|
2035
|
+
padding: "8px 16px",
|
|
2036
|
+
fontSize: 13,
|
|
2037
|
+
fontWeight: 500,
|
|
2038
|
+
borderRadius: 8,
|
|
2039
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
2040
|
+
background: themeVar("panelSurface"),
|
|
2041
|
+
color: themeVar("labelPrimary"),
|
|
2042
|
+
cursor: testing ? "not-allowed" : "pointer",
|
|
2043
|
+
opacity: testing ? 0.6 : 1
|
|
2044
|
+
},
|
|
2045
|
+
children: testing ? "Testing..." : "Test Connection"
|
|
2046
|
+
}
|
|
2047
|
+
),
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2049
|
+
"button",
|
|
2050
|
+
{
|
|
2051
|
+
type: "button",
|
|
2052
|
+
disabled: saving || loading,
|
|
2053
|
+
onClick: () => void handleSave(),
|
|
2054
|
+
style: {
|
|
2055
|
+
padding: "8px 18px",
|
|
2056
|
+
fontSize: 13,
|
|
2057
|
+
fontWeight: 600,
|
|
2058
|
+
borderRadius: 8,
|
|
2059
|
+
border: "none",
|
|
2060
|
+
background: themeVar("buttonPrimaryFill"),
|
|
2061
|
+
color: themeVar("buttonPrimaryText"),
|
|
2062
|
+
cursor: saving ? "not-allowed" : "pointer",
|
|
2063
|
+
opacity: saving ? 0.6 : 1
|
|
2064
|
+
},
|
|
2065
|
+
children: saving ? "Saving..." : "Save Settings"
|
|
2066
|
+
}
|
|
2067
|
+
),
|
|
2068
|
+
source === "settings" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2069
|
+
"button",
|
|
2070
|
+
{
|
|
2071
|
+
type: "button",
|
|
2072
|
+
disabled: saving || loading,
|
|
2073
|
+
onClick: () => void handleReset(),
|
|
2074
|
+
style: {
|
|
2075
|
+
padding: "8px 14px",
|
|
2076
|
+
fontSize: 13,
|
|
2077
|
+
fontWeight: 500,
|
|
2078
|
+
borderRadius: 8,
|
|
2079
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
2080
|
+
background: "transparent",
|
|
2081
|
+
color: themeVar("labelSecondary"),
|
|
2082
|
+
cursor: "pointer",
|
|
2083
|
+
marginLeft: "auto"
|
|
2084
|
+
},
|
|
2085
|
+
children: "Reset to Auto-detected"
|
|
2086
|
+
}
|
|
2087
|
+
),
|
|
2088
|
+
flash && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2089
|
+
"span",
|
|
2090
|
+
{
|
|
2091
|
+
style: {
|
|
2092
|
+
fontSize: 13,
|
|
2093
|
+
color: flash.kind === "ok" ? themeVar("stateSuccess") : themeVar("stateError"),
|
|
2094
|
+
fontWeight: 500
|
|
2095
|
+
},
|
|
2096
|
+
children: flash.message
|
|
2097
|
+
}
|
|
2098
|
+
)
|
|
2099
|
+
]
|
|
2100
|
+
}
|
|
2101
|
+
)
|
|
2102
|
+
]
|
|
2103
|
+
}
|
|
2104
|
+
),
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2106
|
+
"div",
|
|
2107
|
+
{
|
|
2108
|
+
style: {
|
|
2109
|
+
border: `1px solid ${themeVar("hairline")}`,
|
|
2110
|
+
borderRadius: 10,
|
|
2111
|
+
padding: "14px 18px",
|
|
2112
|
+
background: themeVar("panelSurface"),
|
|
2113
|
+
fontSize: 13,
|
|
2114
|
+
color: themeVar("labelSecondary"),
|
|
2115
|
+
lineHeight: 1.5
|
|
2116
|
+
},
|
|
2117
|
+
children: [
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2119
|
+
"p",
|
|
2120
|
+
{
|
|
2121
|
+
style: {
|
|
2122
|
+
margin: "0 0 6px 0",
|
|
2123
|
+
fontWeight: 600,
|
|
2124
|
+
color: themeVar("labelPrimary")
|
|
2125
|
+
},
|
|
2126
|
+
children: "How OpenViking connection works:"
|
|
2127
|
+
}
|
|
2128
|
+
),
|
|
2129
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("ul", { style: { margin: 0, paddingLeft: 18 }, children: [
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { style: { marginBottom: 4 }, children: "All requests to OpenViking proxy through the DSH Desktop host, making it work seamlessly even when managing DSH remotely over Tailscale, mobile, or LAN." }),
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { style: { marginBottom: 4 }, children: [
|
|
2132
|
+
"If OpenViking runs locally on the standard port (1933), the plugin auto-detects credentials from ",
|
|
2133
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: "~/.openviking/ovcli.conf" }),
|
|
2134
|
+
"."
|
|
2135
|
+
] }),
|
|
2136
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
|
|
2137
|
+
"Custom values saved here are persisted in",
|
|
2138
|
+
" ",
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: "~/.dsh/settings.yaml" }),
|
|
2140
|
+
" under the",
|
|
2141
|
+
" ",
|
|
2142
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: "openviking-status" }),
|
|
2143
|
+
" namespace."
|
|
2144
|
+
] })
|
|
2145
|
+
] })
|
|
2146
|
+
]
|
|
2147
|
+
}
|
|
2148
|
+
)
|
|
2149
|
+
]
|
|
2150
|
+
}
|
|
2151
|
+
);
|
|
1449
2152
|
}
|
|
1450
2153
|
|
|
1451
2154
|
// src/client/index.tsx
|
|
@@ -1467,6 +2170,21 @@ function apply(ctx) {
|
|
|
1467
2170
|
),
|
|
1468
2171
|
"openviking-status: composer stats chip"
|
|
1469
2172
|
);
|
|
2173
|
+
ctx.effect(
|
|
2174
|
+
() => ctx.slots.inject(
|
|
2175
|
+
"settings.section",
|
|
2176
|
+
() => ctx.slots.register(
|
|
2177
|
+
{
|
|
2178
|
+
name: "settings.section",
|
|
2179
|
+
id: "openviking-status",
|
|
2180
|
+
order: 35,
|
|
2181
|
+
label: () => "OpenViking"
|
|
2182
|
+
},
|
|
2183
|
+
OpenVikingSettingsSection
|
|
2184
|
+
)
|
|
2185
|
+
),
|
|
2186
|
+
"openviking-status: settings section"
|
|
2187
|
+
);
|
|
1470
2188
|
}
|
|
1471
2189
|
return module.exports;
|
|
1472
2190
|
},
|