@senguoyun/dsh-arkme 0.1.78 → 0.1.80

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 (143) hide show
  1. package/docs/reaction-desktop-review.md +33 -0
  2. package/docs/reaction-pre-merge-review.md +78 -0
  3. package/lib/client.js +15141 -10588
  4. package/lib/client.js.map +1 -1
  5. package/lib/harness-model-client.js +19 -3
  6. package/lib/harness-native-selection-client.js +19 -3
  7. package/lib/harness-sidebar-client.js +165 -16
  8. package/lib/index.js +112 -1
  9. package/lib/persistent-extension.js +1 -1
  10. package/lib/{persistent-runtime-aiHgSAmj.js → persistent-runtime-CGclHTN1.js} +1196 -272
  11. package/lib/sdk.js +8 -0
  12. package/lib/types/arkme-service.d.ts +10 -0
  13. package/lib/types/arkme-service.d.ts.map +1 -1
  14. package/lib/types/client/ArkmeAccountCancellation.d.ts +8 -0
  15. package/lib/types/client/ArkmeAccountCancellation.d.ts.map +1 -0
  16. package/lib/types/client/ArkmeDataManagementSettings.d.ts.map +1 -1
  17. package/lib/types/client/ArkmeDayTimeline.d.ts +2 -0
  18. package/lib/types/client/ArkmeDayTimeline.d.ts.map +1 -1
  19. package/lib/types/client/ArkmeGroupChatControls.d.ts.map +1 -1
  20. package/lib/types/client/ArkmeLogin.d.ts +3 -0
  21. package/lib/types/client/ArkmeLogin.d.ts.map +1 -1
  22. package/lib/types/client/ArkmePersonalDayCalendar.d.ts.map +1 -1
  23. package/lib/types/client/ArkmeReactionActorCard.d.ts +7 -0
  24. package/lib/types/client/ArkmeReactionActorCard.d.ts.map +1 -0
  25. package/lib/types/client/ArkmeReactionHistorySettings.d.ts +7 -0
  26. package/lib/types/client/ArkmeReactionHistorySettings.d.ts.map +1 -0
  27. package/lib/types/client/ArkmeReactionNotification.d.ts +11 -0
  28. package/lib/types/client/ArkmeReactionNotification.d.ts.map +1 -0
  29. package/lib/types/client/ArkmeReactionPhrases.d.ts +8 -0
  30. package/lib/types/client/ArkmeReactionPhrases.d.ts.map +1 -0
  31. package/lib/types/client/ArkmeReactionPreview.d.ts +42 -0
  32. package/lib/types/client/ArkmeReactionPreview.d.ts.map +1 -0
  33. package/lib/types/client/ArkmeRecordingSurface.d.ts +2 -1
  34. package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
  35. package/lib/types/client/ArkmeRichComposerInput.d.ts.map +1 -1
  36. package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
  37. package/lib/types/client/ArkmeSettingsSurface.d.ts +5 -0
  38. package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
  39. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  40. package/lib/types/client/ArkmeVirtualWorkspace.d.ts +2 -1
  41. package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
  42. package/lib/types/client/ReactionLabel.d.ts +8 -0
  43. package/lib/types/client/ReactionLabel.d.ts.map +1 -0
  44. package/lib/types/client/ReactionPhraseDialog.d.ts +14 -0
  45. package/lib/types/client/ReactionPhraseDialog.d.ts.map +1 -0
  46. package/lib/types/client/arkme-auth-flow.d.ts.map +1 -1
  47. package/lib/types/client/arkme-login-locales.d.ts +6 -0
  48. package/lib/types/client/arkme-login-locales.d.ts.map +1 -1
  49. package/lib/types/client/auth-store.d.ts.map +1 -1
  50. package/lib/types/client/calendar-activity-model.d.ts +1 -1
  51. package/lib/types/client/calendar-activity-model.d.ts.map +1 -1
  52. package/lib/types/client/composer-draft-store.d.ts +6 -1
  53. package/lib/types/client/composer-draft-store.d.ts.map +1 -1
  54. package/lib/types/client/conversation-window-sync.d.ts.map +1 -1
  55. package/lib/types/client/harness-account-sessions.d.ts +6 -0
  56. package/lib/types/client/harness-account-sessions.d.ts.map +1 -1
  57. package/lib/types/client/harness-session-dropdown.d.ts.map +1 -1
  58. package/lib/types/client/harness-session-origin.d.ts +2 -1
  59. package/lib/types/client/harness-session-origin.d.ts.map +1 -1
  60. package/lib/types/client/harness-session-summary.d.ts +11 -2
  61. package/lib/types/client/harness-session-summary.d.ts.map +1 -1
  62. package/lib/types/client/locales/actions-en.d.ts.map +1 -1
  63. package/lib/types/client/outgoing-call-runtime.d.ts.map +1 -1
  64. package/lib/types/client/reaction-expression.d.ts +5 -0
  65. package/lib/types/client/reaction-expression.d.ts.map +1 -0
  66. package/lib/types/client/reaction-label-content.d.ts +20 -0
  67. package/lib/types/client/reaction-label-content.d.ts.map +1 -0
  68. package/lib/types/client/reaction-library.d.ts +26 -0
  69. package/lib/types/client/reaction-library.d.ts.map +1 -0
  70. package/lib/types/client/reaction-locate-layout.d.ts +5 -0
  71. package/lib/types/client/reaction-locate-layout.d.ts.map +1 -0
  72. package/lib/types/client/reaction-notifications.d.ts +49 -0
  73. package/lib/types/client/reaction-notifications.d.ts.map +1 -0
  74. package/lib/types/client/reaction-phrase-palette.d.ts +99 -0
  75. package/lib/types/client/reaction-phrase-palette.d.ts.map +1 -0
  76. package/lib/types/client/reaction-phrases.d.ts +7 -0
  77. package/lib/types/client/reaction-phrases.d.ts.map +1 -0
  78. package/lib/types/client/reaction-preview-store.d.ts +70 -0
  79. package/lib/types/client/reaction-preview-store.d.ts.map +1 -0
  80. package/lib/types/client/reaction-visible-target.d.ts +3 -0
  81. package/lib/types/client/reaction-visible-target.d.ts.map +1 -0
  82. package/lib/types/client/record-input-capture.d.ts +2 -0
  83. package/lib/types/client/record-input-capture.d.ts.map +1 -1
  84. package/lib/types/client/recordings/RecordingSearchRow.d.ts +5 -0
  85. package/lib/types/client/recordings/RecordingSearchRow.d.ts.map +1 -0
  86. package/lib/types/client/recordings/recording-search-target.d.ts +4 -0
  87. package/lib/types/client/recordings/recording-search-target.d.ts.map +1 -0
  88. package/lib/types/client/redesign/styles.d.ts.map +1 -1
  89. package/lib/types/client/ui-controller.d.ts +5 -6
  90. package/lib/types/client/ui-controller.d.ts.map +1 -1
  91. package/lib/types/client/use-phrase-layout-motion.d.ts +2 -0
  92. package/lib/types/client/use-phrase-layout-motion.d.ts.map +1 -0
  93. package/lib/types/client/use-reaction-history.d.ts +10 -0
  94. package/lib/types/client/use-reaction-history.d.ts.map +1 -0
  95. package/lib/types/client/use-reaction-phrase-drag.d.ts +19 -0
  96. package/lib/types/client/use-reaction-phrase-drag.d.ts.map +1 -0
  97. package/lib/types/host-api.d.ts.map +1 -1
  98. package/lib/types/index.d.ts +1 -1
  99. package/lib/types/index.d.ts.map +1 -1
  100. package/lib/types/local-database.d.ts +2 -0
  101. package/lib/types/local-database.d.ts.map +1 -1
  102. package/lib/types/reaction-contract.d.ts +217 -0
  103. package/lib/types/reaction-contract.d.ts.map +1 -0
  104. package/lib/types/recording-presentation.d.ts +1 -0
  105. package/lib/types/recording-presentation.d.ts.map +1 -1
  106. package/lib/types/recording-search-result.d.ts +3 -0
  107. package/lib/types/recording-search-result.d.ts.map +1 -0
  108. package/lib/types/recording-search-version.d.ts +17 -0
  109. package/lib/types/recording-search-version.d.ts.map +1 -0
  110. package/lib/types/sdk/index.d.ts +2 -0
  111. package/lib/types/sdk/index.d.ts.map +1 -1
  112. package/lib/types/services/auth-service.d.ts +20 -1
  113. package/lib/types/services/auth-service.d.ts.map +1 -1
  114. package/lib/types/services/chat-realtime-service.d.ts.map +1 -1
  115. package/lib/types/services/chat-service.d.ts +6 -0
  116. package/lib/types/services/chat-service.d.ts.map +1 -1
  117. package/lib/types/services/profile-service.d.ts +1 -1
  118. package/lib/types/services/profile-service.d.ts.map +1 -1
  119. package/lib/types/services/reaction-service.d.ts +28 -0
  120. package/lib/types/services/reaction-service.d.ts.map +1 -0
  121. package/lib/types/services/recording-import-gateway.d.ts +3 -1
  122. package/lib/types/services/recording-import-gateway.d.ts.map +1 -1
  123. package/lib/types/services/recording-import-upload-retry.d.ts +6 -0
  124. package/lib/types/services/recording-import-upload-retry.d.ts.map +1 -0
  125. package/lib/types/services/recording-service.d.ts.map +1 -1
  126. package/lib/types/services/search-service.d.ts +3 -1
  127. package/lib/types/services/search-service.d.ts.map +1 -1
  128. package/lib/types/services/service.d.ts +3 -0
  129. package/lib/types/services/service.d.ts.map +1 -1
  130. package/lib/types/services/world-service.d.ts +3 -0
  131. package/lib/types/services/world-service.d.ts.map +1 -1
  132. package/lib/types/state-store.d.ts +7 -0
  133. package/lib/types/state-store.d.ts.map +1 -1
  134. package/lib/types/tools/business/conversation/index.d.ts.map +1 -1
  135. package/lib/types/tools/business/conversation/reactions.d.ts +3 -0
  136. package/lib/types/tools/business/conversation/reactions.d.ts.map +1 -0
  137. package/lib/types/tools/business/index.d.ts.map +1 -1
  138. package/lib/types/tools/ports/conversations.d.ts +1 -0
  139. package/lib/types/tools/ports/conversations.d.ts.map +1 -1
  140. package/lib/types/tools/registry/registrar.d.ts.map +1 -1
  141. package/lib/types/types.d.ts +46 -2
  142. package/lib/types/types.d.ts.map +1 -1
  143. package/package.json +5 -5
@@ -1756,7 +1756,7 @@ Arkme 用户 {v0}|Arkme user {v0}
1756
1756
  return current.revision + 1;
1757
1757
  }
1758
1758
  function sameAuth(left, right) {
1759
- return left?.status === right?.status && left?.environment === right?.environment && left?.userId === right?.userId && left?.attemptId === right?.attemptId && left?.expiresAtMillis === right?.expiresAtMillis;
1759
+ return left?.status === right?.status && left?.environment === right?.environment && left?.userId === right?.userId && left?.attemptId === right?.attemptId && left?.expiresAtMillis === right?.expiresAtMillis && left?.restDaysCancel === right?.restDaysCancel && left?.cancellationNotice === right?.cancellationNotice;
1760
1760
  }
1761
1761
  var ArkmeAuthStore = class {
1762
1762
  state = {
@@ -1779,6 +1779,10 @@ Arkme 用户 {v0}|Arkme user {v0}
1779
1779
  };
1780
1780
  setAuth(auth) {
1781
1781
  if (sameAuth(this.state.auth, auth) && this.state.checked && !this.state.busy && this.state.error === "") return;
1782
+ if (!["authenticated", "binding-required"].includes(auth.status) && auth.cancellationNotice === void 0 && this.state.auth?.cancellationNotice !== void 0) auth = {
1783
+ ...auth,
1784
+ cancellationNotice: this.state.auth.cancellationNotice
1785
+ };
1782
1786
  this.authGeneration += 1;
1783
1787
  this.publish({
1784
1788
  ...this.state,
@@ -1809,8 +1813,12 @@ Arkme 用户 {v0}|Arkme user {v0}
1809
1813
  });
1810
1814
  const pending = Promise.all([callArkme("auth.status"), callArkme("auth.config")]).then(([auth, config]) => {
1811
1815
  const currentAuth = this.state.auth;
1812
- const preservePendingAttempt = currentAuth?.status === "pending" && (auth.status === "logged-out" || auth.status === "expired");
1813
- const effectiveAuth = this.authGeneration === authGeneration && !preservePendingAttempt ? auth : currentAuth ?? auth;
1816
+ const preservePendingAttempt = (currentAuth?.status === "pending" || currentAuth?.status === "cancellation-pending") && (auth.status === "logged-out" || auth.status === "expired");
1817
+ let effectiveAuth = this.authGeneration === authGeneration && !preservePendingAttempt ? auth : currentAuth ?? auth;
1818
+ if (!["authenticated", "binding-required"].includes(effectiveAuth.status) && effectiveAuth.cancellationNotice === void 0 && currentAuth?.cancellationNotice !== void 0) effectiveAuth = {
1819
+ ...effectiveAuth,
1820
+ cancellationNotice: currentAuth.cancellationNotice
1821
+ };
1814
1822
  this.publish({
1815
1823
  ...this.state,
1816
1824
  auth: effectiveAuth,
@@ -3016,6 +3024,14 @@ Arkme 用户 {v0}|Arkme user {v0}
3016
3024
  async favoriteStickers(signal) {
3017
3025
  return await this.call("favorite-stickers.list", void 0, signal);
3018
3026
  }
3027
+ async reactions(input, signal) {
3028
+ if ((await this.capabilities(signal)).features.reactionsV1 !== true) throw new ArkmeClientError({
3029
+ code: "CAPABILITY_UNSUPPORTED",
3030
+ message: "当前 Arkme Provider 不支持表态,请升级",
3031
+ retryable: false
3032
+ });
3033
+ return await this.call("reactions", input, signal);
3034
+ }
3019
3035
  async addFavoriteSticker(item, signal) {
3020
3036
  if (item.fileAssetUid.trim() === "") throw new TypeError("Arkme favorite sticker asset must not be empty");
3021
3037
  return await this.call("favorite-stickers.add", { item }, signal);
@@ -36,7 +36,7 @@ window.__ModuleLoader__.load({
36
36
  return current.revision + 1;
37
37
  }
38
38
  function sameAuth(left, right) {
39
- return left?.status === right?.status && left?.environment === right?.environment && left?.userId === right?.userId && left?.attemptId === right?.attemptId && left?.expiresAtMillis === right?.expiresAtMillis;
39
+ return left?.status === right?.status && left?.environment === right?.environment && left?.userId === right?.userId && left?.attemptId === right?.attemptId && left?.expiresAtMillis === right?.expiresAtMillis && left?.restDaysCancel === right?.restDaysCancel && left?.cancellationNotice === right?.cancellationNotice;
40
40
  }
41
41
  var ArkmeAuthStore = class {
42
42
  state = {
@@ -59,6 +59,10 @@ window.__ModuleLoader__.load({
59
59
  };
60
60
  setAuth(auth) {
61
61
  if (sameAuth(this.state.auth, auth) && this.state.checked && !this.state.busy && this.state.error === "") return;
62
+ if (!["authenticated", "binding-required"].includes(auth.status) && auth.cancellationNotice === void 0 && this.state.auth?.cancellationNotice !== void 0) auth = {
63
+ ...auth,
64
+ cancellationNotice: this.state.auth.cancellationNotice
65
+ };
62
66
  this.authGeneration += 1;
63
67
  this.publish({
64
68
  ...this.state,
@@ -89,8 +93,12 @@ window.__ModuleLoader__.load({
89
93
  });
90
94
  const pending = Promise.all([callArkme("auth.status"), callArkme("auth.config")]).then(([auth, config]) => {
91
95
  const currentAuth = this.state.auth;
92
- const preservePendingAttempt = currentAuth?.status === "pending" && (auth.status === "logged-out" || auth.status === "expired");
93
- const effectiveAuth = this.authGeneration === authGeneration && !preservePendingAttempt ? auth : currentAuth ?? auth;
96
+ const preservePendingAttempt = (currentAuth?.status === "pending" || currentAuth?.status === "cancellation-pending") && (auth.status === "logged-out" || auth.status === "expired");
97
+ let effectiveAuth = this.authGeneration === authGeneration && !preservePendingAttempt ? auth : currentAuth ?? auth;
98
+ if (!["authenticated", "binding-required"].includes(effectiveAuth.status) && effectiveAuth.cancellationNotice === void 0 && currentAuth?.cancellationNotice !== void 0) effectiveAuth = {
99
+ ...effectiveAuth,
100
+ cancellationNotice: currentAuth.cancellationNotice
101
+ };
94
102
  this.publish({
95
103
  ...this.state,
96
104
  auth: effectiveAuth,
@@ -1310,6 +1318,14 @@ window.__ModuleLoader__.load({
1310
1318
  async favoriteStickers(signal) {
1311
1319
  return await this.call("favorite-stickers.list", void 0, signal);
1312
1320
  }
1321
+ async reactions(input, signal) {
1322
+ if ((await this.capabilities(signal)).features.reactionsV1 !== true) throw new ArkmeClientError({
1323
+ code: "CAPABILITY_UNSUPPORTED",
1324
+ message: "当前 Arkme Provider 不支持表态,请升级",
1325
+ retryable: false
1326
+ });
1327
+ return await this.call("reactions", input, signal);
1328
+ }
1313
1329
  async addFavoriteSticker(item, signal) {
1314
1330
  if (item.fileAssetUid.trim() === "") throw new TypeError("Arkme favorite sticker asset must not be empty");
1315
1331
  return await this.call("favorite-stickers.add", { item }, signal);
@@ -4,13 +4,39 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
7
29
  let react = require("react");
30
+ react = __toESM(react, 1);
8
31
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
32
  let react_jsx_runtime = require("react/jsx-runtime");
10
33
  //#region src/client/harness-session-origin.ts
11
- function sessionOrigin(row) {
12
- if (row.local) return [];
13
- return [`实例:${row.runtimeName}`, ...row.sameDesktop ? [] : [`电脑:${row.desktopName}`]];
34
+ function isRemoteComputer(row, localDesktopName) {
35
+ const localName = localDesktopName?.trim().toLowerCase(), name = row.desktopName.trim().toLowerCase();
36
+ return !row.local && !row.sameDesktop && !!localName && !!name && name !== localName;
37
+ }
38
+ function sessionOrigin(row, localDesktopName) {
39
+ return isRemoteComputer(row, localDesktopName) ? [`电脑:${row.desktopName.trim()}`] : [];
14
40
  }
15
41
  /** Current-version presentation adapter. Native card, title, time, status and copy remain owned by DSH. */
16
42
  function installSessionOriginHover(doc, resolve) {
@@ -1234,6 +1260,14 @@ window.__ModuleLoader__.load({
1234
1260
  async favoriteStickers(signal) {
1235
1261
  return await this.call("favorite-stickers.list", void 0, signal);
1236
1262
  }
1263
+ async reactions(input, signal) {
1264
+ if ((await this.capabilities(signal)).features.reactionsV1 !== true) throw new ArkmeClientError({
1265
+ code: "CAPABILITY_UNSUPPORTED",
1266
+ message: "当前 Arkme Provider 不支持表态,请升级",
1267
+ retryable: false
1268
+ });
1269
+ return await this.call("reactions", input, signal);
1270
+ }
1237
1271
  async addFavoriteSticker(item, signal) {
1238
1272
  if (item.fileAssetUid.trim() === "") throw new TypeError("Arkme favorite sticker asset must not be empty");
1239
1273
  return await this.call("favorite-stickers.add", { item }, signal);
@@ -1755,10 +1789,11 @@ window.__ModuleLoader__.load({
1755
1789
  }
1756
1790
  function createCatalog(surface, remove) {
1757
1791
  const owner = surface.ownerDocument;
1758
- let rows = [], localRuntimeRef, users = 0;
1792
+ let rows = [], localRuntimeRef, localDesktopName, users = 0;
1759
1793
  let snapshot = {
1760
1794
  rows,
1761
- localRuntimeRef
1795
+ localRuntimeRef,
1796
+ localDesktopName
1762
1797
  }, active = true, busy = false;
1763
1798
  const listeners = /* @__PURE__ */ new Set();
1764
1799
  let controller = new AbortController();
@@ -1766,7 +1801,8 @@ window.__ModuleLoader__.load({
1766
1801
  const publish = () => {
1767
1802
  snapshot = {
1768
1803
  rows,
1769
- localRuntimeRef
1804
+ localRuntimeRef,
1805
+ localDesktopName
1770
1806
  };
1771
1807
  listeners.forEach((listener) => listener());
1772
1808
  };
@@ -1784,6 +1820,7 @@ window.__ModuleLoader__.load({
1784
1820
  }, signal);
1785
1821
  if (page.contractVersion !== 1 || !Array.isArray(page.items)) throw new Error("会话目录不可用");
1786
1822
  localRuntimeRef = page.localRuntimeRef;
1823
+ localDesktopName = page.localRuntime?.desktopName;
1787
1824
  next.push(...page.items.map((row) => {
1788
1825
  const previous = rows.find((old) => accountSessionKey(old) === accountSessionKey(row));
1789
1826
  return page.warning && previous && row.workspaceName === "工作区信息暂不可用" ? {
@@ -1804,8 +1841,8 @@ window.__ModuleLoader__.load({
1804
1841
  if (merged !== rows || snapshot.localRuntimeRef !== localRuntimeRef) {
1805
1842
  rows = merged;
1806
1843
  window.__ARKME_NATIVE_DIRECTORY__?.publish(rows);
1807
- publish();
1808
1844
  }
1845
+ if (snapshot.rows !== rows || snapshot.localRuntimeRef !== localRuntimeRef || snapshot.localDesktopName !== localDesktopName) publish();
1809
1846
  } catch {} finally {
1810
1847
  if (signal === controller.signal) busy = false;
1811
1848
  }
@@ -1868,9 +1905,18 @@ window.__ModuleLoader__.load({
1868
1905
  }
1869
1906
  return entry;
1870
1907
  }
1871
- /** All native sources share one account-scoped catalog. */
1872
- function AccountSessionBrowser({ Native, surface, ...props }) {
1873
- const account = (0, react.useSyncExternalStore)((listener) => {
1908
+ /** Header and browser consume the same account-scoped discovery owner. */
1909
+ function useAccountSessionCatalog(surface) {
1910
+ const catalog = (0, react.useMemo)(() => accountSessionCatalog(surface), [surface, useSurfaceAccount(surface)]);
1911
+ const snapshot = (0, react.useSyncExternalStore)(catalog.subscribe, catalog.getSnapshot);
1912
+ (0, react.useEffect)(() => {
1913
+ catalog.start();
1914
+ return () => catalog.dispose();
1915
+ }, [catalog]);
1916
+ return snapshot;
1917
+ }
1918
+ function useSurfaceAccount(surface) {
1919
+ return (0, react.useSyncExternalStore)((listener) => {
1874
1920
  const observer = new MutationObserver(listener);
1875
1921
  observer.observe(surface, {
1876
1922
  attributes: true,
@@ -1878,6 +1924,10 @@ window.__ModuleLoader__.load({
1878
1924
  });
1879
1925
  return () => observer.disconnect();
1880
1926
  }, () => `${surface.getAttribute("data-arkme-account-id")}:${surface.getAttribute("data-arkme-account-scope")}`);
1927
+ }
1928
+ /** All native sources share one account-scoped catalog. */
1929
+ function AccountSessionBrowser({ Native, surface, ...props }) {
1930
+ const account = useSurfaceAccount(surface);
1881
1931
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountBrowser, {
1882
1932
  Native,
1883
1933
  surface,
@@ -1932,7 +1982,7 @@ window.__ModuleLoader__.load({
1932
1982
  const row = snapshot.rows.find((row) => (row.runtimeRef === snapshot.localRuntimeRef ? row.sessionRef : accountSessionKey(row)) === id);
1933
1983
  return row ? {
1934
1984
  title: native.displayTitle,
1935
- lines: sessionOrigin(row)
1985
+ lines: sessionOrigin(row, snapshot.localDesktopName)
1936
1986
  } : void 0;
1937
1987
  };
1938
1988
  (0, react.useEffect)(() => installSessionOriginHover(document, (element) => originResolver.current(element)), []);
@@ -2633,6 +2683,21 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
2633
2683
  [${PREFIX}summary] [data-slot="conversation.session.header.actions"] > * { font-size: inherit; line-height: inherit; }
2634
2684
  [${PREFIX}turn-count] { display: inline-flex; align-items: center; white-space: nowrap; }
2635
2685
  [${PREFIX}summary] [data-slot="conversation.session.header.actions"] > * + [${PREFIX}turn-count]::before { content: '·'; margin: 0 7px; }
2686
+ [${PREFIX}summary]:has([${PREFIX}computer]) { overflow: visible; }
2687
+ [${PREFIX}summary] [data-slot="conversation.session.header.actions"]:has([${PREFIX}computer]) { display: flex; align-items: center; overflow: visible; min-width: 0; }
2688
+ [${PREFIX}summary] [data-slot="conversation.session.header.actions"]:has([${PREFIX}computer]) > :not([${PREFIX}computer]) { flex: none; }
2689
+ [${PREFIX}computer] { display: inline-flex; align-items: center; gap: 4px; min-width: 0; max-width: 240px; }
2690
+ [${PREFIX}computer]::before { content: ''; flex: none; height: 12px; border-left: 1px solid var(--dsw-alias-border-l3, #d4d6da); margin: 0 6px; }
2691
+ [${PREFIX}computer]:first-child::before { display: none; }
2692
+ [${PREFIX}remote-label] { flex: none; color: var(--dsw-alias-label-secondary, #626872); }
2693
+ [${PREFIX}computer-name] { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2694
+ [${PREFIX}computer]:focus-visible { outline: 2px solid #4c70ef; outline-offset: 2px; border-radius: 2px; }
2695
+ /* Narrow headers give the metadata the full row; keep native React ancestry. */
2696
+ @container arkme-session-header (max-width: 600px) {
2697
+ [${PREFIX}title-row]:has([${PREFIX}computer]) { position: relative; padding-bottom: 22px; }
2698
+ [${PREFIX}summary]:has([${PREFIX}computer]) { position: absolute; left: 0; right: 0; bottom: 0; }
2699
+ [${PREFIX}summary] [data-slot="conversation.session.header.actions"]:has([${PREFIX}computer]) { max-width: 100%; }
2700
+ }
2636
2701
  /* The embedded conversation can be much narrower than the browser. Keep
2637
2702
  native controls in their React ancestry, wrapping only in that case. */
2638
2703
  @container arkme-session-header (max-width: 360px) {
@@ -2990,6 +3055,52 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
2990
3055
  };
2991
3056
  }
2992
3057
  //#endregion
3058
+ //#region node_modules/@phosphor-icons/react/dist/lib/context.es.js
3059
+ const o = (0, react.createContext)({
3060
+ color: "currentColor",
3061
+ size: "1em",
3062
+ weight: "regular",
3063
+ mirrored: !1
3064
+ });
3065
+ //#endregion
3066
+ //#region node_modules/@phosphor-icons/react/dist/lib/IconBase.es.js
3067
+ const p = react.forwardRef((s, a) => {
3068
+ const { alt: n, color: r, size: t, weight: o$1, mirrored: c, children: i, weights: m, ...x } = s, { color: d = "currentColor", size: l, weight: f = "regular", mirrored: g = !1, ...w } = react.useContext(o);
3069
+ return /* @__PURE__ */ react.createElement("svg", {
3070
+ ref: a,
3071
+ xmlns: "http://www.w3.org/2000/svg",
3072
+ width: t != null ? t : l,
3073
+ height: t != null ? t : l,
3074
+ fill: r != null ? r : d,
3075
+ viewBox: "0 0 256 256",
3076
+ transform: c || g ? "scale(-1, 1)" : void 0,
3077
+ ...w,
3078
+ ...x
3079
+ }, !!n && /* @__PURE__ */ react.createElement("title", null, n), i, m.get(o$1 != null ? o$1 : f));
3080
+ });
3081
+ p.displayName = "IconBase";
3082
+ //#endregion
3083
+ //#region node_modules/@phosphor-icons/react/dist/defs/Desktop.es.js
3084
+ const e$1 = /* @__PURE__ */ new Map([
3085
+ ["bold", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208,36H48A28,28,0,0,0,20,64V172a28,28,0,0,0,28,28h68v12H96a12,12,0,0,0,0,24h64a12,12,0,0,0,0-24H140V200h68a28,28,0,0,0,28-28V64A28,28,0,0,0,208,36ZM48,60H208a4,4,0,0,1,4,4v72H44V64A4,4,0,0,1,48,60ZM208,176H48a4,4,0,0,1-4-4V160H212v12A4,4,0,0,1,208,176Z" }))],
3086
+ ["duotone", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", {
3087
+ d: "M224,64v88H32V64A16,16,0,0,1,48,48H208A16,16,0,0,1,224,64Z",
3088
+ opacity: "0.2"
3089
+ }), /* @__PURE__ */ react.createElement("path", { d: "M208,40H48A24,24,0,0,0,24,64V176a24,24,0,0,0,24,24h72v16H96a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16H136V200h72a24,24,0,0,0,24-24V64A24,24,0,0,0,208,40ZM48,56H208a8,8,0,0,1,8,8v80H40V64A8,8,0,0,1,48,56ZM208,184H48a8,8,0,0,1-8-8V160H216v16A8,8,0,0,1,208,184Z" }))],
3090
+ ["fill", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208,40H48A24,24,0,0,0,24,64V176a24,24,0,0,0,24,24h72v16H96a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16H136V200h72a24,24,0,0,0,24-24V64A24,24,0,0,0,208,40Zm0,144H48a8,8,0,0,1-8-8V160H216v16A8,8,0,0,1,208,184Z" }))],
3091
+ ["light", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208,42H48A22,22,0,0,0,26,64V176a22,22,0,0,0,22,22h74v20H96a6,6,0,0,0,0,12h64a6,6,0,0,0,0-12H134V198h74a22,22,0,0,0,22-22V64A22,22,0,0,0,208,42ZM48,54H208a10,10,0,0,1,10,10v82H38V64A10,10,0,0,1,48,54ZM208,186H48a10,10,0,0,1-10-10V158H218v18A10,10,0,0,1,208,186Z" }))],
3092
+ ["regular", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208,40H48A24,24,0,0,0,24,64V176a24,24,0,0,0,24,24h72v16H96a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16H136V200h72a24,24,0,0,0,24-24V64A24,24,0,0,0,208,40ZM48,56H208a8,8,0,0,1,8,8v80H40V64A8,8,0,0,1,48,56ZM208,184H48a8,8,0,0,1-8-8V160H216v16A8,8,0,0,1,208,184Z" }))],
3093
+ ["thin", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208,44H48A20,20,0,0,0,28,64V176a20,20,0,0,0,20,20h76v24H96a4,4,0,0,0,0,8h64a4,4,0,0,0,0-8H132V196h76a20,20,0,0,0,20-20V64A20,20,0,0,0,208,44ZM48,52H208a12,12,0,0,1,12,12v84H36V64A12,12,0,0,1,48,52ZM208,188H48a12,12,0,0,1-12-12V156H220v20A12,12,0,0,1,208,188Z" }))]
3094
+ ]);
3095
+ //#endregion
3096
+ //#region node_modules/@phosphor-icons/react/dist/csr/Desktop.es.js
3097
+ const e = react.forwardRef((t, r) => /* @__PURE__ */ react.createElement(p, {
3098
+ ref: r,
3099
+ ...t,
3100
+ weights: e$1
3101
+ }));
3102
+ e.displayName = "DesktopIcon";
3103
+ //#endregion
2993
3104
  //#region src/client/harness-session-summary.ts
2994
3105
  const SLOT = "conversation.session.header.actions";
2995
3106
  const LOCALE = "arkme.harness.sessionSummary";
@@ -3007,22 +3118,60 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
3007
3118
  "data-turns": turns
3008
3119
  }, t("count", { count: turns }));
3009
3120
  }
3121
+ function SessionComputerLocation({ surface, sessionId, t }) {
3122
+ const { rows, localDesktopName } = useAccountSessionCatalog(surface);
3123
+ const row = rows.find((row) => !row.archived && accountSessionKey(row) === sessionId);
3124
+ if (!row || !isRemoteComputer(row, localDesktopName)) return null;
3125
+ const name = row.desktopName.trim();
3126
+ return (0, react.createElement)("span", {
3127
+ "data-arkme-session-computer": "",
3128
+ title: `${t("remote")} · ${name}`,
3129
+ tabIndex: 0
3130
+ }, (0, react.createElement)(e, {
3131
+ size: 14,
3132
+ "aria-hidden": true,
3133
+ style: { flexShrink: 0 }
3134
+ }), (0, react.createElement)("span", { "data-arkme-session-remote-label": "" }, t("remote")), " · ", (0, react.createElement)("span", {
3135
+ "data-arkme-session-computer-name": "",
3136
+ title: name
3137
+ }, name));
3138
+ }
3010
3139
  /** Add a session-scoped reader; paging, compaction and push updates stay host-owned. */
3011
- function installHarnessSessionSummary(ctx) {
3140
+ function installHarnessSessionSummary(ctx, surface) {
3012
3141
  if (typeof ctx.locale?.register !== "function" || typeof ctx.slots.spec !== "function") return () => {};
3013
3142
  const removeLocale = ctx.locale.register(LOCALE, {
3014
- zh: { count: "{count} 次对话" },
3015
- en: { count: "{count} turns" }
3143
+ zh: {
3144
+ count: "{count} 次对话",
3145
+ remote: "非本机"
3146
+ },
3147
+ en: {
3148
+ count: "{count} turns",
3149
+ remote: "Remote"
3150
+ }
3016
3151
  });
3017
3152
  const removeSlot = ctx.slots.inject(SLOT, () => {
3018
3153
  const spec = ctx.slots.spec(SLOT);
3019
3154
  if (spec?.kind !== "list" || spec.scope !== "session") return () => {};
3020
- return ctx.slots.register({
3155
+ const removeCount = ctx.slots.register({
3021
3156
  name: SLOT,
3022
3157
  id: "arkme-session-turn-count",
3023
3158
  order: 0,
3024
3159
  locale: LOCALE
3025
3160
  }, SessionTurnCount);
3161
+ const removeComputer = surface && ctx.slots.register({
3162
+ name: SLOT,
3163
+ id: "arkme-session-computer",
3164
+ order: 1,
3165
+ locale: LOCALE
3166
+ }, (props) => (0, react.createElement)(SessionComputerLocation, {
3167
+ surface,
3168
+ sessionId: props.sessionId,
3169
+ t: props.t
3170
+ }));
3171
+ return () => {
3172
+ removeComputer?.();
3173
+ removeCount();
3174
+ };
3026
3175
  });
3027
3176
  return () => {
3028
3177
  removeSlot();
@@ -3248,7 +3397,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
3248
3397
  }, () => null));
3249
3398
  restoreDefault = installHarnessSessionListDefault(ctx);
3250
3399
  restoreAccountSessions = installHarnessAccountSessions(ctx, surface);
3251
- restoreSummary = installHarnessSessionSummary(ctx);
3400
+ restoreSummary = installHarnessSessionSummary(ctx, surface);
3252
3401
  restoreActivity = installHarnessActivityReporter(ctx, surface);
3253
3402
  restoreDropdown = installHarnessSessionDropdown(document);
3254
3403
  } else if (!authenticated) {
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as inspectNativeBundleArtifactV3, At as parseArkmeRecordReeditAttachments, Ct as isRecentEmojiId, D as bundleSha256, Dt as retryAfterMillis, E as arkmeSandboxEntryId, Et as ArkmePluginError, F as assertExtensionArtifactSize, Ft as __esmMin, G as validateVoiceprintPcm16Wav, I as canonicalExtensionJson, It as __exportAll, J as arkmeRequiredLinkMetadataFallback, K as arkmeExtensionShareRefFromLink, L as sha256Hex, Lt as __require, M as packLocalNativeBundleDirectoryV3, Mt as registerDSHAgentInputRecordSync, N as readNativeBundleTarballV3, Nt as createDesktopLifecycleReader, O as canonicalBundleJson, Ot as recordOwnerId, P as renderArkmeSandboxHostEntry, Pt as __commonJSMin, Q as ARKME_PROVIDER_CONTRACT_VERSION, R as unpackArkmeExtension, Rt as __toCommonJS, S as ARKME_BUNDLE_ARTIFACT_KIND, St as recordingImportFileNameKey, T as ArkmeBundleArtifactError, Tt as registerManagedAiProvider, U as ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE, W as ArkmeService, X as arkmeRichBackgroundSound, Y as arkmeFileBackgroundSound, Z as ARKME_DEFAULT_SHARE_WEBSITE, _ as arkmeClientContentDigest, _t as isRecordingInstantOnOrAfterUnixEpoch, at as cachedMemberItem, b as verifyExtensionResolutionSignature, bt as sameRecordingImportIdentity, c as persistentExtensionBundleDirectory, ct as ARKME_RUNTIME_INSTANCE_ID, d as readPersistentExtensionActivation, dt as arkmeNormalizedFileMimeType, f as refreshPersistentClientWrapper, ft as arkmePickedFileKind, g as activeProfileExtensionOwnerConflicts, gt as ArkmeDirectMessageAdmissionError, h as renderArkmeBundleClientBundle, ht as SecretValue, i as invokePersistentArkmeExtension, it as applyMemberUpdate, j as packBundleFiles, jt as parseArkmeRecordReeditMentions, k as inspectBundleArtifact, kt as ArkmeRecordReeditDraftConflict, l as persistentExtensionPackageIdentity, lt as ARKME_TOOL_FILE_MAX_BYTES, m as writePersistentExtensionActivation, mt as ArkmeOutgoingCallError, nt as ARKME_WORLD_PUBLISH_MAX_IMAGES, o as persistentArkmeExtensionRuntimeState, ot as mergeMemberJoinEvents, p as repairPersistentExtensionInstallation, pt as isArkmeBotAvatarRef, q as arkmeIsGenericLinkMetadataTitle, r as deactivatePersistentArkmeExtension, rt as ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, s as materializePersistentExtensionBundle, st as validateMemberUpdate, t as activatePersistentArkmeExtension, u as quarantinePersistentExtension, ut as arkmeCanInlineLocalFile, v as arkmeClientContentDigestFromSource, vt as isUnresolvedRecordingImportJob, w as ARKME_NATIVE_BUNDLE_ARTIFACT_KIND, wt as normalizeRecentEmojiIds, x as verifyNativeBundleResolutionSignature, y as verifyBundleResolutionSignature, yt as recordingImportFileKind, z as ARKME_EXTENSION_FORMAT } from "./persistent-runtime-aiHgSAmj.js";
1
+ import { A as inspectNativeBundleArtifactV3, At as parseArkmeRecordReeditAttachments, Ct as isRecentEmojiId, D as bundleSha256, Dt as retryAfterMillis, E as arkmeSandboxEntryId, Et as ArkmePluginError, F as assertExtensionArtifactSize, Ft as __esmMin, G as validateVoiceprintPcm16Wav, I as canonicalExtensionJson, It as __exportAll, J as arkmeRequiredLinkMetadataFallback, K as arkmeExtensionShareRefFromLink, L as sha256Hex, Lt as __require, M as packLocalNativeBundleDirectoryV3, Mt as registerDSHAgentInputRecordSync, N as readNativeBundleTarballV3, Nt as createDesktopLifecycleReader, O as canonicalBundleJson, Ot as recordOwnerId, P as renderArkmeSandboxHostEntry, Pt as __commonJSMin, Q as ARKME_PROVIDER_CONTRACT_VERSION, R as unpackArkmeExtension, Rt as __toCommonJS, S as ARKME_BUNDLE_ARTIFACT_KIND, St as recordingImportFileNameKey, T as ArkmeBundleArtifactError, Tt as registerManagedAiProvider, U as ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE, W as ArkmeService, X as arkmeRichBackgroundSound, Y as arkmeFileBackgroundSound, Z as ARKME_DEFAULT_SHARE_WEBSITE, _ as arkmeClientContentDigest, _t as isRecordingInstantOnOrAfterUnixEpoch, at as cachedMemberItem, b as verifyExtensionResolutionSignature, bt as sameRecordingImportIdentity, c as persistentExtensionBundleDirectory, ct as ARKME_RUNTIME_INSTANCE_ID, d as readPersistentExtensionActivation, dt as arkmeNormalizedFileMimeType, f as refreshPersistentClientWrapper, ft as arkmePickedFileKind, g as activeProfileExtensionOwnerConflicts, gt as ArkmeDirectMessageAdmissionError, h as renderArkmeBundleClientBundle, ht as SecretValue, i as invokePersistentArkmeExtension, it as applyMemberUpdate, j as packBundleFiles, jt as parseArkmeRecordReeditMentions, k as inspectBundleArtifact, kt as ArkmeRecordReeditDraftConflict, l as persistentExtensionPackageIdentity, lt as ARKME_TOOL_FILE_MAX_BYTES, m as writePersistentExtensionActivation, mt as ArkmeOutgoingCallError, nt as ARKME_WORLD_PUBLISH_MAX_IMAGES, o as persistentArkmeExtensionRuntimeState, ot as mergeMemberJoinEvents, p as repairPersistentExtensionInstallation, pt as isArkmeBotAvatarRef, q as arkmeIsGenericLinkMetadataTitle, r as deactivatePersistentArkmeExtension, rt as ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, s as materializePersistentExtensionBundle, st as validateMemberUpdate, t as activatePersistentArkmeExtension, u as quarantinePersistentExtension, ut as arkmeCanInlineLocalFile, v as arkmeClientContentDigestFromSource, vt as isUnresolvedRecordingImportJob, w as ARKME_NATIVE_BUNDLE_ARTIFACT_KIND, wt as normalizeRecentEmojiIds, x as verifyNativeBundleResolutionSignature, y as verifyBundleResolutionSignature, yt as recordingImportFileKind, z as ARKME_EXTENSION_FORMAT } from "./persistent-runtime-CGclHTN1.js";
2
2
  import { a as securePrivateDirectory, c as securePrivateFileSync, i as prepareProfilePackageManager, n as isArkmeProfilePackageName, o as securePrivateDirectorySync, r as localExtensionPnpmArgs, s as securePrivateFile, t as applyArkmeProfileBundlePolicy } from "./profile-bundle-policy-Cwi2iuHi.js";
3
3
  import { _ as parsePluginUpdateManifest, b as validatePluginUpdateServiceOrigin, d as writePluginUpdateLifecycleLog, f as PluginUpdateInstallStateStore, g as existingCachedPluginArtifactPath, h as downloadAndCachePluginArtifact, m as PluginUpdateArtifactError, n as buildTargetInstallArgs, o as reconcilePluginUpdaterProfilePolicy, p as ARKME_PLUGIN_PACKAGE_NAME$1, t as assertTargetArtifactIntegrity, u as detachManagedProfilePluginLink, v as pluginUpdateEndpointUrl, y as validatePluginUpdateArtifactOrigin } from "./plugin-updater-helper-BWIKYugE.js";
4
4
  import { i as invokeArkmeBundle, n as arkmeBundleActive, r as deactivateArkmeBundle } from "./bundle-runtime-QUG0eHSZ.js";
@@ -14299,11 +14299,16 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
14299
14299
  case "auth.app.poll": return await service.pollJiwoLogin(stringParam(params, "attemptId"));
14300
14300
  case "auth.app.cancel": return await service.cancelJiwoLogin(stringParam(params, "attemptId"));
14301
14301
  case "auth.test.login": return await service.testLogin(numberParam(params, "userId", 0));
14302
+ case "auth.email.send": return await service.sendEmailBindCode(numberParam(params, "expectedUserId", 0), stringParam(params, "email"));
14303
+ case "auth.email.bind": return await service.bindEmail(numberParam(params, "expectedUserId", 0), stringParam(params, "email"), stringParam(params, "code"));
14302
14304
  case "auth.phone.send": return await service.sendPhoneCode(stringParam(params, "phone"), captchaParam(params));
14303
14305
  case "auth.phone.unbind.check": return await service.checkPhoneUnbindEligibility(numberParam(params, "expectedUserId", 0));
14304
14306
  case "auth.phone.unbind.send": return await service.sendPhoneUnbindCode(captchaParam(params));
14305
14307
  case "auth.phone.unbind": return await service.unbindPhone(stringParam(params, "code"));
14306
14308
  case "auth.phone.verify": return await service.verifyPhoneCode(stringParam(params, "phone"), stringParam(params, "code"));
14309
+ case "auth.cancellation.preview": return await service.previewCancellation(numberParam(params, "expectedUserId", 0));
14310
+ case "auth.cancellation.submit": return await service.submitCancellation(numberParam(params, "expectedUserId", 0), stringParam(params, "expectedMode"));
14311
+ case "auth.cancellation.login.resolve": return await service.resolveCancellationLogin(requiredBooleanParam(params, "continueLogin"));
14307
14312
  case "auth.logout": return await service.logout();
14308
14313
  case "chat.direct-message-admission": return await service.directMessageAdmission(stringParam(params, "sourceRef"), requestSignal);
14309
14314
  case "chat.direct-message-refusal.set": return await service.setDirectMessageRefusal(stringParam(params, "sourceRef"), requiredBooleanParam(params, "refused"), numberParam(params, "expectedRevision", -1), requestSignal);
@@ -15127,6 +15132,7 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
15127
15132
  case "emoji.recent.list": return await service.recentEmojiIds(stringParam(params, "accountKey"), requestSignal);
15128
15133
  case "emoji.recent.record": return await service.recordRecentEmoji(stringParam(params, "accountKey"), stringParam(params, "emojiId"), requestSignal);
15129
15134
  case "favorite-stickers.list": return await service.favoriteStickers();
15135
+ case "reactions": return await service.reactions(params, requestSignal);
15130
15136
  case "favorite-stickers.add": return await service.addFavoriteSticker(favoriteStickerItemParam(params));
15131
15137
  case "favorite-stickers.send": return await service.sendFavoriteSticker(stringParam(params, "sourceRef"), stringParam(params, "fileAssetUid"), {
15132
15138
  ...stringParam(params, "recordUid") === "" ? {} : { recordUid: stringParam(params, "recordUid") },
@@ -19533,6 +19539,12 @@ var ArkmeLocalDatabase = class {
19533
19539
  if (!this.database.prepare("PRAGMA table_info(user_profile_cache)").all().some((column) => column.name === "can_update_arkme_id")) this.database.exec("ALTER TABLE user_profile_cache ADD COLUMN can_update_arkme_id INTEGER");
19534
19540
  this.secureDatabaseFiles();
19535
19541
  }
19542
+ async readCancellationCompletion() {
19543
+ return await this.operationalState.readCancellationCompletion();
19544
+ }
19545
+ async writeCancellationCompletion(completion) {
19546
+ await this.operationalState.writeCancellationCompletion(completion);
19547
+ }
19536
19548
  async uniqueCode() {
19537
19549
  return await this.operationalState.uniqueCode();
19538
19550
  }
@@ -24804,6 +24816,12 @@ function legacyRecordReeditRevision(drafts, submissions) {
24804
24816
  }
24805
24817
  return revision;
24806
24818
  }
24819
+ function validCancellationCompletion(value) {
24820
+ if (value === null || typeof value !== "object") return false;
24821
+ const candidate = value;
24822
+ const result = candidate.result;
24823
+ return Number.isSafeInteger(candidate.userId) && candidate.userId > 0 && typeof candidate.sessionHash === "string" && /^[a-f0-9]{64}$/.test(candidate.sessionHash) && result != null && ["immediate", "waiting"].includes(result.mode) && ["done", "waiting"].includes(result.status) && Number.isSafeInteger(result.cancel_at) && typeof result.has_phone === "boolean";
24824
+ }
24807
24825
  function parseState(raw) {
24808
24826
  const parsed = JSON.parse(raw);
24809
24827
  if (parsed === null || typeof parsed !== "object") return emptyState$1();
@@ -24835,6 +24853,7 @@ function parseState(raw) {
24835
24853
  return {
24836
24854
  version: 2,
24837
24855
  uniqueCode: typeof source.uniqueCode === "string" && source.uniqueCode.trim() !== "" ? source.uniqueCode : randomUUID(),
24856
+ ...validCancellationCompletion(source.cancellationCompletion) ? { cancellationCompletion: source.cancellationCompletion } : {},
24838
24857
  pendingByUser,
24839
24858
  longArticleDraftsByUser,
24840
24859
  recordReeditDraftsByUser,
@@ -24908,6 +24927,16 @@ var ArkmeStateStore = class {
24908
24927
  constructor(directory) {
24909
24928
  this.path = join(directory, "state.json");
24910
24929
  }
24930
+ async readCancellationCompletion() {
24931
+ return await this.read((state) => state.cancellationCompletion === void 0 ? void 0 : structuredClone(state.cancellationCompletion));
24932
+ }
24933
+ async writeCancellationCompletion(completion) {
24934
+ if (completion !== void 0 && !validCancellationCompletion(completion)) throw new Error("注销完成记录无效");
24935
+ await this.update((state) => {
24936
+ if (completion === void 0) delete state.cancellationCompletion;
24937
+ else state.cancellationCompletion = structuredClone(completion);
24938
+ });
24939
+ }
24911
24940
  async uniqueCode() {
24912
24941
  return await this.read((state) => state.uniqueCode);
24913
24942
  }
@@ -27141,6 +27170,78 @@ const arkoToolModules = [
27141
27170
  })
27142
27171
  ];
27143
27172
  //#endregion
27173
+ //#region src/tools/business/conversation/reactions.ts
27174
+ function request$2(raw, write) {
27175
+ const input = JSON.parse(raw);
27176
+ if (!input || !(write ? [
27177
+ "set",
27178
+ "library-set",
27179
+ "history-policy-set",
27180
+ "notifications-read"
27181
+ ] : [
27182
+ "notifications",
27183
+ "query",
27184
+ "actors",
27185
+ "groups",
27186
+ "history",
27187
+ "received",
27188
+ "history-policy-query",
27189
+ "library-query"
27190
+ ]).includes(input.action) || typeof input.accountKey !== "string") throw new TypeError("Invalid reaction request or action for this tool");
27191
+ return input;
27192
+ }
27193
+ const readReactionsToolModule = defineArkmeCoreToolModule({
27194
+ meta: {
27195
+ id: "business.conversation.reactions-read.v1",
27196
+ toolName: "arkme_reactions_read",
27197
+ kind: "business",
27198
+ phase: "core",
27199
+ effect: "read",
27200
+ profiles: ["business", "hybrid"]
27201
+ },
27202
+ create(ports) {
27203
+ return defineTool({
27204
+ name: "arkme_reactions_read",
27205
+ description: "Read authorized message reactions, actors, own dated reaction history or own phrase library. accountKey is environment:userId from current account. query targets use id, sourceRef and messageActionRef returned by conversation reads. World targets instead use id and worldRecordRef from World reads. Actions: notifications, query, actors, groups, history, received, history-policy-query, library-query. Locked history is denied, never bypass it. Never invent message references.",
27206
+ parameters: { request_json: {
27207
+ type: "string",
27208
+ required: true,
27209
+ description: "ReactionRequest JSON: accountKey and action; notifications after_id/limit (max50); query targets (max50); actors target/key/after_user_id/limit; history start_at/end_at/before_at/before_id/limit (UTC ms, max32 days); groups target/after_key/limit; received world_only/limit/before_at/before_id; history-policy-query and library-query no extra fields."
27210
+ } },
27211
+ output: TEXT_OUTPUT$3,
27212
+ async execute(args, exec) {
27213
+ return taggedJSON("表态", await ports.reactions(request$2(args.request_json, false), exec.signal));
27214
+ }
27215
+ });
27216
+ }
27217
+ });
27218
+ const writeReactionsToolModule = defineArkmeCoreToolModule({
27219
+ meta: {
27220
+ id: "business.conversation.reactions-write.v1",
27221
+ toolName: "arkme_reactions_write",
27222
+ kind: "business",
27223
+ phase: "core",
27224
+ effect: "write",
27225
+ grant: "explicit-user-write",
27226
+ profiles: ["business", "hybrid"]
27227
+ },
27228
+ create(ports) {
27229
+ return defineTool({
27230
+ name: "arkme_reactions_write",
27231
+ description: "Only after an explicit user request, add/remove a message reaction or save the user phrase library. Query current revision first. Use a unique request_id and reuse exactly that request on uncertain failure; never auto-overwrite a revision conflict. set is explicit active true/false, not a toggle. No chat message is sent.",
27232
+ parameters: { request_json: {
27233
+ type: "string",
27234
+ required: true,
27235
+ description: "JSON accountKey; notifications-read requires items:[{id,revision}] (max50) from notifications read results and explicitly acknowledges viewed reactions. Other actions: set, library-set or history-policy-set; expected_revision. set and library-set require request_id. history-policy-set requires locked:boolean and must have explicit user authorization to unlock. set also target:{id,sourceRef,messageActionRef} or {id,worldRecordRef}, expression:{text,emoji?,hand?,color?}, active:boolean. library-set items: ordered expression array (max58); empty clears library only."
27236
+ } },
27237
+ output: TEXT_OUTPUT$3,
27238
+ async execute(args, exec) {
27239
+ return taggedJSON("表态保存结果", await ports.reactions(request$2(args.request_json, true), exec.signal));
27240
+ }
27241
+ });
27242
+ }
27243
+ });
27244
+ //#endregion
27144
27245
  //#region src/tools/business/bots/add-group.ts
27145
27246
  const addGroupBotToolModule = defineArkmeCoreToolModule({
27146
27247
  meta: {
@@ -31828,6 +31929,8 @@ const businessToolModules = [
31828
31929
  directMessageRefusalToolModule,
31829
31930
  groupAiPolishToolModule,
31830
31931
  listFavoriteStickersToolModule,
31932
+ readReactionsToolModule,
31933
+ writeReactionsToolModule,
31831
31934
  addFavoriteStickerToolModule,
31832
31935
  sendFavoriteStickerToolModule,
31833
31936
  manageFavoriteStickerToolModule,
@@ -32035,6 +32138,7 @@ function groupGovernanceQuestion(name, args) {
32035
32138
  //#endregion
32036
32139
  //#region src/tools/registry/registrar.ts
32037
32140
  const CORE_CONFIRMATION_TOOLS = /* @__PURE__ */ new Set([
32141
+ "arkme_reactions_write",
32038
32142
  "arkme_bot_conversation_pin",
32039
32143
  "arkme_direct_message_refusal_set",
32040
32144
  "arkme_topic_home_visibility",
@@ -32083,6 +32187,13 @@ function cleanArgument(value, maxLength) {
32083
32187
  return cleaned.length > maxLength ? `${cleaned.slice(0, maxLength)}…` : cleaned;
32084
32188
  }
32085
32189
  function coreConfirmationQuestion(name, args) {
32190
+ if (name === "arkme_reactions_write") {
32191
+ const request = JSON.parse(String(args.request_json));
32192
+ if (request.action === "history-policy-set") return request.locked === true ? "是否确认锁定自己的表态操作记录?锁定后时间轴、数据管理和 AI 都不能读取这些记录。" : "是否确认解锁自己的表态操作记录,恢复时间轴、数据管理和 AI 的读取?";
32193
+ if (request.action === "notifications-read") return "是否将刚才指定的表态提醒标记为已查看?";
32194
+ if (request.action === "library-set") return "是否确认保存刚才指定的短语、颜色和顺序?这不会发送表态。";
32195
+ return request.active === true ? "是否确认给刚才指定的消息添加这个表态?" : "是否确认取消刚才指定的表态?";
32196
+ }
32086
32197
  if (name === "arkme_direct_message_refusal_set") return args.refused === true ? "是否确认拒收这个私聊用户的消息?拒收期间双方都无法发送新消息,历史记录保留。" : "是否确认解除你对这个私聊用户的拒收?如果对方仍拒收,双方依然无法发送新消息。";
32087
32198
  if (name === "arkme_recording_import") return args.action === "retry" ? "是否确认重试这条失败的录音上传任务?" : `是否确认按指定的开始时间导入所选录音,并将归属设为“${args.ownership === "other" ? "其他" : "自己"}”?`;
32088
32199
  if (name === "arkme_archive_set") return args.self_archived === true ? "是否确认归档此主题及其子主题?内容仍可搜索和引用,可在已归档中恢复。" : "是否确认取消此主题的单独归档?独立归档的子主题会保留;如果父级仍归档,此主题仍随父级归档。";
@@ -1,2 +1,2 @@
1
- import { a as persistentArkmeExtensionActive, i as invokePersistentArkmeExtension, n as applyPersistentArkmeHostExtension, o as persistentArkmeExtensionRuntimeState, r as deactivatePersistentArkmeExtension, t as activatePersistentArkmeExtension } from "./persistent-runtime-aiHgSAmj.js";
1
+ import { a as persistentArkmeExtensionActive, i as invokePersistentArkmeExtension, n as applyPersistentArkmeHostExtension, o as persistentArkmeExtensionRuntimeState, r as deactivatePersistentArkmeExtension, t as activatePersistentArkmeExtension } from "./persistent-runtime-CGclHTN1.js";
2
2
  export { activatePersistentArkmeExtension, applyPersistentArkmeHostExtension, deactivatePersistentArkmeExtension, invokePersistentArkmeExtension, persistentArkmeExtensionActive, persistentArkmeExtensionRuntimeState };