ds-bot 0.1.1 → 0.1.2
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 +4 -4
- package/client.js +512 -312
- package/package.json +1 -4
- package/src/host/channel.js +3 -1
- package/src/host/dsh-update.js +8 -6
- package/src/host/update.js +26 -3
package/client.js
CHANGED
|
@@ -683,6 +683,25 @@ var ZH = {
|
|
|
683
683
|
"Compared with the day before": "与前一天相比",
|
|
684
684
|
"Compared with the {count} days before": "与再往前 {count} 天相比",
|
|
685
685
|
"{share}% of all usage from {span}": "占 {span} 全部用量的 {share}%",
|
|
686
|
+
// About
|
|
687
|
+
"About DS Bot": "关于 DS Bot",
|
|
688
|
+
"Version {version}": "版本 {version}",
|
|
689
|
+
"Star DS Bot on GitHub": "在 GitHub 上给 DS Bot 点 Star",
|
|
690
|
+
"{count} stars": "{count} 个 Star",
|
|
691
|
+
"If DS Bot helps you, a star on GitHub helps more people find it.": "如果 DS Bot 对你有用,欢迎在 GitHub 上点个 Star,让更多人看到它。",
|
|
692
|
+
Updates: "更新",
|
|
693
|
+
"Check for updates": "检查更新",
|
|
694
|
+
"Checking…": "正在检查…",
|
|
695
|
+
"Up to date": "已是最新版本",
|
|
696
|
+
"Checked {time}": "检查于 {time}",
|
|
697
|
+
"Could not check for updates.": "没能检查更新。",
|
|
698
|
+
"Update checks are off.": "已关闭更新检查。",
|
|
699
|
+
"Installed from a local folder; update it there.": "从本地文件夹安装,请在那里更新。",
|
|
700
|
+
"Updates are not offered for this install.": "这种安装方式不提供更新。",
|
|
701
|
+
Links: "链接",
|
|
702
|
+
"Source code": "源代码",
|
|
703
|
+
"Release notes": "发布说明",
|
|
704
|
+
Open: "打开",
|
|
686
705
|
// Feedback and errors
|
|
687
706
|
Feedback: "反馈",
|
|
688
707
|
"Report a problem": "报告问题",
|
|
@@ -1094,8 +1113,8 @@ function bodyOf(def, paint, flat = false) {
|
|
|
1094
1113
|
return "";
|
|
1095
1114
|
}
|
|
1096
1115
|
}
|
|
1097
|
-
var eyeMarkup = ([cx, cy, w,
|
|
1098
|
-
var happyEyeMarkup = ([cx, cy, w,
|
|
1116
|
+
var eyeMarkup = ([cx, cy, w, h30, tilt]) => `<g transform="translate(${cx} ${cy}) rotate(${tilt})"><rect class="bt-eye" x="${-w / 2}" y="${-h30 / 2}" width="${w}" height="${h30}" rx="${w / 2}"/></g>`;
|
|
1117
|
+
var happyEyeMarkup = ([cx, cy, w, h30, tilt]) => `<g transform="translate(${cx} ${cy}) rotate(${tilt})"><path class="bt-eye-happy" opacity="0" d="M${-w * 0.62} ${h30 * 0.14}Q0 ${-h30 * 0.42} ${w * 0.62} ${h30 * 0.14}" fill="none" stroke="#000" stroke-width="${w * 0.5}" stroke-linecap="round"/></g>`;
|
|
1099
1118
|
var maskBox = (size) => `maskUnits="userSpaceOnUse" x="${-size}" y="${-size}" width="${size * 3}" height="${size * 3}"`;
|
|
1100
1119
|
var holes = (def, eyes) => `<rect x="${-def.size}" y="${-def.size}" width="${def.size * 3}" height="${def.size * 3}" fill="#fff"/>${eyes}`;
|
|
1101
1120
|
var MASK_ID = "%MASK%";
|
|
@@ -1470,12 +1489,12 @@ function liveSprings(apply2) {
|
|
|
1470
1489
|
const dt = Math.min(0.5, Math.max(1e-3, (now - last) / 1e3));
|
|
1471
1490
|
last = now;
|
|
1472
1491
|
const steps = Math.ceil(dt * 240);
|
|
1473
|
-
const
|
|
1492
|
+
const h30 = dt / steps;
|
|
1474
1493
|
let moving = false;
|
|
1475
1494
|
for (const value of values.values()) {
|
|
1476
1495
|
for (let index = 0; index < steps; index += 1) {
|
|
1477
|
-
value.v += (-value.k * (value.x - value.to) - value.c * value.v) *
|
|
1478
|
-
value.x += value.v *
|
|
1496
|
+
value.v += (-value.k * (value.x - value.to) - value.c * value.v) * h30;
|
|
1497
|
+
value.x += value.v * h30;
|
|
1479
1498
|
}
|
|
1480
1499
|
if (Math.abs(value.x - value.to) < 0.05 && Math.abs(value.v) < 1) {
|
|
1481
1500
|
value.x = value.to;
|
|
@@ -2892,6 +2911,7 @@ function PinMarkIcon() {
|
|
|
2892
2911
|
}
|
|
2893
2912
|
var UnreadIcon = lineIcon(["M10 3.5a4.5 4.5 0 0 0-4.5 4.5v3L4 13.5h12L14.5 11V8", "M8.3 16a1.8 1.8 0 0 0 3.4 0", "M15.5 3.2a1.6 1.6 0 1 1 0 3.2 1.6 1.6 0 0 1 0-3.2z"]);
|
|
2894
2913
|
var PencilIcon = lineIcon(["M9 4H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-3", "M14.3 3.7a1.6 1.6 0 0 1 2.3 2.3L10.5 12l-3 .8.8-3z"]);
|
|
2914
|
+
var InfoIcon = lineIcon(["M10 3.5a6.5 6.5 0 1 1 0 13 6.5 6.5 0 0 1 0-13z", "M10 9.25v4", "M10 6.6h.01"]);
|
|
2895
2915
|
var StarLineIcon = lineIcon(["M10 3l2.1 4.3 4.7.7-3.4 3.3.8 4.7L10 13.8 5.8 16l.8-4.7L3.2 8l4.7-.7z"]);
|
|
2896
2916
|
var CopyIcon = lineIcon(["M8.5 7h6A1.5 1.5 0 0 1 16 8.5v6a1.5 1.5 0 0 1-1.5 1.5h-6A1.5 1.5 0 0 1 7 14.5v-6A1.5 1.5 0 0 1 8.5 7z", "M4 12.5V5.5A1.5 1.5 0 0 1 5.5 4H13"]);
|
|
2897
2917
|
var HideIcon = lineIcon(["M3 3l14 14", "M8.6 5.2A7.6 7.6 0 0 1 10 5c4.5 0 7 5 7 5a12.6 12.6 0 0 1-2 2.6M12.2 14.5A6.8 6.8 0 0 1 10 15c-4.5 0-7-5-7-5a12.4 12.4 0 0 1 3-3.4", "M8.5 8.5a2 2 0 0 0 3 3"]);
|
|
@@ -4369,6 +4389,16 @@ function ActivityIndicator({ sessionId, useRoster, useSessionStatus, useLive, ac
|
|
|
4369
4389
|
), host);
|
|
4370
4390
|
}
|
|
4371
4391
|
|
|
4392
|
+
// src/client/dsh-offer.js
|
|
4393
|
+
var APP_OFFER = /* @__PURE__ */ new Set(["available", "downloading", "verifying", "installing", "ready"]);
|
|
4394
|
+
var bare = (value) => String(value ?? "").trim().replace(/^v/i, "").split("+")[0];
|
|
4395
|
+
var sameVersion = (a, b) => bare(a) !== "" && bare(a) === bare(b);
|
|
4396
|
+
function showsDshRow(dsh, app) {
|
|
4397
|
+
if (!dsh?.verified || !dsh.current || sameVersion(dsh.verified, dsh.current)) return false;
|
|
4398
|
+
if (dsh.kind === "npm") return true;
|
|
4399
|
+
return dsh.kind === "app" && APP_OFFER.has(app?.phase) && sameVersion(app.version, dsh.verified);
|
|
4400
|
+
}
|
|
4401
|
+
|
|
4372
4402
|
// src/client/sidebar.js
|
|
4373
4403
|
var import_react8 = require("react");
|
|
4374
4404
|
var import_react_dom3 = require("react-dom");
|
|
@@ -4722,7 +4752,7 @@ function UpdateButton({ useUpdate, actions }) {
|
|
|
4722
4752
|
const phase = update?.phase ?? "idle";
|
|
4723
4753
|
const dsh = update?.dsh;
|
|
4724
4754
|
const dshPhase = dsh?.phase ?? "idle";
|
|
4725
|
-
const dshRow = dsh
|
|
4755
|
+
const dshRow = showsDshRow(dsh, update?.app);
|
|
4726
4756
|
if (!update?.available && !dshRow && phase === "idle" && dshPhase === "idle") return null;
|
|
4727
4757
|
const cloudPhase = phase === "installing" || dshPhase === "installing" ? "installing" : phase !== "idle" ? phase : dshPhase;
|
|
4728
4758
|
const toggle = () => {
|
|
@@ -4741,7 +4771,7 @@ function UpdateButton({ useUpdate, actions }) {
|
|
|
4741
4771
|
const label = phase === "installing" ? t("Updating DS Bot…") : dshPhase === "installing" ? t("Updating DSH…") : phase === "installed" ? t("DS Bot {version} is installed. Restart DSH to use it.", { version: update.installed ?? update.latest }) : dshPhase === "installed" ? t("Restart DSH to start using DSH {version}.", { version: dsh.installed ?? dsh.verified }) : update?.available ? t("DS Bot {version} is available", { version: update.latest }) : t("DSH {version} is available", { version: dsh?.verified });
|
|
4742
4772
|
const message = error || (phase === "failed" ? update.error : "");
|
|
4743
4773
|
const dshMessage = dshError || (dshPhase === "failed" ? dsh?.error : "");
|
|
4744
|
-
const dshText = dshPhase === "installed" ? t("Restart DSH to start using DSH {version}.", { version: dsh.installed ?? dsh.verified }) : dsh?.available === false && dsh?.blockedBy
|
|
4774
|
+
const dshText = dshPhase === "installed" ? t("Restart DSH to start using DSH {version}.", { version: dsh.installed ?? dsh.verified }) : dsh?.available === false && dsh?.blockedBy ? t("Update DS Bot {version} first.", { version: dsh.blockedBy }) : t("You have {version}.", { version: dsh?.current });
|
|
4745
4775
|
return (0, import_react8.createElement)(
|
|
4746
4776
|
import_react8.Fragment,
|
|
4747
4777
|
null,
|
|
@@ -4786,7 +4816,8 @@ function UpdateButton({ useUpdate, actions }) {
|
|
|
4786
4816
|
(0, import_react8.createElement)(
|
|
4787
4817
|
"div",
|
|
4788
4818
|
{ className: "bt-update-actions" },
|
|
4789
|
-
dsh.kind === "app" ? (0, import_react8.createElement)("button", { type: "button", className: "bt-update-go", onClick: () => actions.openAppUpdates()
|
|
4819
|
+
dsh.kind === "app" ? dsh.available ? (0, import_react8.createElement)("button", { type: "button", className: "bt-update-go", onClick: () => void actions.openAppUpdates(dsh.verified).catch(() => {
|
|
4820
|
+
}) }, t("Open updates")) : null : !dsh.available && dshPhase === "idle" ? null : dshPhase === "installed" ? null : (0, import_react8.createElement)("button", {
|
|
4790
4821
|
type: "button",
|
|
4791
4822
|
className: "bt-update-go",
|
|
4792
4823
|
disabled: dshPhase === "installing",
|
|
@@ -5089,7 +5120,7 @@ var SIDEBAR_CSS = `
|
|
|
5089
5120
|
.bt-update-go:hover:not(:disabled){opacity:.9}
|
|
5090
5121
|
.bt-update-go:active:not(:disabled){transform:scale(.96)}
|
|
5091
5122
|
.bt-update-go:disabled{opacity:.6;cursor:default}
|
|
5092
|
-
.bt-update-dsh{margin-top:12px;padding-top:12px;border-top:.5px solid var(--bt-line-2)}
|
|
5123
|
+
.bt-update-dsh:not(:first-child){margin-top:12px;padding-top:12px;border-top:.5px solid var(--bt-line-2)}
|
|
5093
5124
|
@media (prefers-reduced-motion:reduce){.bt-round.bt-update,.bt-update-pop,.bt-update .bt-cloud-arrow{animation:none}}
|
|
5094
5125
|
|
|
5095
5126
|
/* The DSH Agent row and its expanding Session list. The black whale is the
|
|
@@ -9502,55 +9533,196 @@ var FEEDBACK_CSS = `
|
|
|
9502
9533
|
@media (prefers-reduced-motion:reduce){.bt-toast{animation:none}.bt-toast[data-leaving]{transition:none}}
|
|
9503
9534
|
`;
|
|
9504
9535
|
|
|
9505
|
-
// src/client/
|
|
9536
|
+
// src/client/about.js
|
|
9506
9537
|
var import_react25 = require("react");
|
|
9538
|
+
var CHEER_MS = 1800;
|
|
9539
|
+
var starCount = (count) => new Intl.NumberFormat(dateLocale(), { notation: "compact", maximumFractionDigits: 1 }).format(count);
|
|
9540
|
+
function botHint(update) {
|
|
9541
|
+
if (update.phase === "installing") return t("Updating DS Bot…");
|
|
9542
|
+
if (update.phase === "installed") return t("Restart DSH to start using DS Bot {version}.", { version: update.installed ?? update.latest });
|
|
9543
|
+
if (update.phase === "failed") return t("The update did not finish: {reason}", { reason: hostText(update.error ?? "") });
|
|
9544
|
+
if (update.available) return t("DS Bot {version} is available", { version: update.latest });
|
|
9545
|
+
if (update.enabled === false) return t("Update checks are off.");
|
|
9546
|
+
if (update.source === "path") return t("Installed from a local folder; update it there.");
|
|
9547
|
+
if (!update.checkedAt) return null;
|
|
9548
|
+
if (!update.latest && update.source !== "registry") return t("Updates are not offered for this install.");
|
|
9549
|
+
const checked = t("Checked {time}", { time: whenText(update.checkedAt) });
|
|
9550
|
+
return `${update.latest ? t("Up to date") : t("Could not check for updates.")} · ${checked}`;
|
|
9551
|
+
}
|
|
9552
|
+
function dshHint(dsh, shown) {
|
|
9553
|
+
if (dsh.phase === "installing") return t("Updating DSH…");
|
|
9554
|
+
if (dsh.phase === "installed") return t("Restart DSH to start using DSH {version}.", { version: dsh.installed ?? dsh.verified });
|
|
9555
|
+
if (dsh.phase === "failed") return t("The update did not finish: {reason}", { reason: hostText(dsh.error ?? "") });
|
|
9556
|
+
if (dsh.available === false && dsh.blockedBy) return t("Update DS Bot {version} first.", { version: dsh.blockedBy });
|
|
9557
|
+
if (shown) return t("DSH {version} is available", { version: dsh.verified });
|
|
9558
|
+
return t("Version {version}", { version: dsh.current });
|
|
9559
|
+
}
|
|
9560
|
+
var linkProps = (href) => ({ className: "bt-soft bt-soft-sm bt-about-link", href, target: "_blank", rel: "noopener noreferrer" });
|
|
9561
|
+
function AboutPage({ useUpdate, actions, run, Section, Row: Row3 }) {
|
|
9562
|
+
const update = useUpdate((value) => value) ?? {};
|
|
9563
|
+
const [checking, setChecking] = (0, import_react25.useState)(false);
|
|
9564
|
+
const [stars, setStars] = (0, import_react25.useState)(null);
|
|
9565
|
+
(0, import_react25.useEffect)(() => {
|
|
9566
|
+
let live = true;
|
|
9567
|
+
actions.repoStars().then((count) => {
|
|
9568
|
+
if (live && Number.isInteger(count)) setStars(count);
|
|
9569
|
+
}, () => {
|
|
9570
|
+
});
|
|
9571
|
+
return () => {
|
|
9572
|
+
live = false;
|
|
9573
|
+
};
|
|
9574
|
+
}, []);
|
|
9575
|
+
const [cheer, setCheer] = (0, import_react25.useState)(true);
|
|
9576
|
+
(0, import_react25.useEffect)(() => {
|
|
9577
|
+
if (!cheer) return void 0;
|
|
9578
|
+
const timer = setTimeout(() => setCheer(false), CHEER_MS);
|
|
9579
|
+
return () => clearTimeout(timer);
|
|
9580
|
+
}, [cheer]);
|
|
9581
|
+
const check = () => {
|
|
9582
|
+
setChecking(true);
|
|
9583
|
+
void run(actions.checkUpdate()).then((done) => {
|
|
9584
|
+
setChecking(false);
|
|
9585
|
+
if (done) setCheer(true);
|
|
9586
|
+
});
|
|
9587
|
+
};
|
|
9588
|
+
const phase = update.phase ?? "idle";
|
|
9589
|
+
const dsh = update.dsh;
|
|
9590
|
+
const dshPhase = dsh?.phase ?? "idle";
|
|
9591
|
+
(0, import_react25.useEffect)(() => {
|
|
9592
|
+
if (phase === "installed" || dshPhase === "installed") setCheer(true);
|
|
9593
|
+
}, [phase, dshPhase]);
|
|
9594
|
+
const markState = checking ? "searching" : phase === "installing" || dshPhase === "installing" ? "working" : cheer ? "done" : "idle";
|
|
9595
|
+
const dshNew = showsDshRow(dsh, update.app);
|
|
9596
|
+
const dshShown = dshNew && dsh.available;
|
|
9597
|
+
const botControl = phase === "installed" ? null : update.available || phase === "installing" ? (0, import_react25.createElement)(
|
|
9598
|
+
"button",
|
|
9599
|
+
{ type: "button", className: "bt-fb-primary", disabled: phase === "installing", onClick: () => run(actions.installUpdate()) },
|
|
9600
|
+
phase === "installing" ? t("Updating…") : phase === "failed" ? t("Try again") : t("Update")
|
|
9601
|
+
) : (0, import_react25.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", disabled: checking || update.enabled === false, onClick: check }, checking ? t("Checking…") : t("Check for updates"));
|
|
9602
|
+
const dshControl = !dshNew || dshPhase === "installed" ? null : dsh.kind === "app" ? dsh.available ? (0, import_react25.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", onClick: () => run(actions.openAppUpdates(dsh.verified)) }, t("Open updates")) : null : dsh.available || dshPhase !== "idle" ? (0, import_react25.createElement)(
|
|
9603
|
+
"button",
|
|
9604
|
+
{ type: "button", className: "bt-fb-primary", disabled: dshPhase === "installing", onClick: () => run(actions.installDshUpdate()) },
|
|
9605
|
+
dshPhase === "installing" ? t("Updating…") : dshPhase === "failed" ? t("Try again") : t("Update")
|
|
9606
|
+
) : null;
|
|
9607
|
+
const repo = update.repoUrl;
|
|
9608
|
+
return [
|
|
9609
|
+
(0, import_react25.createElement)(
|
|
9610
|
+
"div",
|
|
9611
|
+
{ key: "hero", className: "bt-about-hero" },
|
|
9612
|
+
(0, import_react25.createElement)("span", { className: "bt-about-mark" }, (0, import_react25.createElement)(BotMark, { look: MAIN_LOOK, bot: { id: "about" }, size: 52, state: markState, live: true, gaze: true, pokeable: true })),
|
|
9613
|
+
(0, import_react25.createElement)(
|
|
9614
|
+
"div",
|
|
9615
|
+
{ className: "bt-about-copy" },
|
|
9616
|
+
(0, import_react25.createElement)("span", { className: "bt-about-name" }, "DS Bot"),
|
|
9617
|
+
update.current ? (0, import_react25.createElement)("span", { className: "bt-about-version" }, t("Version {version}", { version: update.current })) : null
|
|
9618
|
+
),
|
|
9619
|
+
repo ? (0, import_react25.createElement)(
|
|
9620
|
+
"a",
|
|
9621
|
+
{
|
|
9622
|
+
className: "bt-star",
|
|
9623
|
+
href: repo,
|
|
9624
|
+
target: "_blank",
|
|
9625
|
+
rel: "noopener noreferrer",
|
|
9626
|
+
title: t("Star DS Bot on GitHub"),
|
|
9627
|
+
"aria-label": stars === null ? t("Star DS Bot on GitHub") : `${t("Star DS Bot on GitHub")} · ${t("{count} stars", { count: stars })}`
|
|
9628
|
+
},
|
|
9629
|
+
(0, import_react25.createElement)("span", { className: "bt-star-main" }, (0, import_react25.createElement)("span", { className: "bt-star-icon" }, (0, import_react25.createElement)(StarLineIcon)), "Star"),
|
|
9630
|
+
stars === null ? null : (0, import_react25.createElement)("span", { className: "bt-star-count" }, starCount(stars))
|
|
9631
|
+
) : null
|
|
9632
|
+
),
|
|
9633
|
+
repo ? (0, import_react25.createElement)("p", { key: "ask", className: "bt-about-ask" }, t("If DS Bot helps you, a star on GitHub helps more people find it.")) : null,
|
|
9634
|
+
(0, import_react25.createElement)(
|
|
9635
|
+
Section,
|
|
9636
|
+
{ key: "updates", title: t("Updates") },
|
|
9637
|
+
(0, import_react25.createElement)(Row3, { label: "DS Bot", hint: botHint(update) }, botControl, update.available && update.notesUrl ? (0, import_react25.createElement)("a", linkProps(update.notesUrl), t("What's new")) : null),
|
|
9638
|
+
dsh?.current ? (0, import_react25.createElement)(Row3, { label: "DeepSeek Harness", hint: dshHint(dsh, dshShown) }, dshControl) : null
|
|
9639
|
+
),
|
|
9640
|
+
(0, import_react25.createElement)(
|
|
9641
|
+
Section,
|
|
9642
|
+
{ key: "links", title: t("Links") },
|
|
9643
|
+
repo ? (0, import_react25.createElement)(Row3, { label: t("Source code"), hint: repo.replace(/^https:\/\//, "") }, (0, import_react25.createElement)("a", linkProps(repo), (0, import_react25.createElement)(GitHubMark), t("Open"))) : null,
|
|
9644
|
+
update.notesUrl ? (0, import_react25.createElement)(Row3, { label: t("Release notes") }, (0, import_react25.createElement)("a", linkProps(update.notesUrl), t("Open"))) : null,
|
|
9645
|
+
(0, import_react25.createElement)(Row3, { label: t("Report a problem") }, (0, import_react25.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", onClick: () => actions.openSettings("feedback") }, t("Open")))
|
|
9646
|
+
)
|
|
9647
|
+
];
|
|
9648
|
+
}
|
|
9649
|
+
var ABOUT_CSS = `
|
|
9650
|
+
.bt-about-hero{display:flex;align-items:center;gap:14px;padding:16px;border:1px solid var(--bt-line);border-radius:12px;background:var(--bt-card)}
|
|
9651
|
+
.bt-about-mark{flex:none;display:inline-flex;position:relative}
|
|
9652
|
+
.bt-about-mark::before{content:'';position:absolute;inset:-20%;border-radius:50%}
|
|
9653
|
+
body:not([data-bt-motion=quiet]) .bt-about-mark:hover .bt-mark[data-live][data-state=idle]:not(.bt-mark-poke) .bt-b{rotate:8deg;translate:5% -1%;animation:bt-nuzzle .78s ease-in-out .32s infinite}
|
|
9654
|
+
body:not([data-bt-motion=quiet]) .bt-about-mark:hover .bt-mark[data-live][data-state=idle] .bt-eye{scale:1 0;animation:none}
|
|
9655
|
+
body:not([data-bt-motion=quiet]) .bt-about-mark:hover .bt-mark[data-live][data-state=idle] .bt-eye-happy{opacity:1;transition-delay:.1s}
|
|
9656
|
+
.bt-about-copy{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
|
|
9657
|
+
.bt-about-name{font-size:16px;line-height:22px;font-weight:600}
|
|
9658
|
+
.bt-about-version{font-size:12px;line-height:16px;color:var(--bt-ink-2);font-variant-numeric:tabular-nums}
|
|
9659
|
+
.bt-about-ask{margin:-10px 4px 0;font-size:12px;line-height:16px;color:var(--bt-ink-3)}
|
|
9660
|
+
.bt-star{flex:none;display:inline-flex;align-items:stretch;height:30px;border-radius:999px;border:1px solid var(--bt-line-2,var(--bt-line));overflow:hidden;color:var(--bt-ink);text-decoration:none;font-size:12px;line-height:28px;transition:transform .12s ease,border-color .15s ease}
|
|
9661
|
+
.bt-star:hover{border-color:color-mix(in srgb,#e3a008 55%,var(--bt-line))}
|
|
9662
|
+
.bt-star:active{transform:scale(.96)}
|
|
9663
|
+
.bt-star-main{display:inline-flex;align-items:center;gap:6px;padding:0 12px 0 10px;background:var(--bt-hover);font-weight:500}
|
|
9664
|
+
.bt-star-icon{display:inline-flex;color:var(--bt-ink-2);transition:color .15s ease}
|
|
9665
|
+
.bt-star-icon path{transition:fill .15s ease}
|
|
9666
|
+
.bt-star:hover .bt-star-icon{color:#e3a008;animation:bt-star-pop ${SPRING_POP.duration}ms ${SPRING_POP.easing}}
|
|
9667
|
+
.bt-star:hover .bt-star-icon path{fill:currentColor}
|
|
9668
|
+
.bt-star-count{display:inline-flex;align-items:center;padding:0 11px;border-left:1px solid var(--bt-line-2,var(--bt-line));color:var(--bt-ink-2);font-variant-numeric:tabular-nums;animation:bt-star-count-in ${SPRING_POP.duration}ms ${SPRING_POP.easing},bt-veil-in .2s ease-out}
|
|
9669
|
+
@keyframes bt-star-pop{from{scale:.6;rotate:-30deg}}
|
|
9670
|
+
@keyframes bt-star-count-in{from{translate:-6px 0}}
|
|
9671
|
+
.bt-about-link{display:inline-flex;align-items:center;gap:6px;text-decoration:none}
|
|
9672
|
+
.bt-about-link svg{width:14px;height:14px}
|
|
9673
|
+
.bt-fb-primary:disabled{opacity:.6;cursor:default;filter:none}
|
|
9674
|
+
@media (prefers-reduced-motion:reduce){.bt-star:hover .bt-star-icon,.bt-star-count{animation:none}}
|
|
9675
|
+
`;
|
|
9676
|
+
|
|
9677
|
+
// src/client/settings.js
|
|
9678
|
+
var import_react26 = require("react");
|
|
9507
9679
|
var capitalize2 = (word) => word[0].toUpperCase() + word.slice(1);
|
|
9508
|
-
var SETTINGS_PAGES = [["general", "General"], ["bots", "Bots"], ["groups", "Group chats"], ["connectors", "Connectors"], ["schedules", "Scheduled tasks"], ["usage", "Usage"], ["secrets", "Secrets"], ["feedback", "Feedback"]];
|
|
9509
|
-
var PAGE_ICONS = { ...SETTINGS_ICONS, connectors: ConnectorIcon, schedules: ClockIcon, secrets: KeyIcon, feedback: FeedbackIcon };
|
|
9680
|
+
var SETTINGS_PAGES = [["general", "General"], ["bots", "Bots"], ["groups", "Group chats"], ["connectors", "Connectors"], ["schedules", "Scheduled tasks"], ["usage", "Usage"], ["secrets", "Secrets"], ["feedback", "Feedback"], ["about", "About DS Bot"]];
|
|
9681
|
+
var PAGE_ICONS = { ...SETTINGS_ICONS, connectors: ConnectorIcon, schedules: ClockIcon, secrets: KeyIcon, feedback: FeedbackIcon, about: InfoIcon };
|
|
9510
9682
|
function SetSection({ title, children }) {
|
|
9511
|
-
return (0,
|
|
9683
|
+
return (0, import_react26.createElement)("section", { className: "bt-set-section" }, (0, import_react26.createElement)("h3", null, title), (0, import_react26.createElement)("div", { className: "bt-set-card" }, children));
|
|
9512
9684
|
}
|
|
9513
9685
|
function SetRow({ label, hint, children }) {
|
|
9514
|
-
return (0,
|
|
9686
|
+
return (0, import_react26.createElement)(
|
|
9515
9687
|
"div",
|
|
9516
9688
|
{ className: "bt-set-row" },
|
|
9517
|
-
(0,
|
|
9518
|
-
children ? (0,
|
|
9689
|
+
(0, import_react26.createElement)("div", { className: "bt-set-copy" }, (0, import_react26.createElement)("span", null, label), hint ? (0, import_react26.createElement)("span", { className: "bt-set-hint" }, hint) : null),
|
|
9690
|
+
children ? (0, import_react26.createElement)("div", { className: "bt-set-control" }, children) : null
|
|
9519
9691
|
);
|
|
9520
9692
|
}
|
|
9521
9693
|
function GeneralPage({ roster, actions, run }) {
|
|
9522
9694
|
const prefs = roster.prefs ?? {};
|
|
9523
9695
|
const themes = allThemes();
|
|
9524
9696
|
const current = themes[prefs.theme] ? prefs.theme : "deepseek";
|
|
9525
|
-
const [custom, setCustom] = (0,
|
|
9526
|
-
const timer = (0,
|
|
9527
|
-
(0,
|
|
9697
|
+
const [custom, setCustom] = (0, import_react26.useState)(prefs.accent ?? "#4d6bfe");
|
|
9698
|
+
const timer = (0, import_react26.useRef)(0);
|
|
9699
|
+
(0, import_react26.useEffect)(() => () => clearTimeout(timer.current), []);
|
|
9528
9700
|
const pickCustom = (value) => {
|
|
9529
9701
|
setCustom(value);
|
|
9530
9702
|
clearTimeout(timer.current);
|
|
9531
9703
|
timer.current = setTimeout(() => run(actions.setPrefs({ accent: value })), 350);
|
|
9532
9704
|
};
|
|
9533
9705
|
return [
|
|
9534
|
-
(0,
|
|
9706
|
+
(0, import_react26.createElement)(
|
|
9535
9707
|
SetSection,
|
|
9536
9708
|
{ key: "look", title: t("Appearance") },
|
|
9537
|
-
(0,
|
|
9709
|
+
(0, import_react26.createElement)(
|
|
9538
9710
|
SetRow,
|
|
9539
9711
|
{ label: t("Theme"), hint: t("Colors for the whole team, on every device.") },
|
|
9540
|
-
(0,
|
|
9712
|
+
(0, import_react26.createElement)(
|
|
9541
9713
|
"select",
|
|
9542
9714
|
{ className: "bt-select", "aria-label": t("Theme"), value: current, onChange: (event) => run(actions.setPrefs({ theme: event.target.value })) },
|
|
9543
|
-
Object.entries(themes).map(([id, theme]) => (0,
|
|
9715
|
+
Object.entries(themes).map(([id, theme]) => (0, import_react26.createElement)("option", { key: id, value: id }, t(theme.label)))
|
|
9544
9716
|
)
|
|
9545
9717
|
),
|
|
9546
|
-
(0,
|
|
9718
|
+
(0, import_react26.createElement)(
|
|
9547
9719
|
SetRow,
|
|
9548
9720
|
{ label: t("Accent"), hint: t("Unread marks, badges, and the brand mark.") },
|
|
9549
|
-
(0,
|
|
9721
|
+
(0, import_react26.createElement)(
|
|
9550
9722
|
"div",
|
|
9551
9723
|
{ className: "bt-swatches" },
|
|
9552
|
-
(0,
|
|
9553
|
-
ACCENT_INKS.map((ink) => (0,
|
|
9724
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-swatch bt-swatch-default", title: t("Theme accent"), "aria-label": t("Theme accent"), "aria-pressed": !prefs.accent, onClick: () => run(actions.setPrefs({ accent: null })) }),
|
|
9725
|
+
ACCENT_INKS.map((ink) => (0, import_react26.createElement)("button", {
|
|
9554
9726
|
key: ink,
|
|
9555
9727
|
type: "button",
|
|
9556
9728
|
className: "bt-swatch",
|
|
@@ -9560,21 +9732,21 @@ function GeneralPage({ roster, actions, run }) {
|
|
|
9560
9732
|
style: { background: INKS[ink][0] },
|
|
9561
9733
|
onClick: () => run(actions.setPrefs({ accent: INKS[ink][0] }))
|
|
9562
9734
|
})),
|
|
9563
|
-
(0,
|
|
9735
|
+
(0, import_react26.createElement)(
|
|
9564
9736
|
"label",
|
|
9565
9737
|
{ className: "bt-swatch bt-swatch-custom", title: t("Custom accent"), "data-on": Boolean(prefs.accent) && !ACCENT_INKS.some((ink) => INKS[ink][0] === prefs.accent) },
|
|
9566
|
-
(0,
|
|
9738
|
+
(0, import_react26.createElement)("input", { type: "color", value: custom, "aria-label": t("Custom accent"), onChange: (event) => pickCustom(event.target.value) })
|
|
9567
9739
|
)
|
|
9568
9740
|
)
|
|
9569
9741
|
)
|
|
9570
9742
|
),
|
|
9571
|
-
(0,
|
|
9743
|
+
(0, import_react26.createElement)(
|
|
9572
9744
|
SetSection,
|
|
9573
9745
|
{ key: "mode", title: t("Mode") },
|
|
9574
|
-
(0,
|
|
9746
|
+
(0, import_react26.createElement)(
|
|
9575
9747
|
SetRow,
|
|
9576
9748
|
{ label: t("Classic Agent mode") },
|
|
9577
|
-
(0,
|
|
9749
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", onClick: () => actions.setSurface("agent") }, t("Switch"))
|
|
9578
9750
|
)
|
|
9579
9751
|
)
|
|
9580
9752
|
];
|
|
@@ -9583,52 +9755,52 @@ function MainBotsSection({ roster, actions, run }) {
|
|
|
9583
9755
|
const mains = (roster.mainBotIds ?? []).map((id) => roster.byId[id]).filter(Boolean);
|
|
9584
9756
|
const [first, ...others] = mains;
|
|
9585
9757
|
const candidates = roster.bots.filter((bot) => !isMainOf(roster, bot.id));
|
|
9586
|
-
return (0,
|
|
9758
|
+
return (0, import_react26.createElement)(
|
|
9587
9759
|
SetSection,
|
|
9588
9760
|
{ title: t("Main Bot") },
|
|
9589
|
-
(0,
|
|
9761
|
+
(0, import_react26.createElement)(
|
|
9590
9762
|
SetRow,
|
|
9591
9763
|
{
|
|
9592
9764
|
label: t("Main Bot"),
|
|
9593
9765
|
hint: first ? t("First in the sidebar. Pick another Bot to hand it the role; {name} then stops being a Main Bot.", { name: first.name }) : void 0
|
|
9594
9766
|
},
|
|
9595
|
-
(0,
|
|
9767
|
+
(0, import_react26.createElement)("select", {
|
|
9596
9768
|
className: "bt-select",
|
|
9597
9769
|
"aria-label": t("Main Bot"),
|
|
9598
9770
|
value: first?.id ?? "",
|
|
9599
9771
|
onChange: (event) => run(actions.setMain(event.target.value, true, first ? { replace: first.id } : {}))
|
|
9600
|
-
}, first ? null : (0,
|
|
9772
|
+
}, first ? null : (0, import_react26.createElement)("option", { value: "" }, t("Choose a Bot…")), roster.bots.map((bot) => (0, import_react26.createElement)("option", { key: bot.id, value: bot.id }, bot.name)))
|
|
9601
9773
|
),
|
|
9602
|
-
others.map((bot) => (0,
|
|
9774
|
+
others.map((bot) => (0, import_react26.createElement)(
|
|
9603
9775
|
SetRow,
|
|
9604
9776
|
{ key: bot.id, label: bot.name, hint: t("Also a Main Bot.") },
|
|
9605
|
-
(0,
|
|
9606
|
-
(0,
|
|
9777
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", onClick: () => run(actions.setMain(bot.id, true, { primary: true })) }, t("Move to first")),
|
|
9778
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", onClick: () => run(actions.setMain(bot.id, false)) }, t("Remove Main Bot role"))
|
|
9607
9779
|
)),
|
|
9608
|
-
candidates.length > 0 ? (0,
|
|
9780
|
+
candidates.length > 0 ? (0, import_react26.createElement)(
|
|
9609
9781
|
SetRow,
|
|
9610
9782
|
{ label: t("Add a Main Bot"), hint: t("Main Bots can create and change Bots, and run every group chat.") },
|
|
9611
|
-
(0,
|
|
9783
|
+
(0, import_react26.createElement)("select", {
|
|
9612
9784
|
className: "bt-select",
|
|
9613
9785
|
"aria-label": t("Add a Main Bot"),
|
|
9614
9786
|
value: "",
|
|
9615
9787
|
onChange: (event) => {
|
|
9616
9788
|
if (event.target.value) void run(actions.setMain(event.target.value, true));
|
|
9617
9789
|
}
|
|
9618
|
-
}, (0,
|
|
9790
|
+
}, (0, import_react26.createElement)("option", { value: "" }, t("Choose a Bot…")), candidates.map((bot) => (0, import_react26.createElement)("option", { key: bot.id, value: bot.id }, bot.name)))
|
|
9619
9791
|
) : null
|
|
9620
9792
|
);
|
|
9621
9793
|
}
|
|
9622
9794
|
var MOTIONS = [["quiet", "Quiet"], ["normal", "Normal"], ["lively", "Lively"]];
|
|
9623
9795
|
function MotionSection({ roster, actions, run }) {
|
|
9624
9796
|
const motion = roster.prefs?.motion === "quiet" || roster.prefs?.motion === "lively" ? roster.prefs.motion : "normal";
|
|
9625
|
-
return (0,
|
|
9797
|
+
return (0, import_react26.createElement)(
|
|
9626
9798
|
SetSection,
|
|
9627
9799
|
{ title: t("Animation") },
|
|
9628
|
-
(0,
|
|
9800
|
+
(0, import_react26.createElement)(
|
|
9629
9801
|
SetRow,
|
|
9630
9802
|
{ label: t("Bot animation") },
|
|
9631
|
-
(0,
|
|
9803
|
+
(0, import_react26.createElement)(Segmented, { label: t("Bot animation"), value: motion, className: "bt-motion-seg" }, MOTIONS.map(([id, label]) => (0, import_react26.createElement)("button", {
|
|
9632
9804
|
key: id,
|
|
9633
9805
|
type: "button",
|
|
9634
9806
|
"aria-pressed": motion === id,
|
|
@@ -9640,69 +9812,69 @@ function MotionSection({ roster, actions, run }) {
|
|
|
9640
9812
|
);
|
|
9641
9813
|
}
|
|
9642
9814
|
function BotsPage({ roster, actions, run }) {
|
|
9643
|
-
const [creating, setCreating] = (0,
|
|
9815
|
+
const [creating, setCreating] = (0, import_react26.useState)(false);
|
|
9644
9816
|
return [
|
|
9645
|
-
(0,
|
|
9646
|
-
(0,
|
|
9647
|
-
creating ? (0,
|
|
9817
|
+
(0, import_react26.createElement)(MainBotsSection, { key: "main", roster, actions, run }),
|
|
9818
|
+
(0, import_react26.createElement)(MotionSection, { key: "motion", roster, actions, run }),
|
|
9819
|
+
creating ? (0, import_react26.createElement)(CreateBot, { key: "create", roster, actions, inline: true, onBack: () => setCreating(false), onCreated: (bot) => actions.openSettings("bots", bot.id) }) : (0, import_react26.createElement)(
|
|
9648
9820
|
"div",
|
|
9649
9821
|
{ key: "new", className: "bt-actions" },
|
|
9650
|
-
(0,
|
|
9822
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm bt-with-icon", onClick: () => setCreating(true) }, (0, import_react26.createElement)(PlusIcon), t("New Bot"))
|
|
9651
9823
|
),
|
|
9652
|
-
(0,
|
|
9824
|
+
(0, import_react26.createElement)(
|
|
9653
9825
|
SetSection,
|
|
9654
9826
|
{ key: "bots", title: t("Bots · {count}", { count: roster.bots.length }) },
|
|
9655
|
-
roster.bots.map((bot) => (0,
|
|
9827
|
+
roster.bots.map((bot) => (0, import_react26.createElement)(
|
|
9656
9828
|
"button",
|
|
9657
9829
|
{ key: bot.id, type: "button", className: "bt-set-row", onClick: () => actions.openSettings("bots", bot.id) },
|
|
9658
|
-
(0,
|
|
9830
|
+
(0, import_react26.createElement)(
|
|
9659
9831
|
"span",
|
|
9660
9832
|
{ className: "bt-set-bot" },
|
|
9661
|
-
(0,
|
|
9662
|
-
(0,
|
|
9663
|
-
bot.role ? (0,
|
|
9664
|
-
isMainOf(roster, bot.id) ? (0,
|
|
9665
|
-
bot.hidden && !isMainOf(roster, bot.id) ? (0,
|
|
9833
|
+
(0, import_react26.createElement)(BotAvatar, { bot, size: 28, badge: false, live: false }),
|
|
9834
|
+
(0, import_react26.createElement)("span", { className: "bt-row-title" }, bot.name),
|
|
9835
|
+
bot.role ? (0, import_react26.createElement)("span", { className: "bt-tag" }, bot.role) : null,
|
|
9836
|
+
isMainOf(roster, bot.id) ? (0, import_react26.createElement)("span", { className: "bt-tag" }, t("Main Bot")) : null,
|
|
9837
|
+
bot.hidden && !isMainOf(roster, bot.id) ? (0, import_react26.createElement)("span", { className: "bt-tag" }, t("Hidden")) : null
|
|
9666
9838
|
),
|
|
9667
|
-
(0,
|
|
9839
|
+
(0, import_react26.createElement)("span", { className: "bt-chevron" }, (0, import_react26.createElement)(ChevronRightIcon))
|
|
9668
9840
|
))
|
|
9669
9841
|
)
|
|
9670
9842
|
];
|
|
9671
9843
|
}
|
|
9672
9844
|
function GroupsPage({ roster, actions, run }) {
|
|
9673
|
-
const [creating, setCreating] = (0,
|
|
9845
|
+
const [creating, setCreating] = (0, import_react26.useState)(false);
|
|
9674
9846
|
return [
|
|
9675
|
-
creating ? (0,
|
|
9847
|
+
creating ? (0, import_react26.createElement)(NewGroupForm, { key: "create", roster, actions, run, onCancel: () => setCreating(false), onCreated: (room2) => actions.openSettings("groups", room2.id) }) : (0, import_react26.createElement)(
|
|
9676
9848
|
"div",
|
|
9677
9849
|
{ key: "new", className: "bt-actions" },
|
|
9678
|
-
(0,
|
|
9850
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm bt-with-icon", disabled: roster.bots.length < 2, title: roster.bots.length < 2 ? t("A group chat needs at least two Bots") : void 0, onClick: () => setCreating(true) }, (0, import_react26.createElement)(PlusIcon), t("Create group chat"))
|
|
9679
9851
|
),
|
|
9680
|
-
(0,
|
|
9852
|
+
(0, import_react26.createElement)(
|
|
9681
9853
|
SetSection,
|
|
9682
9854
|
{ key: "groups", title: t("Group chats · {count}", { count: roster.rooms.length }) },
|
|
9683
|
-
roster.rooms.length === 0 ? (0,
|
|
9855
|
+
roster.rooms.length === 0 ? (0, import_react26.createElement)(SetRow, { label: t("No group chats yet."), hint: t("A group chat lets several Bots work on one thing with you.") }) : roster.rooms.map((room2) => {
|
|
9684
9856
|
const admin = roster.byId[room2.admin];
|
|
9685
|
-
return (0,
|
|
9857
|
+
return (0, import_react26.createElement)(
|
|
9686
9858
|
"button",
|
|
9687
9859
|
{ key: room2.id, type: "button", className: "bt-set-row", onClick: () => actions.openSettings("groups", room2.id) },
|
|
9688
|
-
(0,
|
|
9860
|
+
(0, import_react26.createElement)(
|
|
9689
9861
|
"span",
|
|
9690
9862
|
{ className: "bt-set-bot" },
|
|
9691
|
-
(0,
|
|
9692
|
-
(0,
|
|
9693
|
-
(0,
|
|
9694
|
-
admin ? (0,
|
|
9695
|
-
room2.hidden ? (0,
|
|
9863
|
+
(0, import_react26.createElement)(RoomAvatar, { room: room2, roster, size: 28 }),
|
|
9864
|
+
(0, import_react26.createElement)("span", { className: "bt-row-title" }, room2.name),
|
|
9865
|
+
(0, import_react26.createElement)("span", { className: "bt-tag" }, t("{count} members", { count: room2.members.length })),
|
|
9866
|
+
admin ? (0, import_react26.createElement)("span", { className: "bt-tag bt-tag-admin" }, (0, import_react26.createElement)(AdminStar), admin.name) : null,
|
|
9867
|
+
room2.hidden ? (0, import_react26.createElement)("span", { className: "bt-tag" }, t("Hidden")) : null
|
|
9696
9868
|
),
|
|
9697
|
-
(0,
|
|
9869
|
+
(0, import_react26.createElement)("span", { className: "bt-chevron" }, (0, import_react26.createElement)(ChevronRightIcon))
|
|
9698
9870
|
);
|
|
9699
9871
|
})
|
|
9700
9872
|
)
|
|
9701
9873
|
];
|
|
9702
9874
|
}
|
|
9703
|
-
function SettingsDialog({ page, id, roster, actions, leaving = false }) {
|
|
9704
|
-
const [error, setError] = (0,
|
|
9705
|
-
const close = (0,
|
|
9875
|
+
function SettingsDialog({ page, id, roster, actions, useUpdate, leaving = false }) {
|
|
9876
|
+
const [error, setError] = (0, import_react26.useState)("");
|
|
9877
|
+
const close = (0, import_react26.useCallback)(() => actions.closeSettings(), []);
|
|
9706
9878
|
useEscape(close);
|
|
9707
9879
|
const run = (promise) => Promise.resolve(promise).then(() => {
|
|
9708
9880
|
setError("");
|
|
@@ -9720,32 +9892,32 @@ function SettingsDialog({ page, id, roster, actions, leaving = false }) {
|
|
|
9720
9892
|
const nav = useGlide(shown, { axis: "y" });
|
|
9721
9893
|
const pageKey = `${shown}:${bot?.id ?? room2?.id ?? ""}`;
|
|
9722
9894
|
const depth = bot || room2 ? 1 : 0;
|
|
9723
|
-
const last = (0,
|
|
9895
|
+
const last = (0, import_react26.useRef)({ key: pageKey, depth, move: "up" });
|
|
9724
9896
|
if (last.current.key !== pageKey) {
|
|
9725
9897
|
last.current = { key: pageKey, depth, move: depth > last.current.depth ? "in" : depth < last.current.depth ? "out" : "up" };
|
|
9726
9898
|
}
|
|
9727
|
-
const [usageOpened, setUsageOpened] = (0,
|
|
9899
|
+
const [usageOpened, setUsageOpened] = (0, import_react26.useState)(shown === "usage");
|
|
9728
9900
|
if (shown === "usage" && !usageOpened) setUsageOpened(true);
|
|
9729
|
-
const errorLine = error ? (0,
|
|
9730
|
-
return (0,
|
|
9901
|
+
const errorLine = error ? (0, import_react26.createElement)("div", { className: "bt-error", role: "alert", style: { padding: 0 } }, error) : null;
|
|
9902
|
+
return (0, import_react26.createElement)(
|
|
9731
9903
|
"div",
|
|
9732
9904
|
{ className: "bt-settings-layer", "data-leaving": leaving || void 0 },
|
|
9733
|
-
(0,
|
|
9734
|
-
(0,
|
|
9905
|
+
(0, import_react26.createElement)("div", { className: "bt-scrim", onMouseDown: close }),
|
|
9906
|
+
(0, import_react26.createElement)(
|
|
9735
9907
|
"div",
|
|
9736
9908
|
{ className: "bt-settings", role: "dialog", "aria-modal": true, "aria-label": t("DS Bot settings"), "data-wide": shown === "usage" ? "" : void 0 },
|
|
9737
|
-
(0,
|
|
9909
|
+
(0, import_react26.createElement)(
|
|
9738
9910
|
"nav",
|
|
9739
9911
|
{ ref: nav.box, className: "bt-settings-nav", "aria-label": t("Settings pages") },
|
|
9740
|
-
(0,
|
|
9741
|
-
SETTINGS_PAGES.map(([key, text]) => (0,
|
|
9912
|
+
(0, import_react26.createElement)("span", { ref: nav.thumb, className: "bt-thumb", "aria-hidden": true }),
|
|
9913
|
+
SETTINGS_PAGES.map(([key, text]) => (0, import_react26.createElement)("button", {
|
|
9742
9914
|
key,
|
|
9743
9915
|
type: "button",
|
|
9744
9916
|
className: "bt-settings-item",
|
|
9745
9917
|
"aria-current": shown === key ? "page" : void 0,
|
|
9746
9918
|
onClick: () => actions.openSettings(key)
|
|
9747
|
-
}, (0,
|
|
9748
|
-
(0,
|
|
9919
|
+
}, (0, import_react26.createElement)(PAGE_ICONS[key]), t(text))),
|
|
9920
|
+
(0, import_react26.createElement)("button", {
|
|
9749
9921
|
type: "button",
|
|
9750
9922
|
className: "bt-settings-item bt-settings-shell",
|
|
9751
9923
|
title: t("Models, providers, and the rest of DeepSeek Harness"),
|
|
@@ -9753,62 +9925,63 @@ function SettingsDialog({ page, id, roster, actions, leaving = false }) {
|
|
|
9753
9925
|
close();
|
|
9754
9926
|
openHarnessSettings();
|
|
9755
9927
|
}
|
|
9756
|
-
}, (0,
|
|
9928
|
+
}, (0, import_react26.createElement)(SlidersIcon), t("Harness settings"))
|
|
9757
9929
|
),
|
|
9758
|
-
(0,
|
|
9930
|
+
(0, import_react26.createElement)(
|
|
9759
9931
|
"div",
|
|
9760
9932
|
{ className: "bt-settings-main" },
|
|
9761
|
-
(0,
|
|
9933
|
+
(0, import_react26.createElement)(
|
|
9762
9934
|
"div",
|
|
9763
9935
|
{ className: "bt-settings-head" },
|
|
9764
|
-
back ? (0,
|
|
9765
|
-
(0,
|
|
9936
|
+
back ? (0, import_react26.createElement)("button", { type: "button", className: "bt-icon-btn", "aria-label": back, title: back, onClick: () => actions.openSettings(shown) }, (0, import_react26.createElement)(ChevronLeftIcon)) : null,
|
|
9937
|
+
(0, import_react26.createElement)("h2", { key: bot?.id ?? room2?.id ?? shown }, bot?.name ?? room2?.name ?? label)
|
|
9766
9938
|
),
|
|
9767
|
-
shown === "usage" ? null : (0,
|
|
9939
|
+
shown === "usage" ? null : (0, import_react26.createElement)(
|
|
9768
9940
|
"div",
|
|
9769
9941
|
{ key: pageKey, className: "bt-settings-scroll bt-settings-page", "data-move": last.current.move },
|
|
9770
9942
|
errorLine,
|
|
9771
|
-
shown === "general" ? (0,
|
|
9772
|
-
bot ? (0,
|
|
9773
|
-
shown === "bots" && !bot ? (0,
|
|
9774
|
-
room2 ? (0,
|
|
9775
|
-
shown === "groups" && !room2 ? (0,
|
|
9776
|
-
shown === "connectors" ? (0,
|
|
9777
|
-
shown === "schedules" ? (0,
|
|
9778
|
-
shown === "secrets" ? (0,
|
|
9779
|
-
shown === "feedback" ? (0,
|
|
9943
|
+
shown === "general" ? (0, import_react26.createElement)(GeneralPage, { roster, actions, run }) : null,
|
|
9944
|
+
bot ? (0, import_react26.createElement)("div", { className: "bt-settings-form" }, (0, import_react26.createElement)(BotSettingsForm, { key: bot.id, bot, roster, actions, run })) : null,
|
|
9945
|
+
shown === "bots" && !bot ? (0, import_react26.createElement)(BotsPage, { roster, actions, run }) : null,
|
|
9946
|
+
room2 ? (0, import_react26.createElement)("div", { className: "bt-settings-form" }, (0, import_react26.createElement)(GroupSettingsForm, { key: room2.id, room: room2, roster, actions, run })) : null,
|
|
9947
|
+
shown === "groups" && !room2 ? (0, import_react26.createElement)(GroupsPage, { roster, actions, run }) : null,
|
|
9948
|
+
shown === "connectors" ? (0, import_react26.createElement)(ConnectorsPage, { roster, actions }) : null,
|
|
9949
|
+
shown === "schedules" ? (0, import_react26.createElement)(SchedulesPage, { roster, actions, start: id ?? void 0 }) : null,
|
|
9950
|
+
shown === "secrets" ? (0, import_react26.createElement)(SecretsPage, { roster, actions, run, Section: SetSection }) : null,
|
|
9951
|
+
shown === "feedback" ? (0, import_react26.createElement)(FeedbackPage, { actions, run, Section: SetSection, Row: SetRow }) : null,
|
|
9952
|
+
shown === "about" ? (0, import_react26.createElement)(AboutPage, { useUpdate, actions, run, Section: SetSection, Row: SetRow }) : null
|
|
9780
9953
|
),
|
|
9781
|
-
usageOpened ? (0,
|
|
9954
|
+
usageOpened ? (0, import_react26.createElement)(
|
|
9782
9955
|
"div",
|
|
9783
9956
|
{ key: "usage", className: "bt-settings-scroll bt-settings-usage", "data-off": shown === "usage" ? void 0 : "", "aria-hidden": shown === "usage" ? void 0 : true },
|
|
9784
9957
|
shown === "usage" ? errorLine : null,
|
|
9785
|
-
(0,
|
|
9958
|
+
(0, import_react26.createElement)(UsagePage, { roster, actions, focusId: usageFocus })
|
|
9786
9959
|
) : null
|
|
9787
9960
|
),
|
|
9788
|
-
(0,
|
|
9961
|
+
(0, import_react26.createElement)("button", { type: "button", className: "bt-settings-close", "aria-label": t("Close settings"), onClick: close }, (0, import_react26.createElement)(CloseIcon))
|
|
9789
9962
|
)
|
|
9790
9963
|
);
|
|
9791
9964
|
}
|
|
9792
9965
|
|
|
9793
9966
|
// src/client/context-menu.js
|
|
9794
|
-
var
|
|
9967
|
+
var import_react27 = require("react");
|
|
9795
9968
|
function ContextMenu({ menu, roster, actions, leaving = false }) {
|
|
9796
9969
|
useEscape(() => actions.closeMenu());
|
|
9797
|
-
(0,
|
|
9970
|
+
(0, import_react27.useEffect)(() => {
|
|
9798
9971
|
const onDown = (event) => {
|
|
9799
9972
|
if (!(event.target instanceof Element) || !event.target.closest(".bt-menu")) actions.closeMenu();
|
|
9800
9973
|
};
|
|
9801
9974
|
window.addEventListener("mousedown", onDown);
|
|
9802
9975
|
return () => window.removeEventListener("mousedown", onDown);
|
|
9803
9976
|
}, []);
|
|
9804
|
-
const ref = (0,
|
|
9805
|
-
const [place, setPlace] = (0,
|
|
9806
|
-
(0,
|
|
9977
|
+
const ref = (0, import_react27.useRef)(null);
|
|
9978
|
+
const [place, setPlace] = (0, import_react27.useState)({ left: menu.x, top: menu.y });
|
|
9979
|
+
(0, import_react27.useLayoutEffect)(() => {
|
|
9807
9980
|
const box = ref.current?.getBoundingClientRect();
|
|
9808
9981
|
if (!box) return;
|
|
9809
9982
|
setPlace({ left: Math.max(8, Math.min(menu.x, window.innerWidth - box.width - 8)), top: Math.max(8, Math.min(menu.y, window.innerHeight - box.height - 8)) });
|
|
9810
9983
|
}, [menu.x, menu.y]);
|
|
9811
|
-
if (menu.kind === "agent" || menu.kind === "agent-session") return (0,
|
|
9984
|
+
if (menu.kind === "agent" || menu.kind === "agent-session") return (0, import_react27.createElement)(AgentMenu, { menu, roster, actions, leaving });
|
|
9812
9985
|
const bot = roster.byId[menu.id];
|
|
9813
9986
|
const room2 = roster.roomsById[menu.id];
|
|
9814
9987
|
const entry = bot ?? room2;
|
|
@@ -9839,14 +10012,14 @@ function ContextMenu({ menu, roster, actions, leaving = false }) {
|
|
|
9839
10012
|
isMainBot ? null : [room2 ? t("Delete group") : t("Delete"), TrashIcon, () => bot ? actions.deleteBot(bot.id) : actions.deleteRoom(menu.id), true]
|
|
9840
10013
|
]
|
|
9841
10014
|
].map((group) => group.filter(Boolean)).filter((group) => group.length > 0);
|
|
9842
|
-
return (0,
|
|
10015
|
+
return (0, import_react27.createElement)(
|
|
9843
10016
|
"div",
|
|
9844
10017
|
{ ref, className: "bt-menu", role: "menu", "aria-label": t("{name} actions", { name: bot?.name ?? room2.name }), style: place, "data-leaving": leaving || void 0 },
|
|
9845
|
-
groups.map((group, index) => (0,
|
|
9846
|
-
|
|
10018
|
+
groups.map((group, index) => (0, import_react27.createElement)(
|
|
10019
|
+
import_react27.Fragment,
|
|
9847
10020
|
{ key: index },
|
|
9848
|
-
index > 0 ? (0,
|
|
9849
|
-
group.map(([label, Icon, run, danger]) => (0,
|
|
10021
|
+
index > 0 ? (0, import_react27.createElement)("div", { className: "bt-menu-sep", role: "separator" }) : null,
|
|
10022
|
+
group.map(([label, Icon, run, danger]) => (0, import_react27.createElement)("button", {
|
|
9850
10023
|
key: label,
|
|
9851
10024
|
type: "button",
|
|
9852
10025
|
role: "menuitem",
|
|
@@ -9855,14 +10028,14 @@ function ContextMenu({ menu, roster, actions, leaving = false }) {
|
|
|
9855
10028
|
actions.closeMenu();
|
|
9856
10029
|
void Promise.resolve(run()).catch((error) => actions.reportError(error, "menu"));
|
|
9857
10030
|
}
|
|
9858
|
-
}, (0,
|
|
10031
|
+
}, (0, import_react27.createElement)(Icon), label))
|
|
9859
10032
|
))
|
|
9860
10033
|
);
|
|
9861
10034
|
}
|
|
9862
10035
|
function AgentMenu({ menu, roster, actions, leaving }) {
|
|
9863
|
-
const ref = (0,
|
|
9864
|
-
const [place, setPlace] = (0,
|
|
9865
|
-
(0,
|
|
10036
|
+
const ref = (0, import_react27.useRef)(null);
|
|
10037
|
+
const [place, setPlace] = (0, import_react27.useState)({ left: menu.x, top: menu.y });
|
|
10038
|
+
(0, import_react27.useLayoutEffect)(() => {
|
|
9866
10039
|
const box = ref.current?.getBoundingClientRect();
|
|
9867
10040
|
if (!box) return;
|
|
9868
10041
|
setPlace({ left: Math.max(8, Math.min(menu.x, window.innerWidth - box.width - 8)), top: Math.max(8, Math.min(menu.y, window.innerHeight - box.height - 8)) });
|
|
@@ -9884,14 +10057,14 @@ function AgentMenu({ menu, roster, actions, leaving }) {
|
|
|
9884
10057
|
[t("Archive"), TrashIcon, () => actions.archiveAgentSession(agent.id, menu.id), true]
|
|
9885
10058
|
]
|
|
9886
10059
|
];
|
|
9887
|
-
return (0,
|
|
10060
|
+
return (0, import_react27.createElement)(
|
|
9888
10061
|
"div",
|
|
9889
10062
|
{ ref, className: "bt-menu", role: "menu", "aria-label": menu.kind === "agent" ? "DSH Agent" : t("Session actions"), style: place, "data-leaving": leaving || void 0 },
|
|
9890
|
-
groups.map((group, index) => (0,
|
|
9891
|
-
|
|
10063
|
+
groups.map((group, index) => (0, import_react27.createElement)(
|
|
10064
|
+
import_react27.Fragment,
|
|
9892
10065
|
{ key: index },
|
|
9893
|
-
index > 0 ? (0,
|
|
9894
|
-
group.map(([label, Icon, run, danger]) => (0,
|
|
10066
|
+
index > 0 ? (0, import_react27.createElement)("div", { className: "bt-menu-sep", role: "separator" }) : null,
|
|
10067
|
+
group.map(([label, Icon, run, danger]) => (0, import_react27.createElement)("button", {
|
|
9895
10068
|
key: label,
|
|
9896
10069
|
type: "button",
|
|
9897
10070
|
role: "menuitem",
|
|
@@ -9900,7 +10073,7 @@ function AgentMenu({ menu, roster, actions, leaving }) {
|
|
|
9900
10073
|
actions.closeMenu();
|
|
9901
10074
|
void Promise.resolve(run()).catch((error) => console.warn("[ds-bot]", error));
|
|
9902
10075
|
}
|
|
9903
|
-
}, (0,
|
|
10076
|
+
}, (0, import_react27.createElement)(Icon), label))
|
|
9904
10077
|
))
|
|
9905
10078
|
);
|
|
9906
10079
|
}
|
|
@@ -9971,7 +10144,7 @@ function migrateStorage(storage = globalThis.localStorage) {
|
|
|
9971
10144
|
}
|
|
9972
10145
|
|
|
9973
10146
|
// src/client/details-drawer.js
|
|
9974
|
-
var
|
|
10147
|
+
var import_react28 = require("react");
|
|
9975
10148
|
function transcriptOf(list, id, name, hiddenTurns = []) {
|
|
9976
10149
|
const outline = list.projectionsBySession?.[id]?.values?.turnOutline ?? list.byId[id]?.projectionValues?.turnOutline;
|
|
9977
10150
|
if (!Array.isArray(outline)) return "";
|
|
@@ -9996,10 +10169,10 @@ var EMPTY_TABS = { ids: [], active: null };
|
|
|
9996
10169
|
var PERMISSION_LABELS = { "read-only": "Read only", "workspace-write": "Workspace", "danger-full-access": "Full access" };
|
|
9997
10170
|
var DANGER = /* @__PURE__ */ new Set(["danger-full-access"]);
|
|
9998
10171
|
function PermissionRow({ bot, roster, actions, run }) {
|
|
9999
|
-
const [pending, setPending] = (0,
|
|
10172
|
+
const [pending, setPending] = (0, import_react28.useState)(null);
|
|
10000
10173
|
const catalog = roster.permissions;
|
|
10001
10174
|
const saved = bot.permission ?? catalog?.defaultPreset;
|
|
10002
|
-
(0,
|
|
10175
|
+
(0, import_react28.useEffect)(() => {
|
|
10003
10176
|
if (pending === saved) setPending(null);
|
|
10004
10177
|
}, [pending, saved]);
|
|
10005
10178
|
if (!catalog?.options?.length) return null;
|
|
@@ -10009,14 +10182,14 @@ function PermissionRow({ bot, roster, actions, run }) {
|
|
|
10009
10182
|
setPending(value);
|
|
10010
10183
|
void run(actions.updateBot(bot.id, { permission: value })).catch(() => setPending(null));
|
|
10011
10184
|
};
|
|
10012
|
-
return (0,
|
|
10185
|
+
return (0, import_react28.createElement)(
|
|
10013
10186
|
"div",
|
|
10014
10187
|
{ className: "bt-drawer-permission" },
|
|
10015
|
-
(0,
|
|
10016
|
-
(0,
|
|
10188
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t("Permissions")),
|
|
10189
|
+
(0, import_react28.createElement)(
|
|
10017
10190
|
Segmented,
|
|
10018
10191
|
{ label: t("Permissions"), value: current },
|
|
10019
|
-
catalog.options.map((option) => (0,
|
|
10192
|
+
catalog.options.map((option) => (0, import_react28.createElement)("button", {
|
|
10020
10193
|
key: option.value,
|
|
10021
10194
|
type: "button",
|
|
10022
10195
|
"aria-pressed": option.value === current,
|
|
@@ -10030,42 +10203,42 @@ function PermissionRow({ bot, roster, actions, run }) {
|
|
|
10030
10203
|
function BrowserCards({ bot, sessionId, roster, actions, useBrowserTabs, useBrowserPages }) {
|
|
10031
10204
|
const state = useBrowserTabs((map) => map[bot.id] ?? EMPTY_TABS);
|
|
10032
10205
|
const pages = useBrowserPages((map) => map);
|
|
10033
|
-
(0,
|
|
10206
|
+
(0, import_react28.useEffect)(() => {
|
|
10034
10207
|
actions.browserEnsure?.(bot.id);
|
|
10035
10208
|
}, [bot.id]);
|
|
10036
10209
|
if (roster.browser !== true || !actions.browserShow) {
|
|
10037
|
-
return (0,
|
|
10210
|
+
return (0, import_react28.createElement)("div", { className: "bt-muted" }, t("The browser is in the DSH Desktop app."));
|
|
10038
10211
|
}
|
|
10039
10212
|
if (state.ids.length === 0) {
|
|
10040
|
-
return (0,
|
|
10213
|
+
return (0, import_react28.createElement)(
|
|
10041
10214
|
"div",
|
|
10042
10215
|
{ className: "bt-browser-empty-mark" },
|
|
10043
|
-
(0,
|
|
10044
|
-
(0,
|
|
10045
|
-
(0,
|
|
10046
|
-
(0,
|
|
10216
|
+
(0, import_react28.createElement)(BotMark, { bot, size: 40, state: "idle", live: true }),
|
|
10217
|
+
(0, import_react28.createElement)("div", { className: "bt-browser-empty-title" }, t("{name}'s browser", { name: bot.name })),
|
|
10218
|
+
(0, import_react28.createElement)("div", { className: "bt-muted" }, t("Open a page here and {name} can read it with you. Logins and cookies stay with {name}; other Bots never see them.", { name: bot.name })),
|
|
10219
|
+
(0, import_react28.createElement)("button", { type: "button", className: "bt-browser-retry", onClick: () => actions.openBrowser(sessionId) }, t("Open browser"))
|
|
10047
10220
|
);
|
|
10048
10221
|
}
|
|
10049
|
-
return (0,
|
|
10222
|
+
return (0, import_react28.createElement)(
|
|
10050
10223
|
"div",
|
|
10051
10224
|
{ className: "bt-bcards" },
|
|
10052
10225
|
state.ids.map((tabId, index) => {
|
|
10053
10226
|
const page = pages[tabId] ?? {};
|
|
10054
10227
|
const label = page.title || shortUrl(page.url) || t("New tab");
|
|
10055
|
-
return (0,
|
|
10228
|
+
return (0, import_react28.createElement)(
|
|
10056
10229
|
"div",
|
|
10057
10230
|
{ key: tabId, className: "bt-bcard", "data-active": state.active === tabId || void 0, style: { animationDelay: `${index * 30}ms` } },
|
|
10058
|
-
(0,
|
|
10231
|
+
(0, import_react28.createElement)(
|
|
10059
10232
|
"button",
|
|
10060
10233
|
{ type: "button", className: "bt-bcard-shot", "aria-label": t("Open {title}", { title: label }), title: page.url, onClick: () => actions.browserPick(sessionId, tabId) },
|
|
10061
|
-
page.excerpt ? (0,
|
|
10234
|
+
page.excerpt ? (0, import_react28.createElement)(
|
|
10062
10235
|
"span",
|
|
10063
10236
|
{ className: "bt-bcard-preview" },
|
|
10064
|
-
(0,
|
|
10065
|
-
(0,
|
|
10066
|
-
) : (0,
|
|
10237
|
+
(0, import_react28.createElement)("span", { className: "bt-bcard-ptitle" }, label),
|
|
10238
|
+
(0, import_react28.createElement)("span", { className: "bt-bcard-excerpt" }, page.excerpt)
|
|
10239
|
+
) : (0, import_react28.createElement)("span", { className: "bt-bcard-blank" }, (0, import_react28.createElement)(GlobeIcon), (0, import_react28.createElement)("span", null, label))
|
|
10067
10240
|
),
|
|
10068
|
-
(0,
|
|
10241
|
+
(0, import_react28.createElement)("button", {
|
|
10069
10242
|
type: "button",
|
|
10070
10243
|
className: "bt-bcard-x",
|
|
10071
10244
|
"aria-label": t("Close tab"),
|
|
@@ -10074,62 +10247,62 @@ function BrowserCards({ bot, sessionId, roster, actions, useBrowserTabs, useBrow
|
|
|
10074
10247
|
void actions.browserCloseTab(bot.id, tabId);
|
|
10075
10248
|
}
|
|
10076
10249
|
}, "×"),
|
|
10077
|
-
(0,
|
|
10250
|
+
(0, import_react28.createElement)(
|
|
10078
10251
|
"div",
|
|
10079
10252
|
{ className: "bt-bcard-row" },
|
|
10080
|
-
(0,
|
|
10081
|
-
(0,
|
|
10082
|
-
page.url ? (0,
|
|
10253
|
+
(0, import_react28.createElement)(Favicon, { src: page.favicon, className: "bt-bcard-fav" }),
|
|
10254
|
+
(0, import_react28.createElement)("span", { className: "bt-bcard-title" }, label),
|
|
10255
|
+
page.url ? (0, import_react28.createElement)("span", { className: "bt-bcard-host" }, hostOf(page.url)) : null
|
|
10083
10256
|
)
|
|
10084
10257
|
);
|
|
10085
10258
|
}),
|
|
10086
|
-
(0,
|
|
10259
|
+
(0, import_react28.createElement)("button", { type: "button", className: "bt-bcard-new", style: { animationDelay: `${state.ids.length * 30}ms` }, onClick: () => actions.browserNewTab(sessionId) }, (0, import_react28.createElement)(PlusIcon), t("New tab"))
|
|
10087
10260
|
);
|
|
10088
10261
|
}
|
|
10089
10262
|
function About({ text, title = "About" }) {
|
|
10090
|
-
const [open, setOpen] = (0,
|
|
10263
|
+
const [open, setOpen] = (0, import_react28.useState)(false);
|
|
10091
10264
|
const long = text.split("\n").length > 5 || text.length > 240;
|
|
10092
|
-
const body = (0,
|
|
10265
|
+
const body = (0, import_react28.useRef)(null);
|
|
10093
10266
|
useMorph(body, open);
|
|
10094
|
-
return (0,
|
|
10267
|
+
return (0, import_react28.createElement)(
|
|
10095
10268
|
"div",
|
|
10096
10269
|
null,
|
|
10097
|
-
(0,
|
|
10098
|
-
(0,
|
|
10099
|
-
long ? (0,
|
|
10270
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t(title)),
|
|
10271
|
+
(0, import_react28.createElement)("div", { ref: body, className: "bt-about", "data-open": open || void 0 }, text),
|
|
10272
|
+
long ? (0, import_react28.createElement)("button", { type: "button", className: "bt-more", onClick: () => setOpen((value) => !value) }, open ? t("Show less") : t("Show more")) : null
|
|
10100
10273
|
);
|
|
10101
10274
|
}
|
|
10102
10275
|
function GroupOverview({ room: room2, roster, actions, usage, openSettings }) {
|
|
10103
10276
|
const members = room2.members.map((id) => roster.byId[id]).filter(Boolean);
|
|
10104
10277
|
return [
|
|
10105
|
-
room2.notice ? (0,
|
|
10106
|
-
(0,
|
|
10278
|
+
room2.notice ? (0, import_react28.createElement)(About, { key: "notice", title: "Notice", text: room2.notice }) : (0, import_react28.createElement)("button", { key: "notice", type: "button", className: "bt-more", onClick: openSettings }, t("Add a notice in group settings")),
|
|
10279
|
+
(0, import_react28.createElement)(
|
|
10107
10280
|
"div",
|
|
10108
10281
|
{ key: "members" },
|
|
10109
|
-
(0,
|
|
10110
|
-
(0,
|
|
10282
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t("Members · {count}", { count: members.length })),
|
|
10283
|
+
(0, import_react28.createElement)("div", { className: "bt-members", role: "list" }, members.map((member) => (0, import_react28.createElement)(
|
|
10111
10284
|
"div",
|
|
10112
10285
|
{ key: member.id, className: "bt-member", role: "listitem" },
|
|
10113
|
-
(0,
|
|
10286
|
+
(0, import_react28.createElement)(
|
|
10114
10287
|
"button",
|
|
10115
10288
|
{ type: "button", className: "bt-member-name", title: t("Open {name}'s chat", { name: member.name }), onClick: () => actions.openSession(member.id) },
|
|
10116
|
-
(0,
|
|
10117
|
-
(0,
|
|
10289
|
+
(0, import_react28.createElement)(BotAvatar, { bot: member, size: 26, main: isMainOf(roster, member.id), admin: room2.admin === member.id, live: false }),
|
|
10290
|
+
(0, import_react28.createElement)("span", null, member.name)
|
|
10118
10291
|
),
|
|
10119
|
-
room2.admin === member.id ? (0,
|
|
10292
|
+
room2.admin === member.id ? (0, import_react28.createElement)("span", { className: "bt-chip bt-chip-admin" }, t("Admin")) : null
|
|
10120
10293
|
)))
|
|
10121
10294
|
),
|
|
10122
|
-
(0,
|
|
10295
|
+
(0, import_react28.createElement)(
|
|
10123
10296
|
"div",
|
|
10124
10297
|
{ key: "mode" },
|
|
10125
|
-
(0,
|
|
10126
|
-
(0,
|
|
10298
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t("Who answers")),
|
|
10299
|
+
(0, import_react28.createElement)("div", { className: "bt-kv" }, (0, import_react28.createElement)("span", null, t(ROOM_MODES.find(([id]) => id === shownMode(room2, roster))?.[1] ?? "Everyone")))
|
|
10127
10300
|
),
|
|
10128
|
-
usage ? (0,
|
|
10301
|
+
usage ? (0, import_react28.createElement)(
|
|
10129
10302
|
"div",
|
|
10130
10303
|
{ key: "usage" },
|
|
10131
|
-
(0,
|
|
10132
|
-
(0,
|
|
10304
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t("Usage")),
|
|
10305
|
+
(0, import_react28.createElement)("div", { className: "bt-kv" }, (0, import_react28.createElement)("span", null, room2.name), (0, import_react28.createElement)("span", null, usage))
|
|
10133
10306
|
) : null
|
|
10134
10307
|
];
|
|
10135
10308
|
}
|
|
@@ -10137,15 +10310,15 @@ function DetailsDrawer({ sessionId, startRenaming, startTab, hasStrip, roster, a
|
|
|
10137
10310
|
const owner = roster.byId[sessionId];
|
|
10138
10311
|
const part = owner ? currentPart(owner) : sessionId;
|
|
10139
10312
|
const isMainBot = isMainOf(roster, owner?.id);
|
|
10140
|
-
const [tab, setTab] = (0,
|
|
10313
|
+
const [tab, setTab] = (0, import_react28.useState)("details");
|
|
10141
10314
|
const room2 = roster.roomsById[sessionId];
|
|
10142
|
-
const [view, setView] = (0,
|
|
10143
|
-
const [editing, setEditing] = (0,
|
|
10144
|
-
const [draftName, setDraftName] = (0,
|
|
10145
|
-
const [copied, setCopied] = (0,
|
|
10146
|
-
const [error, setError] = (0,
|
|
10315
|
+
const [view, setView] = (0, import_react28.useState)(startTab === "settings" && (owner || room2) ? "settings" : "overview");
|
|
10316
|
+
const [editing, setEditing] = (0, import_react28.useState)(Boolean(startRenaming && (roster.byId[sessionId] || roster.roomsById[sessionId])));
|
|
10317
|
+
const [draftName, setDraftName] = (0, import_react28.useState)(roster.byId[sessionId]?.name ?? (roster.roomsById[sessionId]?.named ? roster.roomsById[sessionId].name : ""));
|
|
10318
|
+
const [copied, setCopied] = (0, import_react28.useState)(false);
|
|
10319
|
+
const [error, setError] = (0, import_react28.useState)("");
|
|
10147
10320
|
const glide = useGlide(tab);
|
|
10148
|
-
const last = (0,
|
|
10321
|
+
const last = (0, import_react28.useRef)({ view, tab, move: void 0 });
|
|
10149
10322
|
if (last.current.view !== view) last.current = { view, tab, move: view === "settings" ? "in" : "out" };
|
|
10150
10323
|
else if (last.current.tab !== tab) last.current = { view, tab, move: "tab" };
|
|
10151
10324
|
const move = last.current.move;
|
|
@@ -10170,36 +10343,36 @@ function DetailsDrawer({ sessionId, startRenaming, startTab, hasStrip, roster, a
|
|
|
10170
10343
|
setTimeout(() => setCopied(false), 1600);
|
|
10171
10344
|
});
|
|
10172
10345
|
};
|
|
10173
|
-
const errorLine = error ? (0,
|
|
10346
|
+
const errorLine = error ? (0, import_react28.createElement)("div", { className: "bt-error", role: "alert", style: { padding: 0 } }, error) : null;
|
|
10174
10347
|
if ((bot || room2) && view === "settings") {
|
|
10175
10348
|
return [
|
|
10176
|
-
(0,
|
|
10349
|
+
(0, import_react28.createElement)(
|
|
10177
10350
|
"div",
|
|
10178
10351
|
{ key: "head", className: "bt-subhead", "data-move": move },
|
|
10179
|
-
(0,
|
|
10180
|
-
(0,
|
|
10181
|
-
hasStrip ? null : (0,
|
|
10352
|
+
(0, import_react28.createElement)("button", { type: "button", className: "bt-icon-btn", "aria-label": t("Back to details"), onClick: () => setView("overview") }, (0, import_react28.createElement)(ChevronLeftIcon)),
|
|
10353
|
+
(0, import_react28.createElement)("span", { className: "bt-subhead-title" }, bot ? t("Settings") : t("Group settings")),
|
|
10354
|
+
hasStrip ? null : (0, import_react28.createElement)("button", { type: "button", className: "bt-icon-btn", "aria-label": t("Close details"), onClick: close }, (0, import_react28.createElement)(CloseIcon))
|
|
10182
10355
|
),
|
|
10183
|
-
(0,
|
|
10356
|
+
(0, import_react28.createElement)(
|
|
10184
10357
|
"div",
|
|
10185
10358
|
{ key: "set-body", className: "bt-drawer-body bt-set-body", "data-move": move },
|
|
10186
10359
|
errorLine,
|
|
10187
|
-
bot ? (0,
|
|
10360
|
+
bot ? (0, import_react28.createElement)(BotSettingsForm, { bot, roster, actions, run }) : (0, import_react28.createElement)(GroupSettingsForm, { room: room2, roster, actions, run, onDeleted: close })
|
|
10188
10361
|
)
|
|
10189
10362
|
];
|
|
10190
10363
|
}
|
|
10191
|
-
const top = (0,
|
|
10364
|
+
const top = (0, import_react28.createElement)(
|
|
10192
10365
|
"div",
|
|
10193
10366
|
{ className: "bt-drawer-top", "data-move": side },
|
|
10194
|
-
bot || room2 ? (0,
|
|
10195
|
-
bot && roster.browser === true && actions.openBrowser ? (0,
|
|
10196
|
-
bot || room2 ? (0,
|
|
10197
|
-
hasStrip ? null : (0,
|
|
10367
|
+
bot || room2 ? (0, import_react28.createElement)("button", { type: "button", className: "bt-round", "aria-label": bot ? t("Edit Bot") : t("Group settings"), title: bot ? t("Edit Bot") : t("Group settings"), "data-info-row": "settings", onClick: () => setView("settings") }, (0, import_react28.createElement)(GearIcon)) : null,
|
|
10368
|
+
bot && roster.browser === true && actions.openBrowser ? (0, import_react28.createElement)("button", { type: "button", className: "bt-round", "aria-label": t("Open browser"), title: t("Open this Bot's browser"), onClick: () => actions.openBrowser(sessionId) }, (0, import_react28.createElement)(GlobeIcon)) : null,
|
|
10369
|
+
bot || room2 ? (0, import_react28.createElement)("button", { type: "button", className: "bt-round", "aria-label": copied ? t("Copied conversation") : t("Share conversation"), title: copied ? t("Copied") : t("Copy conversation as Markdown"), onClick: share }, copied ? (0, import_react28.createElement)("span", { key: "copied", className: "bt-pop-in" }, "✓") : (0, import_react28.createElement)(ShareIcon)) : null,
|
|
10370
|
+
hasStrip ? null : (0, import_react28.createElement)("button", { type: "button", className: "bt-round", "aria-label": t("Close details"), onClick: close }, (0, import_react28.createElement)(CloseIcon))
|
|
10198
10371
|
);
|
|
10199
10372
|
if (!bot && !room2) {
|
|
10200
10373
|
return [
|
|
10201
|
-
(0,
|
|
10202
|
-
(0,
|
|
10374
|
+
(0, import_react28.createElement)(import_react28.Fragment, { key: "top" }, top),
|
|
10375
|
+
(0, import_react28.createElement)("div", { key: "body", className: "bt-drawer-body" }, (0, import_react28.createElement)("div", { className: "bt-muted" }, t("This conversation is not part of your Bot team.")))
|
|
10203
10376
|
];
|
|
10204
10377
|
}
|
|
10205
10378
|
const current = bot?.name ?? room2.name;
|
|
@@ -10213,12 +10386,12 @@ function DetailsDrawer({ sessionId, startRenaming, startTab, hasStrip, roster, a
|
|
|
10213
10386
|
const subtitle = bot ? bot.role : roomSubtitle(room2, roster);
|
|
10214
10387
|
const tabs = bot ? ["details", "browser"] : ["details"];
|
|
10215
10388
|
return [
|
|
10216
|
-
(0,
|
|
10217
|
-
(0,
|
|
10389
|
+
(0, import_react28.createElement)(import_react28.Fragment, { key: "top" }, top),
|
|
10390
|
+
(0, import_react28.createElement)(
|
|
10218
10391
|
"div",
|
|
10219
10392
|
{ key: "id", className: "bt-drawer-id", "data-move": side },
|
|
10220
|
-
bot ? (0,
|
|
10221
|
-
editing ? (0,
|
|
10393
|
+
bot ? (0, import_react28.createElement)(BotAvatar, { bot, size: 64, state: botState(running, doing, roster.questions?.[part] !== void 0), main: isMainBot, badge: false, gaze: true, pokeable: true }) : (0, import_react28.createElement)(RoomAvatar, { room: room2, roster, size: 64 }),
|
|
10394
|
+
editing ? (0, import_react28.createElement)("input", {
|
|
10222
10395
|
className: "bt-drawer-name-input",
|
|
10223
10396
|
autoFocus: true,
|
|
10224
10397
|
value: draftName,
|
|
@@ -10233,49 +10406,49 @@ function DetailsDrawer({ sessionId, startRenaming, startTab, hasStrip, roster, a
|
|
|
10233
10406
|
setEditing(false);
|
|
10234
10407
|
}
|
|
10235
10408
|
}
|
|
10236
|
-
}) : (0,
|
|
10409
|
+
}) : (0, import_react28.createElement)("button", { type: "button", className: "bt-drawer-name", "aria-label": t("Rename {name}", { name: current }), title: t("Rename"), onClick: () => {
|
|
10237
10410
|
setDraftName(room2 && !room2.named ? "" : current);
|
|
10238
10411
|
setEditing(true);
|
|
10239
10412
|
} }, current),
|
|
10240
|
-
subtitle ? (0,
|
|
10413
|
+
subtitle ? (0, import_react28.createElement)("span", { className: "bt-drawer-role" }, subtitle) : null
|
|
10241
10414
|
),
|
|
10242
|
-
(0,
|
|
10415
|
+
(0, import_react28.createElement)(
|
|
10243
10416
|
"div",
|
|
10244
10417
|
{ key: "tabs", ref: glide.box, className: "bt-tabs", role: "tablist", "data-move": side },
|
|
10245
|
-
(0,
|
|
10246
|
-
tabs.map((key) => (0,
|
|
10418
|
+
(0, import_react28.createElement)("span", { ref: glide.thumb, className: "bt-thumb", "aria-hidden": true }),
|
|
10419
|
+
tabs.map((key) => (0, import_react28.createElement)("button", { key, type: "button", role: "tab", className: "bt-tab", "aria-selected": tab === key, onClick: () => setTab(key) }, t(TAB_LABELS[key])))
|
|
10247
10420
|
),
|
|
10248
|
-
(0,
|
|
10421
|
+
(0, import_react28.createElement)(
|
|
10249
10422
|
"div",
|
|
10250
10423
|
{ key: `body:${tab}`, className: "bt-drawer-body", "data-move": move },
|
|
10251
10424
|
errorLine,
|
|
10252
|
-
room2 && tab === "details" ? (0,
|
|
10425
|
+
room2 && tab === "details" ? (0, import_react28.createElement)(GroupOverview, { room: room2, roster, actions, usage, openSettings: () => setView("settings") }) : null,
|
|
10253
10426
|
bot && tab === "details" ? [
|
|
10254
|
-
(0,
|
|
10427
|
+
(0, import_react28.createElement)(
|
|
10255
10428
|
"div",
|
|
10256
10429
|
{ key: "model", className: "bt-drawer-model" },
|
|
10257
|
-
(0,
|
|
10258
|
-
(0,
|
|
10259
|
-
modelOf(bot, roster) ? null : (0,
|
|
10430
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t("Model")),
|
|
10431
|
+
(0, import_react28.createElement)(ModelMenu, { bot, roster, actions, run, wide: true }),
|
|
10432
|
+
modelOf(bot, roster) ? null : (0, import_react28.createElement)("div", { className: "bt-note" }, t("Pick a model and {name} can start.", { name: bot.name }))
|
|
10260
10433
|
),
|
|
10261
|
-
(0,
|
|
10262
|
-
bot.instructions ? (0,
|
|
10263
|
-
roster.memory === false ? null : (0,
|
|
10264
|
-
usage ? (0,
|
|
10434
|
+
(0, import_react28.createElement)(PermissionRow, { key: "permission", bot, roster, actions, run }),
|
|
10435
|
+
bot.instructions ? (0, import_react28.createElement)(About, { key: "about", text: bot.instructions }) : (0, import_react28.createElement)("button", { key: "about", type: "button", className: "bt-more", onClick: () => setView("settings") }, t("Add instructions in Bot settings")),
|
|
10436
|
+
roster.memory === false ? null : (0, import_react28.createElement)(MemoryRow, { key: "memory", bot, actions }),
|
|
10437
|
+
usage ? (0, import_react28.createElement)(
|
|
10265
10438
|
"div",
|
|
10266
10439
|
{ key: "usage" },
|
|
10267
|
-
(0,
|
|
10268
|
-
(0,
|
|
10440
|
+
(0, import_react28.createElement)("div", { className: "bt-section-title" }, t("Usage")),
|
|
10441
|
+
(0, import_react28.createElement)("div", { className: "bt-kv" }, (0, import_react28.createElement)("span", null, bot.name), (0, import_react28.createElement)("span", null, usage))
|
|
10269
10442
|
) : null,
|
|
10270
|
-
(0,
|
|
10443
|
+
(0, import_react28.createElement)(ScheduleSummary, { key: "routines", bot, actions })
|
|
10271
10444
|
] : null,
|
|
10272
|
-
bot && tab === "browser" ? (0,
|
|
10445
|
+
bot && tab === "browser" ? (0, import_react28.createElement)(BrowserCards, { bot, sessionId, roster, actions, useBrowserTabs, useBrowserPages }) : null
|
|
10273
10446
|
)
|
|
10274
10447
|
];
|
|
10275
10448
|
}
|
|
10276
10449
|
|
|
10277
10450
|
// src/client/browser-pane.js
|
|
10278
|
-
var
|
|
10451
|
+
var import_react29 = require("react");
|
|
10279
10452
|
var import_react_dom7 = require("react-dom");
|
|
10280
10453
|
var PANEL_LINGER_MS = 300;
|
|
10281
10454
|
var WIDTH_KEY = STORAGE.browserWidth;
|
|
@@ -10290,10 +10463,10 @@ var EMPTY_TABS2 = { ids: [], active: null };
|
|
|
10290
10463
|
var SPRING_LEAD2 = springEasing(576, 39.4);
|
|
10291
10464
|
var SPRING_TRAIL2 = springEasing(144, 19.7);
|
|
10292
10465
|
var icon = (paths) => function BrowserIcon() {
|
|
10293
|
-
return (0,
|
|
10466
|
+
return (0, import_react29.createElement)(
|
|
10294
10467
|
"svg",
|
|
10295
10468
|
{ width: 16, height: 16, viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true },
|
|
10296
|
-
paths.map((d, index) => (0,
|
|
10469
|
+
paths.map((d, index) => (0, import_react29.createElement)("path", { key: index, d }))
|
|
10297
10470
|
);
|
|
10298
10471
|
};
|
|
10299
10472
|
var GlobeIcon = icon(["M10 3a7 7 0 1 0 0 14 7 7 0 0 0 0-14z", "M3 10h14", "M10 3c2 2.2 2.9 4.5 2.9 7S12 14.8 10 17c-2-2.2-2.9-4.5-2.9-7S8 5.2 10 3z"]);
|
|
@@ -10305,9 +10478,9 @@ var CloseIcon2 = icon(["M5.5 5.5l9 9M14.5 5.5l-9 9"]);
|
|
|
10305
10478
|
var PlusTabIcon = icon(["M10 5v10M5 10h10"]);
|
|
10306
10479
|
var LockIcon2 = icon(["M6.5 9V7a3.5 3.5 0 0 1 7 0v2", "M5.5 9h9v7h-9z"]);
|
|
10307
10480
|
function Favicon({ src, className }) {
|
|
10308
|
-
const [failed, setFailed] = (0,
|
|
10309
|
-
if (!src || failed === src) return (0,
|
|
10310
|
-
return (0,
|
|
10481
|
+
const [failed, setFailed] = (0, import_react29.useState)(null);
|
|
10482
|
+
if (!src || failed === src) return (0, import_react29.createElement)("span", { className: `${className} bt-ptab-globe` }, (0, import_react29.createElement)(GlobeIcon));
|
|
10483
|
+
return (0, import_react29.createElement)("img", { className, src, alt: "", "aria-hidden": true, onError: () => setFailed(src) });
|
|
10311
10484
|
}
|
|
10312
10485
|
var savedWidth = () => {
|
|
10313
10486
|
try {
|
|
@@ -10366,11 +10539,11 @@ var reducedMotion2 = () => typeof matchMedia === "function" && matchMedia("(pref
|
|
|
10366
10539
|
var tabLabel = (page) => page.title || shortAddress(page.url) || t("New tab");
|
|
10367
10540
|
function PanelStrip({ bot, subject, view, ids, active, reading, onView, actions, useBrowserPages }) {
|
|
10368
10541
|
const pages = useBrowserPages((map) => map);
|
|
10369
|
-
const wrap = (0,
|
|
10370
|
-
const ind = (0,
|
|
10371
|
-
const spot = (0,
|
|
10372
|
-
const under = (0,
|
|
10373
|
-
(0,
|
|
10542
|
+
const wrap = (0, import_react29.useRef)(null);
|
|
10543
|
+
const ind = (0, import_react29.useRef)(null);
|
|
10544
|
+
const spot = (0, import_react29.useRef)(null);
|
|
10545
|
+
const under = (0, import_react29.useRef)(null);
|
|
10546
|
+
(0, import_react29.useLayoutEffect)(() => {
|
|
10374
10547
|
const box = wrap.current;
|
|
10375
10548
|
const capsule = ind.current;
|
|
10376
10549
|
if (!box || !capsule) return void 0;
|
|
@@ -10399,7 +10572,7 @@ function PanelStrip({ bot, subject, view, ids, active, reading, onView, actions,
|
|
|
10399
10572
|
trail.cancel();
|
|
10400
10573
|
};
|
|
10401
10574
|
});
|
|
10402
|
-
(0,
|
|
10575
|
+
(0, import_react29.useEffect)(() => {
|
|
10403
10576
|
const box = wrap.current;
|
|
10404
10577
|
if (!box) return void 0;
|
|
10405
10578
|
const observer = new ResizeObserver(() => {
|
|
@@ -10413,13 +10586,13 @@ function PanelStrip({ bot, subject, view, ids, active, reading, onView, actions,
|
|
|
10413
10586
|
observer.observe(box);
|
|
10414
10587
|
return () => observer.disconnect();
|
|
10415
10588
|
}, []);
|
|
10416
|
-
return (0,
|
|
10589
|
+
return (0, import_react29.createElement)(
|
|
10417
10590
|
"div",
|
|
10418
10591
|
{ className: "bt-ptabs", role: "tablist", "aria-label": t("Panel tabs") },
|
|
10419
|
-
(0,
|
|
10592
|
+
(0, import_react29.createElement)(
|
|
10420
10593
|
"div",
|
|
10421
10594
|
{ className: "bt-ptabs-in", ref: wrap },
|
|
10422
|
-
(0,
|
|
10595
|
+
(0, import_react29.createElement)(
|
|
10423
10596
|
"button",
|
|
10424
10597
|
{
|
|
10425
10598
|
type: "button",
|
|
@@ -10429,13 +10602,13 @@ function PanelStrip({ bot, subject, view, ids, active, reading, onView, actions,
|
|
|
10429
10602
|
title: bot.name,
|
|
10430
10603
|
onClick: () => onView("details")
|
|
10431
10604
|
},
|
|
10432
|
-
(0,
|
|
10433
|
-
view === "details" ? (0,
|
|
10605
|
+
(0, import_react29.createElement)(BotMark, { bot, size: 20, state: reading ? "searching" : "idle" }),
|
|
10606
|
+
view === "details" ? (0, import_react29.createElement)("span", { className: "bt-ptab-name" }, bot.name) : null
|
|
10434
10607
|
),
|
|
10435
10608
|
ids.map((tabId) => {
|
|
10436
10609
|
const page = pages[tabId] ?? EMPTY_PAGE;
|
|
10437
10610
|
const on = view === "browser" && tabId === active;
|
|
10438
|
-
return (0,
|
|
10611
|
+
return (0, import_react29.createElement)(
|
|
10439
10612
|
"button",
|
|
10440
10613
|
{
|
|
10441
10614
|
key: tabId,
|
|
@@ -10456,9 +10629,9 @@ function PanelStrip({ bot, subject, view, ids, active, reading, onView, actions,
|
|
|
10456
10629
|
}
|
|
10457
10630
|
}
|
|
10458
10631
|
},
|
|
10459
|
-
(0,
|
|
10460
|
-
(0,
|
|
10461
|
-
(0,
|
|
10632
|
+
(0, import_react29.createElement)(Favicon, { src: page.favicon, className: "bt-ptab-fav" }),
|
|
10633
|
+
(0, import_react29.createElement)("span", { className: "bt-ptab-title" }, tabLabel(page)),
|
|
10634
|
+
(0, import_react29.createElement)("span", {
|
|
10462
10635
|
className: "bt-ptab-x",
|
|
10463
10636
|
role: "button",
|
|
10464
10637
|
"aria-label": t("Close tab"),
|
|
@@ -10470,20 +10643,20 @@ function PanelStrip({ bot, subject, view, ids, active, reading, onView, actions,
|
|
|
10470
10643
|
}, "×")
|
|
10471
10644
|
);
|
|
10472
10645
|
}),
|
|
10473
|
-
(0,
|
|
10646
|
+
(0, import_react29.createElement)("span", { ref: ind, className: "bt-ptab-ind", "aria-hidden": true })
|
|
10474
10647
|
),
|
|
10475
10648
|
// New tab and Close stay outside the scrolling tabs, so a narrow panel keeps both.
|
|
10476
|
-
(0,
|
|
10477
|
-
(0,
|
|
10649
|
+
(0, import_react29.createElement)("button", { type: "button", className: "bt-ptab-new", "aria-label": t("New tab"), title: t("New tab"), onClick: () => actions.browserNewTab(subject) }, (0, import_react29.createElement)(PlusTabIcon)),
|
|
10650
|
+
(0, import_react29.createElement)("button", { type: "button", className: "bt-icon-btn bt-ptab-close", "aria-label": t("Close panel"), title: t("Close panel"), onClick: () => actions.closePanel() }, (0, import_react29.createElement)(CloseIcon2))
|
|
10478
10651
|
);
|
|
10479
10652
|
}
|
|
10480
10653
|
function BrowserView({ bot, tabId, leaving, landed, actions, useBrowserPages }) {
|
|
10481
10654
|
const page = useBrowserPages((pages) => pages[tabId ?? ""]) ?? EMPTY_PAGE;
|
|
10482
|
-
const frame = (0,
|
|
10483
|
-
const input = (0,
|
|
10484
|
-
const [draft, setDraft] = (0,
|
|
10655
|
+
const frame = (0, import_react29.useRef)(null);
|
|
10656
|
+
const input = (0, import_react29.useRef)(null);
|
|
10657
|
+
const [draft, setDraft] = (0, import_react29.useState)(null);
|
|
10485
10658
|
const showGuest = landed && !leaving && Boolean(page.url) && !page.error;
|
|
10486
|
-
(0,
|
|
10659
|
+
(0, import_react29.useLayoutEffect)(() => {
|
|
10487
10660
|
const element = frame.current;
|
|
10488
10661
|
if (!element || leaving || !tabId) {
|
|
10489
10662
|
void actions.browserShow(null);
|
|
@@ -10509,7 +10682,7 @@ function BrowserView({ bot, tabId, leaving, landed, actions, useBrowserPages })
|
|
|
10509
10682
|
window.removeEventListener("resize", schedule);
|
|
10510
10683
|
};
|
|
10511
10684
|
}, [tabId, showGuest, leaving]);
|
|
10512
|
-
(0,
|
|
10685
|
+
(0, import_react29.useEffect)(() => {
|
|
10513
10686
|
setDraft(null);
|
|
10514
10687
|
if (landed && !page.url) input.current?.focus();
|
|
10515
10688
|
}, [tabId, landed]);
|
|
@@ -10525,27 +10698,27 @@ function BrowserView({ bot, tabId, leaving, landed, actions, useBrowserPages })
|
|
|
10525
10698
|
};
|
|
10526
10699
|
const editing = draft !== null;
|
|
10527
10700
|
const secure = /^https:/i.test(page.url);
|
|
10528
|
-
return (0,
|
|
10701
|
+
return (0, import_react29.createElement)(
|
|
10529
10702
|
"div",
|
|
10530
10703
|
{ className: "bt-panel-view bt-panel-browser", "aria-label": t("{name}'s browser", { name: bot.name }) },
|
|
10531
|
-
(0,
|
|
10704
|
+
(0, import_react29.createElement)(
|
|
10532
10705
|
"div",
|
|
10533
10706
|
{ className: "bt-browser-bar" },
|
|
10534
|
-
(0,
|
|
10535
|
-
(0,
|
|
10536
|
-
(0,
|
|
10707
|
+
(0, import_react29.createElement)("button", { type: "button", className: "bt-icon-btn", "aria-label": t("Back"), title: t("Back"), disabled: !page.canGoBack, onClick: () => actions.browserCommand(tabId, "back") }, (0, import_react29.createElement)(BackIcon)),
|
|
10708
|
+
(0, import_react29.createElement)("button", { type: "button", className: "bt-icon-btn", "aria-label": t("Forward"), title: t("Forward"), disabled: !page.canGoForward, onClick: () => actions.browserCommand(tabId, "forward") }, (0, import_react29.createElement)(ForwardIcon)),
|
|
10709
|
+
(0, import_react29.createElement)("button", {
|
|
10537
10710
|
type: "button",
|
|
10538
10711
|
className: "bt-icon-btn",
|
|
10539
10712
|
disabled: !page.url,
|
|
10540
10713
|
"aria-label": page.loading ? t("Stop") : t("Reload"),
|
|
10541
10714
|
title: page.loading ? t("Stop") : t("Reload"),
|
|
10542
10715
|
onClick: () => actions.browserCommand(tabId, page.loading ? "stop" : "reload")
|
|
10543
|
-
}, (0,
|
|
10544
|
-
(0,
|
|
10716
|
+
}, (0, import_react29.createElement)(page.loading ? StopIcon : ReloadIcon)),
|
|
10717
|
+
(0, import_react29.createElement)(
|
|
10545
10718
|
"form",
|
|
10546
10719
|
{ className: "bt-browser-address", onSubmit: go, "data-editing": editing || void 0 },
|
|
10547
|
-
(0,
|
|
10548
|
-
(0,
|
|
10720
|
+
(0, import_react29.createElement)("span", { className: "bt-browser-scheme", "aria-hidden": true }, (0, import_react29.createElement)(secure && !editing ? LockIcon2 : GlobeIcon)),
|
|
10721
|
+
(0, import_react29.createElement)("input", {
|
|
10549
10722
|
ref: input,
|
|
10550
10723
|
type: "text",
|
|
10551
10724
|
spellCheck: false,
|
|
@@ -10569,25 +10742,25 @@ function BrowserView({ bot, tabId, leaving, landed, actions, useBrowserPages })
|
|
|
10569
10742
|
}
|
|
10570
10743
|
})
|
|
10571
10744
|
),
|
|
10572
|
-
page.loading ? (0,
|
|
10745
|
+
page.loading ? (0, import_react29.createElement)("span", { className: "bt-browser-progress", "aria-hidden": true }) : null
|
|
10573
10746
|
),
|
|
10574
|
-
(0,
|
|
10747
|
+
(0, import_react29.createElement)(
|
|
10575
10748
|
"div",
|
|
10576
10749
|
{ ref: frame, className: "bt-browser-frame", "data-guest": showGuest || void 0 },
|
|
10577
|
-
page.error ? (0,
|
|
10750
|
+
page.error ? (0, import_react29.createElement)(
|
|
10578
10751
|
"div",
|
|
10579
10752
|
{ className: "bt-browser-empty" },
|
|
10580
|
-
(0,
|
|
10581
|
-
(0,
|
|
10582
|
-
page.url ? (0,
|
|
10753
|
+
(0, import_react29.createElement)("div", { className: "bt-browser-empty-title" }, t("This page didn’t load")),
|
|
10754
|
+
(0, import_react29.createElement)("div", { className: "bt-browser-empty-text" }, t(page.error)),
|
|
10755
|
+
page.url ? (0, import_react29.createElement)("button", { type: "button", className: "bt-browser-retry", onClick: () => {
|
|
10583
10756
|
void actions.browserNavigate(tabId, page.url);
|
|
10584
10757
|
} }, t("Try again")) : null
|
|
10585
|
-
) : !page.url ? (0,
|
|
10758
|
+
) : !page.url ? (0, import_react29.createElement)(
|
|
10586
10759
|
"div",
|
|
10587
10760
|
{ className: "bt-browser-empty" },
|
|
10588
|
-
(0,
|
|
10589
|
-
(0,
|
|
10590
|
-
(0,
|
|
10761
|
+
(0, import_react29.createElement)(BotMark, { bot, size: 48, state: "idle", live: true }),
|
|
10762
|
+
(0, import_react29.createElement)("div", { className: "bt-browser-empty-title" }, t("{name}'s browser", { name: bot.name })),
|
|
10763
|
+
(0, import_react29.createElement)("div", { className: "bt-browser-empty-text" }, t("Open a page here and {name} can read it with you. Logins and cookies stay with {name}; other Bots never see them.", { name: bot.name }))
|
|
10591
10764
|
) : null
|
|
10592
10765
|
)
|
|
10593
10766
|
);
|
|
@@ -10599,41 +10772,41 @@ function BotPanel({ pane, leaving, roster, actions, useSessions, useSessionStatu
|
|
|
10599
10772
|
const tabState = useBrowserTabs((map) => bot ? map[bot.id] ?? EMPTY_TABS2 : EMPTY_TABS2);
|
|
10600
10773
|
const active = tabState.active;
|
|
10601
10774
|
const page = useBrowserPages((pages) => (active ? pages[active] : null) ?? EMPTY_PAGE);
|
|
10602
|
-
const root = (0,
|
|
10603
|
-
const fly = (0,
|
|
10604
|
-
const [landed, setLanded] = (0,
|
|
10605
|
-
const [settling, setSettling] = (0,
|
|
10606
|
-
const [width, setWidth] = (0,
|
|
10607
|
-
const [viewport, setViewport] = (0,
|
|
10608
|
-
const [dragging, setDragging] = (0,
|
|
10609
|
-
const [resizing, setResizing] = (0,
|
|
10775
|
+
const root = (0, import_react29.useRef)(null);
|
|
10776
|
+
const fly = (0, import_react29.useRef)(null);
|
|
10777
|
+
const [landed, setLanded] = (0, import_react29.useState)(false);
|
|
10778
|
+
const [settling, setSettling] = (0, import_react29.useState)(false);
|
|
10779
|
+
const [width, setWidth] = (0, import_react29.useState)(savedWidth);
|
|
10780
|
+
const [viewport, setViewport] = (0, import_react29.useState)(() => window.innerWidth);
|
|
10781
|
+
const [dragging, setDragging] = (0, import_react29.useState)(false);
|
|
10782
|
+
const [resizing, setResizing] = (0, import_react29.useState)(false);
|
|
10610
10783
|
const instant = dragging || resizing;
|
|
10611
|
-
const [reading, setReading] = (0,
|
|
10784
|
+
const [reading, setReading] = (0, import_react29.useState)(false);
|
|
10612
10785
|
const panelWidth = fitWidth(width ?? (view === "browser" ? DEFAULT_WIDTH : DETAILS_WIDTH), widthRange(view, viewport));
|
|
10613
|
-
(0,
|
|
10786
|
+
(0, import_react29.useLayoutEffect)(() => {
|
|
10614
10787
|
if (view === "browser" && width === null) setWidth(DEFAULT_WIDTH);
|
|
10615
10788
|
}, [view, width]);
|
|
10616
|
-
(0,
|
|
10789
|
+
(0, import_react29.useLayoutEffect)(() => {
|
|
10617
10790
|
chatRoom.hold(instant);
|
|
10618
10791
|
}, [instant]);
|
|
10619
|
-
const [last, setLast] = (0,
|
|
10792
|
+
const [last, setLast] = (0, import_react29.useState)({ view, width: panelWidth });
|
|
10620
10793
|
if (last.view !== view || last.width !== panelWidth) {
|
|
10621
10794
|
setLast({ view, width: panelWidth });
|
|
10622
10795
|
if (last.view !== view) setSettling(last.width !== panelWidth && !instant);
|
|
10623
10796
|
}
|
|
10624
|
-
const shownView = (0,
|
|
10625
|
-
(0,
|
|
10797
|
+
const shownView = (0, import_react29.useRef)(view);
|
|
10798
|
+
(0, import_react29.useLayoutEffect)(() => {
|
|
10626
10799
|
const switched = settling && shownView.current !== view;
|
|
10627
10800
|
shownView.current = view;
|
|
10628
10801
|
if (switched) chatRoom.hold(true);
|
|
10629
10802
|
chatRoom.set(leaving ? null : panelWidth);
|
|
10630
10803
|
if (switched) chatRoom.hold(false);
|
|
10631
10804
|
}, [view, panelWidth, leaving]);
|
|
10632
|
-
(0,
|
|
10805
|
+
(0, import_react29.useEffect)(() => () => {
|
|
10633
10806
|
chatRoom.set(null);
|
|
10634
10807
|
chatRoom.hold(false);
|
|
10635
10808
|
}, []);
|
|
10636
|
-
(0,
|
|
10809
|
+
(0, import_react29.useEffect)(() => {
|
|
10637
10810
|
let timer;
|
|
10638
10811
|
const onResize = () => {
|
|
10639
10812
|
setResizing(true);
|
|
@@ -10647,28 +10820,28 @@ function BotPanel({ pane, leaving, roster, actions, useSessions, useSessionStatu
|
|
|
10647
10820
|
window.removeEventListener("resize", onResize);
|
|
10648
10821
|
};
|
|
10649
10822
|
}, []);
|
|
10650
|
-
(0,
|
|
10823
|
+
(0, import_react29.useEffect)(() => {
|
|
10651
10824
|
if (!settling) return void 0;
|
|
10652
10825
|
const timer = setTimeout(() => setSettling(false), SPRING_SHAPE.duration + 40);
|
|
10653
10826
|
return () => clearTimeout(timer);
|
|
10654
10827
|
}, [settling, view]);
|
|
10655
|
-
(0,
|
|
10828
|
+
(0, import_react29.useEffect)(() => {
|
|
10656
10829
|
const timer = setTimeout(() => setLanded(true), 360);
|
|
10657
10830
|
return () => clearTimeout(timer);
|
|
10658
10831
|
}, []);
|
|
10659
|
-
(0,
|
|
10832
|
+
(0, import_react29.useEffect)(() => {
|
|
10660
10833
|
if (canBrowse) actions.browserEnsure(bot.id);
|
|
10661
10834
|
}, [bot?.id, canBrowse]);
|
|
10662
|
-
(0,
|
|
10835
|
+
(0, import_react29.useEffect)(() => {
|
|
10663
10836
|
if (view === "browser" && (active === null || !tabState.ids.includes(active))) actions.setPanelView("details");
|
|
10664
10837
|
}, [view, active, tabState.ids.length]);
|
|
10665
|
-
(0,
|
|
10838
|
+
(0, import_react29.useEffect)(() => {
|
|
10666
10839
|
if (view !== "browser" || leaving) void actions.browserShow?.(null);
|
|
10667
10840
|
}, [view, leaving]);
|
|
10668
|
-
(0,
|
|
10841
|
+
(0, import_react29.useEffect)(() => () => {
|
|
10669
10842
|
void actions.browserShow?.(null);
|
|
10670
10843
|
}, []);
|
|
10671
|
-
(0,
|
|
10844
|
+
(0, import_react29.useEffect)(() => {
|
|
10672
10845
|
if (!page.readAt || Date.now() - page.readAt > READ_FLASH_MS) return void 0;
|
|
10673
10846
|
setReading(true);
|
|
10674
10847
|
const timer = setTimeout(() => setReading(false), READ_FLASH_MS);
|
|
@@ -10705,7 +10878,7 @@ function BotPanel({ pane, leaving, roster, actions, useSessions, useSessionStatu
|
|
|
10705
10878
|
return actions[name](...args);
|
|
10706
10879
|
};
|
|
10707
10880
|
}
|
|
10708
|
-
(0,
|
|
10881
|
+
(0, import_react29.useLayoutEffect)(() => {
|
|
10709
10882
|
const move = fly.current;
|
|
10710
10883
|
if (!move) return;
|
|
10711
10884
|
fly.current = null;
|
|
@@ -10788,7 +10961,7 @@ function BotPanel({ pane, leaving, roster, actions, useSessions, useSessionStatu
|
|
|
10788
10961
|
for (const name of ends) grip.addEventListener(name, onEnd);
|
|
10789
10962
|
};
|
|
10790
10963
|
const hasStrip = canBrowse && tabState.ids.length > 0;
|
|
10791
|
-
return (0,
|
|
10964
|
+
return (0, import_react29.createElement)(
|
|
10792
10965
|
"aside",
|
|
10793
10966
|
{
|
|
10794
10967
|
ref: root,
|
|
@@ -10805,15 +10978,15 @@ function BotPanel({ pane, leaving, roster, actions, useSessions, useSessionStatu
|
|
|
10805
10978
|
if (event.target === event.currentTarget) setLanded(true);
|
|
10806
10979
|
}
|
|
10807
10980
|
},
|
|
10808
|
-
leaving ? null : (0,
|
|
10981
|
+
leaving ? null : (0, import_react29.createElement)("div", { className: "bt-panel-grip", role: "separator", "aria-orientation": "vertical", "aria-label": t("Resize panel"), onPointerDown: startResize }),
|
|
10809
10982
|
// Over the whole window while dragging: the cursor stays a resize cursor and the
|
|
10810
10983
|
// pages underneath (the chat, the guest) see no pointer.
|
|
10811
|
-
dragging ? (0, import_react_dom7.createPortal)((0,
|
|
10812
|
-
hasStrip ? (0,
|
|
10813
|
-
view === "browser" && bot ? (0,
|
|
10984
|
+
dragging ? (0, import_react_dom7.createPortal)((0, import_react29.createElement)("div", { className: "bt-drag-shield", "aria-hidden": true }), document.body) : null,
|
|
10985
|
+
hasStrip ? (0, import_react29.createElement)(PanelStrip, { bot, subject: pane.id, view, ids: tabState.ids, active, reading, onView: switchView, actions: panelActions, useBrowserPages }) : null,
|
|
10986
|
+
view === "browser" && bot ? (0, import_react29.createElement)(BrowserView, { key: `browser:${active}`, bot, tabId: active, leaving, landed: landed && !settling, actions, useBrowserPages }) : (0, import_react29.createElement)(
|
|
10814
10987
|
"div",
|
|
10815
10988
|
{ key: `details:${pane.id}:${pane.renaming ? "rename" : ""}:${pane.tab ?? ""}`, className: "bt-panel-view" },
|
|
10816
|
-
(0,
|
|
10989
|
+
(0, import_react29.createElement)(DetailsDrawer, {
|
|
10817
10990
|
sessionId: pane.id,
|
|
10818
10991
|
startRenaming: pane.renaming,
|
|
10819
10992
|
startTab: pane.tab,
|
|
@@ -10909,24 +11082,24 @@ var BROWSER_CSS = `
|
|
|
10909
11082
|
`;
|
|
10910
11083
|
|
|
10911
11084
|
// src/client/overlays.js
|
|
10912
|
-
var
|
|
11085
|
+
var import_react30 = require("react");
|
|
10913
11086
|
var import_react_dom8 = require("react-dom");
|
|
10914
11087
|
var DIALOG_EXIT_MS = 160;
|
|
10915
11088
|
var MENU_EXIT_MS3 = 120;
|
|
10916
|
-
function Overlays({ useRoster, useUi, useSessions, useSessionStatus, useActivity, useRegistry, useBrowserPages, useBrowserTabs, actions }) {
|
|
11089
|
+
function Overlays({ useRoster, useUi, useSessions, useSessionStatus, useActivity, useRegistry, useBrowserPages, useBrowserTabs, useUpdate, actions }) {
|
|
10917
11090
|
const roster = useRoster((value) => value);
|
|
10918
11091
|
const ui = useUi((value) => value);
|
|
10919
11092
|
useRegistry((value) => value);
|
|
10920
11093
|
const current = useSessions((list) => Object.values(list.byId).find((session) => (session?.retainedBy?.mainView ?? 0) > 0)?.id ?? null);
|
|
10921
|
-
const previous = (0,
|
|
10922
|
-
(0,
|
|
11094
|
+
const previous = (0, import_react30.useRef)(current);
|
|
11095
|
+
(0, import_react30.useEffect)(() => {
|
|
10923
11096
|
if (previous.current === current) return;
|
|
10924
11097
|
previous.current = current;
|
|
10925
11098
|
if (current) actions.followPanel?.(current);
|
|
10926
11099
|
}, [current]);
|
|
10927
11100
|
const open = ui.details ? { id: ui.details, view: ui.view ?? "details", renaming: ui.renaming, tab: ui.tab } : null;
|
|
10928
|
-
const [kept, setKept] = (0,
|
|
10929
|
-
(0,
|
|
11101
|
+
const [kept, setKept] = (0, import_react30.useState)(open);
|
|
11102
|
+
(0, import_react30.useEffect)(() => {
|
|
10930
11103
|
if (open) {
|
|
10931
11104
|
setKept(open);
|
|
10932
11105
|
return void 0;
|
|
@@ -10938,17 +11111,17 @@ function Overlays({ useRoster, useUi, useSessions, useSessionStatus, useActivity
|
|
|
10938
11111
|
const [settings, settingsLeaving] = useLinger(ui.settings, DIALOG_EXIT_MS);
|
|
10939
11112
|
const [memory, memoryLeaving] = useLinger(ui.memory && roster.byId[ui.memory] ? ui.memory : null, DIALOG_EXIT_MS);
|
|
10940
11113
|
const [menu, menuLeaving] = useLinger(ui.menu, MENU_EXIT_MS3);
|
|
10941
|
-
return (0,
|
|
10942
|
-
|
|
11114
|
+
return (0, import_react30.createElement)(
|
|
11115
|
+
import_react30.Fragment,
|
|
10943
11116
|
null,
|
|
10944
|
-
pane ? (0, import_react_dom8.createPortal)((0,
|
|
10945
|
-
ui.newChat ? (0, import_react_dom8.createPortal)((0,
|
|
10946
|
-
ui.palette ? (0, import_react_dom8.createPortal)((0,
|
|
10947
|
-
ui.exchange ? (0, import_react_dom8.createPortal)((0,
|
|
10948
|
-
ui.voice ? (0, import_react_dom8.createPortal)((0,
|
|
10949
|
-
menu ? (0, import_react_dom8.createPortal)((0,
|
|
10950
|
-
settings ? (0, import_react_dom8.createPortal)((0,
|
|
10951
|
-
memory && roster.byId[memory] ? (0, import_react_dom8.createPortal)((0,
|
|
11117
|
+
pane ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(BotPanel, { pane, leaving: open === null, roster, actions, useSessions, useSessionStatus, useActivity, useBrowserTabs, useBrowserPages }), document.body) : null,
|
|
11118
|
+
ui.newChat ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(NewChat, { key: ui.newChat, mode: ui.newChat, roster, actions }), document.body) : null,
|
|
11119
|
+
ui.palette ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(CommandPalette, { key: ui.palette.token, start: ui.palette.query, token: ui.palette.token, roster, actions, useSessions }), document.body) : null,
|
|
11120
|
+
ui.exchange ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(ExchangeDialog, { pair: ui.exchange, roster, actions }), document.body) : null,
|
|
11121
|
+
ui.voice ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(VoiceMode, { key: ui.voice, sessionId: ui.voice, roster, actions, useSessions, useSessionStatus }), document.body) : null,
|
|
11122
|
+
menu ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(ContextMenu, { key: `${menu.kind ?? ""}:${menu.id}:${menu.x}:${menu.y}`, menu, roster, actions, leaving: menuLeaving }), document.body) : null,
|
|
11123
|
+
settings ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(SettingsDialog, { page: settings.page, id: settings.id, roster, actions, useUpdate, leaving: settingsLeaving }), document.body) : null,
|
|
11124
|
+
memory && roster.byId[memory] ? (0, import_react_dom8.createPortal)((0, import_react30.createElement)(MemoryDialog, { key: memory, bot: roster.byId[memory], actions, leaving: memoryLeaving }), document.body) : null
|
|
10952
11125
|
);
|
|
10953
11126
|
}
|
|
10954
11127
|
|
|
@@ -11949,7 +12122,7 @@ function apply(ctx) {
|
|
|
11949
12122
|
if (stopped) return;
|
|
11950
12123
|
const value = await call("update-check", { fresh: false }).catch(() => null);
|
|
11951
12124
|
if (stopped) return;
|
|
11952
|
-
if (value) update.set(value);
|
|
12125
|
+
if (value) update.set((previous) => ({ ...value, app: previous.app }));
|
|
11953
12126
|
timer = setTimeout(loop, value?.phase === "installing" || value?.dsh?.phase === "installing" ? 2e3 : 60 * 6e4);
|
|
11954
12127
|
};
|
|
11955
12128
|
wakeUpdate = loop;
|
|
@@ -11961,6 +12134,22 @@ function apply(ctx) {
|
|
|
11961
12134
|
};
|
|
11962
12135
|
};
|
|
11963
12136
|
}, "ds-bot: update check");
|
|
12137
|
+
const appUpdates = window.dshDesktop?.protocolVersion === 1 ? window.dshDesktop.updates ?? null : null;
|
|
12138
|
+
if (appUpdates?.status && appUpdates.subscribe) {
|
|
12139
|
+
ctx.effect(() => {
|
|
12140
|
+
let stopped = false;
|
|
12141
|
+
const take = (app) => {
|
|
12142
|
+
if (!stopped && app) update.set((previous) => ({ ...previous, app }));
|
|
12143
|
+
};
|
|
12144
|
+
void appUpdates.status().then(take, () => {
|
|
12145
|
+
});
|
|
12146
|
+
const unsubscribe = appUpdates.subscribe(take);
|
|
12147
|
+
return () => {
|
|
12148
|
+
stopped = true;
|
|
12149
|
+
unsubscribe?.();
|
|
12150
|
+
};
|
|
12151
|
+
}, "ds-bot: app update status");
|
|
12152
|
+
}
|
|
11964
12153
|
const bridge = window.dshDesktop?.protocolVersion === 1 ? window.dshDesktop.browser ?? null : null;
|
|
11965
12154
|
const browsers = bridge ? createBotBrowsers({ bridge, createSource }) : null;
|
|
11966
12155
|
if (browsers) {
|
|
@@ -12426,7 +12615,17 @@ function apply(ctx) {
|
|
|
12426
12615
|
update.set((previous) => ({ ...previous, dsh }));
|
|
12427
12616
|
wakeUpdate();
|
|
12428
12617
|
};
|
|
12429
|
-
actions.openAppUpdates = () =>
|
|
12618
|
+
actions.openAppUpdates = async (verified) => {
|
|
12619
|
+
const app = await appUpdates?.status?.();
|
|
12620
|
+
if (app) update.set((previous) => ({ ...previous, app }));
|
|
12621
|
+
if (sameVersion(app?.version, verified)) await appUpdates.open();
|
|
12622
|
+
};
|
|
12623
|
+
actions.checkUpdate = async () => {
|
|
12624
|
+
const value = await call("update-check", { fresh: true });
|
|
12625
|
+
update.set((previous) => ({ ...value, app: previous.app }));
|
|
12626
|
+
wakeUpdate();
|
|
12627
|
+
};
|
|
12628
|
+
actions.repoStars = () => call("repo-stars");
|
|
12430
12629
|
actions.noteTurnTime = (sessionId, turn, key, time) => {
|
|
12431
12630
|
if (sessionId === void 0 || !Number.isFinite(turn) || !Number.isFinite(time)) return;
|
|
12432
12631
|
turnClock.set((state) => {
|
|
@@ -12488,6 +12687,7 @@ function apply(ctx) {
|
|
|
12488
12687
|
installCompiledStyles(USAGE_CSS, "usage"),
|
|
12489
12688
|
installCompiledStyles(SCHEDULE_CSS, "schedules"),
|
|
12490
12689
|
installCompiledStyles(FEEDBACK_CSS, "feedback"),
|
|
12690
|
+
installCompiledStyles(ABOUT_CSS, "about"),
|
|
12491
12691
|
browsers ? installCompiledStyles(BROWSER_CSS, "browser") : null,
|
|
12492
12692
|
installTheme(),
|
|
12493
12693
|
shadow("sidebar.workspaces", { priority: -10, inject: face }, TeamSidebar),
|