@botharness/ui 1.0.1 → 1.0.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/lib/client.js CHANGED
@@ -2802,11 +2802,11 @@ window.__ModuleLoader__.load({
2802
2802
  async function sha256Hex(text) {
2803
2803
  return hex(await crypto.subtle.digest("SHA-256", encoder.encode(text)));
2804
2804
  }
2805
- function record$1(value) {
2805
+ function record$3(value) {
2806
2806
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2807
2807
  }
2808
2808
  function parseChallenge(value) {
2809
- const source = record$1(value);
2809
+ const source = record$3(value);
2810
2810
  if (source === void 0 || source["algorithm"] !== "SHA-256") return void 0;
2811
2811
  const { challenge, maxnumber, salt, signature } = source;
2812
2812
  if (typeof challenge !== "string" || typeof salt !== "string" || typeof signature !== "string") return;
@@ -2840,11 +2840,11 @@ window.__ModuleLoader__.load({
2840
2840
  }
2841
2841
  //#endregion
2842
2842
  //#region packages/core/src/marketplace/client.ts
2843
- function record(value) {
2843
+ function record$2(value) {
2844
2844
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2845
2845
  }
2846
2846
  function parseEntry(value) {
2847
- const source = record(value);
2847
+ const source = record$2(value);
2848
2848
  if (source === void 0) return void 0;
2849
2849
  if (![
2850
2850
  "id",
@@ -2859,7 +2859,7 @@ window.__ModuleLoader__.load({
2859
2859
  const description = source["description"];
2860
2860
  const stars = source["stars"];
2861
2861
  const topics = source["topics"];
2862
- const head = record(source["headCommit"]);
2862
+ const head = record$2(source["headCommit"]);
2863
2863
  if (description !== null && typeof description !== "string") return void 0;
2864
2864
  if (typeof stars !== "number" || !Array.isArray(topics)) return void 0;
2865
2865
  const displayName = source["displayName"];
@@ -2885,7 +2885,7 @@ window.__ModuleLoader__.load({
2885
2885
  };
2886
2886
  }
2887
2887
  function parseMarketplacePage(value) {
2888
- const source = record(value);
2888
+ const source = record$2(value);
2889
2889
  if (source === void 0 || !Array.isArray(source["bots"])) return void 0;
2890
2890
  const bots = source["bots"].map(parseEntry);
2891
2891
  if (!bots.every((bot) => bot !== void 0)) return void 0;
@@ -2896,7 +2896,7 @@ window.__ModuleLoader__.load({
2896
2896
  } : { bots };
2897
2897
  }
2898
2898
  function parseMarketplaceDetail(value) {
2899
- const source = record(value);
2899
+ const source = record$2(value);
2900
2900
  const bot = parseEntry(source?.["bot"]);
2901
2901
  const readme = source?.["readme"];
2902
2902
  const commitSha = source?.["commitSha"];
@@ -2909,10 +2909,10 @@ window.__ModuleLoader__.load({
2909
2909
  };
2910
2910
  }
2911
2911
  function parseMarketplaceTopics(value) {
2912
- const topics = record(value)?.["topics"];
2912
+ const topics = record$2(value)?.["topics"];
2913
2913
  if (!Array.isArray(topics)) return void 0;
2914
2914
  const parsed = topics.map((item) => {
2915
- const source = record(item);
2915
+ const source = record$2(item);
2916
2916
  return typeof source?.["topic"] === "string" && typeof source["count"] === "number" ? {
2917
2917
  topic: source["topic"],
2918
2918
  count: source["count"]
@@ -2921,7 +2921,7 @@ window.__ModuleLoader__.load({
2921
2921
  return parsed.every((item) => item !== void 0) ? parsed : void 0;
2922
2922
  }
2923
2923
  function parseMarketplaceSubmission(value) {
2924
- const bot = parseEntry(record(value)?.["bot"]);
2924
+ const bot = parseEntry(record$2(value)?.["bot"]);
2925
2925
  return bot === void 0 ? void 0 : { bot };
2926
2926
  }
2927
2927
  //#endregion
@@ -8715,6 +8715,503 @@ window.__ModuleLoader__.load({
8715
8715
  });
8716
8716
  }
8717
8717
  //#endregion
8718
+ //#region packages/core/src/release/version.ts
8719
+ const RELEASE_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u;
8720
+ function parse(version) {
8721
+ const match = RELEASE_VERSION.exec(version);
8722
+ if (match === null) return void 0;
8723
+ return {
8724
+ core: [
8725
+ Number(match[1]),
8726
+ Number(match[2]),
8727
+ Number(match[3])
8728
+ ],
8729
+ prerelease: match[4] === void 0 ? [] : match[4].split(".")
8730
+ };
8731
+ }
8732
+ function compareIdentifier(left, right) {
8733
+ const leftNumeric = /^\d+$/u.test(left);
8734
+ const rightNumeric = /^\d+$/u.test(right);
8735
+ if (leftNumeric && rightNumeric) return Math.sign(Number(left) - Number(right));
8736
+ if (leftNumeric) return -1;
8737
+ if (rightNumeric) return 1;
8738
+ return left < right ? -1 : left > right ? 1 : 0;
8739
+ }
8740
+ function isReleaseVersion(version) {
8741
+ const parsed = parse(version);
8742
+ return parsed !== void 0 && parsed.core.some((part) => part > 0);
8743
+ }
8744
+ function compareVersions(left, right) {
8745
+ const a = parse(left);
8746
+ const b = parse(right);
8747
+ if (a === void 0 || b === void 0) return 0;
8748
+ for (let index = 0; index < 3; index += 1) {
8749
+ const difference = a.core[index] - b.core[index];
8750
+ if (difference !== 0) return Math.sign(difference);
8751
+ }
8752
+ if (a.prerelease.length === 0 || b.prerelease.length === 0) return Math.sign(b.prerelease.length - a.prerelease.length);
8753
+ const length = Math.max(a.prerelease.length, b.prerelease.length);
8754
+ for (let index = 0; index < length; index += 1) {
8755
+ const left = a.prerelease[index];
8756
+ const right = b.prerelease[index];
8757
+ if (left === void 0) return -1;
8758
+ if (right === void 0) return 1;
8759
+ const order = compareIdentifier(left, right);
8760
+ if (order !== 0) return order;
8761
+ }
8762
+ return 0;
8763
+ }
8764
+ //#endregion
8765
+ //#region packages/core/src/release/notes.ts
8766
+ function record$1(value) {
8767
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
8768
+ }
8769
+ function parseText(value) {
8770
+ const source = record$1(value);
8771
+ return typeof source?.["en"] === "string" && typeof source["zh"] === "string" ? {
8772
+ en: source["en"],
8773
+ zh: source["zh"]
8774
+ } : void 0;
8775
+ }
8776
+ function parseSection(value) {
8777
+ const source = record$1(value);
8778
+ if (typeof source?.["name"] !== "string" || !Array.isArray(source["entries"])) return void 0;
8779
+ const entries = source["entries"].map(parseText);
8780
+ return entries.every((entry) => entry !== void 0) ? {
8781
+ name: source["name"],
8782
+ entries
8783
+ } : void 0;
8784
+ }
8785
+ function parseReleaseNotes(value) {
8786
+ if (!Array.isArray(value)) return void 0;
8787
+ const notes = [];
8788
+ for (const item of value) {
8789
+ const source = record$1(item);
8790
+ const summary = parseText(source?.["summary"]);
8791
+ const sections = Array.isArray(source?.["sections"]) ? source["sections"].map(parseSection) : void 0;
8792
+ if (typeof source?.["version"] !== "string" || typeof source["date"] !== "string" || summary === void 0 || sections === void 0 || !sections.every((section) => section !== void 0)) return void 0;
8793
+ notes.push({
8794
+ version: source["version"],
8795
+ date: source["date"],
8796
+ summary,
8797
+ sections
8798
+ });
8799
+ }
8800
+ return notes;
8801
+ }
8802
+ //#endregion
8803
+ //#region packages/client/src/client/release-notes.ts
8804
+ const RELEASE_NOTES_SEEN_KEY = "botharness.releaseNotes.seenVersion";
8805
+ function record(value) {
8806
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
8807
+ }
8808
+ function parseReleaseInfo(value) {
8809
+ const source = record(value);
8810
+ const releases = parseReleaseNotes(source?.["releases"]);
8811
+ return typeof source?.["version"] === "string" && releases !== void 0 ? {
8812
+ version: source["version"],
8813
+ releases
8814
+ } : void 0;
8815
+ }
8816
+ function parseReleaseUpdate(value) {
8817
+ const source = record(value);
8818
+ const current = source?.["current"];
8819
+ const latest = source?.["latest"];
8820
+ if (typeof current !== "string") return void 0;
8821
+ switch (source?.["status"]) {
8822
+ case "development":
8823
+ case "unavailable": return {
8824
+ status: source["status"],
8825
+ current
8826
+ };
8827
+ case "current": return typeof latest === "string" ? {
8828
+ status: "current",
8829
+ current,
8830
+ latest
8831
+ } : void 0;
8832
+ case "available": {
8833
+ const releases = parseReleaseNotes(source["releases"]);
8834
+ return typeof latest === "string" && releases !== void 0 ? {
8835
+ status: "available",
8836
+ current,
8837
+ latest,
8838
+ releases
8839
+ } : void 0;
8840
+ }
8841
+ default: return;
8842
+ }
8843
+ }
8844
+ function readSeen(storage) {
8845
+ try {
8846
+ const value = storage?.getItem(RELEASE_NOTES_SEEN_KEY);
8847
+ return value !== null && value !== void 0 && isReleaseVersion(value) ? value : void 0;
8848
+ } catch {
8849
+ return;
8850
+ }
8851
+ }
8852
+ var ReleaseNotesController = class {
8853
+ source;
8854
+ call;
8855
+ storage;
8856
+ started;
8857
+ constructor(call, storage) {
8858
+ this.call = call;
8859
+ this.storage = storage;
8860
+ this.source = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
8861
+ version: void 0,
8862
+ announcement: void 0,
8863
+ firstRun: false,
8864
+ viewing: void 0,
8865
+ update: { status: "idle" }
8866
+ });
8867
+ }
8868
+ start() {
8869
+ this.started ??= this.announce().catch((error) => {
8870
+ this.started = void 0;
8871
+ console.warn("botharness: failed to read release notes", error);
8872
+ });
8873
+ return this.started;
8874
+ }
8875
+ dismiss() {
8876
+ const version = this.source.getSnapshot().version;
8877
+ if (version !== void 0 && isReleaseVersion(version)) try {
8878
+ this.storage?.setItem(RELEASE_NOTES_SEEN_KEY, version);
8879
+ } catch {
8880
+ console.warn("botharness: failed to remember the seen release");
8881
+ }
8882
+ this.source.update((draft) => {
8883
+ draft.announcement = void 0;
8884
+ });
8885
+ }
8886
+ view(releases) {
8887
+ this.source.update((draft) => {
8888
+ draft.viewing = releases;
8889
+ });
8890
+ }
8891
+ async checkUpdate(force = false) {
8892
+ const current = this.source.getSnapshot().update.status;
8893
+ if (current === "checking" || !force && current !== "idle") return;
8894
+ this.source.update((draft) => {
8895
+ draft.update = { status: "checking" };
8896
+ });
8897
+ let update;
8898
+ try {
8899
+ const result = await this.call("releaseUpdate", {});
8900
+ update = result.ok ? parseReleaseUpdate(result.value) : void 0;
8901
+ } catch {
8902
+ update = void 0;
8903
+ }
8904
+ this.source.update((draft) => {
8905
+ draft.update = update ?? {
8906
+ status: "unavailable",
8907
+ current: draft.version ?? ""
8908
+ };
8909
+ });
8910
+ }
8911
+ async announce() {
8912
+ const seen = readSeen(this.storage);
8913
+ const result = await this.call("releaseInfo", seen === void 0 ? {} : { since: seen });
8914
+ if (!result.ok) throw new Error(result.error.message);
8915
+ const info = parseReleaseInfo(result.value);
8916
+ if (info === void 0) throw new Error("invalid releaseInfo response");
8917
+ const fresh = isReleaseVersion(info.version) && (seen === void 0 || compareVersions(info.version, seen) > 0);
8918
+ this.source.update((draft) => {
8919
+ draft.version = info.version;
8920
+ draft.announcement = fresh && info.releases.length > 0 ? info.releases : void 0;
8921
+ draft.firstRun = seen === void 0;
8922
+ });
8923
+ if (fresh && info.releases.length === 0) this.dismiss();
8924
+ }
8925
+ };
8926
+ //#endregion
8927
+ //#region packages/client/src/client/modal.ts
8928
+ const Modal = _deepseek_ai_dsh_client_ui_primitives.Modal;
8929
+ //#endregion
8930
+ //#region packages/client/src/client/release-notes-view.tsx
8931
+ const SECTIONS = {
8932
+ "Breaking Changes": {
8933
+ key: "releaseNotes.section.breaking",
8934
+ tone: "danger"
8935
+ },
8936
+ Security: {
8937
+ key: "releaseNotes.section.security",
8938
+ tone: "danger"
8939
+ },
8940
+ Added: {
8941
+ key: "releaseNotes.section.added",
8942
+ tone: "success"
8943
+ },
8944
+ Changed: {
8945
+ key: "releaseNotes.section.changed",
8946
+ tone: "info"
8947
+ },
8948
+ Fixed: {
8949
+ key: "releaseNotes.section.fixed",
8950
+ tone: "warning"
8951
+ },
8952
+ Documentation: {
8953
+ key: "releaseNotes.section.documentation",
8954
+ tone: "neutral"
8955
+ },
8956
+ Deprecated: {
8957
+ key: "releaseNotes.section.deprecated",
8958
+ tone: "warning"
8959
+ },
8960
+ Removed: {
8961
+ key: "releaseNotes.section.removed",
8962
+ tone: "neutral"
8963
+ }
8964
+ };
8965
+ function releaseUpdateCommand(version) {
8966
+ return `dsh plugin --profile web add deepseekbot@${version}`;
8967
+ }
8968
+ function useReleaseNotes(controller) {
8969
+ return (0, react.useSyncExternalStore)(controller.source.subscribe, controller.source.getSnapshot);
8970
+ }
8971
+ function ReleaseNotesList({ releases, badge, t }) {
8972
+ const language = t("releaseNotes.language") === "en" ? "en" : "zh";
8973
+ const labels = (0, react.useMemo)(() => ({
8974
+ code: {
8975
+ copyLabel: t("message.code.copy"),
8976
+ copiedLabel: t("message.code.copied")
8977
+ },
8978
+ footnotes: t("message.footnotes")
8979
+ }), [t]);
8980
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8981
+ className: "bh-release-notes",
8982
+ "data-release-notes": true,
8983
+ children: releases.map((release, index) => {
8984
+ const entries = release.sections.flatMap((section) => section.entries.map((entry) => ({
8985
+ section: section.name,
8986
+ entry
8987
+ })));
8988
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
8989
+ className: "bh-release-note",
8990
+ "data-release-version": release.version,
8991
+ open: index === 0,
8992
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
8993
+ className: "bh-release-note-head",
8994
+ children: [
8995
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8996
+ className: "bh-release-note-version",
8997
+ children: ["v", release.version]
8998
+ }),
8999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
9000
+ dateTime: release.date,
9001
+ children: release.date
9002
+ }),
9003
+ index === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
9004
+ tone: "info",
9005
+ children: badge
9006
+ }) : null,
9007
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9008
+ className: "bh-release-note-rule",
9009
+ "aria-hidden": "true"
9010
+ }),
9011
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9012
+ className: "bh-release-note-count",
9013
+ children: t("releaseNotes.entryCount", { count: entries.length })
9014
+ })
9015
+ ]
9016
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9017
+ className: "bh-release-note-body",
9018
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9019
+ className: "bh-release-note-summary",
9020
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
9021
+ text: release.summary[language],
9022
+ labels
9023
+ })
9024
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
9025
+ className: "bh-release-note-entries",
9026
+ children: entries.map(({ section, entry }, entryIndex) => {
9027
+ const known = SECTIONS[section];
9028
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
9029
+ "data-release-section": section,
9030
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
9031
+ tone: known?.tone ?? "outline",
9032
+ className: "bh-release-note-chip",
9033
+ children: known === void 0 ? section : t(known.key)
9034
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9035
+ className: "bh-release-note-text",
9036
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
9037
+ text: entry[language],
9038
+ labels
9039
+ })
9040
+ })]
9041
+ }, entryIndex);
9042
+ })
9043
+ })]
9044
+ })]
9045
+ }, release.version);
9046
+ })
9047
+ });
9048
+ }
9049
+ function openSite(t) {
9050
+ window.open(t("releaseNotes.siteUrl"), "_blank", "noopener,noreferrer");
9051
+ }
9052
+ function ReleaseNotesDialog({ releases, title, badge, description, onClose, t }) {
9053
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Modal, {
9054
+ open: releases !== void 0,
9055
+ onClose,
9056
+ title,
9057
+ closeLabel: t("releaseNotes.close"),
9058
+ ...description === void 0 ? {} : { description },
9059
+ className: "bh-release-dialog",
9060
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9061
+ variant: "outline",
9062
+ className: "bh-release-site-button",
9063
+ onClick: () => {
9064
+ openSite(t);
9065
+ },
9066
+ children: t("releaseNotes.site")
9067
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9068
+ variant: "primary",
9069
+ onClick: onClose,
9070
+ children: t("releaseNotes.done")
9071
+ })] }),
9072
+ children: releases === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReleaseNotesList, {
9073
+ releases,
9074
+ badge,
9075
+ t
9076
+ })
9077
+ });
9078
+ }
9079
+ function ReleaseNotesAnnouncement({ controller, t }) {
9080
+ const snapshot = useReleaseNotes(controller);
9081
+ const mount = useMountedResource(() => {
9082
+ controller.start();
9083
+ }, [controller]);
9084
+ const version = snapshot.version ?? "";
9085
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9086
+ ref: mount,
9087
+ hidden: true,
9088
+ "aria-hidden": "true"
9089
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReleaseNotesDialog, {
9090
+ releases: snapshot.announcement,
9091
+ title: t("releaseNotes.announce.title", { version }),
9092
+ badge: t("releaseNotes.current"),
9093
+ description: t(snapshot.firstRun ? "releaseNotes.announce.firstRun" : "releaseNotes.announce.description"),
9094
+ onClose: () => {
9095
+ controller.dismiss();
9096
+ },
9097
+ t
9098
+ })] });
9099
+ }
9100
+ function statusText(snapshot, t) {
9101
+ const version = snapshot.version;
9102
+ if (version === void 0) return t("release.status.loading");
9103
+ const update = snapshot.update;
9104
+ switch (update.status) {
9105
+ case "development": return t("release.status.development", { version });
9106
+ case "available": return t("release.status.available", {
9107
+ version,
9108
+ latest: update.latest
9109
+ });
9110
+ case "current": return t("release.status.current", { version });
9111
+ case "unavailable": return t("release.status.unavailable", { version });
9112
+ default: return t("release.status.checking", { version });
9113
+ }
9114
+ }
9115
+ function ReleaseSettings({ releaseNotes, t }) {
9116
+ const snapshot = useReleaseNotes(releaseNotes);
9117
+ const [copied, setCopied] = (0, react.useState)(false);
9118
+ const mount = useMountedResource(() => {
9119
+ releaseNotes.start().then(() => releaseNotes.checkUpdate());
9120
+ }, [releaseNotes]);
9121
+ const update = snapshot.update;
9122
+ const command = update.status === "available" ? releaseUpdateCommand(update.latest) : void 0;
9123
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9124
+ className: "bh-release-settings",
9125
+ ref: mount,
9126
+ "data-release-settings": true,
9127
+ children: [
9128
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9129
+ className: "bh-settings-row bh-release-row",
9130
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9131
+ className: "bh-settings-row-text",
9132
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9133
+ className: "bh-settings-row-title",
9134
+ children: t("release.row.title")
9135
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9136
+ className: "bh-settings-row-desc",
9137
+ role: "status",
9138
+ "aria-live": "polite",
9139
+ children: statusText(snapshot, t)
9140
+ })]
9141
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9142
+ className: "bh-release-actions",
9143
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9144
+ size: "sm",
9145
+ variant: "outline",
9146
+ onClick: () => {
9147
+ openSite(t);
9148
+ },
9149
+ children: t("release.changelog")
9150
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9151
+ size: "sm",
9152
+ variant: "outline",
9153
+ disabled: update.status === "checking" || update.status === "development",
9154
+ onClick: () => {
9155
+ releaseNotes.checkUpdate(true);
9156
+ },
9157
+ children: t("release.check")
9158
+ })]
9159
+ })]
9160
+ }),
9161
+ update.status === "available" && command !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9162
+ className: "bh-release-update",
9163
+ "data-release-update": update.latest,
9164
+ children: [
9165
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9166
+ className: "bh-release-update-head",
9167
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9168
+ className: "bh-release-update-title",
9169
+ children: t("release.update.title", { latest: update.latest })
9170
+ }), update.releases.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9171
+ size: "sm",
9172
+ variant: "outline",
9173
+ onClick: () => {
9174
+ releaseNotes.view(update.releases);
9175
+ },
9176
+ children: t("release.update.notes")
9177
+ }) : null]
9178
+ }),
9179
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9180
+ className: "bh-settings-row-desc",
9181
+ children: t("release.update.cli")
9182
+ }),
9183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9184
+ className: "bh-release-command",
9185
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: command }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9186
+ size: "sm",
9187
+ variant: "outline",
9188
+ onClick: () => {
9189
+ navigator.clipboard?.writeText(command).then(() => {
9190
+ setCopied(true);
9191
+ });
9192
+ },
9193
+ children: t(copied ? "release.update.copied" : "release.update.copy")
9194
+ })]
9195
+ }),
9196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9197
+ className: "bh-settings-row-desc",
9198
+ children: t("release.update.desktop", { spec: `deepseekbot@${update.latest}` })
9199
+ })
9200
+ ]
9201
+ }) : null,
9202
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReleaseNotesDialog, {
9203
+ releases: snapshot.viewing,
9204
+ title: t("release.update.dialog", { latest: update.status === "available" ? update.latest : "" }),
9205
+ badge: t("releaseNotes.latest"),
9206
+ onClose: () => {
9207
+ releaseNotes.view(void 0);
9208
+ },
9209
+ t
9210
+ })
9211
+ ]
9212
+ });
9213
+ }
9214
+ //#endregion
8718
9215
  //#region node_modules/.pnpm/@botharness+botui-core@0.3.0/node_modules/@botharness/botui-core/dist/index.js
8719
9216
  const TAU$1 = Math.PI * 2;
8720
9217
  function clamp$1(v, a, b) {
@@ -11297,7 +11794,42 @@ window.__ModuleLoader__.load({
11297
11794
  "rail.copied": "已复制",
11298
11795
  "rail.you": "你",
11299
11796
  "rail.noMessages": "暂无消息",
11300
- "roster.readOnly": "名册存储不可用,陈列只读"
11797
+ "roster.readOnly": "名册存储不可用,陈列只读",
11798
+ "releaseNotes.language": "zh",
11799
+ "releaseNotes.siteUrl": "https://deepseekbot.botharness.ai/changelog/",
11800
+ "releaseNotes.site": "去官网查看",
11801
+ "releaseNotes.close": "关闭",
11802
+ "releaseNotes.done": "知道了",
11803
+ "releaseNotes.announce.title": "DeepSeekBot {version} 更新内容",
11804
+ "releaseNotes.announce.description": "以下是自你上次查看以来的变化。",
11805
+ "releaseNotes.announce.firstRun": "欢迎使用 DeepSeekBot,这是当前版本带来的内容。",
11806
+ "releaseNotes.latest": "最新",
11807
+ "releaseNotes.current": "当前版本",
11808
+ "releaseNotes.entryCount": "{count} 项",
11809
+ "releaseNotes.section.added": "新增",
11810
+ "releaseNotes.section.changed": "变更",
11811
+ "releaseNotes.section.fixed": "修复",
11812
+ "releaseNotes.section.documentation": "文档",
11813
+ "releaseNotes.section.breaking": "不兼容",
11814
+ "releaseNotes.section.deprecated": "弃用",
11815
+ "releaseNotes.section.removed": "移除",
11816
+ "releaseNotes.section.security": "安全",
11817
+ "release.row.title": "DeepSeekBot 版本",
11818
+ "release.status.loading": "正在读取当前版本…",
11819
+ "release.status.development": "源码构建({version}),不检查更新",
11820
+ "release.status.checking": "当前版本 {version},正在检查更新…",
11821
+ "release.status.current": "当前版本 {version},已是最新版本",
11822
+ "release.status.available": "当前版本 {version},新版本 {latest} 可用",
11823
+ "release.status.unavailable": "当前版本 {version},暂时无法连接 npm 检查更新",
11824
+ "release.changelog": "更新日志",
11825
+ "release.check": "检查更新",
11826
+ "release.update.title": "可以更新到 {latest}",
11827
+ "release.update.notes": "查看新版本内容",
11828
+ "release.update.dialog": "DeepSeekBot {latest} 更新内容",
11829
+ "release.update.cli": "在终端运行以下命令更新,完成后重启 DSH:",
11830
+ "release.update.copy": "复制",
11831
+ "release.update.copied": "已复制",
11832
+ "release.update.desktop": "桌面版:打开「插件 → 添加插件」,输入 {spec} 安装,然后重启 DSH。"
11301
11833
  };
11302
11834
  function zhTranslate(key, params) {
11303
11835
  let text = zh[key] ?? key;
@@ -12871,7 +13403,42 @@ My relationship with the Human, established lore and topics to avoid: [fill in].
12871
13403
  "rail.copied": "Copied",
12872
13404
  "rail.you": "You",
12873
13405
  "rail.noMessages": "No messages yet",
12874
- "roster.readOnly": "Roster storage unavailable; the arrangement is read-only"
13406
+ "roster.readOnly": "Roster storage unavailable; the arrangement is read-only",
13407
+ "releaseNotes.language": "en",
13408
+ "releaseNotes.siteUrl": "https://deepseekbot.botharness.ai/en/changelog/",
13409
+ "releaseNotes.site": "View on website",
13410
+ "releaseNotes.close": "Close",
13411
+ "releaseNotes.done": "Got it",
13412
+ "releaseNotes.announce.title": "What's new in DeepSeekBot {version}",
13413
+ "releaseNotes.announce.description": "Here is what changed since you last looked.",
13414
+ "releaseNotes.announce.firstRun": "Welcome to DeepSeekBot. Here is what this version brings.",
13415
+ "releaseNotes.latest": "Latest",
13416
+ "releaseNotes.current": "Installed",
13417
+ "releaseNotes.entryCount": "{count} changes",
13418
+ "releaseNotes.section.added": "Added",
13419
+ "releaseNotes.section.changed": "Changed",
13420
+ "releaseNotes.section.fixed": "Fixed",
13421
+ "releaseNotes.section.documentation": "Docs",
13422
+ "releaseNotes.section.breaking": "Breaking",
13423
+ "releaseNotes.section.deprecated": "Deprecated",
13424
+ "releaseNotes.section.removed": "Removed",
13425
+ "releaseNotes.section.security": "Security",
13426
+ "release.row.title": "DeepSeekBot version",
13427
+ "release.status.loading": "Reading the installed version…",
13428
+ "release.status.development": "Source build ({version}); updates are not checked",
13429
+ "release.status.checking": "Version {version}, checking for updates…",
13430
+ "release.status.current": "Version {version}, up to date",
13431
+ "release.status.available": "Version {version}, {latest} is available",
13432
+ "release.status.unavailable": "Version {version}, could not reach npm to check for updates",
13433
+ "release.changelog": "Changelog",
13434
+ "release.check": "Check for updates",
13435
+ "release.update.title": "Update to {latest}",
13436
+ "release.update.notes": "See what's new",
13437
+ "release.update.dialog": "What's new in DeepSeekBot {latest}",
13438
+ "release.update.cli": "Run this command in a terminal, then restart DSH:",
13439
+ "release.update.copy": "Copy",
13440
+ "release.update.copied": "Copied",
13441
+ "release.update.desktop": "Desktop app: open Plugins → Add plugin, install {spec}, then restart DSH."
12875
13442
  };
12876
13443
  //#endregion
12877
13444
  //#region node_modules/.pnpm/@botharness+pixel-morph@0.2.0/node_modules/@botharness/pixel-morph/dist/index.js
@@ -15071,9 +15638,6 @@ My relationship with the Human, established lore and topics to avoid: [fill in].
15071
15638
  }, [])
15072
15639
  };
15073
15640
  }
15074
- //#endregion
15075
- //#region packages/client/src/client/modal.ts
15076
- const Modal = _deepseek_ai_dsh_client_ui_primitives.Modal;
15077
15641
  function hiddenChannelSequence(channels, hiddenIds) {
15078
15642
  const byId = new Map(channels.map((channel) => [channel.id, channel]));
15079
15643
  const seen = /* @__PURE__ */ new Set();
@@ -40291,25 +40855,32 @@ My relationship with the Human, established lore and topics to avoid: [fill in].
40291
40855
  t
40292
40856
  }, `${scopeKey}:${state.conversation.channel?.id ?? ""}`);
40293
40857
  }
40294
- function BotPanel({ actions, nativeSessions, channelSidebar, profileCards, nativeChatT, t }) {
40858
+ function BotPanel({ actions, nativeSessions, channelSidebar, profileCards, nativeChatT, releaseNotes, t }) {
40295
40859
  const modeMount = useMountedResource(() => {
40296
40860
  store.setMode("bot");
40297
40861
  return () => {
40298
40862
  store.setMode("dsh");
40299
40863
  };
40300
40864
  }, []);
40301
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
40302
- ref: modeMount,
40303
- hidden: true,
40304
- "aria-hidden": "true"
40305
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BotMain, {
40306
- actions,
40307
- nativeSessions,
40308
- channelSidebar,
40309
- profileCards,
40310
- nativeChatT,
40311
- t
40312
- })] });
40865
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
40866
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
40867
+ ref: modeMount,
40868
+ hidden: true,
40869
+ "aria-hidden": "true"
40870
+ }),
40871
+ releaseNotes === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReleaseNotesAnnouncement, {
40872
+ controller: releaseNotes,
40873
+ t
40874
+ }),
40875
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BotMain, {
40876
+ actions,
40877
+ nativeSessions,
40878
+ channelSidebar,
40879
+ profileCards,
40880
+ nativeChatT,
40881
+ t
40882
+ })
40883
+ ] });
40313
40884
  }
40314
40885
  //#endregion
40315
40886
  //#region packages/client/src/client/memory-git-lanes.ts
@@ -49716,6 +50287,146 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
49716
50287
  .bh-overview-usage .bh-profile-pin:hover {background:var(--bh-hover);color:var(--bh-text);}
49717
50288
  .bh-overview-usage .bh-profile-pin:disabled {cursor:default;opacity:0.5;}
49718
50289
  .bh-statistics-content > header h3 {font-size:var(--bh-overview-font);margin:0;}
50290
+ .bh-release-dialog {
50291
+ width: min(680px, calc(100vw - 32px));
50292
+ }
50293
+ .bh-release-notes {
50294
+ display: flex;
50295
+ flex-direction: column;
50296
+ gap: 4px;
50297
+ max-height: min(60vh, 560px);
50298
+ overflow-y: auto;
50299
+ min-width: 0;
50300
+ }
50301
+ .bh-release-note {
50302
+ min-width: 0;
50303
+ }
50304
+ .bh-release-note-head {
50305
+ display: flex;
50306
+ align-items: center;
50307
+ gap: 8px;
50308
+ padding: 8px 0;
50309
+ cursor: pointer;
50310
+ list-style: none;
50311
+ color: var(--dsw-alias-label-tertiary);
50312
+ font-size: 12px;
50313
+ line-height: 20px;
50314
+ }
50315
+ .bh-release-note-head::-webkit-details-marker {
50316
+ display: none;
50317
+ }
50318
+ .bh-release-note-head::before {
50319
+ content: '';
50320
+ flex: none;
50321
+ width: 6px;
50322
+ height: 6px;
50323
+ margin: 0 2px;
50324
+ border-right: 1.5px solid currentColor;
50325
+ border-bottom: 1.5px solid currentColor;
50326
+ transform: rotate(-45deg);
50327
+ transition: transform 0.15s ease;
50328
+ }
50329
+ .bh-release-note[open] > .bh-release-note-head::before {
50330
+ transform: rotate(45deg);
50331
+ }
50332
+ .bh-release-note-head:hover .bh-release-note-version {
50333
+ color: var(--bh-accent, var(--dsw-alias-state-business-primary));
50334
+ }
50335
+ .bh-release-note-version {
50336
+ font-size: 15px;
50337
+ font-weight: 600;
50338
+ line-height: 22px;
50339
+ color: var(--dsw-alias-label-primary);
50340
+ }
50341
+ .bh-release-note-rule {
50342
+ flex: 1;
50343
+ min-width: 16px;
50344
+ height: 1px;
50345
+ background: var(--dsw-alias-border-l2);
50346
+ }
50347
+ .bh-release-note-count {
50348
+ flex: none;
50349
+ font-variant-numeric: tabular-nums;
50350
+ }
50351
+ .bh-release-note-body {
50352
+ display: flex;
50353
+ flex-direction: column;
50354
+ gap: 10px;
50355
+ padding: 2px 0 12px 18px;
50356
+ }
50357
+ .bh-release-note-summary {
50358
+ color: var(--dsw-alias-label-secondary);
50359
+ font-size: 13px;
50360
+ }
50361
+ .bh-release-note-entries {
50362
+ display: grid;
50363
+ grid-template-columns: auto minmax(0, 1fr);
50364
+ align-items: start;
50365
+ gap: 8px 10px;
50366
+ margin: 0;
50367
+ padding: 0;
50368
+ list-style: none;
50369
+ }
50370
+ .bh-release-note-entries > li {
50371
+ display: contents;
50372
+ }
50373
+ .bh-release-note-chip {
50374
+ justify-self: stretch;
50375
+ justify-content: center;
50376
+ margin-top: 2px;
50377
+ white-space: nowrap;
50378
+ }
50379
+ .bh-release-note-text {
50380
+ min-width: 0;
50381
+ font-size: 13px;
50382
+ color: var(--dsw-alias-label-primary);
50383
+ }
50384
+ .bh-release-site-button {
50385
+ margin-right: auto;
50386
+ }
50387
+ .bh-release-actions {
50388
+ display: flex;
50389
+ align-items: center;
50390
+ gap: 8px;
50391
+ flex: none;
50392
+ }
50393
+ .bh-release-update {
50394
+ display: flex;
50395
+ flex-direction: column;
50396
+ gap: 8px;
50397
+ margin: 12px 0 4px;
50398
+ padding: 12px 14px;
50399
+ border: 1px solid var(--dsw-alias-border-l2);
50400
+ border-radius: 10px;
50401
+ }
50402
+ .bh-release-update-head {
50403
+ display: flex;
50404
+ align-items: center;
50405
+ justify-content: space-between;
50406
+ gap: 8px;
50407
+ }
50408
+ .bh-release-update-title {
50409
+ font-size: 14px;
50410
+ font-weight: 600;
50411
+ color: var(--dsw-alias-label-primary);
50412
+ }
50413
+ .bh-release-command {
50414
+ display: flex;
50415
+ align-items: center;
50416
+ gap: 8px;
50417
+ min-width: 0;
50418
+ }
50419
+ .bh-release-command code {
50420
+ flex: 1;
50421
+ min-width: 0;
50422
+ overflow-x: auto;
50423
+ padding: 6px 10px;
50424
+ border-radius: 6px;
50425
+ background: var(--dsw-alias-bg-module-platform);
50426
+ font-family: var(--dsw-font-family-mono, monospace);
50427
+ font-size: 12px;
50428
+ white-space: nowrap;
50429
+ }
49719
50430
  `;
49720
50431
  //#endregion
49721
50432
  //#region packages/client/src/client/index.ts
@@ -49775,6 +50486,7 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
49775
50486
  }
49776
50487
  });
49777
50488
  const prefs = new BotModePrefs(storage);
50489
+ const releaseNotes = new ReleaseNotesController(call, storage);
49778
50490
  const lastView = typeof window === "undefined" ? void 0 : consumeLastView(window, storage);
49779
50491
  let restoreBotMode = hmrView === void 0 && lastView?.mode === "bot";
49780
50492
  const nativeSessions = {
@@ -49893,6 +50605,13 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
49893
50605
  };
49894
50606
  }
49895
50607
  });
50608
+ settingsCtx.slots.inject("botharness.settings.item", () => settingsCtx.slots.register({
50609
+ name: "botharness.settings.item",
50610
+ id: "release",
50611
+ order: -20,
50612
+ locale: LOCALE_NS,
50613
+ inject: () => ({ releaseNotes })
50614
+ }, ReleaseSettings));
49896
50615
  settingsCtx.slots.inject("botharness.settings.item", () => settingsCtx.slots.register({
49897
50616
  name: "botharness.settings.item",
49898
50617
  id: "human-name",
@@ -49960,7 +50679,8 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
49960
50679
  channelSidebar,
49961
50680
  profileCards,
49962
50681
  nativeChatT,
49963
- nativeSessions
50682
+ nativeSessions,
50683
+ releaseNotes
49964
50684
  })
49965
50685
  }, BotPanel);
49966
50686
  if (restoreBotMode) {