@xmanrui/dsh-im 3.0.7 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.en.md +25 -2
  2. package/README.md +25 -2
  3. package/THIRD_PARTY_NOTICES.md +20 -0
  4. package/lib/client.js +542 -47
  5. package/lib/index.js +232 -225
  6. package/package.json +3 -2
  7. package/plugin-src/client/i18n.js +56 -0
  8. package/plugin-src/client/index.js +19 -2
  9. package/plugin-src/client/styles.js +34 -1
  10. package/plugin-src/client/update-panel.js +367 -0
  11. package/plugin-src/host/channels/dingtalk/index.mjs +1 -1
  12. package/plugin-src/host/channels/dingtalk/production.mjs +3 -11
  13. package/plugin-src/host/channels/discord/index.mjs +1 -1
  14. package/plugin-src/host/channels/feishu/index.mjs +1 -1
  15. package/plugin-src/host/channels/feishu/production.mjs +3 -13
  16. package/plugin-src/host/channels/office/production.mjs +3 -3
  17. package/plugin-src/host/channels/qq/index.mjs +1 -1
  18. package/plugin-src/host/channels/qq/production.mjs +3 -11
  19. package/plugin-src/host/channels/shared/production.mjs +3 -11
  20. package/plugin-src/host/channels/slack/index.mjs +1 -1
  21. package/plugin-src/host/channels/slack/production.mjs +4 -3
  22. package/plugin-src/host/channels/telegram/index.mjs +1 -1
  23. package/plugin-src/host/channels/wecom/index.mjs +1 -1
  24. package/plugin-src/host/channels/wecom/production.mjs +3 -11
  25. package/plugin-src/host/channels/weixin/index.mjs +1 -1
  26. package/plugin-src/host/channels/weixin/production.mjs +3 -11
  27. package/plugin-src/host/channels/whatsapp/index.mjs +1 -1
  28. package/plugin-src/host/channels/whatsapp/production.mjs +3 -11
  29. package/plugin-src/host/harness-connection.mjs +15 -0
  30. package/plugin-src/host/index.mjs +10 -1
  31. package/plugin-src/host/update-rpc.mjs +50 -0
  32. package/plugin-src/host/update-runtime.mjs +338 -0
  33. package/plugin-src/host/update-service.mjs +385 -0
  34. package/scripts/verify-package.mjs +12 -0
  35. package/src/channels/dingtalk/dingtalk-bridge.mjs +5 -1
  36. package/src/channels/feishu/bridge.mjs +11 -3
  37. package/src/channels/feishu/feishu-cards.mjs +2 -0
  38. package/src/channels/qq/qq-bridge.mjs +5 -1
  39. package/src/channels/shared/bot-workspace-store.mjs +3 -0
  40. package/src/channels/shared/harness-client.mjs +252 -281
  41. package/src/channels/shared/harness-mux.mjs +123 -0
  42. package/src/channels/shared/history-command.mjs +193 -0
  43. package/src/channels/shared/i18n-en/shared-b.mjs +1 -0
  44. package/src/channels/shared/i18n-en/shared-c.mjs +40 -0
  45. package/src/channels/shared/text-harness-bridge.mjs +5 -1
  46. package/src/channels/shared/workspace-command.mjs +1 -0
  47. package/src/channels/wecom/wecom-bridge.mjs +5 -1
  48. package/src/channels/weixin/weixin-bridge.mjs +5 -1
package/lib/client.js CHANGED
@@ -42,12 +42,12 @@ __export(index_exports, {
42
42
  name: () => name
43
43
  });
44
44
  module.exports = __toCommonJS(index_exports);
45
- var React20 = __toESM(require("react"), 1);
45
+ var React21 = __toESM(require("react"), 1);
46
46
 
47
47
  // package.json
48
48
  var package_default = {
49
49
  name: "@xmanrui/dsh-im",
50
- version: "3.0.7",
50
+ version: "3.1.0",
51
51
  description: "\u628A\u4E5D\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
52
52
  keywords: [
53
53
  "deepseek-harness",
@@ -149,7 +149,8 @@ var package_default = {
149
149
  "https-proxy-agent": "5.0.1",
150
150
  react: "18.3.1",
151
151
  "react-dom": "18.3.1",
152
- "react-test-renderer": "18.3.1"
152
+ "react-test-renderer": "18.3.1",
153
+ semver: "7.8.5"
153
154
  }
154
155
  };
155
156
 
@@ -310,6 +311,62 @@ var EN = Object.freeze({
310
311
  "IM \u6E20\u9053": "IM channels",
311
312
  "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA": "Connecting DeepSeek Harness",
312
313
  "\u5F53\u524D\u7248\u672C": "Current version",
314
+ "DSH-IM \u66F4\u65B0": "DSH-IM update",
315
+ "\u68C0\u67E5\u66F4\u65B0": "Check for updates",
316
+ "\u91CD\u65B0\u68C0\u67E5": "Check again",
317
+ "\u5237\u65B0\u72B6\u6001": "Refresh status",
318
+ "\u66F4\u65B0\u81F3": "Update to",
319
+ "\u5B89\u88C5\u66F4\u65B0": "Install update",
320
+ "\u6B63\u5728\u66F4\u65B0\u2026": "Updating\u2026",
321
+ "\u5F85\u624B\u52A8\u91CD\u542F": "Restart needed",
322
+ "\u8FD0\u884C\u7248\u672C": "Running version",
323
+ "\u5DF2\u5B89\u88C5\u7248\u672C": "Installed version",
324
+ "npm \u6700\u65B0\u7248\u672C": "Latest on npm",
325
+ "\u76EE\u6807 profile": "Target profile",
326
+ "\u76EE\u6807\u7248\u672C": "Target version",
327
+ "\u66F4\u65B0\u6765\u6E90": "Update source",
328
+ "\u9875\u9762\u7248\u672C": "Page version",
329
+ "\u65E0\u6CD5\u786E\u8BA4": "Unknown",
330
+ "\u53D1\u73B0\u65B0\u7248\u672C": "Update available",
331
+ "\u5DF2\u662F\u6700\u65B0\u7248\u672C": "Up to date",
332
+ "\u5F53\u524D\u7248\u672C\u65E0\u9700\u66F4\u65B0": "No newer version available",
333
+ "\u5DF2\u83B7\u53D6 npm \u6700\u65B0\u7248\u672C": "Latest npm version retrieved",
334
+ "\u68C0\u67E5 npm \u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002": "Check the latest npm version. Nothing is installed automatically.",
335
+ "\u6B63\u5728\u4ECE npm \u68C0\u67E5\u6700\u65B0\u7248\u672C\u2026": "Checking npm for the latest version\u2026",
336
+ "\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7A0D\u5019\u2026": "Installing, please wait\u2026",
337
+ "\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u7ED3\u679C\u2026": "Verifying the installation\u2026",
338
+ "\u5DF2\u5B89\u88C5\uFF0C\u5F85\u624B\u52A8\u91CD\u542F": "Installed \u2014 manual restart needed",
339
+ "\u66F4\u65B0\u5DF2\u751F\u6548": "Updated version is active",
340
+ "\u66F4\u65B0\u5931\u8D25": "Update failed",
341
+ "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25": "Update request failed",
342
+ "\u4EC5\u66F4\u65B0 DSH-IM\u3002\u5B89\u88C5\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u540E\u53F0\uFF1B\u672C\u529F\u80FD\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u6216\u4E3B\u52A8\u5237\u65B0\u9875\u9762\u3002": "Only DSH-IM will be updated. Restart the backend manually after installation. This feature does not automatically restart it or initiate a page refresh.",
343
+ "\u5F53\u524D\u662F\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\uFF0C\u53EA\u80FD\u68C0\u67E5\u7248\u672C\uFF1B\u8BF7\u624B\u52A8\u66F4\u65B0\u6E90\u7801\uFF0C\u6216\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u3002": "This is a source or linked installation. You can check versions, but must update the source manually or migrate to an npm installation.",
344
+ "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D profile\uFF0C\u8BF7\u5728\u5BF9\u5E94\u7684 Harness \u73AF\u5883\u4E2D\u624B\u52A8\u66F4\u65B0\u3002": "The current profile could not be identified. Update manually in the corresponding Harness environment.",
345
+ "\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u6309\u94AE\u5B89\u88C5\uFF0C\u8BF7\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u3002": "This runtime cannot install through this button. Update the plugin manually.",
346
+ "\u5F53\u524D npm \u6E90\u914D\u7F6E\u4E0E\u5B98\u65B9\u6E90\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u5148\u68C0\u67E5 registry \u914D\u7F6E\u3002": "The npm registry configuration differs from the official registry. Check your registry settings first.",
347
+ "\u5F53\u524D Host \u7684 Node.js \u7248\u672C\u4E0D\u6EE1\u8DB3\u65B0\u7248\u8981\u6C42\uFF0C\u8BF7\u5148\u66F4\u65B0\u8FD0\u884C\u73AF\u5883\u3002": "The Host Node.js version does not meet the new version\u2019s requirements. Update the runtime first.",
348
+ "\u65B0\u7248\u672C\u5DF2\u5B89\u88C5\uFF0C\u8BF7\u5728\u65B9\u4FBF\u65F6\u624B\u52A8\u91CD\u542F\u5F53\u524D Harness \u6216 Desktop\u3002": "The new version is installed. Manually restart this Harness or Desktop when convenient.",
349
+ "\u4E0A\u6B21\u5B89\u88C5\u7ED3\u679C\u65E0\u6CD5\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u6B64 profile \u7684\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u3002": "The previous installation result is uncertain. Check this profile\u2019s plugin installation first.",
350
+ "\u65E0\u6CD5\u8BBF\u95EE npm \u6216\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u65B0\u68C0\u67E5\u3002": "npm is unreachable or the request timed out. Check again later.",
351
+ "npm \u8FD4\u56DE\u7684\u7248\u672C\u4FE1\u606F\u65E0\u6548\uFF0C\u6682\u65F6\u65E0\u6CD5\u66F4\u65B0\u3002": "npm returned invalid release information. Updating is unavailable.",
352
+ "\u7248\u672C\u786E\u8BA4\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u540E\u518D\u5B89\u88C5\u3002": "The version confirmation expired. Check again before installing.",
353
+ "\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u3002": "The plugin installation changed. Check again.",
354
+ "\u6B64 profile \u6B63\u5728\u66F4\u65B0\uFF0C\u8BF7\u7A0D\u540E\u67E5\u770B\u72B6\u6001\u3002": "This profile is already updating. Check its status shortly.",
355
+ "\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002": "Installation failed. Check the current installation before retrying.",
356
+ "\u5B89\u88C5\u7ED3\u679C\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u63D2\u4EF6\u7248\u672C\u3002": "Installation verification failed. Check the plugin version manually.",
357
+ "\u65E0\u6CD5\u5B89\u5168\u4FDD\u5B58\u66F4\u65B0\u72B6\u6001\uFF0C\u8BF7\u5148\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u7ED3\u679C\u3002": "Update state could not be saved safely. Check the current installation result before retrying.",
358
+ "\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002": "The previous update was interrupted. Check the installation before retrying.",
359
+ "\u66F4\u65B0\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u8BF7\u624B\u52A8\u91CD\u65B0\u6253\u5F00\u8BBE\u7F6E\u9875\u3002": "The update service has closed. Reopen settings manually.",
360
+ "\u66F4\u65B0\u8BF7\u6C42\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u7248\u672C\u3002": "The update request is invalid. Check the version again.",
361
+ "\u5F53\u524D\u63D2\u4EF6\u5B89\u88C5\u4E0D\u5B8C\u6574\u6216\u4E0E profile \u4E0D\u7B26\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u5B89\u88C5\u914D\u7F6E\u3002": "The plugin installation is incomplete or does not match this profile. Check the installation configuration manually.",
362
+ "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D npm \u6E90\u914D\u7F6E\uFF0C\u6682\u65F6\u4E0D\u80FD\u5B89\u88C5\u66F4\u65B0\u3002": "The npm registry configuration could not be verified. Installation is unavailable.",
363
+ "\u5B89\u88C5\u8D85\u65F6\uFF0C\u8BF7\u5148\u786E\u8BA4\u5F53\u524D\u5B89\u88C5\u72B6\u6001\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5\u3002": "Installation timed out. Check the current installation before retrying.",
364
+ "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "The update request failed. Try again.",
365
+ "\u66F4\u65B0\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002": "The update service returned an unrecognized response.",
366
+ "\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002": "This Host does not support the update API. Update the plugin manually and restart first.",
367
+ "\u5173\u95ED\u7A97\u53E3\u4E0D\u4F1A\u53D6\u6D88\u5B89\u88C5\u3002\u8BF7\u52FF\u540C\u65F6\u5728\u5176\u4ED6\u7A97\u53E3\u7BA1\u7406\u6B64 profile \u7684\u63D2\u4EF6\u3002": "Closing this window does not cancel installation. Do not manage this profile\u2019s plugins in another window at the same time.",
368
+ "\u9875\u9762\u7248\u672C\u4E0E\u8FD0\u884C\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u624B\u52A8\u91CD\u542F Harness \u6216 Desktop\u3002": "The page and running versions differ. Refresh the page manually; if they still differ, manually restart Harness or Desktop.",
369
+ "\u8BF7\u5728\u673A\u5668\u4EBA\u7A7A\u95F2\u65F6\u5B89\u88C5\uFF1B\u5B89\u88C5\u4F1A\u4FEE\u6539\u5F53\u524D profile \u7684\u4F9D\u8D56\uFF0C\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u3002": "Install while bots are idle. This changes the current profile\u2019s dependencies and requires a manual restart afterward.",
313
370
  "AI Office": "AI Office",
314
371
  "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09": "(Experimental)",
315
372
  "AI Office \u8BBE\u7F6E": "AI Office settings",
@@ -2414,7 +2471,7 @@ function AccountCard({
2414
2471
  const state = busy === "reconnect" ? "connecting" : account.state;
2415
2472
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
2416
2473
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
2417
- const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
2474
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
2418
2475
  return h2(
2419
2476
  "article",
2420
2477
  { className: "ddt-card dim-botCard", tabIndex: -1, "data-bot-id": account.botId },
@@ -2474,7 +2531,7 @@ function AccountCard({
2474
2531
  "\u79FB\u9664\u63A5\u5165"
2475
2532
  )
2476
2533
  ),
2477
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
2534
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
2478
2535
  account.lastMessageError ? h2(LastMessageErrorSummary, {
2479
2536
  className: "ddt-summary",
2480
2537
  error: account.lastMessageError
@@ -3137,11 +3194,11 @@ function createTokenChannelApi(channel4, connectionSummary, {
3137
3194
  agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog)
3138
3195
  };
3139
3196
  };
3140
- const presentError10 = (error) => ({
3197
+ const presentError11 = (error) => ({
3141
3198
  code: text2(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
3142
3199
  message: text2(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
3143
3200
  });
3144
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult10, normalizeSnapshot: normalizeSnapshot9, presentError: presentError10 });
3201
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult10, normalizeSnapshot: normalizeSnapshot9, presentError: presentError11 });
3145
3202
  }
3146
3203
 
3147
3204
  // plugin-src/client/channels/discord/api.js
@@ -3210,7 +3267,7 @@ function createTokenChannelSettings(definition) {
3210
3267
  const state = busy === "reconnect" ? "connecting" : account.state;
3211
3268
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
3212
3269
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
3213
- const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
3270
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
3214
3271
  const identity = account.bot.username ? `@${account.bot.username}` : account.bot.idMasked;
3215
3272
  return h2(
3216
3273
  "article",
@@ -3281,7 +3338,7 @@ function createTokenChannelSettings(definition) {
3281
3338
  disabled: Boolean(busy)
3282
3339
  }, "\u79FB\u9664\u63A5\u5165")
3283
3340
  ),
3284
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
3341
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
3285
3342
  account.lastMessageError ? h2(LastMessageErrorSummary, {
3286
3343
  className: "ddt-summary",
3287
3344
  error: account.lastMessageError
@@ -4497,7 +4554,7 @@ function BotCard({
4497
4554
  const repairTooltipId = React12.useId();
4498
4555
  const stateForDisplay = busy === "reconnect" ? "connecting" : state;
4499
4556
  const tone = stateForDisplay === "connected" ? "success" : stateForDisplay === "connecting" ? "warning" : "error";
4500
- const summary = actionError?.message ?? connection.error?.message ?? (connected ? null : health.summary);
4557
+ const summary2 = actionError?.message ?? connection.error?.message ?? (connected ? null : health.summary);
4501
4558
  const titleId = `bxf-bot-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
4502
4559
  return h2(
4503
4560
  "article",
@@ -4611,10 +4668,10 @@ function BotCard({
4611
4668
  "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}`
4612
4669
  }, "\u79FB\u9664\u63A5\u5165")
4613
4670
  ),
4614
- summary ? h2(
4671
+ summary2 ? h2(
4615
4672
  "div",
4616
4673
  { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
4617
- summary
4674
+ summary2
4618
4675
  ) : null,
4619
4676
  connection.lastMessageError ? h2(LastMessageErrorSummary, {
4620
4677
  className: "bxf-healthSummary",
@@ -6358,7 +6415,7 @@ function AccountCard2({
6358
6415
  }) {
6359
6416
  const tone = account.connected ? "success" : account.state === "error" ? "error" : "warning";
6360
6417
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
6361
- const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
6418
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
6362
6419
  return h2(
6363
6420
  "article",
6364
6421
  { className: "ddt-card dim-botCard", "data-bot-id": account.botId },
@@ -6410,7 +6467,7 @@ function AccountCard2({
6410
6467
  h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6411
6468
  h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
6412
6469
  ),
6413
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
6470
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
6414
6471
  account.lastMessageError ? h2(LastMessageErrorSummary, {
6415
6472
  className: "ddt-summary",
6416
6473
  error: account.lastMessageError
@@ -7906,7 +7963,7 @@ function AccountCard3({
7906
7963
  }) {
7907
7964
  const tone = account.connected ? "success" : account.state === "error" ? "error" : "warning";
7908
7965
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
7909
- const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
7966
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
7910
7967
  return h2(
7911
7968
  "article",
7912
7969
  { className: "ddt-card dim-botCard", "data-bot-id": account.botId },
@@ -7958,7 +8015,7 @@ function AccountCard3({
7958
8015
  h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
7959
8016
  h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7960
8017
  ),
7961
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
8018
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
7962
8019
  account.lastMessageError ? h2(LastMessageErrorSummary, {
7963
8020
  className: "ddt-summary",
7964
8021
  error: account.lastMessageError
@@ -8730,7 +8787,7 @@ function AccountCard4({
8730
8787
  }) {
8731
8788
  const state = busy === "reconnect" ? "connecting" : account.state;
8732
8789
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
8733
- const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
8790
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
8734
8791
  return h2(
8735
8792
  "article",
8736
8793
  { className: "dxw-card dim-botCard", tabIndex: -1, "data-bot-id": account.botId },
@@ -8781,7 +8838,7 @@ function AccountCard4({
8781
8838
  ),
8782
8839
  h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8783
8840
  ),
8784
- summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null,
8841
+ summary2 ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary2) : null,
8785
8842
  account.lastMessageError ? h2(LastMessageErrorSummary, {
8786
8843
  className: "dxw-summary",
8787
8844
  error: account.lastMessageError
@@ -9933,7 +9990,7 @@ function WhatsappAccountCard({
9933
9990
  const state = busy === "reconnect" ? "connecting" : account.state;
9934
9991
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
9935
9992
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
9936
- const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
9993
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
9937
9994
  return h2(
9938
9995
  "article",
9939
9996
  { className: "ddt-card dim-botCard", "data-bot-id": account.botId },
@@ -10002,7 +10059,7 @@ function WhatsappAccountCard({
10002
10059
  disabled: Boolean(busy)
10003
10060
  }, "\u79FB\u9664\u63A5\u5165")
10004
10061
  ),
10005
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
10062
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
10006
10063
  account.lastMessageError ? h2(LastMessageErrorSummary, {
10007
10064
  className: "ddt-summary",
10008
10065
  error: account.lastMessageError
@@ -10387,6 +10444,32 @@ var CSS11 = String.raw`
10387
10444
  .dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
10388
10445
  .dim-brandVersion { color: var(--dsw-alias-label-tertiary, #8f959e); font: 500 10px/16px ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0; }
10389
10446
  .dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
10447
+ .dim-titleActions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
10448
+ .dim-updateButton { min-height: 30px; display: inline-flex; align-items: center; justify-content: center; gap: 3px; padding: 5px 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 18px; font-weight: 560; cursor: pointer; }
10449
+ .dim-updateButton:hover:not(:disabled) { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
10450
+ .dim-updateButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
10451
+ .dim-updateButton:disabled { opacity: .55; cursor: default; }
10452
+ .dim-updateTrigger { white-space: nowrap; }
10453
+ .dim-updateBackdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); }
10454
+ .dim-updateBackdrop, .dim-updateBackdrop * { box-sizing: border-box; }
10455
+ .dim-updateDialog { width: min(480px, 100%); max-height: calc(100vh - 48px); overflow-y: auto; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 16px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 20px 70px rgb(0 0 0 / 20%); text-align: left; }
10456
+ .dim-updateDialog:focus { outline: none; }
10457
+ .dim-updateDialog h3 { margin: 22px 24px 8px; font-size: 18px; line-height: 25px; font-weight: 680; }
10458
+ .dim-updateDescription { margin: 0 24px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 13px; line-height: 20px; }
10459
+ .dim-updateBody { padding: 18px 24px 20px; }
10460
+ .dim-updateVersions { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 18px; margin: 0 0 18px; font-size: 12px; line-height: 18px; }
10461
+ .dim-updateVersions dt { color: var(--dsw-alias-label-secondary, #646a73); }
10462
+ .dim-updateVersions dd { min-width: 0; margin: 0; overflow-wrap: anywhere; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
10463
+ .dim-updateStatus { padding: 12px 14px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 10px; background: var(--dsw-alias-bg-layer-1, #f7f8fa); font-size: 13px; line-height: 20px; }
10464
+ .dim-updateStatus strong { font-weight: 600; }
10465
+ .dim-updateStatus p { margin: 6px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 19px; overflow-wrap: anywhere; }
10466
+ .dim-updateStatusError { border-color: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #d92d20) 25%, var(--dsw-alias-border-l2, #dfe1e5)); }
10467
+ .dim-updateHint, .dim-updateError { margin: 12px 0 0; font-size: 12px; line-height: 19px; overflow-wrap: anywhere; }
10468
+ .dim-updateHint { color: var(--dsw-alias-label-secondary, #646a73); }
10469
+ .dim-updateError { color: var(--dsw-alias-state-danger-primary, #d92d20); }
10470
+ .dim-updateFooter { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 8px; padding: 14px 24px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
10471
+ .dim-updateFooter .dim-updateButton:first-child { margin-right: auto; }
10472
+ .dim-updatePrimary, .dim-updatePrimary:hover:not(:disabled) { border-color: var(--dsw-alias-state-business-primary, #3370ff); color: #fff; background: var(--dsw-alias-state-business-primary, #3370ff); }
10390
10473
  .dim-githubAction { position: relative; display: inline-flex; flex: none; }
10391
10474
  .dim-githubLink { min-height: 30px; display: inline-flex; align-items: center; gap: 5px; flex: none; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 12px; line-height: normal; font-weight: 560; text-decoration: none; transition: border-color .15s ease, color .15s ease, background .15s ease; }
10392
10475
  .dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
@@ -10395,7 +10478,7 @@ var CSS11 = String.raw`
10395
10478
  .dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
10396
10479
  .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
10397
10480
  .dim-layout { display: grid; grid-template-columns: 174px 1px minmax(0, 1fr); gap: 24px; align-items: start; }
10398
- .dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 1px 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; }
10481
+ .dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 0 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; }
10399
10482
  .dim-rail::-webkit-scrollbar { width: 4px; }
10400
10483
  .dim-rail::-webkit-scrollbar-thumb { border-radius: 99px; background: var(--dsw-alias-border-l2, #dfe1e5); }
10401
10484
  .dim-channel { width: 100%; min-height: 48px; display: grid; grid-template-columns: 30px minmax(0, 1fr); align-items: center; gap: 10px; padding: 8px 12px; border: 1px solid var(--dsw-alias-border-l2, #eef0f3); border-radius: 14px; color: inherit; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 2px 8px rgb(31 35 41 / 3%); font: inherit; text-align: left; cursor: pointer; transition: border-color .16s ease, background .16s ease, box-shadow .16s ease; }
@@ -10654,6 +10737,13 @@ var CSS11 = String.raw`
10654
10737
  @media (max-width: 560px) {
10655
10738
  .dim-title { flex-direction: column; gap: 10px; }
10656
10739
  .dim-title p { white-space: normal; }
10740
+ .dim-titleActions { justify-content: flex-start; }
10741
+ .dim-updateBackdrop { padding: 12px; }
10742
+ .dim-updateDialog { max-height: calc(100vh - 24px); }
10743
+ .dim-updateDialog h3 { margin: 18px 18px 8px; }
10744
+ .dim-updateDescription { margin: 0 18px; }
10745
+ .dim-updateBody { padding: 16px 18px; }
10746
+ .dim-updateFooter { padding: 12px 18px; }
10657
10747
  .dim-githubTooltip { right: auto; left: 0; }
10658
10748
  .dim-rail { grid-template-columns: minmax(0, 1fr); }
10659
10749
  .dim-loopbackRecovery { align-items: stretch; flex-direction: column; gap: 12px; }
@@ -10686,6 +10776,393 @@ function installImStyles() {
10686
10776
  return () => style.remove();
10687
10777
  }
10688
10778
 
10779
+ // plugin-src/client/update-panel.js
10780
+ var React20 = __toESM(require("react"), 1);
10781
+ var import_react_dom2 = require("react-dom");
10782
+ var UPDATE_RPC_CHANNEL = "/dsh-im";
10783
+ var ACTIVE_STATES4 = /* @__PURE__ */ new Set(["installing", "verifying"]);
10784
+ var BLOCKED_REASONS = Object.freeze({
10785
+ "source-install": "\u5F53\u524D\u662F\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\uFF0C\u53EA\u80FD\u68C0\u67E5\u7248\u672C\uFF1B\u8BF7\u624B\u52A8\u66F4\u65B0\u6E90\u7801\uFF0C\u6216\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u3002",
10786
+ "unknown-profile": "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D profile\uFF0C\u8BF7\u5728\u5BF9\u5E94\u7684 Harness \u73AF\u5883\u4E2D\u624B\u52A8\u66F4\u65B0\u3002",
10787
+ "unsupported-runtime": "\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u6309\u94AE\u5B89\u88C5\uFF0C\u8BF7\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u3002",
10788
+ "registry-conflict": "\u5F53\u524D npm \u6E90\u914D\u7F6E\u4E0E\u5B98\u65B9\u6E90\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u5148\u68C0\u67E5 registry \u914D\u7F6E\u3002",
10789
+ "incompatible-node": "\u5F53\u524D Host \u7684 Node.js \u7248\u672C\u4E0D\u6EE1\u8DB3\u65B0\u7248\u8981\u6C42\uFF0C\u8BF7\u5148\u66F4\u65B0\u8FD0\u884C\u73AF\u5883\u3002",
10790
+ "pending-restart": "\u65B0\u7248\u672C\u5DF2\u5B89\u88C5\uFF0C\u8BF7\u5728\u65B9\u4FBF\u65F6\u624B\u52A8\u91CD\u542F\u5F53\u524D Harness \u6216 Desktop\u3002",
10791
+ "recovery-required": "\u4E0A\u6B21\u5B89\u88C5\u7ED3\u679C\u65E0\u6CD5\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u6B64 profile \u7684\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u3002"
10792
+ });
10793
+ var ERROR_MESSAGES = Object.freeze({
10794
+ "check-failed": "\u65E0\u6CD5\u8BBF\u95EE npm \u6216\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u65B0\u68C0\u67E5\u3002",
10795
+ "update-failed": "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
10796
+ "invalid-release": "npm \u8FD4\u56DE\u7684\u7248\u672C\u4FE1\u606F\u65E0\u6548\uFF0C\u6682\u65F6\u65E0\u6CD5\u66F4\u65B0\u3002",
10797
+ "check-expired": "\u7248\u672C\u786E\u8BA4\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u540E\u518D\u5B89\u88C5\u3002",
10798
+ "installation-changed": "\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u3002",
10799
+ "update-busy": "\u6B64 profile \u6B63\u5728\u66F4\u65B0\uFF0C\u8BF7\u7A0D\u540E\u67E5\u770B\u72B6\u6001\u3002",
10800
+ "install-failed": "\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002",
10801
+ "verify-failed": "\u5B89\u88C5\u7ED3\u679C\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u63D2\u4EF6\u7248\u672C\u3002",
10802
+ "state-unavailable": "\u65E0\u6CD5\u5B89\u5168\u4FDD\u5B58\u66F4\u65B0\u72B6\u6001\uFF0C\u8BF7\u5148\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u7ED3\u679C\u3002",
10803
+ interrupted: "\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002",
10804
+ disposed: "\u66F4\u65B0\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u8BF7\u624B\u52A8\u91CD\u65B0\u6253\u5F00\u8BBE\u7F6E\u9875\u3002",
10805
+ "bad-request": "\u66F4\u65B0\u8BF7\u6C42\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u7248\u672C\u3002",
10806
+ "invalid-installation": "\u5F53\u524D\u63D2\u4EF6\u5B89\u88C5\u4E0D\u5B8C\u6574\u6216\u4E0E profile \u4E0D\u7B26\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u5B89\u88C5\u914D\u7F6E\u3002",
10807
+ "executor-unavailable": BLOCKED_REASONS["unsupported-runtime"],
10808
+ "registry-check-failed": "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D npm \u6E90\u914D\u7F6E\uFF0C\u6682\u65F6\u4E0D\u80FD\u5B89\u88C5\u66F4\u65B0\u3002",
10809
+ "install-interrupted": "\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002",
10810
+ "install-timeout": "\u5B89\u88C5\u8D85\u65F6\uFF0C\u8BF7\u5148\u786E\u8BA4\u5F53\u524D\u5B89\u88C5\u72B6\u6001\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5\u3002",
10811
+ "invalid-version": "npm \u8FD4\u56DE\u7684\u7248\u672C\u4FE1\u606F\u65E0\u6548\uFF0C\u6682\u65F6\u65E0\u6CD5\u66F4\u65B0\u3002"
10812
+ });
10813
+ function unwrapSnapshot(result) {
10814
+ if (result?.ok === false) {
10815
+ const error = new Error(result.error?.message || "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
10816
+ error.code = result.error?.code;
10817
+ throw error;
10818
+ }
10819
+ const value = result?.value;
10820
+ if (result?.ok !== true || typeof value?.runningVersion !== "string" || typeof value?.canInstall !== "boolean") {
10821
+ throw new Error("\u66F4\u65B0\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002");
10822
+ }
10823
+ return value;
10824
+ }
10825
+ function presentError10(error) {
10826
+ const code = error?.rpcError?.code ?? error?.code ?? "";
10827
+ const message = error?.rpcError?.message ?? error?.message ?? "";
10828
+ if (code === "update-unavailable" || /(?:not[-_ ]found|unimplemented|unknown[-_ ](?:endpoint|channel)|no[-_ ]handler)/i.test(code) || /(?:not found|unknown (?:endpoint|channel)|not registered|no .*handler|HTTP 404)/i.test(message)) {
10829
+ return "\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002";
10830
+ }
10831
+ return BLOCKED_REASONS[code] ?? ERROR_MESSAGES[code] ?? (message.slice(0, 400) || "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
10832
+ }
10833
+ function summary(snapshot, action, error) {
10834
+ if (action === "checking") return "\u6B63\u5728\u4ECE npm \u68C0\u67E5\u6700\u65B0\u7248\u672C\u2026";
10835
+ if (action === "starting" || snapshot?.job?.state === "installing") return "\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7A0D\u5019\u2026";
10836
+ if (snapshot?.job?.state === "verifying") return "\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u7ED3\u679C\u2026";
10837
+ if (snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart") {
10838
+ return "\u5DF2\u5B89\u88C5\uFF0C\u5F85\u624B\u52A8\u91CD\u542F";
10839
+ }
10840
+ if (snapshot?.job?.state === "completed") return "\u66F4\u65B0\u5DF2\u751F\u6548";
10841
+ if (snapshot?.job?.state === "failed") return "\u66F4\u65B0\u5931\u8D25";
10842
+ if (snapshot?.job?.state === "interrupted") return "\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002";
10843
+ if (error) return "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25";
10844
+ if (snapshot?.canInstall) return "\u53D1\u73B0\u65B0\u7248\u672C";
10845
+ if (snapshot?.checkedAt && snapshot.latestVersion === snapshot.runningVersion) return "\u5DF2\u662F\u6700\u65B0\u7248\u672C";
10846
+ if (snapshot?.blockedReason === "no-update") return "\u5F53\u524D\u7248\u672C\u65E0\u9700\u66F4\u65B0";
10847
+ if (snapshot?.checkedAt) return "\u5DF2\u83B7\u53D6 npm \u6700\u65B0\u7248\u672C";
10848
+ return "\u68C0\u67E5 npm \u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002";
10849
+ }
10850
+ function retainDialogFocus(event) {
10851
+ event?.currentTarget?.closest?.(".dim-updateDialog")?.focus?.({ preventScroll: true });
10852
+ }
10853
+ function UpdateDialog({ children, onClose }) {
10854
+ const dialogRef = React20.useRef(null);
10855
+ const titleId = React20.useId();
10856
+ const descriptionId = React20.useId();
10857
+ React20.useEffect(() => {
10858
+ const previous = globalThis.document?.activeElement;
10859
+ dialogRef.current?.focus?.();
10860
+ return () => {
10861
+ if (previous?.isConnected) previous.focus?.();
10862
+ };
10863
+ }, []);
10864
+ const content = h2(
10865
+ "div",
10866
+ {
10867
+ className: "dim-updateBackdrop",
10868
+ onMouseDown: (event) => {
10869
+ if (event.target === event.currentTarget) onClose();
10870
+ }
10871
+ },
10872
+ h2(
10873
+ "section",
10874
+ {
10875
+ ref: dialogRef,
10876
+ className: "dim-updateDialog",
10877
+ role: "dialog",
10878
+ "aria-modal": "true",
10879
+ "aria-labelledby": titleId,
10880
+ "aria-describedby": descriptionId,
10881
+ tabIndex: -1,
10882
+ onKeyDown: (event) => {
10883
+ if (event.key === "Escape") {
10884
+ event.preventDefault();
10885
+ event.stopPropagation();
10886
+ onClose();
10887
+ }
10888
+ if (event.key !== "Tab") return;
10889
+ const buttons = dialogRef.current?.querySelectorAll?.("button:not(:disabled)");
10890
+ if (!buttons?.length) return;
10891
+ const first = buttons[0];
10892
+ const last = buttons[buttons.length - 1];
10893
+ const active = globalThis.document?.activeElement;
10894
+ if (event.shiftKey && (active === first || active === dialogRef.current)) {
10895
+ event.preventDefault();
10896
+ last.focus();
10897
+ } else if (!event.shiftKey && (active === last || active === dialogRef.current)) {
10898
+ event.preventDefault();
10899
+ first.focus();
10900
+ }
10901
+ }
10902
+ },
10903
+ h2("h3", { id: titleId }, "DSH-IM \u66F4\u65B0"),
10904
+ h2(
10905
+ "p",
10906
+ { id: descriptionId, className: "dim-updateDescription" },
10907
+ "\u4EC5\u66F4\u65B0 DSH-IM\u3002\u5B89\u88C5\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u540E\u53F0\uFF1B\u672C\u529F\u80FD\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u6216\u4E3B\u52A8\u5237\u65B0\u9875\u9762\u3002"
10908
+ ),
10909
+ children
10910
+ )
10911
+ );
10912
+ return typeof document !== "undefined" && document.body ? (0, import_react_dom2.createPortal)(content, document.body) : content;
10913
+ }
10914
+ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
10915
+ const [snapshot, setSnapshot] = React20.useState(null);
10916
+ const [action, setAction] = React20.useState("status");
10917
+ const [error, setError] = React20.useState(null);
10918
+ const [open, setOpen] = React20.useState(false);
10919
+ const [uncertainInstall, setUncertainInstall] = React20.useState(false);
10920
+ const mounted = React20.useRef(false);
10921
+ const busy = React20.useRef(false);
10922
+ const readController = React20.useRef(null);
10923
+ const pollReadController = React20.useRef(null);
10924
+ const installRequest = React20.useRef(null);
10925
+ const onStatusRef = React20.useRef(onStatus);
10926
+ onStatusRef.current = onStatus;
10927
+ const accept = React20.useCallback((next) => {
10928
+ setSnapshot(next);
10929
+ onStatusRef.current?.(next);
10930
+ }, []);
10931
+ const acceptAuthoritative = (next) => {
10932
+ pollReadController.current?.abort();
10933
+ setUncertainInstall(false);
10934
+ accept(next);
10935
+ };
10936
+ const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
10937
+ if (typeof rpcCall !== "function") {
10938
+ const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
10939
+ unavailable.code = "update-unavailable";
10940
+ throw unavailable;
10941
+ }
10942
+ return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
10943
+ }, [rpcCall]);
10944
+ React20.useEffect(() => {
10945
+ mounted.current = true;
10946
+ busy.current = true;
10947
+ const controller = new AbortController();
10948
+ void invoke("update.status", {}, controller.signal).then((next) => {
10949
+ if (!controller.signal.aborted) accept(next);
10950
+ }).catch((cause) => {
10951
+ if (!controller.signal.aborted) setError(presentError10(cause));
10952
+ }).finally(() => {
10953
+ if (!controller.signal.aborted) {
10954
+ busy.current = false;
10955
+ setAction(null);
10956
+ }
10957
+ });
10958
+ return () => {
10959
+ mounted.current = false;
10960
+ controller.abort();
10961
+ readController.current?.abort();
10962
+ };
10963
+ }, [accept, invoke]);
10964
+ const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
10965
+ const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
10966
+ const shouldPoll = activeJob || uncertainInstall;
10967
+ React20.useEffect(() => {
10968
+ if (!shouldPoll) return void 0;
10969
+ let controller;
10970
+ const scheduler = createPollScheduler({
10971
+ setTimeoutFn: (callback, delay) => globalThis.setTimeout(callback, delay),
10972
+ clearTimeoutFn: (timer) => globalThis.clearTimeout(timer)
10973
+ });
10974
+ const poll = async () => {
10975
+ const pendingController = new AbortController();
10976
+ controller = pendingController;
10977
+ pollReadController.current = pendingController;
10978
+ let keepPolling = true;
10979
+ try {
10980
+ const next = await invoke("update.status", {}, pendingController.signal);
10981
+ if (!pendingController.signal.aborted) {
10982
+ accept(next);
10983
+ setError(null);
10984
+ setUncertainInstall(false);
10985
+ keepPolling = ACTIVE_STATES4.has(next.job?.state);
10986
+ }
10987
+ } catch (cause) {
10988
+ if (!pendingController.signal.aborted) setError(presentError10(cause));
10989
+ } finally {
10990
+ if (pollReadController.current === pendingController) pollReadController.current = null;
10991
+ }
10992
+ if (keepPolling) scheduler.schedule(poll, 1e3);
10993
+ };
10994
+ scheduler.schedule(poll, 1e3);
10995
+ return () => {
10996
+ controller?.abort();
10997
+ scheduler.dispose();
10998
+ };
10999
+ }, [accept, invoke, shouldPoll]);
11000
+ const readSnapshot = async (endpoint) => {
11001
+ const checkLatest = endpoint === "update.check";
11002
+ if (!mounted.current || busy.current || checkLatest && (activeJob || restartRequired)) return;
11003
+ busy.current = true;
11004
+ setAction(checkLatest ? "checking" : "status");
11005
+ setError(null);
11006
+ if (checkLatest) {
11007
+ installRequest.current = null;
11008
+ setSnapshot((current) => current ? { ...current, canInstall: false, checkId: null, latestVersion: null, checkedAt: null } : current);
11009
+ }
11010
+ const controller = new AbortController();
11011
+ readController.current = controller;
11012
+ try {
11013
+ const next = await invoke(endpoint, {}, controller.signal);
11014
+ if (!controller.signal.aborted && mounted.current) {
11015
+ if (checkLatest) accept(next);
11016
+ else acceptAuthoritative(next);
11017
+ }
11018
+ } catch (cause) {
11019
+ if (!controller.signal.aborted && mounted.current) setError(presentError10(cause));
11020
+ } finally {
11021
+ if (!controller.signal.aborted && mounted.current) {
11022
+ busy.current = false;
11023
+ setAction(null);
11024
+ }
11025
+ }
11026
+ };
11027
+ const check = () => readSnapshot("update.check");
11028
+ const refreshStatus = () => readSnapshot("update.status");
11029
+ const install = async () => {
11030
+ if (busy.current || !snapshot?.canInstall || !snapshot.checkId) return;
11031
+ busy.current = true;
11032
+ setAction("starting");
11033
+ setError(null);
11034
+ if (installRequest.current?.checkId !== snapshot.checkId) {
11035
+ installRequest.current = {
11036
+ checkId: snapshot.checkId,
11037
+ requestId: globalThis.crypto?.randomUUID?.() ?? `update-${Date.now()}-${Math.random().toString(36).slice(2)}`
11038
+ };
11039
+ }
11040
+ try {
11041
+ const next = await invoke("update.install", installRequest.current);
11042
+ if (mounted.current) acceptAuthoritative(next);
11043
+ } catch (cause) {
11044
+ if (mounted.current) {
11045
+ setError(presentError10(cause));
11046
+ setUncertainInstall(true);
11047
+ }
11048
+ } finally {
11049
+ if (mounted.current) {
11050
+ busy.current = false;
11051
+ setAction(null);
11052
+ }
11053
+ }
11054
+ };
11055
+ const busyAction = action !== null;
11056
+ const blocked = BLOCKED_REASONS[snapshot?.blockedReason] ?? ERROR_MESSAGES[snapshot?.blockedReason];
11057
+ const canConfirm = snapshot?.canInstall && snapshot.checkId && !activeJob && !restartRequired;
11058
+ const versionsDiffer = snapshot && clientVersion && snapshot.runningVersion !== clientVersion;
11059
+ const failedJob = ["failed", "interrupted"].includes(snapshot?.job?.state);
11060
+ const jobMessage = snapshot?.job?.message;
11061
+ const targetVersion = snapshot?.job?.targetVersion;
11062
+ const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
11063
+ return h2(
11064
+ React20.Fragment,
11065
+ null,
11066
+ h2("button", {
11067
+ type: "button",
11068
+ className: "dim-updateButton dim-updateTrigger",
11069
+ disabled: busyAction,
11070
+ "aria-haspopup": "dialog",
11071
+ onClick: () => {
11072
+ setOpen(true);
11073
+ if (restartRequired) void refreshStatus();
11074
+ else if (!snapshot?.canInstall && !snapshot?.job) void check();
11075
+ }
11076
+ }, buttonLabel, buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : null),
11077
+ open ? h2(
11078
+ UpdateDialog,
11079
+ { onClose: () => setOpen(false) },
11080
+ h2(
11081
+ "div",
11082
+ { className: "dim-updateBody" },
11083
+ h2(
11084
+ "dl",
11085
+ { className: "dim-updateVersions" },
11086
+ h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
11087
+ h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
11088
+ snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
11089
+ React20.Fragment,
11090
+ null,
11091
+ h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
11092
+ h2("dd", null, `v${snapshot.installedVersion}`)
11093
+ ) : null,
11094
+ h2("dt", null, "npm \u6700\u65B0\u7248\u672C"),
11095
+ h2("dd", null, snapshot?.latestVersion ? `v${snapshot.latestVersion}` : "\u5C1A\u672A\u68C0\u67E5"),
11096
+ targetVersion ? h2(
11097
+ React20.Fragment,
11098
+ null,
11099
+ h2("dt", null, "\u76EE\u6807\u7248\u672C"),
11100
+ h2("dd", null, `v${targetVersion}`)
11101
+ ) : null,
11102
+ h2("dt", null, "\u76EE\u6807 profile"),
11103
+ h2("dd", null, snapshot?.profileName ?? "\u65E0\u6CD5\u786E\u8BA4"),
11104
+ h2("dt", null, "\u66F4\u65B0\u6765\u6E90"),
11105
+ h2("dd", null, "registry.npmjs.org"),
11106
+ versionsDiffer ? h2(
11107
+ React20.Fragment,
11108
+ null,
11109
+ h2("dt", null, "\u9875\u9762\u7248\u672C"),
11110
+ h2("dd", null, `v${clientVersion}`)
11111
+ ) : null
11112
+ ),
11113
+ h2(
11114
+ "div",
11115
+ {
11116
+ className: `dim-updateStatus${error || failedJob ? " dim-updateStatusError" : ""}`,
11117
+ role: "status",
11118
+ "aria-live": "polite",
11119
+ "aria-atomic": "true"
11120
+ },
11121
+ h2("strong", null, summary(snapshot, action, error)),
11122
+ activeJob || action === "starting" ? h2("p", null, "\u5173\u95ED\u7A97\u53E3\u4E0D\u4F1A\u53D6\u6D88\u5B89\u88C5\u3002\u8BF7\u52FF\u540C\u65F6\u5728\u5176\u4ED6\u7A97\u53E3\u7BA1\u7406\u6B64 profile \u7684\u63D2\u4EF6\u3002") : null,
11123
+ restartRequired ? h2("p", null, BLOCKED_REASONS["pending-restart"]) : null,
11124
+ failedJob && jobMessage ? h2(
11125
+ "p",
11126
+ null,
11127
+ BLOCKED_REASONS[jobMessage] ?? ERROR_MESSAGES[jobMessage] ?? jobMessage
11128
+ ) : null
11129
+ ),
11130
+ error ? h2("p", { className: "dim-updateError", role: "alert" }, error) : null,
11131
+ blocked && !restartRequired ? h2("p", { className: "dim-updateHint" }, blocked) : null,
11132
+ versionsDiffer && !restartRequired ? h2("p", { className: "dim-updateHint" }, "\u9875\u9762\u7248\u672C\u4E0E\u8FD0\u884C\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u624B\u52A8\u91CD\u542F Harness \u6216 Desktop\u3002") : null,
11133
+ canConfirm ? h2(
11134
+ "p",
11135
+ { className: "dim-updateHint" },
11136
+ "\u8BF7\u5728\u673A\u5668\u4EBA\u7A7A\u95F2\u65F6\u5B89\u88C5\uFF1B\u5B89\u88C5\u4F1A\u4FEE\u6539\u5F53\u524D profile \u7684\u4F9D\u8D56\uFF0C\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u3002"
11137
+ ) : null
11138
+ ),
11139
+ h2(
11140
+ "footer",
11141
+ { className: "dim-updateFooter" },
11142
+ h2("button", { type: "button", className: "dim-updateButton", onClick: () => setOpen(false) }, "\u5173\u95ED"),
11143
+ restartRequired || !activeJob ? h2("button", {
11144
+ type: "button",
11145
+ className: "dim-updateButton",
11146
+ disabled: busyAction,
11147
+ onClick: (event) => {
11148
+ retainDialogFocus(event);
11149
+ void (restartRequired ? refreshStatus() : check());
11150
+ }
11151
+ }, restartRequired ? "\u5237\u65B0\u72B6\u6001" : "\u91CD\u65B0\u68C0\u67E5") : null,
11152
+ canConfirm ? h2("button", {
11153
+ type: "button",
11154
+ className: "dim-updateButton dim-updatePrimary",
11155
+ disabled: busyAction,
11156
+ onClick: (event) => {
11157
+ retainDialogFocus(event);
11158
+ void install();
11159
+ }
11160
+ }, "\u5B89\u88C5\u66F4\u65B0") : null
11161
+ )
11162
+ ) : null
11163
+ );
11164
+ }
11165
+
10689
11166
  // plugin-src/client/index.js
10690
11167
  var name = "im-settings";
10691
11168
  var inject = ["slots", "connection", "locale", "workspaces"];
@@ -10808,18 +11285,23 @@ function IMSettingsTab({
10808
11285
  weixinRpcCall,
10809
11286
  whatsappRpcCall,
10810
11287
  officeRpcCall,
11288
+ updateRpcCall,
10811
11289
  workspaceDirectoryPicker,
10812
11290
  browserLocation = globalThis.location,
10813
11291
  navigateToRecoveryUrl = replacePageLocation
10814
11292
  }) {
10815
- const [selected, setSelected] = React20.useState("weixin");
10816
- const [loopbackRecovery, setLoopbackRecovery] = React20.useState(null);
10817
- const githubTooltipId = React20.useId();
11293
+ const [selected, setSelected] = React21.useState("weixin");
11294
+ const [loopbackRecovery, setLoopbackRecovery] = React21.useState(null);
11295
+ const [runningVersion, setRunningVersion] = React21.useState(IM_PLUGIN_VERSION);
11296
+ const githubTooltipId = React21.useId();
10818
11297
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
10819
- const reportLoopbackRecovery = React20.useCallback((recovery) => {
11298
+ const reportLoopbackRecovery = React21.useCallback((recovery) => {
10820
11299
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
10821
11300
  }, []);
10822
- const rpcCalls = React20.useMemo(() => createLoopbackAwareRpcCalls({
11301
+ const reportUpdateStatus = React21.useCallback((snapshot) => {
11302
+ setRunningVersion(snapshot.runningVersion);
11303
+ }, []);
11304
+ const rpcCalls = React21.useMemo(() => createLoopbackAwareRpcCalls({
10823
11305
  dingtalkRpcCall,
10824
11306
  discordRpcCall,
10825
11307
  feishuRpcCall,
@@ -10829,7 +11311,8 @@ function IMSettingsTab({
10829
11311
  wecomRpcCall,
10830
11312
  weixinRpcCall,
10831
11313
  whatsappRpcCall,
10832
- officeRpcCall
11314
+ officeRpcCall,
11315
+ updateRpcCall
10833
11316
  }, {
10834
11317
  location: browserLocation,
10835
11318
  onRecovery: reportLoopbackRecovery
@@ -10843,6 +11326,7 @@ function IMSettingsTab({
10843
11326
  reportLoopbackRecovery,
10844
11327
  slackRpcCall,
10845
11328
  telegramRpcCall,
11329
+ updateRpcCall,
10846
11330
  wecomRpcCall,
10847
11331
  weixinRpcCall,
10848
11332
  whatsappRpcCall
@@ -10863,31 +11347,40 @@ function IMSettingsTab({
10863
11347
  "div",
10864
11348
  { className: "dim-brandHeading" },
10865
11349
  h2("strong", { className: "dim-brandName" }, "DSH-IM"),
10866
- h2("span", { className: "dim-brandVersion" }, `v${IM_PLUGIN_VERSION}`)
11350
+ h2("span", { className: "dim-brandVersion" }, `v${runningVersion}`)
10867
11351
  ),
10868
11352
  h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA")
10869
11353
  ),
10870
11354
  h2(
10871
- "span",
10872
- { className: "dim-githubAction" },
11355
+ "div",
11356
+ { className: "dim-titleActions" },
11357
+ h2(UpdatePanel, {
11358
+ rpcCall: rpcCalls.updateRpcCall,
11359
+ clientVersion: IM_PLUGIN_VERSION,
11360
+ onStatus: reportUpdateStatus
11361
+ }),
10873
11362
  h2(
10874
- "a",
10875
- {
10876
- className: "dim-githubLink",
10877
- href: "https://github.com/xmanrui/dsh-im",
10878
- target: "_blank",
10879
- rel: "noopener noreferrer",
10880
- "aria-label": "dsh-im GitHub",
10881
- "aria-describedby": githubTooltipId
10882
- },
10883
- h2("span", null, "GitHub"),
10884
- h2("span", { className: "dim-githubArrow", "aria-hidden": "true" }, "\u2197")
10885
- ),
10886
- h2("span", {
10887
- id: githubTooltipId,
10888
- className: "dim-githubTooltip",
10889
- role: "tooltip"
10890
- }, "\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub")
11363
+ "span",
11364
+ { className: "dim-githubAction" },
11365
+ h2(
11366
+ "a",
11367
+ {
11368
+ className: "dim-githubLink",
11369
+ href: "https://github.com/xmanrui/dsh-im",
11370
+ target: "_blank",
11371
+ rel: "noopener noreferrer",
11372
+ "aria-label": "dsh-im GitHub",
11373
+ "aria-describedby": githubTooltipId
11374
+ },
11375
+ h2("span", null, "GitHub"),
11376
+ h2("span", { className: "dim-githubArrow", "aria-hidden": "true" }, "\u2197")
11377
+ ),
11378
+ h2("span", {
11379
+ id: githubTooltipId,
11380
+ className: "dim-githubTooltip",
11381
+ role: "tooltip"
11382
+ }, "\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub")
11383
+ )
10891
11384
  )
10892
11385
  ),
10893
11386
  h2(
@@ -10970,6 +11463,7 @@ function apply(ctx) {
10970
11463
  const whatsappRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
10971
11464
  const slackRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(SLACK_RPC_CHANNEL, endpoint, payload, signal);
10972
11465
  const officeRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(OFFICE_RPC_CHANNEL, endpoint, payload, signal);
11466
+ const updateRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(UPDATE_RPC_CHANNEL, endpoint, payload, signal);
10973
11467
  const workspaceDirectoryPicker = Object.freeze({
10974
11468
  listDirectory: (path, signal) => ctx.workspaces.listDirectory(path, signal),
10975
11469
  pickDirectory: () => ctx.workspaces.pickDirectory()
@@ -10991,6 +11485,7 @@ function apply(ctx) {
10991
11485
  weixinRpcCall,
10992
11486
  whatsappRpcCall,
10993
11487
  officeRpcCall,
11488
+ updateRpcCall,
10994
11489
  workspaceDirectoryPicker
10995
11490
  })
10996
11491
  }, IMSettingsTab));