@senguoyun/dsh-arkme 0.1.60 → 0.1.61

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 (99) hide show
  1. package/cordis.patch.yml +6 -0
  2. package/docs/search-dsh-navigation.md +37 -0
  3. package/lib/client.js +2947 -2367
  4. package/lib/client.js.map +1 -1
  5. package/lib/harness-model-client.js +9 -0
  6. package/lib/harness-native-selection-client.js +1341 -0
  7. package/lib/harness-onboarding-client.js +64 -2
  8. package/lib/harness-session-client.js +39 -2
  9. package/lib/index.js +111 -156
  10. package/lib/persistent-extension.js +1 -1
  11. package/lib/{persistent-runtime-DqPfc6RO.js → persistent-runtime-CXd9RuRR.js} +29688 -29315
  12. package/lib/sdk.js +9 -0
  13. package/lib/types/arkme-service.d.ts +4 -1
  14. package/lib/types/arkme-service.d.ts.map +1 -1
  15. package/lib/types/client/ArkmeChatMemberActions.d.ts +1 -1
  16. package/lib/types/client/ArkmeChatMemberActions.d.ts.map +1 -1
  17. package/lib/types/client/ArkmeDetailShell.d.ts +3 -1
  18. package/lib/types/client/ArkmeDetailShell.d.ts.map +1 -1
  19. package/lib/types/client/ArkmeFileViewer.d.ts +1 -0
  20. package/lib/types/client/ArkmeFileViewer.d.ts.map +1 -1
  21. package/lib/types/client/ArkmeMessageActions.d.ts.map +1 -1
  22. package/lib/types/client/ArkmeNoteDetails.d.ts +2 -1
  23. package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
  24. package/lib/types/client/ArkmeRecordEditHistory.d.ts +10 -0
  25. package/lib/types/client/ArkmeRecordEditHistory.d.ts.map +1 -0
  26. package/lib/types/client/ArkmeRichContent.d.ts +2 -1
  27. package/lib/types/client/ArkmeRichContent.d.ts.map +1 -1
  28. package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
  29. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  30. package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts +2 -1
  31. package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts.map +1 -1
  32. package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
  33. package/lib/types/client/ArkmeWorldSurface.d.ts +3 -3
  34. package/lib/types/client/ArkmeWorldSurface.d.ts.map +1 -1
  35. package/lib/types/client/DeepSeekHarnessSurface.d.ts +4 -0
  36. package/lib/types/client/DeepSeekHarnessSurface.d.ts.map +1 -1
  37. package/lib/types/client/api.d.ts +1 -1
  38. package/lib/types/client/api.d.ts.map +1 -1
  39. package/lib/types/client/arkme-theme.d.ts +1 -0
  40. package/lib/types/client/arkme-theme.d.ts.map +1 -1
  41. package/lib/types/client/clipboard-text.d.ts +2 -0
  42. package/lib/types/client/clipboard-text.d.ts.map +1 -0
  43. package/lib/types/client/harness-native-selection-client.d.ts +13 -0
  44. package/lib/types/client/harness-native-selection-client.d.ts.map +1 -0
  45. package/lib/types/client/harness-native-selection-geometry.d.ts +47 -0
  46. package/lib/types/client/harness-native-selection-geometry.d.ts.map +1 -0
  47. package/lib/types/client/harness-native-selection-loader.d.ts +4 -0
  48. package/lib/types/client/harness-native-selection-loader.d.ts.map +1 -0
  49. package/lib/types/client/harness-native-selection.d.ts +35 -0
  50. package/lib/types/client/harness-native-selection.d.ts.map +1 -0
  51. package/lib/types/client/harness-onboarding-client.d.ts.map +1 -1
  52. package/lib/types/client/harness-session-client.d.ts.map +1 -1
  53. package/lib/types/client/harness-session-summary.d.ts +0 -7
  54. package/lib/types/client/harness-session-summary.d.ts.map +1 -1
  55. package/lib/types/client/harness-slots-contract.d.ts +12 -0
  56. package/lib/types/client/harness-slots-contract.d.ts.map +1 -0
  57. package/lib/types/client/index.d.ts.map +1 -1
  58. package/lib/types/client/interwoven-moments.d.ts.map +1 -1
  59. package/lib/types/client/member-records-loader.d.ts +10 -0
  60. package/lib/types/client/member-records-loader.d.ts.map +1 -0
  61. package/lib/types/client/member-records-viewport.d.ts +10 -0
  62. package/lib/types/client/member-records-viewport.d.ts.map +1 -0
  63. package/lib/types/client/message-selection-presentation.d.ts +42 -2
  64. package/lib/types/client/message-selection-presentation.d.ts.map +1 -1
  65. package/lib/types/client/redesign/contacts/ContactProfileDetail.d.ts.map +1 -1
  66. package/lib/types/client/redesign/contacts/ContactWorldList.d.ts +2 -1
  67. package/lib/types/client/redesign/contacts/ContactWorldList.d.ts.map +1 -1
  68. package/lib/types/client/timeline-message-order.d.ts +4 -0
  69. package/lib/types/client/timeline-message-order.d.ts.map +1 -0
  70. package/lib/types/client/ui-controller.d.ts +7 -1
  71. package/lib/types/client/ui-controller.d.ts.map +1 -1
  72. package/lib/types/dsh-search-origins.d.ts +4 -0
  73. package/lib/types/dsh-search-origins.d.ts.map +1 -0
  74. package/lib/types/harness-embed-contract.d.ts +10 -0
  75. package/lib/types/harness-embed-contract.d.ts.map +1 -1
  76. package/lib/types/harness-embed-route.d.ts +2 -1
  77. package/lib/types/harness-embed-route.d.ts.map +1 -1
  78. package/lib/types/host-api.d.ts.map +1 -1
  79. package/lib/types/index.d.ts.map +1 -1
  80. package/lib/types/managed-ai/adapter.d.ts.map +1 -1
  81. package/lib/types/managed-ai/transport.d.ts.map +1 -1
  82. package/lib/types/record-edit-history.d.ts +21 -0
  83. package/lib/types/record-edit-history.d.ts.map +1 -0
  84. package/lib/types/sdk/index.d.ts +7 -0
  85. package/lib/types/sdk/index.d.ts.map +1 -1
  86. package/lib/types/services/chat-service.d.ts +2 -0
  87. package/lib/types/services/chat-service.d.ts.map +1 -1
  88. package/lib/types/services/contact-directory-service.d.ts.map +1 -1
  89. package/lib/types/services/media-service.d.ts +7 -0
  90. package/lib/types/services/media-service.d.ts.map +1 -1
  91. package/lib/types/services/record-edit-history-service.d.ts +25 -0
  92. package/lib/types/services/record-edit-history-service.d.ts.map +1 -0
  93. package/lib/types/services/record-service.d.ts.map +1 -1
  94. package/lib/types/services/search-service.d.ts +1 -0
  95. package/lib/types/services/search-service.d.ts.map +1 -1
  96. package/lib/types/services/source-service.d.ts.map +1 -1
  97. package/lib/types/types.d.ts +18 -2
  98. package/lib/types/types.d.ts.map +1 -1
  99. package/package.json +5 -5
@@ -21,19 +21,79 @@ window.__ModuleLoader__.load({
21
21
  } catch {}
22
22
  }
23
23
  //#endregion
24
+ //#region src/harness-embed-contract.ts
25
+ const ARKME_NATIVE_SELECTION_CLIENT_ID = "@senguoyun/dsh-arkme/harness-native-selection";
26
+ //#endregion
27
+ //#region src/client/harness-native-selection-loader.ts
28
+ /** Called after native readiness. This resource is deliberately absent from the boot graph. */
29
+ function loadNativeSelection(ctx, doc, url) {
30
+ const modules = ctx.modules;
31
+ if (typeof modules?.import !== "function") return () => {};
32
+ let stopped = false;
33
+ let restore;
34
+ const script = doc.createElement("script");
35
+ script.src = url;
36
+ script.async = true;
37
+ const failed = () => {
38
+ script.remove();
39
+ console.warn("Arkme native selection unavailable; native chat remains active.");
40
+ };
41
+ script.onerror = failed;
42
+ script.onload = () => {
43
+ modules.import(ARKME_NATIVE_SELECTION_CLIENT_ID).then((value) => {
44
+ if (stopped) return;
45
+ const module = value;
46
+ if (typeof module?.install !== "function") throw new Error("Missing native selection entry");
47
+ restore = module.install(ctx, doc);
48
+ }).catch(() => {
49
+ if (!stopped) failed();
50
+ });
51
+ };
52
+ doc.head.append(script);
53
+ return () => {
54
+ if (stopped) return;
55
+ stopped = true;
56
+ script.onload = null;
57
+ script.onerror = null;
58
+ script.remove();
59
+ restore?.();
60
+ };
61
+ }
62
+ //#endregion
24
63
  //#region src/client/harness-onboarding-client.tsx
25
- const inject = ["slots", "sessions"];
64
+ const inject = [
65
+ "slots",
66
+ "sessions",
67
+ "modules"
68
+ ];
26
69
  /** Runs in the native iframe. The settings coordinator owns when this step mounts. */
27
70
  function apply(ctx) {
28
71
  const sessions = ctx.sessions;
29
72
  let completed = false;
30
73
  let wasActive;
74
+ let selectionStarted = false;
75
+ let disposeSelection;
76
+ let selectionTimer;
31
77
  const publish = () => {
32
78
  const snapshot = sessions.list.getSnapshot();
33
79
  const active = snapshot.phase === "ready" && (snapshot.current === void 0 || snapshot.byId[snapshot.current]?.blank === true);
34
80
  if (active && wasActive === false) completed = false;
35
81
  wasActive = active;
36
- const state = snapshot.phase === "ready" && (!active || completed) ? "ready" : "pending";
82
+ const ready = snapshot.phase === "ready" && (!active || completed);
83
+ const state = ready ? "ready" : "pending";
84
+ if (ready && !selectionStarted) {
85
+ const asset = document.querySelector("meta[name=\"arkme-native-selection\"]")?.content;
86
+ if (asset && /^\/arkme-self\/harness-native-selection-client\.js\?rev=[a-f0-9]+$/.test(asset)) {
87
+ selectionStarted = true;
88
+ selectionTimer = setTimeout(() => {
89
+ try {
90
+ disposeSelection = loadNativeSelection(ctx, document, asset);
91
+ } catch (error) {
92
+ console.warn("Arkme native selection could not start.", error);
93
+ }
94
+ }, 0);
95
+ }
96
+ }
37
97
  if (document.body.dataset.arkmeHarnessOnboarding !== state) {
38
98
  document.body.dataset.arkmeHarnessOnboarding = state;
39
99
  homeTourDiagnostic("harness-onboarding-state", {
@@ -56,6 +116,8 @@ window.__ModuleLoader__.load({
56
116
  const unsubscribe = sessions.list.subscribe(publish);
57
117
  return () => {
58
118
  unsubscribe();
119
+ clearTimeout(selectionTimer);
120
+ disposeSelection?.();
59
121
  delete document.body.dataset.arkmeHarnessOnboarding;
60
122
  };
61
123
  }, "arkme: native onboarding readiness");
@@ -4,8 +4,16 @@ 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 src/harness-embed-contract.ts
8
+ /** Same-origin bridge owned and disposed by the embedded session client. */
9
+ const HARNESS_SESSION_NAVIGATION_KEY = "__arkmeHarnessSessionNavigation";
10
+ //#endregion
7
11
  //#region src/client/harness-session-client.ts
8
- const inject = ["sessions"];
12
+ const inject = [
13
+ "sessions",
14
+ "remote",
15
+ "remote.session"
16
+ ];
9
17
  const REFRESH_MS = 1e4;
10
18
  /** The iframe reads selection through the public DSH store; Arkme owns visibility. */
11
19
  function apply(ctx) {
@@ -13,9 +21,37 @@ window.__ModuleLoader__.load({
13
21
  const surface = window.frameElement?.parentElement;
14
22
  if (surface?.getAttribute("data-arkme-owned") !== "deepseek-harness-surface") return () => void 0;
15
23
  const apiPath = document.querySelector("meta[name=\"arkme-session-api\"]")?.content;
16
- if (apiPath === void 0 || !/^\/[A-Za-z0-9/_-]+$/.test(apiPath)) return () => void 0;
17
24
  const sessions = ctx.sessions;
18
25
  if (sessions === void 0) return () => void 0;
26
+ const frameWindow = window;
27
+ const navigation = {
28
+ async has(sessionId) {
29
+ if (!/^[A-Za-z0-9_.:-]{1,256}$/.test(sessionId)) throw new Error("DSH 对话标识无效");
30
+ const remote = ctx.remote?.session;
31
+ if (typeof remote?.list !== "function") throw new Error("当前 DSH 版本无法核验本机会话");
32
+ const result = await remote.list({});
33
+ if (!result.ok) throw new Error(result.error?.message || "本机会话列表读取失败,请稍后重试");
34
+ if (!Array.isArray(result.value?.items)) throw new Error("本机会话列表响应不完整");
35
+ if (!result.value.items.some((item) => item.sessionId === sessionId)) return false;
36
+ const refreshable = sessions;
37
+ if (sessions.list.getSnapshot().byId[sessionId] === void 0) {
38
+ if (typeof refreshable.refresh !== "function") throw new Error("本机会话列表尚未就绪,请稍后重试");
39
+ await refreshable.refresh();
40
+ }
41
+ if (sessions.list.getSnapshot().byId[sessionId] === void 0) throw new Error("本机会话列表尚未就绪,请稍后重试");
42
+ return true;
43
+ },
44
+ open(sessionId) {
45
+ if (typeof sessionId !== "string" || sessionId.trim() === "") throw new Error("DSH 对话标识无效");
46
+ if (typeof sessions.open !== "function") throw new Error("当前 DSH 版本暂不支持打开任务");
47
+ sessions.open(sessionId);
48
+ }
49
+ };
50
+ frameWindow[HARNESS_SESSION_NAVIGATION_KEY] = navigation;
51
+ const disposeNavigation = () => {
52
+ if (frameWindow["__arkmeHarnessSessionNavigation"] === navigation) delete frameWindow[HARNESS_SESSION_NAVIGATION_KEY];
53
+ };
54
+ if (apiPath === void 0 || !/^\/[A-Za-z0-9/_-]+$/.test(apiPath)) return disposeNavigation;
19
55
  const windowRef = crypto.randomUUID();
20
56
  let revision = 0;
21
57
  let stopped = false;
@@ -106,6 +142,7 @@ window.__ModuleLoader__.load({
106
142
  window.addEventListener("pageshow", changed);
107
143
  report();
108
144
  return () => {
145
+ disposeNavigation();
109
146
  stopped = true;
110
147
  clearSelection();
111
148
  observer.disconnect();
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as ARKME_DEFAULT_SHARE_WEBSITE, A as inspectNativeBundleArtifactV3, At as createDesktopLifecycleReader, D as bundleSha256, Dt as ArkmePluginError, E as arkmeSandboxEntryId, Et as normalizeRecentEmojiIds, F as assertExtensionArtifactSize, Ft as __toCommonJS, G as validateVoiceprintPcm16Wav, I as canonicalExtensionJson, J as arkmeRequiredLinkMetadataFallback, K as arkmeExtensionShareRefFromLink, L as sha256Hex, M as packLocalNativeBundleDirectoryV3, Mt as __esmMin, N as readNativeBundleTarballV3, Nt as __exportAll, O as canonicalBundleJson, Ot as retryAfterMillis, P as renderArkmeSandboxHostEntry, Pt as __require, Q as parseArkmeRecordReeditAttachments, R as unpackArkmeExtension, S as ARKME_BUNDLE_ARTIFACT_KIND, St as sameRecordingImportIdentity, T as ArkmeBundleArtifactError, Tt as isRecentEmojiId, U as ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE, W as ArkmeService, X as arkmeRichBackgroundSound, Y as arkmeFileBackgroundSound, Z as ArkmeRecordReeditDraftConflict, _ as arkmeClientContentDigest, _t as SecretValue, at as ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, b as verifyExtensionResolutionSignature, bt as isUnresolvedRecordingImportJob, c as persistentExtensionBundleDirectory, ct as mergeMemberJoinEvents, d as readPersistentExtensionActivation, dt as ARKME_TOOL_FILE_MAX_BYTES, et as ARKME_PROVIDER_CONTRACT_VERSION, f as refreshPersistentClientWrapper, ft as arkmeCanInlineLocalFile, g as activeProfileExtensionOwnerConflicts, gt as ArkmeOutgoingCallError, h as renderArkmeBundleClientBundle, ht as isArkmeBotAvatarRef, i as invokePersistentArkmeExtension, it as ARKME_WORLD_PUBLISH_MAX_IMAGES, j as packBundleFiles, jt as __commonJSMin, k as inspectBundleArtifact, kt as recordOwnerId, l as persistentExtensionPackageIdentity, lt as validateMemberUpdate, m as writePersistentExtensionActivation, mt as arkmePickedFileKind, o as persistentArkmeExtensionRuntimeState, ot as applyMemberUpdate, p as repairPersistentExtensionInstallation, pt as arkmeNormalizedFileMimeType, q as arkmeIsGenericLinkMetadataTitle, r as deactivatePersistentArkmeExtension, s as materializePersistentExtensionBundle, st as cachedMemberItem, t as activatePersistentArkmeExtension, u as quarantinePersistentExtension, ut as ARKME_RUNTIME_INSTANCE_ID, v as arkmeClientContentDigestFromSource, vt as ArkmeDirectMessageAdmissionError, w as ARKME_NATIVE_BUNDLE_ARTIFACT_KIND, wt as recordingImportFileNameKey, x as verifyNativeBundleResolutionSignature, xt as recordingImportFileKind, y as verifyBundleResolutionSignature, yt as isRecordingInstantOnOrAfterUnixEpoch, z as ARKME_EXTENSION_FORMAT } from "./persistent-runtime-DqPfc6RO.js";
1
+ import { $ as ARKME_DEFAULT_SHARE_WEBSITE, A as inspectNativeBundleArtifactV3, At as registerDSHAgentInputRecordSync, D as bundleSha256, Dt as ArkmePluginError, E as arkmeSandboxEntryId, Et as normalizeRecentEmojiIds, F as assertExtensionArtifactSize, Ft as __require, G as validateVoiceprintPcm16Wav, I as canonicalExtensionJson, It as __toCommonJS, J as arkmeRequiredLinkMetadataFallback, K as arkmeExtensionShareRefFromLink, L as sha256Hex, M as packLocalNativeBundleDirectoryV3, Mt as __commonJSMin, N as readNativeBundleTarballV3, Nt as __esmMin, O as canonicalBundleJson, Ot as retryAfterMillis, P as renderArkmeSandboxHostEntry, Pt as __exportAll, Q as parseArkmeRecordReeditAttachments, R as unpackArkmeExtension, S as ARKME_BUNDLE_ARTIFACT_KIND, St as sameRecordingImportIdentity, T as ArkmeBundleArtifactError, Tt as isRecentEmojiId, U as ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE, W as ArkmeService, X as arkmeRichBackgroundSound, Y as arkmeFileBackgroundSound, Z as ArkmeRecordReeditDraftConflict, _ as arkmeClientContentDigest, _t as SecretValue, at as ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, b as verifyExtensionResolutionSignature, bt as isUnresolvedRecordingImportJob, c as persistentExtensionBundleDirectory, ct as mergeMemberJoinEvents, d as readPersistentExtensionActivation, dt as ARKME_TOOL_FILE_MAX_BYTES, et as ARKME_PROVIDER_CONTRACT_VERSION, f as refreshPersistentClientWrapper, ft as arkmeCanInlineLocalFile, g as activeProfileExtensionOwnerConflicts, gt as ArkmeOutgoingCallError, h as renderArkmeBundleClientBundle, ht as isArkmeBotAvatarRef, i as invokePersistentArkmeExtension, it as ARKME_WORLD_PUBLISH_MAX_IMAGES, j as packBundleFiles, jt as createDesktopLifecycleReader, k as inspectBundleArtifact, kt as recordOwnerId, l as persistentExtensionPackageIdentity, lt as validateMemberUpdate, m as writePersistentExtensionActivation, mt as arkmePickedFileKind, o as persistentArkmeExtensionRuntimeState, ot as applyMemberUpdate, p as repairPersistentExtensionInstallation, pt as arkmeNormalizedFileMimeType, q as arkmeIsGenericLinkMetadataTitle, r as deactivatePersistentArkmeExtension, s as materializePersistentExtensionBundle, st as cachedMemberItem, t as activatePersistentArkmeExtension, u as quarantinePersistentExtension, ut as ARKME_RUNTIME_INSTANCE_ID, v as arkmeClientContentDigestFromSource, vt as ArkmeDirectMessageAdmissionError, w as ARKME_NATIVE_BUNDLE_ARTIFACT_KIND, wt as recordingImportFileNameKey, x as verifyNativeBundleResolutionSignature, xt as recordingImportFileKind, y as verifyBundleResolutionSignature, yt as isRecordingInstantOnOrAfterUnixEpoch, z as ARKME_EXTENSION_FORMAT } from "./persistent-runtime-CXd9RuRR.js";
2
2
  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-y7wzJLOx.js";
3
3
  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-DLXDyohJ.js";
4
4
  import { i as invokeArkmeBundle, n as arkmeBundleActive, r as deactivateArkmeBundle } from "./bundle-runtime-CE73h3vS.js";
@@ -148,6 +148,7 @@ const ARKME_HARNESS_MODEL_CLIENT_PATH = "/arkme-self/harness-model-client.js";
148
148
  const ARKME_HARNESS_ONBOARDING_CLIENT_PATH = "/arkme-self/harness-onboarding-client.js";
149
149
  const ARKME_HARNESS_TRAJECTORY_CLIENT_PATH = "/arkme-self/harness-trajectory-client.js";
150
150
  const ARKME_HARNESS_SIDEBAR_CLIENT_PATH = "/arkme-self/harness-sidebar-client.js";
151
+ const ARKME_NATIVE_SELECTION_CLIENT_PATH = "/arkme-self/harness-native-selection-client.js";
151
152
  //#endregion
152
153
  //#region src/plugin-update-policy.ts
153
154
  const PLUGIN_UPDATE_TERMINAL_STATE_TTL_MS = 10 * 6e4;
@@ -10481,103 +10482,6 @@ function createOpenClawFileSecretStore(options) {
10481
10482
  };
10482
10483
  }
10483
10484
  //#endregion
10484
- //#region src/dsh-agent-input-sync.ts
10485
- function sessionEventSource(value) {
10486
- return value !== null && typeof value === "object" && typeof value.on === "function" ? value : void 0;
10487
- }
10488
- function objectValue$2(value) {
10489
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
10490
- }
10491
- function stringValue(value) {
10492
- return typeof value === "string" ? value : "";
10493
- }
10494
- function numberValue(value) {
10495
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
10496
- }
10497
- function stableRecordUid(namespace, key) {
10498
- const bytes = createHash("sha256").update(`dsh-arkme:${namespace}:${key}`).digest().subarray(0, 16);
10499
- bytes[6] = (bytes[6] ?? 0) & 15 | 80;
10500
- bytes[8] = (bytes[8] ?? 0) & 63 | 128;
10501
- const hex = bytes.toString("hex");
10502
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
10503
- }
10504
- function dshAgentInputRecordUid(sessionId, eventSeq) {
10505
- return stableRecordUid("dsh-agent-input", `${sessionId}\0${String(eventSeq)}`);
10506
- }
10507
- function dshAgentInputTextFromEvent(event) {
10508
- const envelope = objectValue$2(event);
10509
- if (envelope.type !== "user/message") return void 0;
10510
- const data = objectValue$2(envelope.data);
10511
- if (objectValue$2(data.source).kind !== "user") return void 0;
10512
- const text = (Array.isArray(data.content) ? data.content : []).map((block) => {
10513
- const item = objectValue$2(block);
10514
- return item.type === "text" ? stringValue(item.text).trim() : "";
10515
- }).filter(Boolean).join("\n").trim();
10516
- return text === "" ? void 0 : text;
10517
- }
10518
- function registerDSHAgentInputRecordSync(ctx, service, options = {}) {
10519
- const logger = options.logger ?? ctx.logger;
10520
- const maxAttempts = Math.max(1, Math.trunc(options.maxAttempts ?? 3));
10521
- const retryDelayMillis = Math.max(0, Math.trunc(options.retryDelayMillis ?? 5e3));
10522
- const inFlight = /* @__PURE__ */ new Set();
10523
- const synced = /* @__PURE__ */ new Set();
10524
- const timers = /* @__PURE__ */ new Set();
10525
- let disposed = false;
10526
- const sync = (key, recordUid, text, sendAtMillis, attempt) => {
10527
- inFlight.add(key);
10528
- let retrying = false;
10529
- service.createDSHAgentInputText(recordUid, text, sendAtMillis).then(() => {
10530
- if (disposed) return;
10531
- synced.add(key);
10532
- }).catch((error) => {
10533
- if (disposed) return;
10534
- if (attempt < maxAttempts) {
10535
- retrying = true;
10536
- const timer = setTimeout(() => {
10537
- timers.delete(timer);
10538
- if (disposed) {
10539
- inFlight.delete(key);
10540
- return;
10541
- }
10542
- sync(key, recordUid, text, sendAtMillis, attempt + 1);
10543
- }, retryDelayMillis);
10544
- timers.add(timer);
10545
- return;
10546
- }
10547
- const message = error instanceof Error && error.message.trim() !== "" ? error.message : String(error);
10548
- logger.warn(`dsh-arkme: failed to sync DSH Agent input record: ${message}`);
10549
- }).finally(() => {
10550
- if (!retrying || disposed) inFlight.delete(key);
10551
- });
10552
- };
10553
- const listener = (rawSession, rawEvent) => {
10554
- if (disposed) return;
10555
- const event = objectValue$2(rawEvent);
10556
- const sessionId = stringValue(objectValue$2(rawSession).id).trim();
10557
- const eventSeq = Math.trunc(numberValue(event.seq));
10558
- if (sessionId === "" || eventSeq < 0) return;
10559
- const text = dshAgentInputTextFromEvent(event);
10560
- if (text === void 0) return;
10561
- const key = `${sessionId}\0${String(eventSeq)}`;
10562
- if (inFlight.has(key) || synced.has(key)) return;
10563
- sync(key, dshAgentInputRecordUid(sessionId, eventSeq), text, numberValue(event.time), 1);
10564
- };
10565
- ctx.effect(() => {
10566
- const source = sessionEventSource(ctx);
10567
- if (source === void 0) {
10568
- logger.warn("dsh-arkme: DSH session/event API is unavailable; DSH Agent input sync disabled");
10569
- return () => {};
10570
- }
10571
- const dispose = source.on("session/event", listener, { global: true });
10572
- return () => {
10573
- disposed = true;
10574
- dispose();
10575
- for (const timer of timers) clearTimeout(timer);
10576
- timers.clear();
10577
- };
10578
- }, "dsh-arkme: DSH Agent input record sync");
10579
- }
10580
- //#endregion
10581
10485
  //#region src/directory-reader.ts
10582
10486
  /** Transport-neutral dispatch only: each business owner keeps its own projection and credentials. */
10583
10487
  function readDirectoryPage(service, teams, section, options = {}) {
@@ -11825,6 +11729,7 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
11825
11729
  case "source.interwoven-detail": return await service.interwovenMomentDetail(requiredInterwovenParam(params, "sourceRef"), requiredInterwovenParam(params, "momentRef"));
11826
11730
  case "source.related-quick-notes.from-message": return await service.relatedQuickNotesFromMessage(requiredRelatedQuickNoteParam(params, "sourceRef"), requiredRelatedQuickNoteParam(params, "messageActionRef", MAX_MESSAGE_ACTION_REF_CHARS), requestSignal);
11827
11731
  case "source.related-quick-notes.from-moment": return await service.relatedQuickNotesFromMoment(requiredRelatedQuickNoteParam(params, "sourceRef"), requiredRelatedQuickNoteParam(params, "momentRef"), requestSignal);
11732
+ case "source.record-edit-history": return await service.recordEditHistoryPage(stringParam(params, "sourceRef"), stringParam(params, "messageActionRef"), numberParam(params, "cursorEditAt", 0), requestSignal);
11828
11733
  case "source.related-quick-note.detail": return await service.relatedQuickNoteDetail(requiredRelatedQuickNoteParam(params, "sourceRef"), requiredRelatedQuickNoteParam(params, "relatedRef"), requestSignal);
11829
11734
  case "source.message-preparing.report":
11830
11735
  case "source.message-preparing.cancel": {
@@ -12559,7 +12464,8 @@ function createHarnessEmbedRouteHandler(options) {
12559
12464
  projectedGraph.rev = shortHash(`${projectedGraph.rev}:${rev}`);
12560
12465
  }
12561
12466
  let html = replaceHarnessBootGraph(await options.readRootHtml(request), fullGraph, projectedGraph);
12562
- if (options.sessionClient !== void 0) {
12467
+ if (options.selectionClientRevision && /^[a-f0-9]+$/.test(options.selectionClientRevision)) html = html.replace("</head>", `<meta name="arkme-native-selection" content="/arkme-self/harness-native-selection-client.js?rev=${options.selectionClientRevision}"></head>`);
12468
+ if (options.sessionClient?.apiPath !== void 0) {
12563
12469
  const apiPath = options.sessionClient.apiPath;
12564
12470
  if (!/^\/[A-Za-z0-9/_-]+$/.test(apiPath) || !html.includes("</head>")) throw new Error("harness session observer configuration is invalid");
12565
12471
  html = html.replace("</head>", `<meta name="arkme-session-api" content="${apiPath}"></head>`);
@@ -16596,10 +16502,9 @@ async function parseHttpError(response) {
16596
16502
  }
16597
16503
  function requestImageAttachments(options) {
16598
16504
  const result = [];
16599
- for (const message of options.messages) {
16600
- if (message.role !== "user") continue;
16601
- for (const block of message.content) if (block.type === "image") result.push(block.attachment);
16602
- }
16505
+ for (const message of options.messages) if (message.role === "system") assertTextOnly(message.content, "系统消息");
16506
+ else if (message.role === "assistant") assertAssistantBlocks(message.content);
16507
+ else for (const block of userContentLeaves(message.content)) if (block.type === "image") result.push(block.attachment);
16603
16508
  return result;
16604
16509
  }
16605
16510
  function inputAssetOwnerAttachmentScope(bearer, attachment) {
@@ -16633,15 +16538,11 @@ function assertTextOnly(blocks, location) {
16633
16538
  function assertAssistantBlocks(blocks) {
16634
16539
  for (const block of blocks) if (block.type !== "text" && block.type !== "reasoning" && block.type !== "tool-call") throw new LlmError(`助手消息不支持内容类型“${block.type}”`, "UNSUPPORTED_CONTENT");
16635
16540
  }
16636
- function assertUserBlocks(blocks) {
16637
- for (const block of blocks) {
16638
- if (block.type === "text" || block.type === "image") continue;
16639
- if (block.type === "tool-result") {
16640
- assertTextOnly(block.content, "工具结果");
16641
- continue;
16642
- }
16643
- throw new LlmError(`用户消息不支持内容类型“${block.type}”`, "UNSUPPORTED_CONTENT");
16644
- }
16541
+ /** One traversal for validation, image accounting and tool-result serialization. */
16542
+ function* userContentLeaves(blocks) {
16543
+ for (const block of blocks) if (block.type === "text" || block.type === "image") yield block;
16544
+ else if (block.type === "tool-result") yield* userContentLeaves(block.content);
16545
+ else throw new LlmError(`用户或工具结果不支持内容类型“${block.type}”`, "UNSUPPORTED_CONTENT");
16645
16546
  }
16646
16547
  function limitConcurrency(maximum, operation, signal) {
16647
16548
  let active = 0;
@@ -16706,47 +16607,78 @@ function serializeAssistant(message) {
16706
16607
  };
16707
16608
  }
16708
16609
  async function serializeMessages(messages, resolveImage, signal) {
16709
- for (const message of messages) if (message.role === "system") assertTextOnly(message.content, "系统消息");
16710
- else if (message.role === "assistant") assertAssistantBlocks(message.content);
16711
- else assertUserBlocks(message.content);
16712
16610
  const resolveImageLimited = limitConcurrency(MAX_CONCURRENT_INPUT_ASSET_UPLOADS, resolveImage, signal);
16713
- return (await Promise.all(messages.map(async (message) => {
16714
- if (message.role === "system") return [{
16715
- role: "system",
16716
- content: flattenText(message.content)
16717
- }];
16718
- if (message.role === "assistant") return [serializeAssistant(message)];
16611
+ const contentParts = async (blocks) => (await Promise.all(Array.from(userContentLeaves(blocks), async (block) => block.type === "text" ? {
16612
+ type: "text",
16613
+ text: block.text
16614
+ } : {
16615
+ type: "image_asset",
16616
+ asset_ref: await resolveImageLimited(block.attachment)
16617
+ }))).filter((part) => part.type !== "text" || part.text.length > 0);
16618
+ const groups = await Promise.all(messages.map(async (message) => {
16619
+ if (message.role === "system") return {
16620
+ regular: {
16621
+ role: "system",
16622
+ content: flattenText(message.content)
16623
+ },
16624
+ tools: [],
16625
+ toolImages: []
16626
+ };
16627
+ if (message.role === "assistant") return {
16628
+ regular: serializeAssistant(message),
16629
+ tools: [],
16630
+ toolImages: []
16631
+ };
16719
16632
  const toolResults = message.content.filter((block) => block.type === "tool-result");
16720
- const parts = (await Promise.all(message.content.map(async (block) => {
16721
- if (block.type === "text") return block.text.length === 0 ? void 0 : {
16722
- type: "text",
16723
- text: block.text
16724
- };
16725
- if (block.type === "image") return {
16726
- type: "image_asset",
16727
- asset_ref: await resolveImageLimited(block.attachment)
16728
- };
16729
- }))).filter((part) => part !== void 0);
16730
- const wire = [];
16731
- if (parts.length > 0 || toolResults.length === 0) if (parts.length === 0) wire.push({
16633
+ const [parts, results] = await Promise.all([contentParts(message.content.filter((block) => block.type !== "tool-result")), Promise.all(toolResults.map(async (result) => ({
16634
+ result,
16635
+ parts: await contentParts(result.content)
16636
+ })))]);
16637
+ let regular;
16638
+ if (parts.length > 0 || toolResults.length === 0) regular = {
16732
16639
  role: "user",
16733
- content: ""
16734
- });
16735
- else if (parts.every((part) => part.type === "text")) wire.push({
16736
- role: "user",
16737
- content: parts.map((part) => part.type === "text" ? part.text : "").join("")
16738
- });
16739
- else wire.push({
16640
+ content: parts.every((part) => part.type === "text") ? parts.map((part) => part.type === "text" ? part.text : "").join("") : parts
16641
+ };
16642
+ const tools = [];
16643
+ const toolImages = [];
16644
+ for (const { result, parts: resultParts } of results) {
16645
+ tools.push({
16646
+ role: "tool",
16647
+ tool_call_id: String(result.toolCallId),
16648
+ content: resultParts.map((part) => part.type === "text" ? part.text : "").join("") || "(no output)"
16649
+ });
16650
+ const images = resultParts.filter((part) => part.type === "image_asset");
16651
+ if (images.length > 0) toolImages.push({
16652
+ type: "text",
16653
+ text: `Images from tool call ${String(result.toolCallId)}:`
16654
+ }, ...images);
16655
+ }
16656
+ return {
16657
+ ...regular === void 0 ? {} : { regular },
16658
+ tools,
16659
+ toolImages
16660
+ };
16661
+ }));
16662
+ const wire = [];
16663
+ let pendingToolImages = [];
16664
+ const flushToolImages = () => {
16665
+ if (pendingToolImages.length === 0) return;
16666
+ wire.push({
16740
16667
  role: "user",
16741
- content: parts
16742
- });
16743
- for (const result of toolResults) wire.push({
16744
- role: "tool",
16745
- tool_call_id: String(result.toolCallId),
16746
- content: flattenText(result.content) || "(no output)"
16668
+ content: pendingToolImages
16747
16669
  });
16748
- return wire;
16749
- }))).flat();
16670
+ pendingToolImages = [];
16671
+ };
16672
+ for (const group of groups) {
16673
+ if (group.regular !== void 0) {
16674
+ flushToolImages();
16675
+ wire.push(group.regular);
16676
+ }
16677
+ wire.push(...group.tools);
16678
+ pendingToolImages.push(...group.toolImages);
16679
+ }
16680
+ flushToolImages();
16681
+ return wire;
16750
16682
  }
16751
16683
  async function serializeRequest(options, resolveImage, signal) {
16752
16684
  const messages = [];
@@ -17354,6 +17286,10 @@ function managedAiLocalizedFailure(facts) {
17354
17286
  code: facts.code,
17355
17287
  message: "无法读取历史图片,请检查本地附件存储后重试"
17356
17288
  };
17289
+ if (facts.code === "UNSUPPORTED_CONTENT") return {
17290
+ code: facts.code,
17291
+ message: "当前模型或图片服务不支持这类内容,请检查模型选择和附件后重试"
17292
+ };
17357
17293
  if (facts.code === "CONTEXT_WINDOW_EXCEEDED") return {
17358
17294
  code: facts.code,
17359
17295
  message: "对话内容过长,请新建对话或减少上下文后重试"
@@ -36514,7 +36450,7 @@ function apply(ctx, config) {
36514
36450
  ...config,
36515
36451
  fileStateDirectory: join(stateDirectory, "files"),
36516
36452
  recordingImportDirectory: join(stateDirectory, "recording-imports")
36517
- }, sessionStore, localDatabase, fetch, pendingSessionStore);
36453
+ }, sessionStore, localDatabase, fetch, pendingSessionStore, void 0, void 0, void 0, () => ctx.get("sessionQuery"));
36518
36454
  const openApiMcpCredentialNamespace = `${config.keychainServicePrefix}.${config.environment}.openapi-mcp`;
36519
36455
  const openApiMcpController = new ManagedOpenApiMcpController({
36520
36456
  mountMcp: config.openApiMcpEnabled,
@@ -36887,11 +36823,11 @@ function apply(ctx, config) {
36887
36823
  expectedPort: ctx.webServer.port,
36888
36824
  allowNonLoopback: config.allowNonLoopback
36889
36825
  });
36890
- const sessionClient = config.dshRemoteFeatureEnabled ? {
36826
+ const sessionClient = {
36891
36827
  source: readFileSync(new URL("../lib/harness-session-client.js", import.meta.url)),
36892
- apiPath: config.routePath
36893
- } : void 0;
36894
- if (sessionClient !== void 0) ctx.effect(() => ctx.webServer.register({
36828
+ ...config.dshRemoteFeatureEnabled ? { apiPath: config.routePath } : {}
36829
+ };
36830
+ ctx.effect(() => ctx.webServer.register({
36895
36831
  kind: "exact",
36896
36832
  path: HARNESS_SESSION_CLIENT_PATH,
36897
36833
  handler: (_request, response) => {
@@ -36906,6 +36842,24 @@ function apply(ctx, config) {
36906
36842
  const harnessOnboardingClient = readFileSync(new URL("../lib/harness-onboarding-client.js", import.meta.url));
36907
36843
  const harnessTrajectoryClient = readFileSync(new URL("../lib/harness-trajectory-client.js", import.meta.url));
36908
36844
  const harnessSidebarClient = readFileSync(new URL("../lib/harness-sidebar-client.js", import.meta.url));
36845
+ let selectionClientRevision;
36846
+ try {
36847
+ const selectionClient = readFileSync(new URL("../lib/harness-native-selection-client.js", import.meta.url));
36848
+ selectionClientRevision = createHash("sha256").update(selectionClient).digest("hex");
36849
+ ctx.effect(() => ctx.webServer.register({
36850
+ kind: "exact",
36851
+ path: ARKME_NATIVE_SELECTION_CLIENT_PATH,
36852
+ handler: (_request, response) => {
36853
+ response.writeHead(200, {
36854
+ "Content-Type": "application/javascript",
36855
+ "Cache-Control": "no-cache"
36856
+ });
36857
+ response.end(selectionClient);
36858
+ }
36859
+ }), "arkme: optional native selection asset");
36860
+ } catch {
36861
+ ctx.logger.warn("dsh-arkme: optional native selection asset unavailable");
36862
+ }
36909
36863
  ctx.effect(() => ctx.webServer.register({
36910
36864
  kind: "exact",
36911
36865
  path: ARKME_HARNESS_SIDEBAR_CLIENT_PATH,
@@ -36940,6 +36894,7 @@ function apply(ctx, config) {
36940
36894
  }
36941
36895
  }), "arkme: Harness onboarding bridge asset");
36942
36896
  const harnessEmbedHandler = createHarnessEmbedRouteHandler({
36897
+ ...selectionClientRevision === void 0 ? {} : { selectionClientRevision },
36943
36898
  sidebarClient: {
36944
36899
  id: "@senguoyun/dsh-arkme/harness-sidebar",
36945
36900
  url: ARKME_HARNESS_SIDEBAR_CLIENT_PATH,
@@ -36956,10 +36911,10 @@ function apply(ctx, config) {
36956
36911
  rev: createHash("sha256").update(harnessOnboardingClient).digest("hex"),
36957
36912
  external: ["react"]
36958
36913
  },
36959
- ...sessionClient === void 0 ? {} : { sessionClient: {
36914
+ sessionClient: {
36960
36915
  revision: createHash("sha256").update(sessionClient.source).digest("hex").slice(0, 12),
36961
- apiPath: sessionClient.apiPath
36962
- } },
36916
+ ..."apiPath" in sessionClient ? { apiPath: sessionClient.apiPath } : {}
36917
+ },
36963
36918
  modelClient: {
36964
36919
  id: "@senguoyun/dsh-arkme/harness-model",
36965
36920
  url: ARKME_HARNESS_MODEL_CLIENT_PATH,
@@ -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-DqPfc6RO.js";
1
+ import { a as persistentArkmeExtensionActive, i as invokePersistentArkmeExtension, n as applyPersistentArkmeHostExtension, o as persistentArkmeExtensionRuntimeState, r as deactivatePersistentArkmeExtension, t as activatePersistentArkmeExtension } from "./persistent-runtime-CXd9RuRR.js";
2
2
  export { activatePersistentArkmeExtension, applyPersistentArkmeHostExtension, deactivatePersistentArkmeExtension, invokePersistentArkmeExtension, persistentArkmeExtensionActive, persistentArkmeExtensionRuntimeState };