soulnet-dsh 0.1.7 → 0.1.9

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
@@ -2320,7 +2320,7 @@ window.__ModuleLoader__.load({
2320
2320
  "inbox.pending.noGreeting": "(no greeting)",
2321
2321
  "inbox.pending.accepted": "Accepted {name}.",
2322
2322
  "inbox.empty": "No friends yet — paste a card URI below, or /add.",
2323
- "inbox.empty.noIdentity": "No identity yet — create one in Settings → SoulMirror network.",
2323
+ "inbox.empty.noIdentity": "No identity yet — create one in Settings → Soulnet.",
2324
2324
  "inbox.noIdentity": "No identity yet",
2325
2325
  "inbox.noMessages": "No messages yet",
2326
2326
  "inbox.typing": "typing…",
@@ -2338,9 +2338,14 @@ window.__ModuleLoader__.load({
2338
2338
  "bubble.mine": "my alter",
2339
2339
  "bubble.auto": "auto-reply",
2340
2340
  "bubble.note": "SoulMirror",
2341
- "settings.nav": "SoulMirror network",
2342
- "settings.title": "SoulMirror network",
2343
- "settings.intro": "This dsh is a node on the SoulMirror network: an end-to-end encrypted A2A identity, friends, and your alter — one dsh session (\"My alter\") that speaks to every friend on your behalf.",
2341
+ "settings.nav": "Soulnet",
2342
+ "sidebar.update": "Upgrade v{v}",
2343
+ "sidebar.update.busy": "Upgrading…",
2344
+ "page.update.installing": "Installing v{v}…",
2345
+ "page.update.restarting": "Restarting the service…",
2346
+ "page.update.reloading": "Back — reloading…",
2347
+ "settings.title": "Soulnet",
2348
+ "settings.intro": "This dsh is a node on Soulnet: an end-to-end encrypted A2A identity, friends, and your alter — one dsh session (\"My alter\") that speaks to every friend on your behalf.",
2344
2349
  "settings.status": "Backend",
2345
2350
  "settings.status.soulnet": "soulnet light peer",
2346
2351
  "settings.status.fake": "in-memory fake",
@@ -2405,14 +2410,14 @@ window.__ModuleLoader__.load({
2405
2410
  "settings.add.sent": "Request sent to {name}. The thread appears once they accept.",
2406
2411
  "settings.error": "Error: {message}",
2407
2412
  "settings.refresh": "Refresh",
2408
- "onboard.title": "Welcome to the SoulMirror network",
2413
+ "onboard.title": "Welcome to Soulnet",
2409
2414
  "onboard.body": "Create your A2A identity: a key pair generated on this machine. Others add you by pasting your card URI.",
2410
2415
  "onboard.name": "Display name",
2411
2416
  "onboard.create": "Create identity",
2412
2417
  "onboard.done": "Done",
2413
2418
  "onboard.later": "Later",
2414
2419
  "onboard.created": "Identity created. Copy your card URI and back up identity.json.",
2415
- "onboard.waiting": "The soulnet peer is not running yet ({state}). Check Settings → SoulMirror network.",
2420
+ "onboard.waiting": "The soulnet peer is not running yet ({state}). Check Settings → Soulnet.",
2416
2421
  "cmd.friends.open": "Open the thread with {name}",
2417
2422
  "cmd.friends.none": "No friends yet",
2418
2423
  "cmd.soulmirror.page": "Open SoulMirror — My alter",
@@ -2430,7 +2435,7 @@ window.__ModuleLoader__.load({
2430
2435
  "page.add.note": "Note (optional, also the greeting)",
2431
2436
  "page.add.send": "Send request",
2432
2437
  "page.empty.noFriends": "No friends yet. Paste a card URI under \"Add friend\" at the bottom of the list, or send yours to a friend.",
2433
- "page.empty.noFriends.noIdentity": "No identity yet — create one in Settings → SoulMirror network.",
2438
+ "page.empty.noFriends.noIdentity": "No identity yet — create one in Settings → Soulnet.",
2434
2439
  "page.empty.noMatch": "No friend matches \"{query}\".",
2435
2440
  "page.header.online": "online",
2436
2441
  "page.header.offline": "offline",
@@ -2748,7 +2753,7 @@ window.__ModuleLoader__.load({
2748
2753
  "inbox.pending.noGreeting": "(没有问候语)",
2749
2754
  "inbox.pending.accepted": "已接受 {name}。",
2750
2755
  "inbox.empty": "还没有好友——在下面贴名片链接,或用 /add。",
2751
- "inbox.empty.noIdentity": "还没有身份——到 设置 → 灵镜网络 创建。",
2756
+ "inbox.empty.noIdentity": "还没有身份——到 设置 → Soulnet 创建。",
2752
2757
  "inbox.noIdentity": "还没有身份",
2753
2758
  "inbox.noMessages": "还没有消息",
2754
2759
  "inbox.typing": "正在输入…",
@@ -2766,9 +2771,14 @@ window.__ModuleLoader__.load({
2766
2771
  "bubble.mine": "我的分身",
2767
2772
  "bubble.auto": "自动回复",
2768
2773
  "bubble.note": "灵镜",
2769
- "settings.nav": "灵镜网络",
2770
- "settings.title": "灵镜网络",
2771
- "settings.intro": "这个 dsh 是灵镜网络上的一个节点:端到端加密的 A2A 身份、好友,以及你的分身——一条 dsh 会话(「我的分身」),替你和所有好友往来。",
2774
+ "settings.nav": "Soulnet",
2775
+ "sidebar.update": "升级 v{v}",
2776
+ "sidebar.update.busy": "升级中…",
2777
+ "page.update.installing": "正在安装 v{v}……",
2778
+ "page.update.restarting": "正在重启服务……",
2779
+ "page.update.reloading": "完成——正在刷新……",
2780
+ "settings.title": "Soulnet",
2781
+ "settings.intro": "这个 dsh 是Soulnet 上的一个节点:端到端加密的 A2A 身份、好友,以及你的分身——一条 dsh 会话(「我的分身」),替你和所有好友往来。",
2772
2782
  "settings.status": "后端",
2773
2783
  "settings.status.soulnet": "soulnet 灵网轻端",
2774
2784
  "settings.status.fake": "内存假实现",
@@ -2833,14 +2843,14 @@ window.__ModuleLoader__.load({
2833
2843
  "settings.add.sent": "已向 {name} 发出申请,对方接受后往来就会出现。",
2834
2844
  "settings.error": "错误:{message}",
2835
2845
  "settings.refresh": "刷新",
2836
- "onboard.title": "欢迎来到灵镜网络",
2846
+ "onboard.title": "欢迎来到Soulnet",
2837
2847
  "onboard.body": "创建你的 A2A 身份:在本机生成一对密钥。别人贴你的名片链接就能加你。",
2838
2848
  "onboard.name": "昵称",
2839
2849
  "onboard.create": "创建身份",
2840
2850
  "onboard.done": "完成",
2841
2851
  "onboard.later": "稍后",
2842
2852
  "onboard.created": "身份已创建。复制名片链接,并备份 identity.json。",
2843
- "onboard.waiting": "soulnet 轻端还没运行({state})。请到 设置 → 灵镜网络 查看。",
2853
+ "onboard.waiting": "soulnet 轻端还没运行({state})。请到 设置 → Soulnet 查看。",
2844
2854
  "cmd.friends.open": "打开与 {name} 的往来",
2845
2855
  "cmd.friends.none": "还没有好友",
2846
2856
  "cmd.soulmirror.page": "打开灵镜——我的分身",
@@ -2858,7 +2868,7 @@ window.__ModuleLoader__.load({
2858
2868
  "page.add.note": "备注(可选,同时作为问候语)",
2859
2869
  "page.add.send": "发送申请",
2860
2870
  "page.empty.noFriends": "还没有好友。把对方的名片链接贴到列表底部的「加好友」,或把你的名片发给对方。",
2861
- "page.empty.noFriends.noIdentity": "还没有身份——到 设置 → 灵镜网络 创建。",
2871
+ "page.empty.noFriends.noIdentity": "还没有身份——到 设置 → Soulnet 创建。",
2862
2872
  "page.empty.noMatch": "没有匹配「{query}」的好友。",
2863
2873
  "page.header.online": "在线",
2864
2874
  "page.header.offline": "离线",
@@ -11068,6 +11078,76 @@ window.__ModuleLoader__.load({
11068
11078
  });
11069
11079
  }
11070
11080
  //#endregion
11081
+ //#region src/client/UpdateAction.tsx
11082
+ /**
11083
+ * Icon-only update button at the RIGHT end of the sidebar-foot SoulMirror row
11084
+ * (list seat `sidebar.footer.action`, ordered after the entry): invisible
11085
+ * until a newer release is known, then a small circled arrow. One click runs
11086
+ * the full install-restart-reload chain; while busy the tooltip narrates the
11087
+ * phase and the icon pulses. The reloaded page re-checks as current and the
11088
+ * button removes itself.
11089
+ */
11090
+ /** Upward arrow (update available). */
11091
+ function ArrowUpIcon({ size = 13 }) {
11092
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
11093
+ width: size,
11094
+ height: size,
11095
+ viewBox: "0 0 16 16",
11096
+ fill: "none",
11097
+ "aria-hidden": true,
11098
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
11099
+ d: "M8 13.2V3.6M3.6 7.6 8 3.2l4.4 4.4",
11100
+ stroke: "currentColor",
11101
+ strokeWidth: "1.7",
11102
+ strokeLinecap: "round",
11103
+ strokeLinejoin: "round"
11104
+ })
11105
+ });
11106
+ }
11107
+ /** Spinning arc shown while the upgrade chain runs. */
11108
+ function SpinnerIcon({ size = 13 }) {
11109
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
11110
+ width: size,
11111
+ height: size,
11112
+ viewBox: "0 0 16 16",
11113
+ fill: "none",
11114
+ "aria-hidden": true,
11115
+ className: "sm-update-spin",
11116
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
11117
+ cx: "8",
11118
+ cy: "8",
11119
+ r: "6",
11120
+ stroke: "currentColor",
11121
+ strokeWidth: "1.7",
11122
+ strokeLinecap: "round",
11123
+ strokeDasharray: "28",
11124
+ strokeDashoffset: "20"
11125
+ })
11126
+ });
11127
+ }
11128
+ function UpdateAction({ t }) {
11129
+ const upgrade = (0, react.useSyncExternalStore)(upgradeStore.subscribe, upgradeStore.getSnapshot);
11130
+ const busy = upgrade.phase === "installing" || upgrade.phase === "restarting" || upgrade.phase === "reloading";
11131
+ if (!upgrade.hasUpdate && !busy) return null;
11132
+ const label = busy ? upgrade.phase === "installing" ? t("page.update.installing", { v: upgrade.latest ?? "" }) : upgrade.phase === "restarting" ? t("page.update.restarting") : t("page.update.reloading") : t("sidebar.update", { v: upgrade.latest ?? "" });
11133
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
11134
+ label,
11135
+ delayMs: 200,
11136
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
11137
+ type: "button",
11138
+ className: `sm-update-fab${busy ? " sm-busy" : ""}`,
11139
+ disabled: busy,
11140
+ "aria-label": label,
11141
+ "data-soulmirror-update-action": upgrade.latest,
11142
+ onClick: () => {
11143
+ if (busy || upgrade.latest === void 0) return;
11144
+ upgradeStore.run();
11145
+ },
11146
+ children: busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SpinnerIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArrowUpIcon, {})
11147
+ })
11148
+ });
11149
+ }
11150
+ //#endregion
11071
11151
  //#region src/client/styles.ts
11072
11152
  /**
11073
11153
  * The rules the SoulMirror surfaces need that inline styles cannot express
@@ -11082,6 +11162,29 @@ window.__ModuleLoader__.load({
11082
11162
  */
11083
11163
  const STYLE_ID = "soulmirror-styles";
11084
11164
  const CSS = `
11165
+ /* Icon-only update button at the right end of the SoulMirror foot row:
11166
+ invisible until a release is known, small circled arrow, tooltip carries
11167
+ the words. Sits beside the entry (the row is a flex line). */
11168
+ .sm-update-fab {
11169
+ flex: none; align-self: center; width: 24px; height: 24px; margin: 4px 2px 0 0;
11170
+ display: inline-flex; align-items: center; justify-content: center;
11171
+ border: 1px solid var(--dsw-alias-brand-primary); border-radius: 50%;
11172
+ background: transparent; color: var(--dsw-alias-brand-primary); cursor: pointer; padding: 0;
11173
+ }
11174
+ .sm-update-fab:hover { background: var(--dsw-alias-brand-primary); color: var(--dsw-alias-label-primary-inverted); }
11175
+ .sm-update-fab:disabled, .sm-update-fab.sm-busy { opacity: .8; cursor: default; }
11176
+ .sm-update-spin { animation: sm-update-spin 900ms linear infinite; }
11177
+ @keyframes sm-update-spin { to { transform: rotate(360deg); } }
11178
+ display: inline-flex; align-items: center; gap: 5px; max-width: 100%; min-width: 0;
11179
+ padding: 2px 9px; border: 1px solid var(--dsw-alias-brand-primary); border-radius: 999px;
11180
+ background: transparent; color: var(--dsw-alias-brand-primary);
11181
+ font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; white-space: nowrap;
11182
+ }
11183
+ .sm-update-chip:hover { background: var(--dsw-alias-brand-primary); color: var(--dsw-alias-label-primary-inverted); }
11184
+ .sm-update-chip:disabled { opacity: .75; cursor: default; }
11185
+ .sm-update-chip.sm-rail { padding: 2px 6px; }
11186
+
11187
+
11085
11188
  /* Native form controls follow the ACTIVE theme: the option list of a <select>
11086
11189
  (and scrollbars, checkboxes...) is OS-rendered and ignores CSS tokens - it
11087
11190
  only obeys color-scheme. dsh marks its dark theme on <body>. */
@@ -11089,8 +11192,8 @@ body[data-ds-dark-theme] { color-scheme: dark; }
11089
11192
  .sm-page-root select option, .sm-page-root select optgroup { background: var(--dsw-specific-menu); color: var(--dsw-alias-label-primary); }
11090
11193
 
11091
11194
  .sm-footer {
11092
- flex: none; display: flex; align-items: center; gap: 8px;
11093
- width: calc(100% + 4px); height: 42px; margin: 4px -2px 0; padding: 0 10px 0 8px;
11195
+ flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 8px;
11196
+ width: auto; height: 42px; margin: 4px -2px 0; padding: 0 10px 0 8px;
11094
11197
  box-sizing: border-box; border: none; border-radius: 12px; background: transparent;
11095
11198
  cursor: pointer; overflow: hidden; color: var(--dsw-alias-label-primary);
11096
11199
  font-family: inherit; font-size: 14px; line-height: 22px; position: relative;
@@ -11507,6 +11610,12 @@ body[data-ds-dark-theme] .sm-page-root {
11507
11610
  order: 0,
11508
11611
  locale: NS
11509
11612
  }, SidebarEntry));
11613
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
11614
+ name: "sidebar.footer.action",
11615
+ id: "soulmirror-update",
11616
+ order: 1,
11617
+ locale: NS
11618
+ }, UpdateAction));
11510
11619
  ctx.slots.inject("sidebar.nav.primary", () => {
11511
11620
  navSeatStore.set(true);
11512
11621
  const dispose = ctx.slots.register({
@@ -11576,14 +11685,29 @@ body[data-ds-dark-theme] .sm-page-root {
11576
11685
  openSession,
11577
11686
  scope
11578
11687
  });
11579
- ctx.slots.inject("settings.section", () => ctx.slots.register({
11580
- name: "settings.section",
11581
- id: "soulmirror",
11582
- order: 80,
11583
- locale: NS,
11584
- label: () => upgradeStore.getSnapshot().hasUpdate ? `${t("settings.nav")} ●` : t("settings.nav"),
11585
- inject: settingsInjected
11586
- }, SoulmirrorSettingsSection));
11688
+ ctx.slots.inject("settings.section", () => {
11689
+ const make = () => ctx.slots.register({
11690
+ name: "settings.section",
11691
+ id: "soulmirror",
11692
+ order: 80,
11693
+ locale: NS,
11694
+ label: () => upgradeStore.getSnapshot().hasUpdate ? `${t("settings.nav")} ●` : t("settings.nav"),
11695
+ inject: settingsInjected
11696
+ }, SoulmirrorSettingsSection);
11697
+ let hadUpdate = upgradeStore.getSnapshot().hasUpdate;
11698
+ let disposeSection = make();
11699
+ const unsubscribe = upgradeStore.subscribe(() => {
11700
+ const now = upgradeStore.getSnapshot().hasUpdate;
11701
+ if (now === hadUpdate) return;
11702
+ hadUpdate = now;
11703
+ disposeSection();
11704
+ disposeSection = make();
11705
+ });
11706
+ return () => {
11707
+ unsubscribe();
11708
+ disposeSection();
11709
+ };
11710
+ });
11587
11711
  ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
11588
11712
  name: "settings.onboarding",
11589
11713
  id: "soulmirror-identity",