@botharness/ui 0.1.0-alpha.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
@@ -214,13 +214,13 @@ window.__ModuleLoader__.load({
214
214
  0
215
215
  ].map((bit) => n >> bit & 255);
216
216
  }
217
- function hex(values) {
217
+ function hex$1(values) {
218
218
  return `#${values.map((v) => Math.min(255, Math.max(0, Math.round(v))).toString(16).padStart(2, "0")).join("")}`;
219
219
  }
220
- const shade = (color, k) => hex(channels$1(color).map((v) => v * k));
220
+ const shade = (color, k) => hex$1(channels$1(color).map((v) => v * k));
221
221
  const mix$1 = (base, tint, k) => {
222
222
  const t = channels$1(tint);
223
- return hex(channels$1(base).map((v, i) => v * (1 - k) + t[i] * k));
223
+ return hex$1(channels$1(base).map((v, i) => v * (1 - k) + t[i] * k));
224
224
  };
225
225
  function paint$1(grid, test, color) {
226
226
  for (let y = 0; y < N$2; y++) for (let x = 0; x < N$2; x++) if (test(x, y)) grid[y][x] = color;
@@ -844,7 +844,7 @@ window.__ModuleLoader__.load({
844
844
  const k = (n + hue * 2) % 12;
845
845
  return l - s * Math.min(l, .12) * Math.max(-1, Math.min(k - 3, 9 - k, 1));
846
846
  };
847
- return hex([
847
+ return hex$1([
848
848
  f(0),
849
849
  f(8),
850
850
  f(4)
@@ -2793,6 +2793,138 @@ window.__ModuleLoader__.load({
2793
2793
  };
2794
2794
  }
2795
2795
  //#endregion
2796
+ //#region packages/core/src/marketplace/altcha.ts
2797
+ const ALTCHA_ALGORITHM = "SHA-256";
2798
+ const encoder = new TextEncoder();
2799
+ function hex(buffer) {
2800
+ return [...new Uint8Array(buffer)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
2801
+ }
2802
+ async function sha256Hex(text) {
2803
+ return hex(await crypto.subtle.digest("SHA-256", encoder.encode(text)));
2804
+ }
2805
+ function record$3(value) {
2806
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2807
+ }
2808
+ function parseChallenge(value) {
2809
+ const source = record$3(value);
2810
+ if (source === void 0 || source["algorithm"] !== "SHA-256") return void 0;
2811
+ const { challenge, maxnumber, salt, signature } = source;
2812
+ if (typeof challenge !== "string" || typeof salt !== "string" || typeof signature !== "string") return;
2813
+ if (typeof maxnumber !== "number" || !Number.isSafeInteger(maxnumber) || maxnumber < 0) return;
2814
+ return {
2815
+ algorithm: ALTCHA_ALGORITHM,
2816
+ challenge,
2817
+ maxnumber,
2818
+ salt,
2819
+ signature
2820
+ };
2821
+ }
2822
+ function encodeSolution(solution) {
2823
+ return btoa(JSON.stringify(solution));
2824
+ }
2825
+ async function solveChallenge(challenge, options = {}) {
2826
+ const batch = options.batch ?? 2e3;
2827
+ for (let start = 0; start <= challenge.maxnumber; start += batch) {
2828
+ if (options.signal?.aborted === true) return void 0;
2829
+ const numbers = Array.from({ length: Math.min(batch, challenge.maxnumber - start + 1) }, (_, index) => start + index);
2830
+ const number = numbers[(await Promise.all(numbers.map((number) => sha256Hex(`${challenge.salt}${number}`)))).indexOf(challenge.challenge)];
2831
+ if (number !== void 0) return encodeSolution({
2832
+ algorithm: ALTCHA_ALGORITHM,
2833
+ challenge: challenge.challenge,
2834
+ number,
2835
+ salt: challenge.salt,
2836
+ signature: challenge.signature
2837
+ });
2838
+ await options.yieldEvery?.();
2839
+ }
2840
+ }
2841
+ //#endregion
2842
+ //#region packages/core/src/marketplace/client.ts
2843
+ function record$2(value) {
2844
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2845
+ }
2846
+ function parseEntry(value) {
2847
+ const source = record$2(value);
2848
+ if (source === void 0) return void 0;
2849
+ if (![
2850
+ "id",
2851
+ "owner",
2852
+ "name",
2853
+ "fullName",
2854
+ "pushedAt",
2855
+ "htmlUrl",
2856
+ "cloneUrl",
2857
+ "defaultBranch"
2858
+ ].every((key) => typeof source[key] === "string")) return void 0;
2859
+ const description = source["description"];
2860
+ const stars = source["stars"];
2861
+ const topics = source["topics"];
2862
+ const head = record$2(source["headCommit"]);
2863
+ if (description !== null && typeof description !== "string") return void 0;
2864
+ if (typeof stars !== "number" || !Array.isArray(topics)) return void 0;
2865
+ const displayName = source["displayName"];
2866
+ const roles = source["roles"];
2867
+ return {
2868
+ id: source["id"],
2869
+ owner: source["owner"],
2870
+ name: source["name"],
2871
+ fullName: source["fullName"],
2872
+ displayName: typeof displayName === "string" && displayName.length > 0 ? displayName : null,
2873
+ roles: Array.isArray(roles) ? roles.filter((role) => typeof role === "string") : [],
2874
+ description,
2875
+ topics: topics.filter((topic) => typeof topic === "string"),
2876
+ stars,
2877
+ pushedAt: source["pushedAt"],
2878
+ htmlUrl: source["htmlUrl"],
2879
+ cloneUrl: source["cloneUrl"],
2880
+ defaultBranch: source["defaultBranch"],
2881
+ headCommit: head !== void 0 && typeof head["sha"] === "string" && typeof head["committedAt"] === "string" ? {
2882
+ sha: head["sha"],
2883
+ committedAt: head["committedAt"]
2884
+ } : null
2885
+ };
2886
+ }
2887
+ function parseMarketplacePage(value) {
2888
+ const source = record$2(value);
2889
+ if (source === void 0 || !Array.isArray(source["bots"])) return void 0;
2890
+ const bots = source["bots"].map(parseEntry);
2891
+ if (!bots.every((bot) => bot !== void 0)) return void 0;
2892
+ const nextCursor = source["nextCursor"];
2893
+ return typeof nextCursor === "string" ? {
2894
+ bots,
2895
+ nextCursor
2896
+ } : { bots };
2897
+ }
2898
+ function parseMarketplaceDetail(value) {
2899
+ const source = record$2(value);
2900
+ const bot = parseEntry(source?.["bot"]);
2901
+ const readme = source?.["readme"];
2902
+ const commitSha = source?.["commitSha"];
2903
+ if (bot === void 0 || readme !== null && typeof readme !== "string") return void 0;
2904
+ if (commitSha !== null && typeof commitSha !== "string") return void 0;
2905
+ return {
2906
+ bot,
2907
+ readme,
2908
+ commitSha
2909
+ };
2910
+ }
2911
+ function parseMarketplaceTopics(value) {
2912
+ const topics = record$2(value)?.["topics"];
2913
+ if (!Array.isArray(topics)) return void 0;
2914
+ const parsed = topics.map((item) => {
2915
+ const source = record$2(item);
2916
+ return typeof source?.["topic"] === "string" && typeof source["count"] === "number" ? {
2917
+ topic: source["topic"],
2918
+ count: source["count"]
2919
+ } : void 0;
2920
+ });
2921
+ return parsed.every((item) => item !== void 0) ? parsed : void 0;
2922
+ }
2923
+ function parseMarketplaceSubmission(value) {
2924
+ const bot = parseEntry(record$2(value)?.["bot"]);
2925
+ return bot === void 0 ? void 0 : { bot };
2926
+ }
2927
+ //#endregion
2796
2928
  //#region packages/client/src/client/roster.ts
2797
2929
  function emptyRosterSnapshot() {
2798
2930
  return {
@@ -3531,6 +3663,41 @@ window.__ModuleLoader__.load({
3531
3663
  if (bot === void 0) throw new Error("invalid create response");
3532
3664
  return bot;
3533
3665
  }
3666
+ async function loadMarketplacePage(call, query = {}) {
3667
+ const page = parseMarketplacePage(await unwrap(call, "marketplaceList", { query }));
3668
+ if (page === void 0) throw new Error("invalid marketplaceList response");
3669
+ return page;
3670
+ }
3671
+ async function loadMarketplaceDetail(call, id) {
3672
+ const detail = parseMarketplaceDetail(await unwrap(call, "marketplaceDetail", { id }));
3673
+ if (detail === void 0) throw new Error("invalid marketplaceDetail response");
3674
+ return detail;
3675
+ }
3676
+ async function loadMarketplaceTopics(call) {
3677
+ const topics = parseMarketplaceTopics({ topics: await unwrap(call, "marketplaceTopics", {}) });
3678
+ if (topics === void 0) throw new Error("invalid marketplaceTopics response");
3679
+ return topics;
3680
+ }
3681
+ async function loadMarketplaceChallenge(call) {
3682
+ const challenge = parseChallenge(await unwrap(call, "marketplaceChallenge", {}));
3683
+ if (challenge === void 0) throw new Error("invalid marketplaceChallenge response");
3684
+ return challenge;
3685
+ }
3686
+ async function submitMarketplaceRepository(call, url, altcha) {
3687
+ const result = parseMarketplaceSubmission(await unwrap(call, "marketplaceSubmit", {
3688
+ url,
3689
+ altcha
3690
+ }));
3691
+ if (result === void 0) throw new Error("invalid marketplaceSubmit response");
3692
+ return result.bot;
3693
+ }
3694
+ async function reportMarketplaceBot(call, id, altcha, reason) {
3695
+ await unwrap(call, "marketplaceReport", {
3696
+ id,
3697
+ altcha,
3698
+ ...reason === void 0 ? {} : { reason }
3699
+ });
3700
+ }
3534
3701
  async function loadChannels(call, signal) {
3535
3702
  return parseChannelRecords(await unwrap(call, "channels", {}, signal));
3536
3703
  }
@@ -4499,7 +4666,8 @@ window.__ModuleLoader__.load({
4499
4666
  ]) || source?.["localChannelId"] !== void 0 && (typeof source["localChannelId"] !== "string" || source["localChannelId"].length === 0) || !Number.isInteger(source?.["grantRevision"]) || Number(source?.["grantRevision"]) < 1 || event?.["version"] !== 1 || ![
4500
4667
  "feishu",
4501
4668
  "slack",
4502
- "discord"
4669
+ "discord",
4670
+ "weixin"
4503
4671
  ].includes(String(event["channel"])) || !strings(event, [
4504
4672
  "botId",
4505
4673
  "fingerprint",
@@ -4519,7 +4687,7 @@ window.__ModuleLoader__.load({
4519
4687
  "messageId",
4520
4688
  "resourceKey",
4521
4689
  "name"
4522
- ]) && (asRecord$1(file)?.["sizeBytes"] === void 0 || Number.isSafeInteger(asRecord$1(file)?.["sizeBytes"]) && Number(asRecord$1(file)?.["sizeBytes"]) > 0 && Number(asRecord$1(file)?.["sizeBytes"]) <= 26214400) && (asRecord$1(file)?.["mediaType"] === void 0 || typeof asRecord$1(file)?.["mediaType"] === "string"))) || replay?.["kind"] !== "provider-redelivery" || replay["resumeCursor"] !== false || replay["gapPossible"] !== true) throw new BridgeCallError("invalid-response", "Invalid source");
4690
+ ]) && (asRecord$1(file)?.["sizeBytes"] === void 0 || Number.isSafeInteger(asRecord$1(file)?.["sizeBytes"]) && Number(asRecord$1(file)?.["sizeBytes"]) > 0 && Number(asRecord$1(file)?.["sizeBytes"]) <= Number.MAX_SAFE_INTEGER) && (asRecord$1(file)?.["mediaType"] === void 0 || typeof asRecord$1(file)?.["mediaType"] === "string"))) || replay?.["kind"] !== "provider-redelivery" || replay["resumeCursor"] !== false || replay["gapPossible"] !== true) throw new BridgeCallError("invalid-response", "Invalid source");
4523
4691
  if (source?.["receptionPaths"] !== void 0 && (!Array.isArray(source["receptionPaths"]) || !source["receptionPaths"].every((value) => {
4524
4692
  const path = asRecord$1(value);
4525
4693
  return path && strings(path, [
@@ -6342,6 +6510,12 @@ window.__ModuleLoader__.load({
6342
6510
  profileActivity: (channelId) => loadProfileActivity(call, channelId),
6343
6511
  overviewMemory: (after) => loadOverviewMemory(call, after),
6344
6512
  overviewUsage: (period, after) => loadOverviewUsage(call, period, after),
6513
+ marketplaceList: (query) => loadMarketplacePage(call, query),
6514
+ marketplaceChallenge: () => loadMarketplaceChallenge(call),
6515
+ marketplaceSubmit: (url, altcha) => submitMarketplaceRepository(call, url, altcha),
6516
+ marketplaceReport: (id, altcha, reason) => reportMarketplaceBot(call, id, altcha, reason),
6517
+ marketplaceTopics: () => loadMarketplaceTopics(call),
6518
+ marketplaceDetail: (id) => loadMarketplaceDetail(call, id),
6345
6519
  profileUsage: (channelId, filter) => loadProfileUsage(call, channelId, filter),
6346
6520
  channelActivityToday: () => loadChannelActivityToday(call),
6347
6521
  groupProfileActivity: (channelId) => loadGroupProfileActivity(call, channelId),
@@ -8541,6 +8715,503 @@ window.__ModuleLoader__.load({
8541
8715
  });
8542
8716
  }
8543
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
8544
9215
  //#region node_modules/.pnpm/@botharness+botui-core@0.3.0/node_modules/@botharness/botui-core/dist/index.js
8545
9216
  const TAU$1 = Math.PI * 2;
8546
9217
  function clamp$1(v, a, b) {
@@ -9919,6 +10590,74 @@ window.__ModuleLoader__.load({
9919
10590
  "roster.menu.createBot": "创建 PersonaBot",
9920
10591
  "roster.menu.createChannel": "创建频道",
9921
10592
  "roster.menu.createSection": "创建频道分组",
10593
+ "roster.menu.marketplace": "Bot 市场",
10594
+ "market.title": "Bot 市场",
10595
+ "market.description": "浏览公开 GitHub 仓库分享的 Bot,安装后会成为一个新的 PersonaBot。",
10596
+ "market.submit.label": "GitHub 仓库地址",
10597
+ "market.submit.placeholder": "贴入 https://github.com/owner/repo 立即收录",
10598
+ "market.submit.hint": "仓库需公开,并在 GitHub 上添加 botharness-bot 话题。",
10599
+ "market.submit.action": "收录",
10600
+ "market.submit.busy": "收录中…",
10601
+ "market.submit.done": "已收录 {name}",
10602
+ "market.loading": "正在加载 Bot 市场…",
10603
+ "market.loadMore": "加载更多",
10604
+ "market.loadingMore": "加载中…",
10605
+ "market.retry": "重试",
10606
+ "market.empty": "还没有收录的 Bot。贴入一个仓库地址试试。",
10607
+ "market.search.label": "搜索 Bot",
10608
+ "market.search.placeholder": "搜索名称、描述、话题或 README",
10609
+ "market.search.relevance": "搜索结果按相关度排序,最多显示前 200 个。",
10610
+ "market.search.empty": "没有符合条件的 Bot。换个关键词或话题试试。",
10611
+ "market.sort.label": "排序",
10612
+ "market.sort.updated": "最近更新",
10613
+ "market.sort.stars": "最多 Star",
10614
+ "market.topics.label": "按话题筛选",
10615
+ "market.topics.all": "全部",
10616
+ "market.detail.open": "查看 {name} 详情",
10617
+ "market.detail.github": "在 GitHub 查看",
10618
+ "market.detail.loading": "正在加载 README…",
10619
+ "market.detail.error": "README 加载失败:{error}",
10620
+ "market.detail.noReadme": "这个仓库没有 README。",
10621
+ "market.error.botNotFound": "这个 Bot 已不在市场中。",
10622
+ "market.challenge.verifying": "正在验证…",
10623
+ "market.report.open": "举报",
10624
+ "market.report.title": "举报这个 Bot",
10625
+ "market.report.hint": "不需要账号。多个不同来源举报后,这个 Bot 会先从市场中隐藏,等待管理员复核。",
10626
+ "market.report.reason": "理由(可选)",
10627
+ "market.report.placeholder": "例如:冒充他人、垃圾内容、恶意指令",
10628
+ "market.report.send": "提交举报",
10629
+ "market.report.sending": "提交中…",
10630
+ "market.report.doneTitle": "已收到举报",
10631
+ "market.report.done": "谢谢。达到一定数量的独立举报后,这个 Bot 会先被隐藏,等待管理员复核。",
10632
+ "market.error.challengeUnavailable": "人机验证暂时不可用,请稍后重试。",
10633
+ "market.error.challenge": "人机验证没有通过或已过期,请重试。",
10634
+ "market.error.rateLimited": "操作太频繁,请稍后再试。",
10635
+ "market.error.repositoryRateLimited": "这个仓库刚刚收录过,5 分钟后才能再次收录。",
10636
+ "market.error.invalidReport": "举报理由最多 500 字。",
10637
+ "market.stars": "★ {count}",
10638
+ "market.updated": "更新于 {date}",
10639
+ "market.install": "安装",
10640
+ "market.install.failed": "安装失败:{error}",
10641
+ "market.back": "返回",
10642
+ "market.confirm.title": "安装 {name}",
10643
+ "market.confirm.source": "来源",
10644
+ "market.confirm.commit": "最新提交",
10645
+ "market.confirm.commitValue": "{sha} · {date}",
10646
+ "market.confirm.noCommit": "未知",
10647
+ "market.confirm.riskTitle": "这是第三方仓库",
10648
+ "market.confirm.risk": "仓库文件会成为新 Bot 的 Memory,可能包含有害内容或会被 Bot 执行的指令。请只安装你信任的仓库。",
10649
+ "market.confirm.newer": "安装时会克隆当时的最新提交,可能比这里显示的更新。",
10650
+ "market.confirm.install": "确认安装",
10651
+ "market.confirm.installing": "安装中…",
10652
+ "market.error.load": "加载失败:{error}",
10653
+ "market.error.unavailable": "Bot 市场暂时无法访问,请稍后重试。",
10654
+ "market.error.invalidUrl": "请贴入 GitHub 仓库地址,例如 https://github.com/owner/repo。",
10655
+ "market.error.notFound": "找不到这个仓库,请确认地址正确且仓库是公开的。",
10656
+ "market.error.private": "这个仓库是私有的,公开后才能收录。",
10657
+ "market.error.archived": "这个仓库已归档,无法收录。",
10658
+ "market.error.missingTopic": "仓库还没有 botharness-bot 话题。在 GitHub 仓库的 About 中添加后再试。",
10659
+ "market.error.blocked": "这个仓库已被屏蔽或因举报隐藏,无法收录。",
10660
+ "market.error.upstream": "GitHub 暂时无法访问,请稍后重试。",
9922
10661
  "section.rename.title": "重命名频道分组",
9923
10662
  "section.delete.title": "删除频道分组",
9924
10663
  "section.delete.description": "将把“{name}”从名册中移除。其中的频道会移出分组、变为未分组频道,不会被删除。",
@@ -9942,6 +10681,37 @@ window.__ModuleLoader__.load({
9942
10681
  "bot.create.importing": "正在克隆仓库…",
9943
10682
  "bot.create.source.label": "记忆来源",
9944
10683
  "bot.create.source.empty": "从空白创建",
10684
+ "bot.create.persona.preset": "人格起点",
10685
+ "bot.create.persona.blank": "空白",
10686
+ "bot.create.persona.colleague": "同事",
10687
+ "bot.create.persona.roleplay": "角色扮演",
10688
+ "bot.create.persona.label": "人格(可选)",
10689
+ "bot.create.persona.hint": "只是起始文本,可自由修改;不会改变工具权限或运行能力。",
10690
+ "bot.create.persona.placeholder": "描述这个 Bot 的身份、表达方式和边界,也可以留空。",
10691
+ "bot.create.persona.colleague.seed": `# 身份
10692
+ 我叫 [名字],是一名 [岗位]。我的背景、性格和价值观:[填写]。
10693
+
10694
+ # 职责
10695
+ 我主要负责 [工作范围]。擅长:[填写];需要他人协助的领域:[填写]。
10696
+
10697
+ # 协作方式
10698
+ 我通常以 [语气和沟通方式] 与 Human 和同事协作。遇到不确定的信息会说明;需要澄清或授权时会先询问。
10699
+
10700
+ # 边界
10701
+ 我的承诺和需要避免的行为:[填写]。
10702
+ `,
10703
+ "bot.create.persona.roleplay.seed": `# 角色与世界
10704
+ 我叫 [名字],是 [种族 / 身份],生活在 [时代、世界和背景]。
10705
+
10706
+ # 个性与动机
10707
+ 我的经历、信念、目标和关系:[填写]。
10708
+
10709
+ # 声音与表现
10710
+ 我的语气、用词和行为习惯:[填写]。标志性的表达:[填写]。
10711
+
10712
+ # 互动边界
10713
+ 与 Human 的关系、需要遵守的设定和希望避开的内容:[填写]。
10714
+ `,
9945
10715
  "bot.create.source.git": "从 Git 仓库导入",
9946
10716
  "bot.create.gitUrl.label": "Git 仓库地址",
9947
10717
  "bot.create.gitUrl.placeholder": "https://github.com/owner/repo.git",
@@ -10041,6 +10811,12 @@ window.__ModuleLoader__.load({
10041
10811
  "im.origin": "外部来源",
10042
10812
  "im.senderLabel": "发送人 ID",
10043
10813
  "im.platformLabel": "平台",
10814
+ "im.platform.weixin": "微信",
10815
+ "im.receiveHintDM": "只接收扫码绑定者的微信私聊文本,进入此 Bot 的 Inbox,不占用本地 DM 历史。",
10816
+ "im.receptionDM": "微信私聊接收已连接",
10817
+ "im.receiveEnableDM": "接收微信私聊",
10818
+ "im.receiveDisableDM": "关闭微信私聊收件",
10819
+ "im.receptionDMOff": "微信私聊收件已关闭",
10044
10820
  "im.platform.feishu": "Lark/飞书",
10045
10821
  "im.conversationLabel": "外部频道",
10046
10822
  "im.conversationId": "外部频道 ID",
@@ -10183,6 +10959,9 @@ window.__ModuleLoader__.load({
10183
10959
  "im.originDetails": "来源详情",
10184
10960
  "im.threadLabel": "话题",
10185
10961
  "im.groupLabel": "群聊",
10962
+ "im.dmLabel": "私聊",
10963
+ "im.weixinUser": "微信用户",
10964
+ "im.weixinReplyOnly": "支持回复已收取的微信私聊文字和文件;主动发送尚未开放。",
10186
10965
  "im.receivedAs": "接收身份:{name}",
10187
10966
  "im.readDetails": "读取记录 · {count} 次",
10188
10967
  "im.sourceError": "无法读取已保存的外部消息",
@@ -11015,7 +11794,42 @@ window.__ModuleLoader__.load({
11015
11794
  "rail.copied": "已复制",
11016
11795
  "rail.you": "你",
11017
11796
  "rail.noMessages": "暂无消息",
11018
- "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。"
11019
11833
  };
11020
11834
  function zhTranslate(key, params) {
11021
11835
  let text = zh[key] ?? key;
@@ -11385,6 +12199,74 @@ window.__ModuleLoader__.load({
11385
12199
  "roster.menu.createBot": "Create PersonaBot",
11386
12200
  "roster.menu.createChannel": "Create channel",
11387
12201
  "roster.menu.createSection": "Create channel section",
12202
+ "roster.menu.marketplace": "Bot Marketplace",
12203
+ "market.title": "Bot Marketplace",
12204
+ "market.description": "Browse Bots shared as public GitHub repositories. Installing one creates a new PersonaBot.",
12205
+ "market.submit.label": "GitHub repository URL",
12206
+ "market.submit.placeholder": "Paste https://github.com/owner/repo to list it now",
12207
+ "market.submit.hint": "The repository must be public and carry the botharness-bot topic on GitHub.",
12208
+ "market.submit.action": "List",
12209
+ "market.submit.busy": "Listing…",
12210
+ "market.submit.done": "Listed {name}",
12211
+ "market.loading": "Loading Bot Marketplace…",
12212
+ "market.loadMore": "Load more",
12213
+ "market.loadingMore": "Loading…",
12214
+ "market.retry": "Retry",
12215
+ "market.empty": "No Bots listed yet. Paste a repository URL to add one.",
12216
+ "market.search.label": "Search Bots",
12217
+ "market.search.placeholder": "Search names, descriptions, topics or READMEs",
12218
+ "market.search.relevance": "Results are ordered by relevance, up to the first 200.",
12219
+ "market.search.empty": "No Bots match. Try another keyword or topic.",
12220
+ "market.sort.label": "Sort",
12221
+ "market.sort.updated": "Recently updated",
12222
+ "market.sort.stars": "Most stars",
12223
+ "market.topics.label": "Filter by topic",
12224
+ "market.topics.all": "All",
12225
+ "market.detail.open": "View {name} details",
12226
+ "market.detail.github": "View on GitHub",
12227
+ "market.detail.loading": "Loading README…",
12228
+ "market.detail.error": "Could not load README: {error}",
12229
+ "market.detail.noReadme": "This repository has no README.",
12230
+ "market.error.botNotFound": "This Bot is no longer in the Marketplace.",
12231
+ "market.challenge.verifying": "Verifying…",
12232
+ "market.report.open": "Report",
12233
+ "market.report.title": "Report this Bot",
12234
+ "market.report.hint": "No account needed. After reports from several different sources, this Bot is hidden from the Marketplace until an administrator reviews it.",
12235
+ "market.report.reason": "Reason (optional)",
12236
+ "market.report.placeholder": "For example: impersonation, spam, harmful instructions",
12237
+ "market.report.send": "Send report",
12238
+ "market.report.sending": "Sending…",
12239
+ "market.report.doneTitle": "Report received",
12240
+ "market.report.done": "Thank you. After enough independent reports, this Bot is hidden until an administrator reviews it.",
12241
+ "market.error.challengeUnavailable": "Verification is unavailable right now. Try again later.",
12242
+ "market.error.challenge": "Verification failed or expired. Try again.",
12243
+ "market.error.rateLimited": "Too many requests. Try again later.",
12244
+ "market.error.repositoryRateLimited": "This repository was just listed. Try again in 5 minutes.",
12245
+ "market.error.invalidReport": "The reason can be at most 500 characters.",
12246
+ "market.stars": "★ {count}",
12247
+ "market.updated": "Updated {date}",
12248
+ "market.install": "Install",
12249
+ "market.install.failed": "Install failed: {error}",
12250
+ "market.back": "Back",
12251
+ "market.confirm.title": "Install {name}",
12252
+ "market.confirm.source": "Source",
12253
+ "market.confirm.commit": "Latest commit",
12254
+ "market.confirm.commitValue": "{sha} · {date}",
12255
+ "market.confirm.noCommit": "Unknown",
12256
+ "market.confirm.riskTitle": "This is a third-party repository",
12257
+ "market.confirm.risk": "Its files become the new Bot's Memory and may contain harmful content or instructions the Bot will follow. Install only repositories you trust.",
12258
+ "market.confirm.newer": "Install clones the latest commit at that moment, which may be newer than shown here.",
12259
+ "market.confirm.install": "Install",
12260
+ "market.confirm.installing": "Installing…",
12261
+ "market.error.load": "Could not load: {error}",
12262
+ "market.error.unavailable": "Bot Marketplace is unreachable right now. Try again later.",
12263
+ "market.error.invalidUrl": "Paste a GitHub repository URL, such as https://github.com/owner/repo.",
12264
+ "market.error.notFound": "Repository not found. Check the URL and that the repository is public.",
12265
+ "market.error.private": "This repository is private. Make it public to list it.",
12266
+ "market.error.archived": "This repository is archived and cannot be listed.",
12267
+ "market.error.missingTopic": "The repository does not have the botharness-bot topic yet. Add it under About on GitHub and retry.",
12268
+ "market.error.blocked": "This repository is blocked or hidden after reports.",
12269
+ "market.error.upstream": "GitHub is unreachable right now. Try again later.",
11388
12270
  "section.rename.title": "Rename channel section",
11389
12271
  "section.delete.title": "Delete channel section",
11390
12272
  "section.delete.description": "Removes “{name}” from the roster. Its channels leave the section and become unsectioned; they are not deleted.",
@@ -11408,6 +12290,37 @@ window.__ModuleLoader__.load({
11408
12290
  "bot.create.importing": "Cloning repository…",
11409
12291
  "bot.create.source.label": "Memory source",
11410
12292
  "bot.create.source.empty": "Start empty",
12293
+ "bot.create.persona.preset": "Persona starting point",
12294
+ "bot.create.persona.blank": "Blank",
12295
+ "bot.create.persona.colleague": "Colleague",
12296
+ "bot.create.persona.roleplay": "Roleplay",
12297
+ "bot.create.persona.label": "Persona (optional)",
12298
+ "bot.create.persona.hint": "Starting text only, freely editable; tools, permissions and runtime capabilities stay the same.",
12299
+ "bot.create.persona.placeholder": "Describe this Bot’s identity, voice and boundaries, or leave it blank.",
12300
+ "bot.create.persona.colleague.seed": `# Identity
12301
+ My name is [name] and I am a [role]. My background, personality and values: [fill in].
12302
+
12303
+ # Responsibilities
12304
+ I am responsible for [scope]. My strengths: [fill in]; areas where I need help: [fill in].
12305
+
12306
+ # Collaboration
12307
+ I work with the Human and colleagues using [tone and communication style]. I explain uncertainty and ask when clarification or authorization is needed.
12308
+
12309
+ # Boundaries
12310
+ My commitments and behaviors to avoid: [fill in].
12311
+ `,
12312
+ "bot.create.persona.roleplay.seed": `# Character and world
12313
+ My name is [name]. I am a [species / identity] living in [era, world and setting].
12314
+
12315
+ # Personality and motivation
12316
+ My history, beliefs, goals and relationships: [fill in].
12317
+
12318
+ # Voice and expression
12319
+ My tone, vocabulary and habits: [fill in]. Characteristic phrases: [fill in].
12320
+
12321
+ # Interaction boundaries
12322
+ My relationship with the Human, established lore and topics to avoid: [fill in].
12323
+ `,
11411
12324
  "bot.create.source.git": "Import Git repository",
11412
12325
  "bot.create.gitUrl.label": "Git repository URL",
11413
12326
  "bot.create.gitUrl.placeholder": "https://github.com/owner/repo.git",
@@ -11507,6 +12420,12 @@ window.__ModuleLoader__.load({
11507
12420
  "im.origin": "External origin",
11508
12421
  "im.senderLabel": "Sender ID",
11509
12422
  "im.platformLabel": "Platform",
12423
+ "im.platform.weixin": "WeChat",
12424
+ "im.receiveHintDM": "Receive plain text from the QR-paired owner into this Bot’s Inbox, without adding local DM history.",
12425
+ "im.receptionDM": "WeChat DM intake connected",
12426
+ "im.receiveEnableDM": "Receive WeChat DMs",
12427
+ "im.receiveDisableDM": "Disable WeChat DM intake",
12428
+ "im.receptionDMOff": "WeChat DM intake disabled",
11510
12429
  "im.platform.feishu": "Lark/Feishu",
11511
12430
  "im.conversationLabel": "External channel",
11512
12431
  "im.conversationId": "External channel ID",
@@ -11649,6 +12568,9 @@ window.__ModuleLoader__.load({
11649
12568
  "im.originDetails": "Origin details",
11650
12569
  "im.threadLabel": "Topic",
11651
12570
  "im.groupLabel": "Group",
12571
+ "im.dmLabel": "Direct message",
12572
+ "im.weixinUser": "WeChat user",
12573
+ "im.weixinReplyOnly": "Replies to received WeChat DM text and files are supported; proactive sending is not available yet.",
11652
12574
  "im.receivedAs": "Received as {name}",
11653
12575
  "im.readDetails": "Read history · {count} reads",
11654
12576
  "im.sourceError": "Unable to read the retained external message",
@@ -12481,7 +13403,42 @@ window.__ModuleLoader__.load({
12481
13403
  "rail.copied": "Copied",
12482
13404
  "rail.you": "You",
12483
13405
  "rail.noMessages": "No messages yet",
12484
- "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."
12485
13442
  };
12486
13443
  //#endregion
12487
13444
  //#region node_modules/.pnpm/@botharness+pixel-morph@0.2.0/node_modules/@botharness/pixel-morph/dist/index.js
@@ -14440,7 +15397,7 @@ window.__ModuleLoader__.load({
14440
15397
  const active = (item) => item.state === "thinking" || item.state === "working";
14441
15398
  return [...items.filter(active), ...items.filter((item) => !active(item))].slice(0, Math.min(max, 3));
14442
15399
  }
14443
- function PersonaBotFacepile({ items, renderAvatar, size, max = 3, className, t = zhTranslate }) {
15400
+ function PersonaBotFacepile({ items, renderAvatar, indicator = true, size, max = 3, className, t = zhTranslate }) {
14444
15401
  if (items.length === 0) return null;
14445
15402
  const visible = personaBotActivityPreview(items, max);
14446
15403
  const overflow = items.length - visible.length;
@@ -14450,6 +15407,7 @@ window.__ModuleLoader__.load({
14450
15407
  const avatar = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotAvatar, {
14451
15408
  ...item,
14452
15409
  size,
15410
+ indicator,
14453
15411
  t
14454
15412
  }, item.personaBotId);
14455
15413
  return renderAvatar === void 0 ? avatar : renderAvatar(item, avatar);
@@ -14480,6 +15438,7 @@ window.__ModuleLoader__.load({
14480
15438
  }) : null,
14481
15439
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotFacepile, {
14482
15440
  items: members,
15441
+ indicator: false,
14483
15442
  size: 22,
14484
15443
  t,
14485
15444
  renderAvatar: (item, avatar) => {
@@ -14679,9 +15638,6 @@ window.__ModuleLoader__.load({
14679
15638
  }, [])
14680
15639
  };
14681
15640
  }
14682
- //#endregion
14683
- //#region packages/client/src/client/modal.ts
14684
- const Modal = _deepseek_ai_dsh_client_ui_primitives.Modal;
14685
15641
  function hiddenChannelSequence(channels, hiddenIds) {
14686
15642
  const byId = new Map(channels.map((channel) => [channel.id, channel]));
14687
15643
  const seen = /* @__PURE__ */ new Set();
@@ -15008,8 +15964,16 @@ window.__ModuleLoader__.load({
15008
15964
  const gitUrlId = (0, react.useId)();
15009
15965
  const roleId = (0, react.useId)();
15010
15966
  const descriptionId = (0, react.useId)();
15967
+ const personaId = (0, react.useId)();
15968
+ const personaPresetId = (0, react.useId)();
15011
15969
  const [displayName, setDisplayName] = (0, react.useState)("");
15012
15970
  const [source, setSource] = (0, react.useState)("empty");
15971
+ const [personaPreset, setPersonaPreset] = (0, react.useState)("blank");
15972
+ const [personaDrafts, setPersonaDrafts] = (0, react.useState)(() => ({
15973
+ blank: "",
15974
+ colleague: t("bot.create.persona.colleague.seed"),
15975
+ roleplay: t("bot.create.persona.roleplay.seed")
15976
+ }));
15013
15977
  const [gitUrl, setGitUrl] = (0, react.useState)("");
15014
15978
  const [roleDraft, setRoleDraft] = (0, react.useState)("");
15015
15979
  const [description, setDescription] = (0, react.useState)("");
@@ -15032,7 +15996,7 @@ window.__ModuleLoader__.load({
15032
15996
  setCause(void 0);
15033
15997
  actions.createBot({
15034
15998
  displayName: displayName.trim(),
15035
- ...source === "git" ? { gitUrl: gitUrl.trim() } : {},
15999
+ ...source === "git" ? { gitUrl: gitUrl.trim() } : { persona: personaDrafts[personaPreset] },
15036
16000
  roles: submittedRoles,
15037
16001
  ...submittedDescription.length === 0 ? {} : { description: submittedDescription }
15038
16002
  }, sectionId).then(() => {
@@ -15169,6 +16133,46 @@ window.__ModuleLoader__.load({
15169
16133
  onChange: (event) => setDescription(event.currentTarget.value)
15170
16134
  })
15171
16135
  }),
16136
+ source === "empty" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
16137
+ id: personaPresetId,
16138
+ label: t("bot.create.persona.preset"),
16139
+ value: personaPreset,
16140
+ options: [
16141
+ {
16142
+ value: "blank",
16143
+ label: t("bot.create.persona.blank")
16144
+ },
16145
+ {
16146
+ value: "colleague",
16147
+ label: t("bot.create.persona.colleague")
16148
+ },
16149
+ {
16150
+ value: "roleplay",
16151
+ label: t("bot.create.persona.roleplay")
16152
+ }
16153
+ ],
16154
+ disabled: creating,
16155
+ onChange: setPersonaPreset
16156
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
16157
+ id: personaId,
16158
+ label: t("bot.create.persona.label"),
16159
+ hint: t("bot.create.persona.hint"),
16160
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
16161
+ id: personaId,
16162
+ className: "bh-name-input bh-personabot-persona",
16163
+ rows: 6,
16164
+ value: personaDrafts[personaPreset],
16165
+ disabled: creating,
16166
+ placeholder: t("bot.create.persona.placeholder"),
16167
+ onChange: (event) => {
16168
+ const value = event.currentTarget.value;
16169
+ setPersonaDrafts((current) => ({
16170
+ ...current,
16171
+ [personaPreset]: value
16172
+ }));
16173
+ }
16174
+ })
16175
+ })] }) : null,
15172
16176
  cause === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15173
16177
  className: "bh-modal-error",
15174
16178
  role: "alert",
@@ -15179,6 +16183,710 @@ window.__ModuleLoader__.load({
15179
16183
  });
15180
16184
  }
15181
16185
  //#endregion
16186
+ //#region packages/client/src/client/marketplace.tsx
16187
+ const marketplaceErrorKeys = {
16188
+ "marketplace-unavailable": "market.error.unavailable",
16189
+ "invalid-repository-url": "market.error.invalidUrl",
16190
+ "repository-not-found": "market.error.notFound",
16191
+ "repository-private": "market.error.private",
16192
+ "repository-archived": "market.error.archived",
16193
+ "repository-missing-topic": "market.error.missingTopic",
16194
+ "repository-blocked": "market.error.blocked",
16195
+ "upstream-unavailable": "market.error.upstream",
16196
+ "bot-not-found": "market.error.botNotFound",
16197
+ "challenge-unavailable": "market.error.challengeUnavailable",
16198
+ "challenge-invalid": "market.error.challenge",
16199
+ "challenge-expired": "market.error.challenge",
16200
+ "challenge-replayed": "market.error.challenge",
16201
+ "rate-limited": "market.error.rateLimited",
16202
+ "repository-rate-limited": "market.error.repositoryRateLimited",
16203
+ "invalid-report": "market.error.invalidReport"
16204
+ };
16205
+ async function proveHuman(actions) {
16206
+ const payload = await solveChallenge(await actions.marketplaceChallenge(), { yieldEvery: () => new Promise((resolve) => setTimeout(resolve, 0)) });
16207
+ if (payload === void 0) throw new BridgeCallError("challenge-invalid", "challenge could not be solved");
16208
+ return payload;
16209
+ }
16210
+ function marketplaceError(error, t) {
16211
+ if (error instanceof BridgeCallError) {
16212
+ const key = marketplaceErrorKeys[error.code];
16213
+ if (key !== void 0) return t(key);
16214
+ }
16215
+ return errorMessage(error);
16216
+ }
16217
+ function shortSha(sha) {
16218
+ return sha.slice(0, 7);
16219
+ }
16220
+ function marketplaceName(bot) {
16221
+ return bot.displayName ?? bot.name;
16222
+ }
16223
+ function MarketplaceName({ bot }) {
16224
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16225
+ className: "bh-market-name",
16226
+ children: [
16227
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: marketplaceName(bot) }),
16228
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16229
+ className: "bh-market-owner",
16230
+ children: bot.displayName === null ? bot.owner : bot.fullName
16231
+ }),
16232
+ bot.roles.map((role) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
16233
+ tone: "outline",
16234
+ children: role
16235
+ }, role))
16236
+ ]
16237
+ });
16238
+ }
16239
+ function day(value) {
16240
+ return value.slice(0, 10);
16241
+ }
16242
+ const VISIBLE_TOPICS = 12;
16243
+ const MAX_QUERY_LENGTH = 100;
16244
+ function queryFor(filters, cursor) {
16245
+ return {
16246
+ sort: filters.sort,
16247
+ ...filters.query.length === 0 ? {} : { q: filters.query },
16248
+ ...filters.topic === void 0 ? {} : { topic: filters.topic },
16249
+ ...cursor === void 0 ? {} : { cursor }
16250
+ };
16251
+ }
16252
+ function mergeBots(current, next) {
16253
+ const seen = new Set(next.map((bot) => bot.id));
16254
+ return [...current.filter((bot) => !seen.has(bot.id)), ...next];
16255
+ }
16256
+ function MarketplaceMeta({ bot, t }) {
16257
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16258
+ className: "bh-market-meta",
16259
+ children: [
16260
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.stars", { count: String(bot.stars) }) }),
16261
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.updated", { date: day(bot.pushedAt) }) }),
16262
+ bot.topics.map((topic) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
16263
+ tone: "neutral",
16264
+ children: topic
16265
+ }, topic))
16266
+ ]
16267
+ });
16268
+ }
16269
+ function MarketplaceRow({ bot, t, onOpen, onInstall }) {
16270
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16271
+ className: "bh-market-row",
16272
+ role: "listitem",
16273
+ "data-market-bot": bot.fullName,
16274
+ children: [
16275
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotAvatar, {
16276
+ personaBotId: "",
16277
+ name: marketplaceName(bot),
16278
+ size: 36,
16279
+ indicator: false,
16280
+ t
16281
+ }),
16282
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
16283
+ type: "button",
16284
+ className: "bh-market-copy bh-market-open",
16285
+ "aria-label": t("market.detail.open", { name: bot.fullName }),
16286
+ onClick: onOpen,
16287
+ children: [
16288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceName, { bot }),
16289
+ bot.description === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16290
+ className: "bh-market-description",
16291
+ children: bot.description
16292
+ }),
16293
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceMeta, {
16294
+ bot,
16295
+ t
16296
+ })
16297
+ ]
16298
+ }),
16299
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16300
+ variant: "outline",
16301
+ onClick: onInstall,
16302
+ children: t("market.install")
16303
+ })
16304
+ ]
16305
+ });
16306
+ }
16307
+ function ReportPanel({ state, t, onReason }) {
16308
+ if (state.status === "closed") return null;
16309
+ if (state.status === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16310
+ className: "bh-market-report",
16311
+ role: "status",
16312
+ "data-market-report": "done",
16313
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("market.report.doneTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.report.done") })]
16314
+ });
16315
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16316
+ className: "bh-market-report",
16317
+ "data-market-report": "open",
16318
+ children: [
16319
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("market.report.title") }),
16320
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16321
+ className: "bh-market-hint",
16322
+ children: t("market.report.hint")
16323
+ }),
16324
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.report.reason") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
16325
+ rows: 3,
16326
+ maxLength: 500,
16327
+ placeholder: t("market.report.placeholder"),
16328
+ value: state.reason,
16329
+ disabled: state.phase !== "idle",
16330
+ onChange: (event) => onReason(event.currentTarget.value)
16331
+ })] }),
16332
+ state.phase === "verifying" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16333
+ className: "bh-market-hint",
16334
+ role: "status",
16335
+ children: t("market.challenge.verifying")
16336
+ }) : null,
16337
+ state.cause === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16338
+ className: "bh-modal-error",
16339
+ role: "alert",
16340
+ children: marketplaceError(state.cause, t)
16341
+ })
16342
+ ]
16343
+ });
16344
+ }
16345
+ function MarketplaceDetailView({ bot, state, t, onRetry, report }) {
16346
+ const labels = (0, react.useMemo)(() => ({
16347
+ code: {
16348
+ copyLabel: t("message.code.copy"),
16349
+ copiedLabel: t("message.code.copied")
16350
+ },
16351
+ footnotes: t("message.footnotes")
16352
+ }), [t]);
16353
+ const shown = state.status === "ready" ? state.detail.bot : bot;
16354
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16355
+ className: "bh-market-detail",
16356
+ "data-market-detail": shown.fullName,
16357
+ children: [
16358
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16359
+ className: "bh-market-confirm-head",
16360
+ children: [
16361
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotAvatar, {
16362
+ personaBotId: "",
16363
+ name: marketplaceName(shown),
16364
+ size: 44,
16365
+ indicator: false,
16366
+ t
16367
+ }),
16368
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16369
+ className: "bh-market-copy",
16370
+ children: [
16371
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceName, { bot: shown }),
16372
+ shown.description === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16373
+ className: "bh-market-description",
16374
+ children: shown.description
16375
+ }),
16376
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceMeta, {
16377
+ bot: shown,
16378
+ t
16379
+ })
16380
+ ]
16381
+ }),
16382
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
16383
+ className: "bh-market-github",
16384
+ href: shown.htmlUrl,
16385
+ target: "_blank",
16386
+ rel: "noreferrer",
16387
+ children: t("market.detail.github")
16388
+ })
16389
+ ]
16390
+ }),
16391
+ report,
16392
+ state.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16393
+ className: "bh-market-state",
16394
+ role: "status",
16395
+ children: t("market.detail.loading")
16396
+ }) : null,
16397
+ state.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16398
+ className: "bh-market-state",
16399
+ role: "alert",
16400
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.detail.error", { error: marketplaceError(state.cause, t) }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16401
+ variant: "outline",
16402
+ onClick: onRetry,
16403
+ children: t("market.retry")
16404
+ })]
16405
+ }) : null,
16406
+ state.status === "ready" && state.detail.readme === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16407
+ className: "bh-market-state",
16408
+ children: t("market.detail.noReadme")
16409
+ }) : null,
16410
+ state.status === "ready" && state.detail.readme !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16411
+ className: "bh-market-readme",
16412
+ "data-market-readme": true,
16413
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
16414
+ text: state.detail.readme,
16415
+ labels
16416
+ })
16417
+ }) : null
16418
+ ]
16419
+ });
16420
+ }
16421
+ function InstallConfirmation({ bot, t, cause }) {
16422
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16423
+ className: "bh-market-confirm",
16424
+ children: [
16425
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16426
+ className: "bh-market-confirm-head",
16427
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotAvatar, {
16428
+ personaBotId: "",
16429
+ name: marketplaceName(bot),
16430
+ size: 44,
16431
+ indicator: false,
16432
+ t
16433
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16434
+ className: "bh-market-copy",
16435
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceName, { bot }), bot.description === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16436
+ className: "bh-market-description",
16437
+ children: bot.description
16438
+ })]
16439
+ })]
16440
+ }),
16441
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
16442
+ className: "bh-market-facts",
16443
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("market.confirm.source") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
16444
+ href: bot.htmlUrl,
16445
+ target: "_blank",
16446
+ rel: "noreferrer",
16447
+ children: bot.fullName
16448
+ }) })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("market.confirm.commit") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
16449
+ "data-market-commit": true,
16450
+ children: bot.headCommit === null ? t("market.confirm.noCommit") : t("market.confirm.commitValue", {
16451
+ sha: shortSha(bot.headCommit.sha),
16452
+ date: day(bot.headCommit.committedAt)
16453
+ })
16454
+ })] })]
16455
+ }),
16456
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16457
+ className: "bh-market-risk",
16458
+ role: "note",
16459
+ children: [
16460
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("market.confirm.riskTitle") }),
16461
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.confirm.risk") }),
16462
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.confirm.newer") })
16463
+ ]
16464
+ }),
16465
+ cause === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16466
+ className: "bh-modal-error",
16467
+ role: "alert",
16468
+ children: t("market.install.failed", { error: personaBotCreateError(cause, t) })
16469
+ })
16470
+ ]
16471
+ });
16472
+ }
16473
+ function MarketplaceModal({ actions, t, onClose, onInstalled }) {
16474
+ const [list, setList] = (0, react.useState)({ status: "loading" });
16475
+ const [filters, setFilters] = (0, react.useState)({
16476
+ sort: "updated",
16477
+ query: ""
16478
+ });
16479
+ const [searchText, setSearchText] = (0, react.useState)("");
16480
+ const [topics, setTopics] = (0, react.useState)([]);
16481
+ const [url, setUrl] = (0, react.useState)("");
16482
+ const [submitPhase, setSubmitPhase] = (0, react.useState)("idle");
16483
+ const submitting = submitPhase !== "idle";
16484
+ const [report, setReport] = (0, react.useState)({ status: "closed" });
16485
+ const [submitCause, setSubmitCause] = (0, react.useState)(void 0);
16486
+ const [submitted, setSubmitted] = (0, react.useState)(void 0);
16487
+ const [selected, setSelected] = (0, react.useState)(void 0);
16488
+ const [viewing, setViewing] = (0, react.useState)(void 0);
16489
+ const [detail, setDetail] = (0, react.useState)({ status: "loading" });
16490
+ const detailGeneration = (0, react.useRef)(0);
16491
+ const [installing, setInstalling] = (0, react.useState)(false);
16492
+ const [installCause, setInstallCause] = (0, react.useState)(void 0);
16493
+ const generation = (0, react.useRef)(0);
16494
+ const searchTimer = (0, react.useRef)(void 0);
16495
+ const latestFilters = (0, react.useRef)(filters);
16496
+ const sortId = (0, react.useId)();
16497
+ const load = (next = filters) => {
16498
+ const ticket = ++generation.current;
16499
+ latestFilters.current = next;
16500
+ setFilters(next);
16501
+ setList({ status: "loading" });
16502
+ actions.marketplaceList(queryFor(next)).then((page) => {
16503
+ if (ticket !== generation.current) return;
16504
+ setList({
16505
+ status: "ready",
16506
+ bots: page.bots,
16507
+ ...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor },
16508
+ loadingMore: false
16509
+ });
16510
+ }, (cause) => {
16511
+ if (ticket === generation.current) setList({
16512
+ status: "error",
16513
+ cause
16514
+ });
16515
+ });
16516
+ };
16517
+ const loadOnMount = useMountedResource(() => {
16518
+ load();
16519
+ actions.marketplaceTopics().then((loaded) => setTopics(loaded.slice(0, VISIBLE_TOPICS)), () => setTopics([]));
16520
+ return () => {
16521
+ generation.current += 1;
16522
+ clearTimeout(searchTimer.current);
16523
+ };
16524
+ }, []);
16525
+ const search = (text) => {
16526
+ setSearchText(text);
16527
+ clearTimeout(searchTimer.current);
16528
+ searchTimer.current = setTimeout(() => {
16529
+ const query = text.trim();
16530
+ const current = latestFilters.current;
16531
+ if (query !== current.query) load({
16532
+ ...current,
16533
+ query
16534
+ });
16535
+ }, 300);
16536
+ };
16537
+ const chooseTopic = (topic) => {
16538
+ const { topic: _previous, ...rest } = filters;
16539
+ load(topic === void 0 ? rest : {
16540
+ ...rest,
16541
+ topic
16542
+ });
16543
+ };
16544
+ const loadMore = () => {
16545
+ if (list.status !== "ready" || list.nextCursor === void 0 || list.loadingMore) return;
16546
+ const ticket = generation.current;
16547
+ const current = list;
16548
+ setList({
16549
+ ...current,
16550
+ loadingMore: true
16551
+ });
16552
+ actions.marketplaceList(queryFor(filters, current.nextCursor)).then((page) => {
16553
+ if (ticket !== generation.current) return;
16554
+ setList({
16555
+ status: "ready",
16556
+ bots: mergeBots(current.bots, page.bots),
16557
+ ...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor },
16558
+ loadingMore: false
16559
+ });
16560
+ }, (cause) => {
16561
+ if (ticket === generation.current) setList({
16562
+ status: "error",
16563
+ cause
16564
+ });
16565
+ });
16566
+ };
16567
+ const openDetail = (bot) => {
16568
+ const ticket = ++detailGeneration.current;
16569
+ setViewing(bot);
16570
+ setReport({ status: "closed" });
16571
+ setDetail({ status: "loading" });
16572
+ actions.marketplaceDetail(bot.id).then((loaded) => {
16573
+ if (ticket === detailGeneration.current) setDetail({
16574
+ status: "ready",
16575
+ detail: loaded
16576
+ });
16577
+ }, (cause) => {
16578
+ if (ticket === detailGeneration.current) setDetail({
16579
+ status: "error",
16580
+ cause
16581
+ });
16582
+ });
16583
+ };
16584
+ const submit = () => {
16585
+ const trimmed = url.trim();
16586
+ if (trimmed.length === 0 || submitting) return;
16587
+ setSubmitPhase("verifying");
16588
+ setSubmitCause(void 0);
16589
+ setSubmitted(void 0);
16590
+ proveHuman(actions).then((altcha) => {
16591
+ setSubmitPhase("sending");
16592
+ return actions.marketplaceSubmit(trimmed, altcha);
16593
+ }).then((bot) => {
16594
+ setSubmitPhase("idle");
16595
+ setUrl("");
16596
+ setSubmitted(bot.fullName);
16597
+ setList((current) => current.status === "ready" ? {
16598
+ ...current,
16599
+ bots: [bot, ...current.bots.filter((item) => item.id !== bot.id)]
16600
+ } : {
16601
+ status: "ready",
16602
+ bots: [bot],
16603
+ loadingMore: false
16604
+ });
16605
+ }, (cause) => {
16606
+ setSubmitPhase("idle");
16607
+ setSubmitCause(cause);
16608
+ });
16609
+ };
16610
+ const sendReport = (bot) => {
16611
+ if (report.status !== "open" || report.phase !== "idle") return;
16612
+ const reason = report.reason.trim();
16613
+ const ticket = detailGeneration.current;
16614
+ setReport({
16615
+ status: "open",
16616
+ reason: report.reason,
16617
+ phase: "verifying"
16618
+ });
16619
+ proveHuman(actions).then((altcha) => {
16620
+ if (ticket === detailGeneration.current) setReport({
16621
+ status: "open",
16622
+ reason: report.reason,
16623
+ phase: "sending"
16624
+ });
16625
+ return actions.marketplaceReport(bot.id, altcha, reason.length === 0 ? void 0 : reason);
16626
+ }).then(() => {
16627
+ if (ticket === detailGeneration.current) setReport({ status: "done" });
16628
+ }, (cause) => {
16629
+ if (ticket === detailGeneration.current) setReport({
16630
+ status: "open",
16631
+ reason: report.reason,
16632
+ phase: "idle",
16633
+ cause
16634
+ });
16635
+ });
16636
+ };
16637
+ const install = () => {
16638
+ if (selected === void 0 || installing) return;
16639
+ setInstalling(true);
16640
+ setInstallCause(void 0);
16641
+ actions.createBot({
16642
+ displayName: marketplaceName(selected),
16643
+ gitUrl: selected.cloneUrl,
16644
+ roles: selected.roles,
16645
+ ...selected.description === null ? {} : { description: selected.description }
16646
+ }).then(() => {
16647
+ setInstalling(false);
16648
+ onInstalled();
16649
+ }, (cause) => {
16650
+ setInstalling(false);
16651
+ setInstallCause(cause);
16652
+ });
16653
+ };
16654
+ if (selected !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Modal, {
16655
+ open: true,
16656
+ onClose: () => {
16657
+ if (!installing) onClose();
16658
+ },
16659
+ closeLabel: t("common.close"),
16660
+ title: t("market.confirm.title", { name: marketplaceName(selected) }),
16661
+ className: "bh-market-modal",
16662
+ 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, {
16663
+ variant: "outline",
16664
+ disabled: installing,
16665
+ onClick: () => {
16666
+ setSelected(void 0);
16667
+ setInstallCause(void 0);
16668
+ },
16669
+ children: t("market.back")
16670
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16671
+ variant: "primary",
16672
+ disabled: installing,
16673
+ onClick: install,
16674
+ children: installing ? t("market.confirm.installing") : t("market.confirm.install")
16675
+ })] }),
16676
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallConfirmation, {
16677
+ bot: selected,
16678
+ t,
16679
+ cause: installCause
16680
+ })
16681
+ });
16682
+ if (viewing !== void 0) {
16683
+ const shown = detail.status === "ready" ? detail.detail.bot : viewing;
16684
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Modal, {
16685
+ open: true,
16686
+ onClose,
16687
+ closeLabel: t("common.close"),
16688
+ title: marketplaceName(shown),
16689
+ className: "bh-market-modal",
16690
+ footer: report.status === "open" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16691
+ variant: "outline",
16692
+ disabled: report.phase !== "idle",
16693
+ onClick: () => setReport({ status: "closed" }),
16694
+ children: t("common.cancel")
16695
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16696
+ variant: "primary",
16697
+ disabled: report.phase !== "idle",
16698
+ onClick: () => sendReport(shown),
16699
+ children: report.phase === "verifying" ? t("market.challenge.verifying") : report.phase === "sending" ? t("market.report.sending") : t("market.report.send")
16700
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
16701
+ report.status === "done" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16702
+ variant: "ghost",
16703
+ className: "bh-market-report-open",
16704
+ onClick: () => setReport({
16705
+ status: "open",
16706
+ reason: "",
16707
+ phase: "idle"
16708
+ }),
16709
+ children: t("market.report.open")
16710
+ }),
16711
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16712
+ variant: "outline",
16713
+ onClick: () => {
16714
+ detailGeneration.current += 1;
16715
+ setViewing(void 0);
16716
+ },
16717
+ children: t("market.back")
16718
+ }),
16719
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16720
+ variant: "primary",
16721
+ onClick: () => {
16722
+ setSelected(shown);
16723
+ setInstallCause(void 0);
16724
+ },
16725
+ children: t("market.install")
16726
+ })
16727
+ ] }),
16728
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceDetailView, {
16729
+ bot: viewing,
16730
+ state: detail,
16731
+ t,
16732
+ onRetry: () => openDetail(viewing),
16733
+ report: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReportPanel, {
16734
+ state: report,
16735
+ t,
16736
+ onReason: (reason) => setReport((current) => current.status === "open" ? {
16737
+ ...current,
16738
+ reason,
16739
+ cause: void 0
16740
+ } : current)
16741
+ })
16742
+ })
16743
+ });
16744
+ }
16745
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Modal, {
16746
+ open: true,
16747
+ onClose,
16748
+ closeLabel: t("common.close"),
16749
+ title: t("market.title"),
16750
+ description: t("market.description"),
16751
+ className: "bh-market-modal",
16752
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16753
+ variant: "outline",
16754
+ onClick: onClose,
16755
+ children: t("common.close")
16756
+ }),
16757
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16758
+ className: "bh-market",
16759
+ ref: loadOnMount,
16760
+ children: [
16761
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16762
+ className: "bh-market-submit",
16763
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
16764
+ "aria-label": t("market.submit.label"),
16765
+ placeholder: t("market.submit.placeholder"),
16766
+ autoCapitalize: "none",
16767
+ autoComplete: "off",
16768
+ spellCheck: false,
16769
+ value: url,
16770
+ disabled: submitting,
16771
+ onChange: (event) => setUrl(event.currentTarget.value),
16772
+ onKeyDown: (event) => {
16773
+ if (event.key !== "Enter") return;
16774
+ event.preventDefault();
16775
+ submit();
16776
+ }
16777
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16778
+ variant: "primary",
16779
+ disabled: submitting || url.trim().length === 0,
16780
+ onClick: submit,
16781
+ children: submitPhase === "verifying" ? t("market.challenge.verifying") : submitting ? t("market.submit.busy") : t("market.submit.action")
16782
+ })]
16783
+ }),
16784
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16785
+ className: "bh-market-hint",
16786
+ children: submitted === void 0 ? t("market.submit.hint") : t("market.submit.done", { name: submitted })
16787
+ }),
16788
+ submitCause === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16789
+ className: "bh-modal-error",
16790
+ role: "alert",
16791
+ children: marketplaceError(submitCause, t)
16792
+ }),
16793
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16794
+ className: "bh-market-browse",
16795
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
16796
+ type: "search",
16797
+ "aria-label": t("market.search.label"),
16798
+ placeholder: t("market.search.placeholder"),
16799
+ autoComplete: "off",
16800
+ maxLength: MAX_QUERY_LENGTH,
16801
+ value: searchText,
16802
+ onChange: (event) => search(event.currentTarget.value)
16803
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
16804
+ id: sortId,
16805
+ label: t("market.sort.label"),
16806
+ value: filters.sort,
16807
+ options: [{
16808
+ value: "updated",
16809
+ label: t("market.sort.updated")
16810
+ }, {
16811
+ value: "stars",
16812
+ label: t("market.sort.stars")
16813
+ }],
16814
+ disabled: filters.query.length > 0,
16815
+ onChange: (sort) => load({
16816
+ ...filters,
16817
+ sort
16818
+ })
16819
+ })]
16820
+ }),
16821
+ filters.query.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16822
+ className: "bh-market-hint",
16823
+ children: t("market.search.relevance")
16824
+ }) : null,
16825
+ topics.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16826
+ className: "bh-market-topics",
16827
+ role: "group",
16828
+ "aria-label": t("market.topics.label"),
16829
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16830
+ type: "button",
16831
+ className: "bh-market-topic",
16832
+ "aria-pressed": filters.topic === void 0,
16833
+ onClick: () => chooseTopic(void 0),
16834
+ children: t("market.topics.all")
16835
+ }), topics.map(({ topic, count }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
16836
+ type: "button",
16837
+ className: "bh-market-topic",
16838
+ "data-market-topic": topic,
16839
+ "aria-pressed": filters.topic === topic,
16840
+ onClick: () => chooseTopic(filters.topic === topic ? void 0 : topic),
16841
+ children: [topic, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16842
+ className: "bh-market-topic-count",
16843
+ children: count
16844
+ })]
16845
+ }, topic))]
16846
+ }),
16847
+ list.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16848
+ className: "bh-market-state",
16849
+ role: "status",
16850
+ children: t("market.loading")
16851
+ }) : null,
16852
+ list.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16853
+ className: "bh-market-state",
16854
+ role: "alert",
16855
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("market.error.load", { error: marketplaceError(list.cause, t) }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16856
+ variant: "outline",
16857
+ onClick: () => load(),
16858
+ children: t("market.retry")
16859
+ })]
16860
+ }) : null,
16861
+ list.status === "ready" && list.bots.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16862
+ className: "bh-market-state",
16863
+ children: filters.query.length > 0 || filters.topic !== void 0 ? t("market.search.empty") : t("market.empty")
16864
+ }) : null,
16865
+ list.status === "ready" && list.bots.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16866
+ className: "bh-market-list",
16867
+ role: "list",
16868
+ "aria-label": t("market.title"),
16869
+ children: list.bots.map((bot) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceRow, {
16870
+ bot,
16871
+ t,
16872
+ onOpen: () => openDetail(bot),
16873
+ onInstall: () => {
16874
+ setSelected(bot);
16875
+ setInstallCause(void 0);
16876
+ }
16877
+ }, bot.id))
16878
+ }) : null,
16879
+ list.status === "ready" && list.nextCursor !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
16880
+ variant: "outline",
16881
+ disabled: list.loadingMore,
16882
+ onClick: loadMore,
16883
+ children: list.loadingMore ? t("market.loadingMore") : t("market.loadMore")
16884
+ }) : null
16885
+ ]
16886
+ })
16887
+ });
16888
+ }
16889
+ //#endregion
15182
16890
  //#region packages/client/src/client/section-management.tsx
15183
16891
  const DANGER_ACTION_CLASS = "bh-danger-action";
15184
16892
  function globalSortMenuItems(t) {
@@ -16173,6 +17881,7 @@ window.__ModuleLoader__.load({
16173
17881
  if (id === "bot") setCreateRequest({ kind: "bot" });
16174
17882
  if (id === "channel") setCreateRequest({ kind: "channel" });
16175
17883
  if (id === "section") setCreateRequest({ kind: "section" });
17884
+ if (id === "marketplace") setCreateRequest({ kind: "marketplace" });
16176
17885
  };
16177
17886
  const selectSortMenu = (id) => {
16178
17887
  setSortMenuOpen(false);
@@ -17130,6 +18839,16 @@ window.__ModuleLoader__.load({
17130
18839
  setCreateRequest(void 0);
17131
18840
  }
17132
18841
  }) : null,
18842
+ createRequest?.kind === "marketplace" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketplaceModal, {
18843
+ t,
18844
+ actions,
18845
+ onClose: () => {
18846
+ setCreateRequest(void 0);
18847
+ },
18848
+ onInstalled: () => {
18849
+ setCreateRequest(void 0);
18850
+ }
18851
+ }) : null,
17133
18852
  createRequest?.kind === "section" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreateSectionModal, {
17134
18853
  t,
17135
18854
  onCancel: () => {
@@ -17468,6 +19187,11 @@ window.__ModuleLoader__.load({
17468
19187
  id: "section",
17469
19188
  label: t("roster.menu.createSection"),
17470
19189
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, { size: 16 })
19190
+ },
19191
+ {
19192
+ id: "marketplace",
19193
+ label: t("roster.menu.marketplace"),
19194
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGlobeOutlineRegular, { size: 16 })
17471
19195
  }
17472
19196
  ];
17473
19197
  }
@@ -18110,6 +19834,7 @@ window.__ModuleLoader__.load({
18110
19834
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotFacepile, {
18111
19835
  t,
18112
19836
  className: "bh-composer-activity-facepile",
19837
+ indicator: false,
18113
19838
  items: activity.items,
18114
19839
  renderAvatar: activity.presentation === "group" ? (item, avatar) => {
18115
19840
  const label = item.name + " · " + personaBotPresentationSummary(item.state ?? "idle", item.activity, item.attention, t);
@@ -20303,11 +22028,15 @@ window.__ModuleLoader__.load({
20303
22028
  if (platform === "feishu") return t("im.platform.feishu");
20304
22029
  if (platform === "slack") return "Slack";
20305
22030
  if (platform === "discord") return "Discord";
22031
+ if (platform === "weixin") return t("im.platform.weixin");
20306
22032
  return platform;
20307
22033
  }
20308
22034
  function bridgeSourceLabel(origin, t) {
20309
22035
  return `${externalPlatformLabel(origin.platform, t)} ${origin.conversationName}`;
20310
22036
  }
22037
+ function externalSenderLabel(origin, t) {
22038
+ return origin.senderName ?? (origin.platform === "weixin" ? t("im.weixinUser") : origin.senderId);
22039
+ }
20311
22040
  //#endregion
20312
22041
  //#region packages/client/src/client/bridge-source-author.tsx
20313
22042
  function BridgeSourceDetails({ origin, t }) {
@@ -33914,14 +35643,14 @@ window.__ModuleLoader__.load({
33914
35643
  children: t("im.localTarget")
33915
35644
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessagingHelp, {
33916
35645
  title: t("im.localTarget"),
33917
- text: grant.receiveTargetChannelId ? t("im.channelTargetHint") : t("im.receiveHint"),
35646
+ text: grant.receiveTargetChannelId ? t("im.channelTargetHint") : t(grant.platform === "weixin" ? "im.receiveHintDM" : "im.receiveHint"),
33918
35647
  t
33919
35648
  })]
33920
35649
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
33921
35650
  id: targetFieldId + "-local",
33922
35651
  "aria-label": t("im.localTarget"),
33923
35652
  value: grant.receiveTargetChannelId ?? "",
33924
- disabled: busy,
35653
+ disabled: busy || grant.platform === "weixin",
33925
35654
  onChange: (event) => {
33926
35655
  const channelId = event.target.value || null;
33927
35656
  operate(() => actions.messagingChannelTarget(slug, grant.id, channelId));
@@ -33945,7 +35674,7 @@ window.__ModuleLoader__.load({
33945
35674
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
33946
35675
  className: "bh-im-status",
33947
35676
  role: "status",
33948
- children: t(`im.reception.${grant.reception ?? "off"}`)
35677
+ children: grant.platform === "weixin" ? t(grant.reception === "receiving" ? "im.receptionDM" : "im.receptionDMOff") : t(`im.reception.${grant.reception ?? "off"}`)
33949
35678
  }),
33950
35679
  grant.receiveScope && grant.groupPolicy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupReceptionSettings, {
33951
35680
  policy: grant.groupPolicy,
@@ -33962,7 +35691,7 @@ window.__ModuleLoader__.load({
33962
35691
  onClick: () => void operate(async () => {
33963
35692
  await actions.messagingReceive(slug, grant.id, grant.receiveScope === void 0);
33964
35693
  }),
33965
- children: t(grant.receiveScope === void 0 ? "im.receiveEnable" : "im.receiveDisable")
35694
+ children: t(grant.receiveScope === void 0 ? grant.platform === "weixin" ? "im.receiveEnableDM" : "im.receiveEnable" : grant.platform === "weixin" ? "im.receiveDisableDM" : "im.receiveDisable")
33966
35695
  })
33967
35696
  ] }) : null,
33968
35697
  grant.threadPolicies?.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadReceptionSettings, {
@@ -33978,7 +35707,7 @@ window.__ModuleLoader__.load({
33978
35707
  return saved;
33979
35708
  }
33980
35709
  }) : null,
33981
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
35710
+ grant.platform === "weixin" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("im.weixinReplyOnly") }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
33982
35711
  className: "bh-im-field",
33983
35712
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("im.message") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
33984
35713
  "aria-label": t("im.message"),
@@ -33987,15 +35716,14 @@ window.__ModuleLoader__.load({
33987
35716
  disabled: busy,
33988
35717
  onChange: (event) => setText(event.target.value)
33989
35718
  })]
33990
- }),
33991
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35719
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
33992
35720
  size: "sm",
33993
35721
  variant: "primary",
33994
35722
  className: "bh-im-submit",
33995
35723
  disabled: busy || !text.trim() || grant.availability !== "available",
33996
35724
  onClick: () => void send(),
33997
35725
  children: t("im.send")
33998
- })
35726
+ })] })
33999
35727
  ] }) : snapshot.accounts.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("im.setup") }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
34000
35728
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
34001
35729
  className: "bh-im-field",
@@ -38757,6 +40485,7 @@ window.__ModuleLoader__.load({
38757
40485
  }) : channelFacepile.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotFacepile, {
38758
40486
  items: channelFacepile,
38759
40487
  size: 22,
40488
+ indicator: false,
38760
40489
  t
38761
40490
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
38762
40491
  className: "bh-channel-mark bh-channel-mark-sm",
@@ -38767,10 +40496,6 @@ window.__ModuleLoader__.load({
38767
40496
  className: "bh-title",
38768
40497
  children: title
38769
40498
  }),
38770
- bot === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotStatusBadges, {
38771
- state: botActivity,
38772
- attention: bot.attention
38773
- }),
38774
40499
  bot === void 0 || bot.roles.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
38775
40500
  className: "bh-role-badges",
38776
40501
  children: bot.roles.map((role) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
@@ -38804,10 +40529,6 @@ window.__ModuleLoader__.load({
38804
40529
  className: "bh-title",
38805
40530
  children: title
38806
40531
  }),
38807
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaBotStatusBadges, {
38808
- state: profileBotActivity,
38809
- attention: profileBot.attention
38810
- }),
38811
40532
  profileBot.roles.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
38812
40533
  className: "bh-role-badges",
38813
40534
  children: profileBot.roles.map((role) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
@@ -39134,25 +40855,32 @@ window.__ModuleLoader__.load({
39134
40855
  t
39135
40856
  }, `${scopeKey}:${state.conversation.channel?.id ?? ""}`);
39136
40857
  }
39137
- function BotPanel({ actions, nativeSessions, channelSidebar, profileCards, nativeChatT, t }) {
40858
+ function BotPanel({ actions, nativeSessions, channelSidebar, profileCards, nativeChatT, releaseNotes, t }) {
39138
40859
  const modeMount = useMountedResource(() => {
39139
40860
  store.setMode("bot");
39140
40861
  return () => {
39141
40862
  store.setMode("dsh");
39142
40863
  };
39143
40864
  }, []);
39144
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
39145
- ref: modeMount,
39146
- hidden: true,
39147
- "aria-hidden": "true"
39148
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BotMain, {
39149
- actions,
39150
- nativeSessions,
39151
- channelSidebar,
39152
- profileCards,
39153
- nativeChatT,
39154
- t
39155
- })] });
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
+ ] });
39156
40884
  }
39157
40885
  //#endregion
39158
40886
  //#region packages/client/src/client/memory-git-lanes.ts
@@ -40478,7 +42206,7 @@ window.__ModuleLoader__.load({
40478
42206
  });
40479
42207
  }
40480
42208
  function MessageCard({ message, t }) {
40481
- const name = message.senderName ?? message.senderId;
42209
+ const name = message.senderLabel ?? message.senderName ?? message.senderId;
40482
42210
  const date = new Date(message.at);
40483
42211
  const time = Number.isNaN(date.getTime()) ? message.at : new Intl.DateTimeFormat(void 0, {
40484
42212
  month: "short",
@@ -40549,7 +42277,7 @@ window.__ModuleLoader__.load({
40549
42277
  children: platform
40550
42278
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
40551
42279
  className: "bh-external-scope",
40552
- children: t(hasThread ? "im.threadLabel" : "im.groupLabel")
42280
+ children: t(hasThread ? "im.threadLabel" : source.event.conversation.kind === "dm" ? "im.dmLabel" : "im.groupLabel")
40553
42281
  })]
40554
42282
  }),
40555
42283
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: source.conversationName }),
@@ -40639,6 +42367,11 @@ window.__ModuleLoader__.load({
40639
42367
  sourceEventId: source.id,
40640
42368
  messageId: source.event.messageId,
40641
42369
  senderId: source.event.actor.id,
42370
+ senderLabel: externalSenderLabel({
42371
+ platform: source.platform,
42372
+ senderId: source.event.actor.id,
42373
+ ...source.event.actor.name ? { senderName: source.event.actor.name } : {}
42374
+ }, t),
40642
42375
  ...source.event.actor.name ? { senderName: source.event.actor.name } : {},
40643
42376
  at: source.at,
40644
42377
  text: source.body,
@@ -41276,7 +43009,7 @@ window.__ModuleLoader__.load({
41276
43009
  };
41277
43010
  const memoryChange = item.sourceKind === "memory-change";
41278
43011
  const summary = memoryChange ? item.summary.replace(/^Memory changed since your last turn:\s*/u, "").replace(/^Working Memory changes since your last turn:\s*/u, "").replace(/^\?\? /u, "") : item.summary;
41279
- const author = item.externalOrigin !== void 0 ? `${externalPlatformLabel(item.externalOrigin.platform, t)} · ${item.externalOrigin.senderName ? `${item.externalOrigin.senderName} (${item.externalOrigin.senderId})` : item.externalOrigin.senderId}` : memoryChange ? t("inbox.memoryChange") : item.sourceKind === "assignment-report" ? t("inbox.assignment") : item.authorKind === "human" ? t("main.author.human") : item.authorKind === "bot" ? bots.find((bot) => bot.slug === item.authorBotSlug)?.displayName ?? item.authorBotSlug ?? t("inbox.bot") : t("inbox.system");
43012
+ const author = item.externalOrigin !== void 0 ? `${externalPlatformLabel(item.externalOrigin.platform, t)} · ${externalSenderLabel(item.externalOrigin, t)}` : memoryChange ? t("inbox.memoryChange") : item.sourceKind === "assignment-report" ? t("inbox.assignment") : item.authorKind === "human" ? t("main.author.human") : item.authorKind === "bot" ? bots.find((bot) => bot.slug === item.authorBotSlug)?.displayName ?? item.authorBotSlug ?? t("inbox.bot") : t("inbox.system");
41280
43013
  const open = async () => {
41281
43014
  if (!item.sourceAvailable) return;
41282
43015
  if (item.externalOrigin !== void 0) {
@@ -43890,6 +45623,14 @@ html[data-botharness-motion='reduce'] .bh-section-chevron {
43890
45623
  gap: 12px;
43891
45624
  min-width: 0;
43892
45625
  }
45626
+ .bh-personabot-persona {
45627
+ min-height: 120px;
45628
+ resize: vertical;
45629
+ }
45630
+ .bh-personabot-persona:focus-visible {
45631
+ outline: 2px solid var(--dsw-alias-state-business-primary);
45632
+ outline-offset: 2px;
45633
+ }
43893
45634
  .bh-personabot-field {
43894
45635
  display: flex;
43895
45636
  flex-direction: column;
@@ -43957,6 +45698,260 @@ html[data-botharness-motion='reduce'] .bh-section-chevron {
43957
45698
  font-size: 12px;
43958
45699
  }
43959
45700
 
45701
+ /* Bot Marketplace is portaled with the native Modal; never depend on .bh-root. */
45702
+ .bh-market-modal {
45703
+ width: min(640px, 100%);
45704
+ max-height: 100%;
45705
+ }
45706
+ .bh-market {
45707
+ display: flex;
45708
+ flex-direction: column;
45709
+ gap: 10px;
45710
+ min-width: 0;
45711
+ }
45712
+ .bh-market-submit {
45713
+ display: flex;
45714
+ gap: 8px;
45715
+ min-width: 0;
45716
+ }
45717
+ .bh-market-submit > :first-child {
45718
+ flex: 1;
45719
+ min-width: 0;
45720
+ }
45721
+ .bh-market-hint {
45722
+ color: var(--dsw-alias-label-tertiary);
45723
+ font-size: 12px;
45724
+ line-height: 18px;
45725
+ }
45726
+ .bh-market-state {
45727
+ display: flex;
45728
+ align-items: center;
45729
+ justify-content: space-between;
45730
+ gap: 8px;
45731
+ padding: 24px 0;
45732
+ color: var(--dsw-alias-label-secondary);
45733
+ font-size: 13px;
45734
+ }
45735
+ .bh-market-browse {
45736
+ display: flex;
45737
+ align-items: center;
45738
+ gap: 8px;
45739
+ min-width: 0;
45740
+ }
45741
+ .bh-market-browse > :first-child {
45742
+ flex: 1;
45743
+ min-width: 0;
45744
+ }
45745
+ .bh-market-topics {
45746
+ display: flex;
45747
+ flex-wrap: wrap;
45748
+ gap: 6px;
45749
+ }
45750
+ .bh-market-topic {
45751
+ display: inline-flex;
45752
+ align-items: center;
45753
+ gap: 4px;
45754
+ height: 24px;
45755
+ padding: 0 9px;
45756
+ border: 1px solid var(--dsw-alias-border-l2);
45757
+ border-radius: 12px;
45758
+ background: transparent;
45759
+ color: var(--dsw-alias-label-secondary);
45760
+ font: inherit;
45761
+ font-size: 12px;
45762
+ cursor: pointer;
45763
+ }
45764
+ .bh-market-topic:hover {
45765
+ background: var(--bh-hover);
45766
+ color: var(--dsw-alias-label-primary);
45767
+ }
45768
+ .bh-market-topic[aria-pressed='true'] {
45769
+ border-color: var(--dsw-alias-label-primary);
45770
+ background: var(--dsw-alias-interactive-bg-hover);
45771
+ color: var(--dsw-alias-label-primary);
45772
+ font-weight: 500;
45773
+ }
45774
+ .bh-market-topic-count {
45775
+ color: var(--dsw-alias-label-tertiary);
45776
+ }
45777
+ .bh-market-list {
45778
+ display: flex;
45779
+ flex-direction: column;
45780
+ max-height: min(52vh, 440px);
45781
+ overflow-y: auto;
45782
+ border-top: 1px solid var(--dsw-alias-separator-primary);
45783
+ }
45784
+ .bh-market-row {
45785
+ display: flex;
45786
+ align-items: flex-start;
45787
+ gap: 10px;
45788
+ padding: 12px 0;
45789
+ border-bottom: 1px solid var(--dsw-alias-separator-primary);
45790
+ }
45791
+ .bh-market-copy {
45792
+ display: flex;
45793
+ flex: 1;
45794
+ flex-direction: column;
45795
+ gap: 4px;
45796
+ min-width: 0;
45797
+ }
45798
+ .bh-market-name {
45799
+ display: flex;
45800
+ align-items: baseline;
45801
+ gap: 6px;
45802
+ min-width: 0;
45803
+ color: var(--dsw-alias-label-primary);
45804
+ font-size: 14px;
45805
+ font-weight: 500;
45806
+ line-height: 20px;
45807
+ }
45808
+ .bh-market-owner {
45809
+ color: var(--dsw-alias-label-tertiary);
45810
+ font-size: 12px;
45811
+ font-weight: 400;
45812
+ }
45813
+ .bh-market-description {
45814
+ color: var(--dsw-alias-label-secondary);
45815
+ font-size: 13px;
45816
+ line-height: 18px;
45817
+ overflow-wrap: anywhere;
45818
+ }
45819
+ .bh-market-meta {
45820
+ display: flex;
45821
+ flex-wrap: wrap;
45822
+ align-items: center;
45823
+ gap: 4px 10px;
45824
+ color: var(--dsw-alias-label-tertiary);
45825
+ font-size: 12px;
45826
+ line-height: 18px;
45827
+ }
45828
+ .bh-market-open {
45829
+ padding: 0;
45830
+ border: 0;
45831
+ background: transparent;
45832
+ color: inherit;
45833
+ font: inherit;
45834
+ text-align: left;
45835
+ cursor: pointer;
45836
+ }
45837
+ .bh-market-open:hover .bh-market-name > :first-child {
45838
+ text-decoration: underline;
45839
+ }
45840
+ .bh-market-detail {
45841
+ display: flex;
45842
+ flex-direction: column;
45843
+ gap: 12px;
45844
+ min-width: 0;
45845
+ }
45846
+ .bh-market-github {
45847
+ flex: none;
45848
+ color: var(--bh-accent);
45849
+ font-size: 13px;
45850
+ text-decoration: none;
45851
+ }
45852
+ .bh-market-github:hover {
45853
+ text-decoration: underline;
45854
+ }
45855
+ .bh-market-readme {
45856
+ max-height: min(56vh, 480px);
45857
+ overflow-y: auto;
45858
+ padding-top: 12px;
45859
+ border-top: 1px solid var(--dsw-alias-border-l2);
45860
+ min-width: 0;
45861
+ }
45862
+ .bh-market-readme img {
45863
+ max-width: 100%;
45864
+ }
45865
+ .bh-market-report-open {
45866
+ margin-right: auto;
45867
+ }
45868
+ .bh-market-report {
45869
+ display: flex;
45870
+ flex-direction: column;
45871
+ gap: 6px;
45872
+ padding: 10px 12px;
45873
+ border: 1px solid var(--dsw-alias-border-l2);
45874
+ border-radius: 8px;
45875
+ color: var(--dsw-alias-label-secondary);
45876
+ font-size: 13px;
45877
+ line-height: 18px;
45878
+ }
45879
+ .bh-market-report strong {
45880
+ color: var(--dsw-alias-label-primary);
45881
+ font-size: 14px;
45882
+ font-weight: 500;
45883
+ }
45884
+ .bh-market-report label {
45885
+ display: flex;
45886
+ flex-direction: column;
45887
+ gap: 4px;
45888
+ }
45889
+ .bh-market-report textarea {
45890
+ box-sizing: border-box;
45891
+ width: 100%;
45892
+ resize: vertical;
45893
+ padding: 8px;
45894
+ border: 1px solid var(--dsw-alias-border-l2);
45895
+ border-radius: 8px;
45896
+ background: var(--dsw-alias-bg-base);
45897
+ color: var(--dsw-alias-label-primary);
45898
+ font: inherit;
45899
+ }
45900
+ .bh-market-report textarea:focus-visible {
45901
+ outline: 2px solid var(--bh-accent);
45902
+ outline-offset: 2px;
45903
+ }
45904
+ .bh-market-confirm {
45905
+ display: flex;
45906
+ flex-direction: column;
45907
+ gap: 14px;
45908
+ min-width: 0;
45909
+ }
45910
+ .bh-market-confirm-head {
45911
+ display: flex;
45912
+ align-items: flex-start;
45913
+ gap: 12px;
45914
+ }
45915
+ .bh-market-facts {
45916
+ display: grid;
45917
+ gap: 8px;
45918
+ margin: 0;
45919
+ font-size: 13px;
45920
+ }
45921
+ .bh-market-facts > div {
45922
+ display: grid;
45923
+ grid-template-columns: 96px minmax(0, 1fr);
45924
+ gap: 12px;
45925
+ }
45926
+ .bh-market-facts dt {
45927
+ color: var(--dsw-alias-label-tertiary);
45928
+ }
45929
+ .bh-market-facts dd {
45930
+ margin: 0;
45931
+ color: var(--dsw-alias-label-primary);
45932
+ font-family: var(--dsw-font-family-mono, monospace);
45933
+ overflow-wrap: anywhere;
45934
+ }
45935
+ .bh-market-facts a {
45936
+ color: var(--dsw-alias-state-business-primary);
45937
+ }
45938
+ .bh-market-risk {
45939
+ display: flex;
45940
+ flex-direction: column;
45941
+ gap: 4px;
45942
+ border: 1px solid var(--dsw-alias-state-warning-secondary);
45943
+ border-radius: 8px;
45944
+ padding: 8px 10px;
45945
+ background: var(--dsw-alias-interactive-bg-hover);
45946
+ color: var(--dsw-alias-label-secondary);
45947
+ font-size: 12px;
45948
+ line-height: 18px;
45949
+ }
45950
+ .bh-market-risk strong {
45951
+ color: var(--dsw-alias-state-warning-primary);
45952
+ font-size: 13px;
45953
+ }
45954
+
43960
45955
  /* Hidden Channel recovery is portaled under body; never depend on .bh-root. */
43961
45956
  .bh-hidden-manager {
43962
45957
  display: flex;
@@ -48292,6 +50287,146 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
48292
50287
  .bh-overview-usage .bh-profile-pin:hover {background:var(--bh-hover);color:var(--bh-text);}
48293
50288
  .bh-overview-usage .bh-profile-pin:disabled {cursor:default;opacity:0.5;}
48294
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
+ }
48295
50430
  `;
48296
50431
  //#endregion
48297
50432
  //#region packages/client/src/client/index.ts
@@ -48351,6 +50486,7 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
48351
50486
  }
48352
50487
  });
48353
50488
  const prefs = new BotModePrefs(storage);
50489
+ const releaseNotes = new ReleaseNotesController(call, storage);
48354
50490
  const lastView = typeof window === "undefined" ? void 0 : consumeLastView(window, storage);
48355
50491
  let restoreBotMode = hmrView === void 0 && lastView?.mode === "bot";
48356
50492
  const nativeSessions = {
@@ -48469,6 +50605,13 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
48469
50605
  };
48470
50606
  }
48471
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));
48472
50615
  settingsCtx.slots.inject("botharness.settings.item", () => settingsCtx.slots.register({
48473
50616
  name: "botharness.settings.item",
48474
50617
  id: "human-name",
@@ -48536,7 +50679,8 @@ button:has(.bh-panel-glyph):is(:hover, :focus-within) ~ .bh-panel-activity[data-
48536
50679
  channelSidebar,
48537
50680
  profileCards,
48538
50681
  nativeChatT,
48539
- nativeSessions
50682
+ nativeSessions,
50683
+ releaseNotes
48540
50684
  })
48541
50685
  }, BotPanel);
48542
50686
  if (restoreBotMode) {