@vibe-lark/larkpal 0.1.86 → 0.1.87

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 (208) hide show
  1. package/dist/account-id-BM1T6029-BzQ_cMoi.mjs +1 -0
  2. package/dist/activation-context--5yu1dPF-XV0Y0pTy.mjs +1 -0
  3. package/dist/anthropic-CFZUCb1w.mjs +39 -0
  4. package/dist/assistant-visible-text-DuFWokAt-BOJV_zwc.mjs +9 -0
  5. package/dist/azure-openai-responses-BEuiMaF-.mjs +1 -0
  6. package/dist/boundary-file-read-BSd9MXPy-gnNVhPKT.mjs +1 -0
  7. package/dist/browser-lifecycle-cleanup-BdNsMhMD-BM97qA_M.mjs +1 -0
  8. package/dist/build-Bkj0hOS2.mjs +3 -0
  9. package/dist/bundled-compat-BpaDaAAu-DJtrIX6i.mjs +27 -0
  10. package/dist/bundled-dir-U738ay4K-BxbzrJOo.mjs +1 -0
  11. package/dist/call-DimWbpgJ-B4pv55RH.mjs +20 -0
  12. package/dist/channel-bootstrap.runtime-BVclcGv1-CEZ0-JP9.mjs +1 -0
  13. package/dist/channel-bootstrap.runtime-Cwcr38m2-Dt6QlQkX.mjs +1 -0
  14. package/dist/chunk-DHbaKqs-.mjs +1 -0
  15. package/dist/cli.mjs +7 -92
  16. package/dist/command-format-LSnUCVVF-Dn4h9IOh.mjs +16 -0
  17. package/dist/config-Bim2pi8a-03N-28sw.mjs +1 -0
  18. package/dist/delivery-context.shared-j5hC5qb1-BSLQG47q.mjs +1 -0
  19. package/dist/diagnostic-ClMwNnUA-BMKvPQJT.mjs +1 -0
  20. package/dist/dist-J5UB83Ws.mjs +601 -0
  21. package/dist/dist-coestTs9.mjs +5 -0
  22. package/dist/env-api-keys-Cuz5irWW.mjs +1 -0
  23. package/dist/event-stream-B7Ei41Bu.mjs +1 -0
  24. package/dist/facade-loader-DFzIYYt_-4bzFvy-b.mjs +1 -0
  25. package/dist/from-Ba69_5cR.mjs +14 -0
  26. package/dist/gateway-method-policy-C7rf0SeV-CTJcMQCE.mjs +1 -0
  27. package/dist/github-copilot-headers-BfhryVuU.mjs +1 -0
  28. package/dist/google-ABo-1guT.mjs +1 -0
  29. package/dist/google-gemini-cli-CGlN1zUA.mjs +2 -0
  30. package/dist/google-shared-C60sNhwd.mjs +301 -0
  31. package/dist/google-vertex-De0nAItu.mjs +1 -0
  32. package/dist/hash-Dw-N8Y9l.mjs +1 -0
  33. package/dist/headers-Bpsp70B9.mjs +1 -0
  34. package/dist/home-dir-C44RaPME-B5iLWwCq.mjs +1 -0
  35. package/dist/ids-BPsM98Uu-CJBJAeVC.mjs +1 -0
  36. package/dist/image-2w3cApg7-CrpUMCvm.mjs +3 -0
  37. package/dist/interactive-init-C5MFL5MW.mjs +8 -0
  38. package/dist/io-CH2g3vsv-JJtUIa_U.mjs +10 -0
  39. package/dist/jiti-loader-cache-Bat69wam-DNIteTtO.mjs +9 -0
  40. package/dist/json-file-BQRNuxmK-hRjIgOXI.mjs +1 -0
  41. package/dist/json-parse-BESd8UAM.mjs +3 -0
  42. package/dist/jws-YaZ38F_i.mjs +12 -0
  43. package/dist/lark-cli-provider-BLMxH6CN.mjs +4 -0
  44. package/dist/lark-logger-xpMKNNtY.mjs +1 -0
  45. package/dist/live-smoke-DpURW676.mjs +33 -0
  46. package/dist/load-context-mb7uvLSn-3xYwSnOZ.mjs +1 -0
  47. package/dist/loader-708jrx4Y-BbJRXNlQ.mjs +4 -0
  48. package/dist/main.mjs +153 -74571
  49. package/dist/manifest-registry-_hxKCS2K-OL8KK_o4.mjs +15 -0
  50. package/dist/mcp-server.mjs +4 -527
  51. package/dist/message-channel-Bk_YHfQg-n2Hw2Y0L.mjs +1 -0
  52. package/dist/message-channel-core-DTA--Gjh-CIh10vfo.mjs +1 -0
  53. package/dist/message.config.runtime-K-k4XOyq-F_h0Cgkl.mjs +1 -0
  54. package/dist/message.gateway.runtime-DqHOHRTQ-ge4c5p4s.mjs +1 -0
  55. package/dist/mistral-DyL3Zo1b.mjs +7 -0
  56. package/dist/model-auth-env-oyg2Hexc-DJbt9J3o.mjs +1 -0
  57. package/dist/models-config-BmpSQJQF-BL6S5qAo.mjs +1 -0
  58. package/dist/models-config.runtime-SOhLEw-f.mjs +1 -0
  59. package/dist/multipart-parser-B9dwXBqu.mjs +2 -0
  60. package/dist/oauth-25y2wc7K.mjs +75 -0
  61. package/dist/openai-C-rgGb7X.mjs +16 -0
  62. package/dist/openai-codex-responses-BbyAPsP1.mjs +7 -0
  63. package/dist/openai-completions-Bu5qvQzb.mjs +5 -0
  64. package/dist/openai-responses-pIdwQBc4.mjs +1 -0
  65. package/dist/openai-responses-shared-DqW1JSux.mjs +10 -0
  66. package/dist/paths-D6msg0S1-BO4XgM1u.mjs +1 -0
  67. package/dist/paths-D92DjaZ--DdtJ-zYp.mjs +1 -0
  68. package/dist/pi-model-discovery-Bd0TWzo8-DvSM0eWu.mjs +1 -0
  69. package/dist/pi-model-discovery-runtime-PrjWOmsV.mjs +1 -0
  70. package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-WPxU5oNX.mjs +2 -0
  71. package/dist/plugin-auto-enable-DdH3n9V8-Dr_bUXkG.mjs +1 -0
  72. package/dist/process-scoped-map-B2cWkYET-Co-i-MXA.mjs +1 -0
  73. package/dist/provider-discovery.runtime-DY0VWQ81.mjs +1 -0
  74. package/dist/provider-model-compat-CFqcq0it-BUwZENrz.mjs +1 -0
  75. package/dist/provider-runtime-C8rljsNs-BDvu6FW3.mjs +1 -0
  76. package/dist/provider-runtime-CT50mNIX-DImw7ZZu.mjs +79 -0
  77. package/dist/provider-stream-COLujAAo-Dpq1DSIk.mjs +248 -0
  78. package/dist/providers.runtime-Ba7tOlq7-B4t6ywCr.mjs +1 -0
  79. package/dist/public-surface-loader-BVl0NQAE-TfJ3izj1.mjs +1 -0
  80. package/dist/resolve-C33B7eeu-DZM_z6Wr.mjs +1 -0
  81. package/dist/runtime-Cym-fqI8-1GOIuRRQ.mjs +1 -0
  82. package/dist/runtime-channel-state-CohMybAh-BBzhl07Q.mjs +1 -0
  83. package/dist/runtime-snapshot-C54O1-gI-DxusscPf.mjs +1 -0
  84. package/dist/runtime-state-IBOIXKOx-Cw1GA1td.mjs +1 -0
  85. package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BsYE2gOd.mjs +1 -0
  86. package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-P6MKP9gQ.mjs +1 -0
  87. package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-5VoyjouO.mjs +1 -0
  88. package/dist/session-archive.runtime-B52_5vs4-cU2tYbBz.mjs +1 -0
  89. package/dist/session-key-Cn2QoOyX-QZeYmbxd.mjs +1 -0
  90. package/dist/session-transcript-files.fs-DEeFXruQ-CXIAFSsr.mjs +1 -0
  91. package/dist/src-CCDx_C-U.mjs +3 -0
  92. package/dist/src-DACmA9V6.mjs +5 -0
  93. package/dist/subagent-announce-L5WsQatW--rMn240x.mjs +2 -0
  94. package/dist/subagent-announce.registry.runtime-DiqZyeTs-DNfNHsls.mjs +1 -0
  95. package/dist/subagent-registry-steer-runtime-DFgZFC0j-XYS1_qwl.mjs +1 -0
  96. package/dist/subagent-system-prompt-C1qnN--K-CsU4f97T.mjs +23 -0
  97. package/dist/target-parsing-loaded-DKkb6jJY-B830OA1a.mjs +12 -0
  98. package/dist/task-registry-delivery-runtime-Dd1CUkZF-B2Hj2k8C.mjs +16 -0
  99. package/dist/task-registry-delivery-runtime-ragbeVx5-Bdvo2Q5u.mjs +1 -0
  100. package/dist/thinking-Bh-7MqXz-uApNUe6g.mjs +1 -0
  101. package/dist/transcript-E_-ISOkD-VTwb782D.mjs +5 -0
  102. package/dist/transcript.runtime-BqhvZZdl-B4E0TiX5.mjs +1 -0
  103. package/dist/transform-messages-BTA3xbAI.mjs +1 -0
  104. package/dist/web-provider-public-artifacts-BlpRwIUS-DbVhDOrY.mjs +1 -0
  105. package/dist/web-search-providers.runtime--0aUtC3b-Bjh4Bmrz.mjs +1 -0
  106. package/package.json +2 -3
  107. package/dist/account-id-BM1T6029-DYjVxojW.mjs +0 -46
  108. package/dist/activation-context--5yu1dPF-Bwsn3moT.mjs +0 -172
  109. package/dist/anthropic-TH8ERTXK.mjs +0 -5962
  110. package/dist/assistant-visible-text-DuFWokAt-CsbII5KS.mjs +0 -596
  111. package/dist/azure-openai-responses-Bt_Ag9Er.mjs +0 -166
  112. package/dist/boundary-file-read-BSd9MXPy--KThL5e6.mjs +0 -594
  113. package/dist/browser-lifecycle-cleanup-BdNsMhMD-O3tnAM4i.mjs +0 -60
  114. package/dist/build-DgTrEpge.mjs +0 -3333
  115. package/dist/bundled-compat-BpaDaAAu-D7oazKjD.mjs +0 -5216
  116. package/dist/bundled-dir-U738ay4K-DXK0q_TV.mjs +0 -258
  117. package/dist/call-DimWbpgJ-ColD4W-y.mjs +0 -9993
  118. package/dist/channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs +0 -2
  119. package/dist/channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs +0 -33
  120. package/dist/chunk-D6SyT4dJ.mjs +0 -36
  121. package/dist/command-format-LSnUCVVF-BQ2SMKka.mjs +0 -685
  122. package/dist/config-Bim2pi8a-BQUdfiEi.mjs +0 -9
  123. package/dist/delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs +0 -72
  124. package/dist/diagnostic-ClMwNnUA-D6nUtLnb.mjs +0 -140
  125. package/dist/dist-CEGw8-2W.mjs +0 -429
  126. package/dist/dist-DD2aJ2UL.mjs +0 -125135
  127. package/dist/env-api-keys-BVvSg7T2.mjs +0 -68
  128. package/dist/event-stream-xaQWmyas.mjs +0 -15226
  129. package/dist/facade-loader-DFzIYYt_-CIr4HKtE.mjs +0 -194
  130. package/dist/from-DF7cl2wz.mjs +0 -3842
  131. package/dist/gateway-method-policy-C7rf0SeV-CJQMEYIE.mjs +0 -28
  132. package/dist/github-copilot-headers-DjqWtUoP.mjs +0 -22
  133. package/dist/google-C2pVrgBZ.mjs +0 -336
  134. package/dist/google-gemini-cli-BBxgS5Ho.mjs +0 -623
  135. package/dist/google-shared-BsWgwEk1.mjs +0 -22791
  136. package/dist/google-vertex-BsVLJrrC.mjs +0 -358
  137. package/dist/hash-DAFtW_W7.mjs +0 -16
  138. package/dist/headers-R3HdCbAE.mjs +0 -8
  139. package/dist/home-dir-C44RaPME-CBRS4HLP.mjs +0 -93
  140. package/dist/ids-BPsM98Uu-CwuxvUai.mjs +0 -77
  141. package/dist/image-2w3cApg7-CxpHvoB5.mjs +0 -207
  142. package/dist/interactive-init-BXQBalNr.mjs +0 -450
  143. package/dist/io-CH2g3vsv-BOGlLlB8.mjs +0 -26218
  144. package/dist/jiti-loader-cache-Bat69wam-D6hCxboy.mjs +0 -5049
  145. package/dist/json-file-BQRNuxmK-DhJM5NsG.mjs +0 -108
  146. package/dist/json-parse-v_HIJjjI.mjs +0 -381
  147. package/dist/jws-GFcTvvVT.mjs +0 -2291
  148. package/dist/lark-cli-provider-BARgbbmo.mjs +0 -554
  149. package/dist/lark-logger-D7_pEVQc.mjs +0 -143
  150. package/dist/live-smoke-BhkBOcH9.mjs +0 -7135
  151. package/dist/load-context-mb7uvLSn-B10MAi3I.mjs +0 -29
  152. package/dist/loader-708jrx4Y-BOswuvpe.mjs +0 -5053
  153. package/dist/manifest-registry-_hxKCS2K-CZdeyN0f.mjs +0 -3512
  154. package/dist/message-channel-Bk_YHfQg-AeNrPPpp.mjs +0 -50
  155. package/dist/message-channel-core-DTA--Gjh-CY4Tkb7N.mjs +0 -29
  156. package/dist/message.config.runtime-K-k4XOyq-DZTmXomP.mjs +0 -2
  157. package/dist/message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs +0 -2
  158. package/dist/mistral-CaR4DiLu.mjs +0 -28657
  159. package/dist/model-auth-env-oyg2Hexc-DU_rOUU5.mjs +0 -1306
  160. package/dist/models-config-BmpSQJQF-Gfvh1n3A.mjs +0 -1282
  161. package/dist/models-config.runtime-BsU_22xk.mjs +0 -2
  162. package/dist/multipart-parser-DedmaB5g.mjs +0 -294
  163. package/dist/oauth-DOJeGfcE.mjs +0 -6392
  164. package/dist/openai-BDtIh3Ja.mjs +0 -6693
  165. package/dist/openai-codex-responses-C5EORu31.mjs +0 -664
  166. package/dist/openai-completions-CR_cS6gX.mjs +0 -669
  167. package/dist/openai-responses-oGxwZyuC.mjs +0 -184
  168. package/dist/openai-responses-shared-BixMSDZE.mjs +0 -398
  169. package/dist/paths-D6msg0S1-C2lYuisN.mjs +0 -189
  170. package/dist/paths-D92DjaZ--CTOESW2b.mjs +0 -192
  171. package/dist/pi-model-discovery-Bd0TWzo8-BFsJmeMb.mjs +0 -227
  172. package/dist/pi-model-discovery-runtime-CCCZxkd8.mjs +0 -2
  173. package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-C5ewk8kK.mjs +0 -399
  174. package/dist/plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs +0 -1456
  175. package/dist/process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs +0 -61
  176. package/dist/provider-discovery.runtime-BPzz1PFj.mjs +0 -58
  177. package/dist/provider-model-compat-CFqcq0it-BDDuBI3A.mjs +0 -118
  178. package/dist/provider-runtime-C8rljsNs-CIT93zoy.mjs +0 -2
  179. package/dist/provider-runtime-CT50mNIX-BwEV6GyO.mjs +0 -573
  180. package/dist/provider-stream-COLujAAo-CbJPDngm.mjs +0 -35449
  181. package/dist/providers.runtime-Ba7tOlq7-CXkhkzU9.mjs +0 -219
  182. package/dist/public-surface-loader-BVl0NQAE-C0piXtsT.mjs +0 -117
  183. package/dist/resolve-C33B7eeu-BNvYTl6k.mjs +0 -1041
  184. package/dist/runtime-Cym-fqI8-DaSDMH-a.mjs +0 -120
  185. package/dist/runtime-channel-state-CohMybAh-hXR6y5Gx.mjs +0 -19
  186. package/dist/runtime-snapshot-C54O1-gI-40cbyi7P.mjs +0 -677
  187. package/dist/runtime-state-IBOIXKOx-Bf9tcLvc.mjs +0 -10
  188. package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BCVImm7a.mjs +0 -39
  189. package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-Cb4nJkRT.mjs +0 -2
  190. package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-BrQdXzOQ.mjs +0 -2
  191. package/dist/session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs +0 -2
  192. package/dist/session-key-Cn2QoOyX-CuHbJMgR.mjs +0 -82
  193. package/dist/session-transcript-files.fs-DEeFXruQ-B1PF6nLy.mjs +0 -147
  194. package/dist/src-BgCX0MLG.mjs +0 -813
  195. package/dist/src-DYbqlAqf.mjs +0 -1177
  196. package/dist/subagent-announce-L5WsQatW-CQWI9GMd.mjs +0 -344
  197. package/dist/subagent-announce.registry.runtime-DiqZyeTs-BKuniyi3.mjs +0 -28
  198. package/dist/subagent-registry-steer-runtime-DFgZFC0j-BhBz0roy.mjs +0 -211
  199. package/dist/subagent-system-prompt-C1qnN--K-DpnTFP47.mjs +0 -3061
  200. package/dist/target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs +0 -1002
  201. package/dist/task-registry-delivery-runtime-Dd1CUkZF-C8U40a3O.mjs +0 -2950
  202. package/dist/task-registry-delivery-runtime-ragbeVx5-CNbFAkjD.mjs +0 -2
  203. package/dist/thinking-Bh-7MqXz-D3woGbO7.mjs +0 -2
  204. package/dist/transcript-E_-ISOkD-DWCfZP2p.mjs +0 -2019
  205. package/dist/transcript.runtime-BqhvZZdl-BPy42vBP.mjs +0 -2
  206. package/dist/transform-messages-DbhIzTxq.mjs +0 -207
  207. package/dist/web-provider-public-artifacts-BlpRwIUS-CGPSV4W2.mjs +0 -295
  208. package/dist/web-search-providers.runtime--0aUtC3b-DyuhC95V.mjs +0 -200
@@ -1,2019 +0,0 @@
1
- import { c as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty, s as normalizeOptionalLowercaseString, u as normalizeStringifiedOptionalString } from "./home-dir-C44RaPME-CBRS4HLP.mjs";
2
- import { t as resolveBundledPluginsDir } from "./bundled-dir-U738ay4K-DXK0q_TV.mjs";
3
- import { O as parseDurationMs, a as parseByteSize, n as loadConfig } from "./io-CH2g3vsv-BOGlLlB8.mjs";
4
- import { Mt as formatErrorMessage, St as createSubsystemLogger, zt as normalizeChannelId } from "./bundled-compat-BpaDaAAu-D7oazKjD.mjs";
5
- import "./message-channel-Bk_YHfQg-AeNrPPpp.mjs";
6
- import { r as resolveLoaderPackageRoot, t as getCachedPluginJitiLoader } from "./jiti-loader-cache-Bat69wam-D6hCxboy.mjs";
7
- import { C as normalizeChannelId$1, t as getRuntimeConfigSnapshot, x as getLoadedChannelPlugin } from "./runtime-snapshot-C54O1-gI-40cbyi7P.mjs";
8
- import { n as getActivePluginChannelRegistryVersion } from "./runtime-Cym-fqI8-DaSDMH-a.mjs";
9
- import { c as parseThreadSessionSuffix } from "./session-key-Cn2QoOyX-CuHbJMgR.mjs";
10
- import "./config-Bim2pi8a-BQUdfiEi.mjs";
11
- import { c as isSessionArchiveArtifactName, n as resolveSessionFilePath, s as isPrimarySessionTranscriptFileName, t as resolveDefaultSessionStorePath } from "./paths-D6msg0S1-C2lYuisN.mjs";
12
- import { n as getProcessStartTime, r as isPidAlive, t as resolveProcessScopedMap } from "./process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs";
13
- import { i as normalizeSessionDeliveryFields } from "./delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs";
14
- import { a as resolveBundledFacadeModuleLocation, i as createFacadeResolutionKey$1, n as loadBundledPluginPublicSurfaceModuleSync$1, o as resolveCachedFacadeModuleLocation, r as loadFacadeModuleAtLocationSync$1 } from "./facade-loader-DFzIYYt_-CIr4HKtE.mjs";
15
- import { i as SessionManager } from "./dist-DD2aJ2UL.mjs";
16
- import { createRequire } from "node:module";
17
- import fs from "node:fs";
18
- import path from "node:path";
19
- import { fileURLToPath } from "node:url";
20
- import fs$1 from "node:fs/promises";
21
- import { randomUUID } from "node:crypto";
22
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/types-ASqeFakT.js
23
- function normalizeSessionRuntimeModelFields(entry) {
24
- const normalizedModel = normalizeOptionalString(entry.model);
25
- const normalizedProvider = normalizeOptionalString(entry.modelProvider);
26
- let next = entry;
27
- if (!normalizedModel) {
28
- if (entry.model !== void 0 || entry.modelProvider !== void 0) {
29
- next = { ...next };
30
- delete next.model;
31
- delete next.modelProvider;
32
- }
33
- return next;
34
- }
35
- if (entry.model !== normalizedModel) {
36
- if (next === entry) next = { ...next };
37
- next.model = normalizedModel;
38
- }
39
- if (!normalizedProvider) {
40
- if (entry.modelProvider !== void 0) {
41
- if (next === entry) next = { ...next };
42
- delete next.modelProvider;
43
- }
44
- return next;
45
- }
46
- if (entry.modelProvider !== normalizedProvider) {
47
- if (next === entry) next = { ...next };
48
- next.modelProvider = normalizedProvider;
49
- }
50
- return next;
51
- }
52
- //#endregion
53
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/session-write-lock-3uPK7XQA.js
54
- function isValidLockNumber(value) {
55
- return typeof value === "number" && Number.isInteger(value) && value >= 0;
56
- }
57
- const CLEANUP_SIGNALS = [
58
- "SIGINT",
59
- "SIGTERM",
60
- "SIGQUIT",
61
- "SIGABRT"
62
- ];
63
- const CLEANUP_STATE_KEY = Symbol.for("openclaw.sessionWriteLockCleanupState");
64
- const HELD_LOCKS_KEY = Symbol.for("openclaw.sessionWriteLockHeldLocks");
65
- const WATCHDOG_STATE_KEY = Symbol.for("openclaw.sessionWriteLockWatchdogState");
66
- const DEFAULT_STALE_MS = 1800 * 1e3;
67
- const DEFAULT_MAX_HOLD_MS = 300 * 1e3;
68
- const DEFAULT_WATCHDOG_INTERVAL_MS = 6e4;
69
- const DEFAULT_TIMEOUT_GRACE_MS = 120 * 1e3;
70
- const MAX_LOCK_HOLD_MS = 2147e6;
71
- const HELD_LOCKS = resolveProcessScopedMap(HELD_LOCKS_KEY);
72
- function resolveCleanupState() {
73
- const proc = process;
74
- if (!proc[CLEANUP_STATE_KEY]) proc[CLEANUP_STATE_KEY] = {
75
- registered: false,
76
- exitHandler: void 0,
77
- cleanupHandlers: /* @__PURE__ */ new Map()
78
- };
79
- return proc[CLEANUP_STATE_KEY];
80
- }
81
- function resolveWatchdogState() {
82
- const proc = process;
83
- if (!proc[WATCHDOG_STATE_KEY]) proc[WATCHDOG_STATE_KEY] = {
84
- started: false,
85
- intervalMs: DEFAULT_WATCHDOG_INTERVAL_MS
86
- };
87
- return proc[WATCHDOG_STATE_KEY];
88
- }
89
- function resolvePositiveMs(value, fallback, opts = {}) {
90
- if (typeof value !== "number" || Number.isNaN(value) || value <= 0) return fallback;
91
- if (value === Number.POSITIVE_INFINITY) return opts.allowInfinity ? value : fallback;
92
- if (!Number.isFinite(value)) return fallback;
93
- return value;
94
- }
95
- function resolveSessionLockMaxHoldFromTimeout(params) {
96
- const minMs = resolvePositiveMs(params.minMs, DEFAULT_MAX_HOLD_MS);
97
- const timeoutMs = resolvePositiveMs(params.timeoutMs, minMs, { allowInfinity: true });
98
- if (timeoutMs === Number.POSITIVE_INFINITY) return MAX_LOCK_HOLD_MS;
99
- const graceMs = resolvePositiveMs(params.graceMs, DEFAULT_TIMEOUT_GRACE_MS);
100
- return Math.min(MAX_LOCK_HOLD_MS, Math.max(minMs, timeoutMs + graceMs));
101
- }
102
- async function releaseHeldLock(normalizedSessionFile, held, opts = {}) {
103
- if (HELD_LOCKS.get(normalizedSessionFile) !== held) return false;
104
- if (opts.force) held.count = 0;
105
- else {
106
- held.count -= 1;
107
- if (held.count > 0) return false;
108
- }
109
- if (held.releasePromise) {
110
- await held.releasePromise.catch(() => void 0);
111
- return true;
112
- }
113
- HELD_LOCKS.delete(normalizedSessionFile);
114
- held.releasePromise = (async () => {
115
- try {
116
- await held.handle.close();
117
- } catch {}
118
- try {
119
- await fs$1.rm(held.lockPath, { force: true });
120
- } catch {}
121
- })();
122
- try {
123
- await held.releasePromise;
124
- return true;
125
- } finally {
126
- held.releasePromise = void 0;
127
- if (HELD_LOCKS.size === 0) stopWatchdogTimer();
128
- }
129
- }
130
- /**
131
- * Synchronously release all held locks.
132
- * Used during process exit when async operations aren't reliable.
133
- */
134
- function releaseAllLocksSync() {
135
- for (const [sessionFile, held] of HELD_LOCKS) {
136
- held.handle.close().catch(() => void 0);
137
- try {
138
- fs.rmSync(held.lockPath, { force: true });
139
- } catch {}
140
- HELD_LOCKS.delete(sessionFile);
141
- }
142
- if (HELD_LOCKS.size === 0) stopWatchdogTimer();
143
- }
144
- async function runLockWatchdogCheck(nowMs = Date.now()) {
145
- let released = 0;
146
- for (const [sessionFile, held] of HELD_LOCKS.entries()) {
147
- const heldForMs = nowMs - held.acquiredAt;
148
- if (heldForMs <= held.maxHoldMs) continue;
149
- process.stderr.write(`[session-write-lock] releasing lock held for ${heldForMs}ms (max=${held.maxHoldMs}ms): ${held.lockPath}\n`);
150
- if (await releaseHeldLock(sessionFile, held, { force: true })) released += 1;
151
- }
152
- return released;
153
- }
154
- function stopWatchdogTimer() {
155
- const watchdogState = resolveWatchdogState();
156
- if (watchdogState.timer) {
157
- clearInterval(watchdogState.timer);
158
- watchdogState.timer = void 0;
159
- }
160
- watchdogState.started = false;
161
- }
162
- function shouldStartBackgroundWatchdog() {
163
- return process.env.VITEST !== "true" || process.env.OPENCLAW_TEST_SESSION_LOCK_WATCHDOG === "1";
164
- }
165
- function ensureWatchdogStarted(intervalMs) {
166
- if (!shouldStartBackgroundWatchdog()) return;
167
- const watchdogState = resolveWatchdogState();
168
- if (watchdogState.started) return;
169
- watchdogState.started = true;
170
- watchdogState.intervalMs = intervalMs;
171
- watchdogState.timer = setInterval(() => {
172
- runLockWatchdogCheck().catch(() => {});
173
- }, intervalMs);
174
- watchdogState.timer.unref?.();
175
- }
176
- function handleTerminationSignal(signal) {
177
- releaseAllLocksSync();
178
- const cleanupState = resolveCleanupState();
179
- if (process.listenerCount(signal) === 1) {
180
- const handler = cleanupState.cleanupHandlers.get(signal);
181
- if (handler) {
182
- process.off(signal, handler);
183
- cleanupState.cleanupHandlers.delete(signal);
184
- }
185
- try {
186
- process.kill(process.pid, signal);
187
- } catch {}
188
- }
189
- }
190
- function registerCleanupHandlers() {
191
- const cleanupState = resolveCleanupState();
192
- cleanupState.registered = true;
193
- if (!cleanupState.exitHandler) {
194
- cleanupState.exitHandler = () => {
195
- releaseAllLocksSync();
196
- };
197
- process.on("exit", cleanupState.exitHandler);
198
- }
199
- ensureWatchdogStarted(DEFAULT_WATCHDOG_INTERVAL_MS);
200
- for (const signal of CLEANUP_SIGNALS) {
201
- if (cleanupState.cleanupHandlers.has(signal)) continue;
202
- try {
203
- const handler = () => handleTerminationSignal(signal);
204
- cleanupState.cleanupHandlers.set(signal, handler);
205
- process.on(signal, handler);
206
- } catch {}
207
- }
208
- }
209
- async function readLockPayload(lockPath) {
210
- try {
211
- const raw = await fs$1.readFile(lockPath, "utf8");
212
- const parsed = JSON.parse(raw);
213
- const payload = {};
214
- if (isValidLockNumber(parsed.pid) && parsed.pid > 0) payload.pid = parsed.pid;
215
- if (typeof parsed.createdAt === "string") payload.createdAt = parsed.createdAt;
216
- if (isValidLockNumber(parsed.starttime)) payload.starttime = parsed.starttime;
217
- return payload;
218
- } catch {
219
- return null;
220
- }
221
- }
222
- function inspectLockPayload(payload, staleMs, nowMs) {
223
- const pid = isValidLockNumber(payload?.pid) && payload.pid > 0 ? payload.pid : null;
224
- const pidAlive = pid !== null ? isPidAlive(pid) : false;
225
- const createdAt = typeof payload?.createdAt === "string" ? payload.createdAt : null;
226
- const createdAtMs = createdAt ? Date.parse(createdAt) : NaN;
227
- const ageMs = Number.isFinite(createdAtMs) ? Math.max(0, nowMs - createdAtMs) : null;
228
- const storedStarttime = isValidLockNumber(payload?.starttime) ? payload.starttime : null;
229
- const pidRecycled = pidAlive && pid !== null && storedStarttime !== null ? (() => {
230
- const currentStarttime = getProcessStartTime(pid);
231
- return currentStarttime !== null && currentStarttime !== storedStarttime;
232
- })() : false;
233
- const staleReasons = [];
234
- if (pid === null) staleReasons.push("missing-pid");
235
- else if (!pidAlive) staleReasons.push("dead-pid");
236
- else if (pidRecycled) staleReasons.push("recycled-pid");
237
- if (ageMs === null) staleReasons.push("invalid-createdAt");
238
- else if (ageMs > staleMs) staleReasons.push("too-old");
239
- return {
240
- pid,
241
- pidAlive,
242
- createdAt,
243
- ageMs,
244
- stale: staleReasons.length > 0,
245
- staleReasons
246
- };
247
- }
248
- function lockInspectionNeedsMtimeStaleFallback(details) {
249
- return details.stale && details.staleReasons.every((reason) => reason === "missing-pid" || reason === "invalid-createdAt");
250
- }
251
- async function shouldReclaimContendedLockFile(lockPath, details, staleMs, nowMs) {
252
- if (!details.stale) return false;
253
- if (!lockInspectionNeedsMtimeStaleFallback(details)) return true;
254
- try {
255
- const stat = await fs$1.stat(lockPath);
256
- return Math.max(0, nowMs - stat.mtimeMs) > staleMs;
257
- } catch (error) {
258
- return error?.code !== "ENOENT";
259
- }
260
- }
261
- function shouldTreatAsOrphanSelfLock(params) {
262
- if ((isValidLockNumber(params.payload?.pid) ? params.payload.pid : null) !== process.pid) return false;
263
- if (isValidLockNumber(params.payload?.starttime)) return false;
264
- return !HELD_LOCKS.has(params.normalizedSessionFile);
265
- }
266
- async function acquireSessionWriteLock(params) {
267
- registerCleanupHandlers();
268
- const allowReentrant = params.allowReentrant ?? false;
269
- const timeoutMs = resolvePositiveMs(params.timeoutMs, 1e4, { allowInfinity: true });
270
- const staleMs = resolvePositiveMs(params.staleMs, DEFAULT_STALE_MS);
271
- const maxHoldMs = resolvePositiveMs(params.maxHoldMs, DEFAULT_MAX_HOLD_MS);
272
- const sessionFile = path.resolve(params.sessionFile);
273
- const sessionDir = path.dirname(sessionFile);
274
- await fs$1.mkdir(sessionDir, { recursive: true });
275
- let normalizedDir = sessionDir;
276
- try {
277
- normalizedDir = await fs$1.realpath(sessionDir);
278
- } catch {}
279
- const normalizedSessionFile = path.join(normalizedDir, path.basename(sessionFile));
280
- const lockPath = `${normalizedSessionFile}.lock`;
281
- const held = HELD_LOCKS.get(normalizedSessionFile);
282
- if (allowReentrant && held) {
283
- held.count += 1;
284
- return { release: async () => {
285
- await releaseHeldLock(normalizedSessionFile, held);
286
- } };
287
- }
288
- const startedAt = Date.now();
289
- let attempt = 0;
290
- while (Date.now() - startedAt < timeoutMs) {
291
- attempt += 1;
292
- let handle = null;
293
- try {
294
- handle = await fs$1.open(lockPath, "wx");
295
- const createdAt = (/* @__PURE__ */ new Date()).toISOString();
296
- const starttime = getProcessStartTime(process.pid);
297
- const lockPayload = {
298
- pid: process.pid,
299
- createdAt
300
- };
301
- if (starttime !== null) lockPayload.starttime = starttime;
302
- await handle.writeFile(JSON.stringify(lockPayload, null, 2), "utf8");
303
- const createdHeld = {
304
- count: 1,
305
- handle,
306
- lockPath,
307
- acquiredAt: Date.now(),
308
- maxHoldMs
309
- };
310
- HELD_LOCKS.set(normalizedSessionFile, createdHeld);
311
- return { release: async () => {
312
- await releaseHeldLock(normalizedSessionFile, createdHeld);
313
- } };
314
- } catch (err) {
315
- if (handle) {
316
- try {
317
- await handle.close();
318
- } catch {}
319
- try {
320
- await fs$1.rm(lockPath, { force: true });
321
- } catch {}
322
- }
323
- if (err.code !== "EEXIST") throw err;
324
- const payload = await readLockPayload(lockPath);
325
- const nowMs = Date.now();
326
- const inspected = inspectLockPayload(payload, staleMs, nowMs);
327
- if (await shouldReclaimContendedLockFile(lockPath, shouldTreatAsOrphanSelfLock({
328
- payload,
329
- normalizedSessionFile
330
- }) ? {
331
- ...inspected,
332
- stale: true,
333
- staleReasons: inspected.staleReasons.includes("orphan-self-pid") ? inspected.staleReasons : [...inspected.staleReasons, "orphan-self-pid"]
334
- } : inspected, staleMs, nowMs)) {
335
- await fs$1.rm(lockPath, { force: true });
336
- continue;
337
- }
338
- const remainingMs = timeoutMs - (Date.now() - startedAt);
339
- if (remainingMs <= 0) break;
340
- const delay = Math.min(1e3, 50 * attempt, remainingMs);
341
- await new Promise((r) => setTimeout(r, delay));
342
- }
343
- }
344
- const payload = await readLockPayload(lockPath);
345
- const owner = typeof payload?.pid === "number" ? `pid=${payload.pid}` : "unknown";
346
- throw new Error(`session file locked (timeout ${timeoutMs}ms): ${owner} ${lockPath}`);
347
- }
348
- [...CLEANUP_SIGNALS];
349
- //#endregion
350
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/json-files-DcOQMqKi.js
351
- function getErrorCode$1(err) {
352
- return err instanceof Error ? err.code : void 0;
353
- }
354
- async function replaceFileWithWindowsFallback(tempPath, filePath, mode) {
355
- try {
356
- await fs$1.rename(tempPath, filePath);
357
- return;
358
- } catch (err) {
359
- const code = getErrorCode$1(err);
360
- if (process.platform !== "win32" || code !== "EPERM" && code !== "EEXIST") throw err;
361
- }
362
- await fs$1.copyFile(tempPath, filePath);
363
- try {
364
- await fs$1.chmod(filePath, mode);
365
- } catch {}
366
- await fs$1.rm(tempPath, { force: true }).catch(() => void 0);
367
- }
368
- async function writeTextAtomic(filePath, content, options) {
369
- const mode = options?.mode ?? 384;
370
- const payload = options?.appendTrailingNewline && !content.endsWith("\n") ? `${content}\n` : content;
371
- const mkdirOptions = { recursive: true };
372
- if (typeof options?.ensureDirMode === "number") mkdirOptions.mode = options.ensureDirMode;
373
- await fs$1.mkdir(path.dirname(filePath), mkdirOptions);
374
- const parentDir = path.dirname(filePath);
375
- const tmp = `${filePath}.${randomUUID()}.tmp`;
376
- try {
377
- const tmpHandle = await fs$1.open(tmp, "w", mode);
378
- try {
379
- await tmpHandle.writeFile(payload, { encoding: "utf8" });
380
- await tmpHandle.sync();
381
- } finally {
382
- await tmpHandle.close().catch(() => void 0);
383
- }
384
- try {
385
- await fs$1.chmod(tmp, mode);
386
- } catch {}
387
- await replaceFileWithWindowsFallback(tmp, filePath, mode);
388
- try {
389
- const dirHandle = await fs$1.open(parentDir, "r");
390
- try {
391
- await dirHandle.sync();
392
- } finally {
393
- await dirHandle.close().catch(() => void 0);
394
- }
395
- } catch {}
396
- try {
397
- await fs$1.chmod(filePath, mode);
398
- } catch {}
399
- } finally {
400
- await fs$1.rm(tmp, { force: true }).catch(() => void 0);
401
- }
402
- }
403
- //#endregion
404
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/parse-finite-number-DdG2XOLD.js
405
- function normalizeNumericString(value) {
406
- const trimmed = value.trim();
407
- return trimmed ? trimmed : void 0;
408
- }
409
- function parseStrictInteger(value) {
410
- if (typeof value === "number") return Number.isSafeInteger(value) ? value : void 0;
411
- if (typeof value !== "string") return;
412
- const normalized = normalizeNumericString(value);
413
- if (!normalized || !/^[+-]?\d+$/.test(normalized)) return;
414
- const parsed = Number(normalized);
415
- return Number.isSafeInteger(parsed) ? parsed : void 0;
416
- }
417
- function parseStrictNonNegativeInteger(value) {
418
- const parsed = parseStrictInteger(value);
419
- return parsed !== void 0 && parsed >= 0 ? parsed : void 0;
420
- }
421
- //#endregion
422
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/store-cache-DufBlCJB.js
423
- function resolveCacheTtlMs(params) {
424
- const { envValue, defaultTtlMs } = params;
425
- if (envValue) {
426
- const parsed = parseStrictNonNegativeInteger(envValue);
427
- if (parsed !== void 0) return parsed;
428
- }
429
- return defaultTtlMs;
430
- }
431
- function isCacheEnabled(ttlMs) {
432
- return ttlMs > 0;
433
- }
434
- function resolveCacheNumeric(value) {
435
- return typeof value === "function" ? value() : value;
436
- }
437
- function resolvePruneIntervalMs(ttlMs, pruneIntervalMs) {
438
- if (typeof pruneIntervalMs === "function") return Math.max(0, Math.floor(pruneIntervalMs(ttlMs)));
439
- if (typeof pruneIntervalMs === "number") return Math.max(0, Math.floor(pruneIntervalMs));
440
- return ttlMs;
441
- }
442
- function isCacheEntryExpired(storedAt, now, ttlMs) {
443
- return now - storedAt > ttlMs;
444
- }
445
- function createExpiringMapCache(options) {
446
- const cache = /* @__PURE__ */ new Map();
447
- const now = options.clock ?? Date.now;
448
- let lastPruneAt = 0;
449
- function getTtlMs() {
450
- return Math.max(0, Math.floor(resolveCacheNumeric(options.ttlMs)));
451
- }
452
- function maybePruneExpiredEntries(nowMs, ttlMs) {
453
- if (!isCacheEnabled(ttlMs)) return;
454
- if (nowMs - lastPruneAt < resolvePruneIntervalMs(ttlMs, options.pruneIntervalMs)) return;
455
- for (const [key, entry] of cache.entries()) if (isCacheEntryExpired(entry.storedAt, nowMs, ttlMs)) cache.delete(key);
456
- lastPruneAt = nowMs;
457
- }
458
- return {
459
- get: (key) => {
460
- const ttlMs = getTtlMs();
461
- if (!isCacheEnabled(ttlMs)) return;
462
- const nowMs = now();
463
- maybePruneExpiredEntries(nowMs, ttlMs);
464
- const entry = cache.get(key);
465
- if (!entry) return;
466
- if (isCacheEntryExpired(entry.storedAt, nowMs, ttlMs)) {
467
- cache.delete(key);
468
- return;
469
- }
470
- return entry.value;
471
- },
472
- set: (key, value) => {
473
- const ttlMs = getTtlMs();
474
- if (!isCacheEnabled(ttlMs)) return;
475
- const nowMs = now();
476
- maybePruneExpiredEntries(nowMs, ttlMs);
477
- cache.set(key, {
478
- storedAt: nowMs,
479
- value
480
- });
481
- },
482
- delete: (key) => {
483
- cache.delete(key);
484
- },
485
- clear: () => {
486
- cache.clear();
487
- lastPruneAt = 0;
488
- },
489
- keys: () => [...cache.keys()],
490
- size: () => cache.size,
491
- pruneExpired: () => {
492
- const ttlMs = getTtlMs();
493
- if (!isCacheEnabled(ttlMs)) return;
494
- const nowMs = now();
495
- for (const [key, entry] of cache.entries()) if (isCacheEntryExpired(entry.storedAt, nowMs, ttlMs)) cache.delete(key);
496
- lastPruneAt = nowMs;
497
- }
498
- };
499
- }
500
- function getFileStatSnapshot(filePath) {
501
- try {
502
- const stats = fs.statSync(filePath);
503
- return {
504
- mtimeMs: stats.mtimeMs,
505
- sizeBytes: stats.size
506
- };
507
- } catch {
508
- return;
509
- }
510
- }
511
- const DEFAULT_SESSION_STORE_TTL_MS = 45e3;
512
- const SESSION_STORE_CACHE = createExpiringMapCache({ ttlMs: getSessionStoreTtl });
513
- const SESSION_STORE_SERIALIZED_CACHE = /* @__PURE__ */ new Map();
514
- function getSessionStoreTtl() {
515
- return resolveCacheTtlMs({
516
- envValue: process.env.OPENCLAW_SESSION_CACHE_TTL_MS,
517
- defaultTtlMs: DEFAULT_SESSION_STORE_TTL_MS
518
- });
519
- }
520
- function isSessionStoreCacheEnabled() {
521
- return isCacheEnabled(getSessionStoreTtl());
522
- }
523
- function invalidateSessionStoreCache(storePath) {
524
- SESSION_STORE_CACHE.delete(storePath);
525
- SESSION_STORE_SERIALIZED_CACHE.delete(storePath);
526
- }
527
- function getSerializedSessionStore(storePath) {
528
- return SESSION_STORE_SERIALIZED_CACHE.get(storePath);
529
- }
530
- function setSerializedSessionStore(storePath, serialized) {
531
- if (serialized === void 0) {
532
- SESSION_STORE_SERIALIZED_CACHE.delete(storePath);
533
- return;
534
- }
535
- SESSION_STORE_SERIALIZED_CACHE.set(storePath, serialized);
536
- }
537
- function dropSessionStoreObjectCache(storePath) {
538
- SESSION_STORE_CACHE.delete(storePath);
539
- }
540
- function readSessionStoreCache(params) {
541
- const cached = SESSION_STORE_CACHE.get(params.storePath);
542
- if (!cached) return null;
543
- if (params.mtimeMs !== cached.mtimeMs || params.sizeBytes !== cached.sizeBytes) {
544
- invalidateSessionStoreCache(params.storePath);
545
- return null;
546
- }
547
- return structuredClone(cached.store);
548
- }
549
- function writeSessionStoreCache(params) {
550
- SESSION_STORE_CACHE.set(params.storePath, {
551
- store: structuredClone(params.store),
552
- mtimeMs: params.mtimeMs,
553
- sizeBytes: params.sizeBytes,
554
- serialized: params.serialized
555
- });
556
- if (params.serialized !== void 0) SESSION_STORE_SERIALIZED_CACHE.set(params.storePath, params.serialized);
557
- }
558
- //#endregion
559
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/store-load-HmCzUIz7.js
560
- const log$1 = createSubsystemLogger("sessions/store");
561
- const DEFAULT_SESSION_PRUNE_AFTER_MS = 720 * 60 * 60 * 1e3;
562
- const DEFAULT_SESSION_MAX_ENTRIES = 500;
563
- const DEFAULT_SESSION_ROTATE_BYTES = 10485760;
564
- const DEFAULT_SESSION_MAINTENANCE_MODE = "enforce";
565
- const DEFAULT_SESSION_DISK_BUDGET_HIGH_WATER_RATIO = .8;
566
- function resolvePruneAfterMs(maintenance) {
567
- const normalized = normalizeStringifiedOptionalString(maintenance?.pruneAfter ?? maintenance?.pruneDays);
568
- if (!normalized) return DEFAULT_SESSION_PRUNE_AFTER_MS;
569
- try {
570
- return parseDurationMs(normalized, { defaultUnit: "d" });
571
- } catch {
572
- return DEFAULT_SESSION_PRUNE_AFTER_MS;
573
- }
574
- }
575
- function resolveRotateBytes(maintenance) {
576
- const raw = maintenance?.rotateBytes;
577
- const normalized = normalizeStringifiedOptionalString(raw);
578
- if (!normalized) return DEFAULT_SESSION_ROTATE_BYTES;
579
- try {
580
- return parseByteSize(normalized, { defaultUnit: "b" });
581
- } catch {
582
- return DEFAULT_SESSION_ROTATE_BYTES;
583
- }
584
- }
585
- function resolveResetArchiveRetentionMs(maintenance, pruneAfterMs) {
586
- const raw = maintenance?.resetArchiveRetention;
587
- if (raw === false) return null;
588
- const normalized = normalizeStringifiedOptionalString(raw);
589
- if (!normalized) return pruneAfterMs;
590
- try {
591
- return parseDurationMs(normalized, { defaultUnit: "d" });
592
- } catch {
593
- return pruneAfterMs;
594
- }
595
- }
596
- function resolveMaxDiskBytes(maintenance) {
597
- const raw = maintenance?.maxDiskBytes;
598
- const normalized = normalizeStringifiedOptionalString(raw);
599
- if (!normalized) return null;
600
- try {
601
- return parseByteSize(normalized, { defaultUnit: "b" });
602
- } catch {
603
- return null;
604
- }
605
- }
606
- function resolveHighWaterBytes(maintenance, maxDiskBytes) {
607
- const computeDefault = () => {
608
- if (maxDiskBytes == null) return null;
609
- if (maxDiskBytes <= 0) return 0;
610
- return Math.max(1, Math.min(maxDiskBytes, Math.floor(maxDiskBytes * DEFAULT_SESSION_DISK_BUDGET_HIGH_WATER_RATIO)));
611
- };
612
- if (maxDiskBytes == null) return null;
613
- const raw = maintenance?.highWaterBytes;
614
- const normalized = normalizeStringifiedOptionalString(raw);
615
- if (!normalized) return computeDefault();
616
- try {
617
- const parsed = parseByteSize(normalized, { defaultUnit: "b" });
618
- return Math.min(parsed, maxDiskBytes);
619
- } catch {
620
- return computeDefault();
621
- }
622
- }
623
- /**
624
- * Resolve maintenance settings from openclaw.json (`session.maintenance`).
625
- * Falls back to built-in defaults when config is missing or unset.
626
- */
627
- function resolveMaintenanceConfigFromInput(maintenance) {
628
- const pruneAfterMs = resolvePruneAfterMs(maintenance);
629
- const maxDiskBytes = resolveMaxDiskBytes(maintenance);
630
- return {
631
- mode: maintenance?.mode ?? DEFAULT_SESSION_MAINTENANCE_MODE,
632
- pruneAfterMs,
633
- maxEntries: maintenance?.maxEntries ?? DEFAULT_SESSION_MAX_ENTRIES,
634
- rotateBytes: resolveRotateBytes(maintenance),
635
- resetArchiveRetentionMs: resolveResetArchiveRetentionMs(maintenance, pruneAfterMs),
636
- maxDiskBytes,
637
- highWaterBytes: resolveHighWaterBytes(maintenance, maxDiskBytes)
638
- };
639
- }
640
- /**
641
- * Remove entries whose `updatedAt` is older than the configured threshold.
642
- * Entries without `updatedAt` are kept (cannot determine staleness).
643
- * Mutates `store` in-place.
644
- */
645
- function pruneStaleEntries(store, overrideMaxAgeMs, opts = {}) {
646
- const maxAgeMs = overrideMaxAgeMs ?? resolveMaintenanceConfigFromInput().pruneAfterMs;
647
- const cutoffMs = Date.now() - maxAgeMs;
648
- let pruned = 0;
649
- for (const [key, entry] of Object.entries(store)) {
650
- if (opts.preserveKeys?.has(key)) continue;
651
- if (entry?.updatedAt != null && entry.updatedAt < cutoffMs) {
652
- opts.onPruned?.({
653
- key,
654
- entry
655
- });
656
- delete store[key];
657
- pruned++;
658
- }
659
- }
660
- if (pruned > 0 && opts.log !== false) log$1.info("pruned stale session entries", {
661
- pruned,
662
- maxAgeMs
663
- });
664
- return pruned;
665
- }
666
- function getEntryUpdatedAt$1(entry) {
667
- return entry?.updatedAt ?? Number.NEGATIVE_INFINITY;
668
- }
669
- function getActiveSessionMaintenanceWarning(params) {
670
- const activeSessionKey = params.activeSessionKey.trim();
671
- if (!activeSessionKey) return null;
672
- const activeEntry = params.store[activeSessionKey];
673
- if (!activeEntry) return null;
674
- const cutoffMs = (params.nowMs ?? Date.now()) - params.pruneAfterMs;
675
- const wouldPrune = activeEntry.updatedAt != null ? activeEntry.updatedAt < cutoffMs : false;
676
- const keys = Object.keys(params.store);
677
- const wouldCap = wouldCapActiveSession({
678
- store: params.store,
679
- keys,
680
- activeEntry,
681
- activeSessionKey,
682
- maxEntries: params.maxEntries
683
- });
684
- if (!wouldPrune && !wouldCap) return null;
685
- return {
686
- activeSessionKey,
687
- activeUpdatedAt: activeEntry.updatedAt,
688
- totalEntries: keys.length,
689
- pruneAfterMs: params.pruneAfterMs,
690
- maxEntries: params.maxEntries,
691
- wouldPrune,
692
- wouldCap
693
- };
694
- }
695
- function wouldCapActiveSession(params) {
696
- if (params.keys.length <= params.maxEntries) return false;
697
- if (params.maxEntries <= 0) return true;
698
- const activeUpdatedAt = getEntryUpdatedAt$1(params.activeEntry);
699
- let newerOrTieBeforeActive = 0;
700
- let seenActive = false;
701
- for (const key of params.keys) {
702
- if (key === params.activeSessionKey) {
703
- seenActive = true;
704
- continue;
705
- }
706
- const entryUpdatedAt = getEntryUpdatedAt$1(params.store[key]);
707
- if (entryUpdatedAt > activeUpdatedAt || !seenActive && entryUpdatedAt === activeUpdatedAt) {
708
- newerOrTieBeforeActive++;
709
- if (newerOrTieBeforeActive >= params.maxEntries) return true;
710
- }
711
- }
712
- return false;
713
- }
714
- /**
715
- * Cap the store to the N most recently updated entries.
716
- * Entries without `updatedAt` are sorted last (removed first when over limit).
717
- * Mutates `store` in-place.
718
- */
719
- function capEntryCount(store, overrideMax, opts = {}) {
720
- const maxEntries = overrideMax ?? resolveMaintenanceConfigFromInput().maxEntries;
721
- const preservedCount = opts.preserveKeys ? Object.keys(store).filter((key) => opts.preserveKeys?.has(key)).length : 0;
722
- const maxRemovableEntries = Math.max(0, maxEntries - preservedCount);
723
- const keys = Object.keys(store).filter((key) => !opts.preserveKeys?.has(key));
724
- if (keys.length <= maxRemovableEntries) return 0;
725
- const toRemove = keys.toSorted((a, b) => {
726
- const aTime = getEntryUpdatedAt$1(store[a]);
727
- return getEntryUpdatedAt$1(store[b]) - aTime;
728
- }).slice(maxRemovableEntries);
729
- for (const key of toRemove) {
730
- const entry = store[key];
731
- if (entry) opts.onCapped?.({
732
- key,
733
- entry
734
- });
735
- delete store[key];
736
- }
737
- if (opts.log !== false) log$1.info("capped session entry count", {
738
- removed: toRemove.length,
739
- maxEntries
740
- });
741
- return toRemove.length;
742
- }
743
- async function getSessionFileSize(storePath) {
744
- try {
745
- return (await fs.promises.stat(storePath)).size;
746
- } catch {
747
- return null;
748
- }
749
- }
750
- /**
751
- * Rotate the sessions file if it exceeds the configured size threshold.
752
- * Renames the current file to `sessions.json.bak.{timestamp}` and cleans up
753
- * old rotation backups, keeping only the 3 most recent `.bak.*` files.
754
- */
755
- async function rotateSessionFile(storePath, overrideBytes) {
756
- const maxBytes = overrideBytes ?? resolveMaintenanceConfigFromInput().rotateBytes;
757
- const fileSize = await getSessionFileSize(storePath);
758
- if (fileSize == null) return false;
759
- if (fileSize <= maxBytes) return false;
760
- const backupPath = `${storePath}.bak.${Date.now()}`;
761
- try {
762
- await fs.promises.rename(storePath, backupPath);
763
- log$1.info("rotated session store file", {
764
- backupPath: path.basename(backupPath),
765
- sizeBytes: fileSize
766
- });
767
- } catch {
768
- return false;
769
- }
770
- try {
771
- const dir = path.dirname(storePath);
772
- const baseName = path.basename(storePath);
773
- const backups = (await fs.promises.readdir(dir)).filter((f) => f.startsWith(`${baseName}.bak.`)).toSorted().toReversed();
774
- const maxBackups = 3;
775
- if (backups.length > maxBackups) {
776
- const toDelete = backups.slice(maxBackups);
777
- for (const old of toDelete) await fs.promises.unlink(path.join(dir, old)).catch(() => void 0);
778
- log$1.info("cleaned up old session store backups", { deleted: toDelete.length });
779
- }
780
- } catch {}
781
- return true;
782
- }
783
- function applySessionStoreMigrations(store) {
784
- for (const entry of Object.values(store)) {
785
- if (!entry || typeof entry !== "object") continue;
786
- const rec = entry;
787
- if (typeof rec.channel !== "string" && typeof rec.provider === "string") {
788
- rec.channel = rec.provider;
789
- delete rec.provider;
790
- }
791
- if (typeof rec.lastChannel !== "string" && typeof rec.lastProvider === "string") {
792
- rec.lastChannel = rec.lastProvider;
793
- delete rec.lastProvider;
794
- }
795
- if (typeof rec.groupChannel !== "string" && typeof rec.room === "string") {
796
- rec.groupChannel = rec.room;
797
- delete rec.room;
798
- } else if ("room" in rec) delete rec.room;
799
- }
800
- }
801
- const log$2 = createSubsystemLogger("sessions/store");
802
- function isSessionStoreRecord(value) {
803
- return !!value && typeof value === "object" && !Array.isArray(value);
804
- }
805
- function normalizeSessionEntryDelivery(entry) {
806
- const normalized = normalizeSessionDeliveryFields({
807
- channel: entry.channel,
808
- lastChannel: entry.lastChannel,
809
- lastTo: entry.lastTo,
810
- lastAccountId: entry.lastAccountId,
811
- lastThreadId: entry.lastThreadId ?? entry.deliveryContext?.threadId ?? entry.origin?.threadId,
812
- deliveryContext: entry.deliveryContext
813
- });
814
- const nextDelivery = normalized.deliveryContext;
815
- const sameDelivery = (entry.deliveryContext?.channel ?? void 0) === nextDelivery?.channel && (entry.deliveryContext?.to ?? void 0) === nextDelivery?.to && (entry.deliveryContext?.accountId ?? void 0) === nextDelivery?.accountId && (entry.deliveryContext?.threadId ?? void 0) === nextDelivery?.threadId;
816
- const sameLast = entry.lastChannel === normalized.lastChannel && entry.lastTo === normalized.lastTo && entry.lastAccountId === normalized.lastAccountId && entry.lastThreadId === normalized.lastThreadId;
817
- if (sameDelivery && sameLast) return entry;
818
- return {
819
- ...entry,
820
- deliveryContext: nextDelivery,
821
- lastChannel: normalized.lastChannel,
822
- lastTo: normalized.lastTo,
823
- lastAccountId: normalized.lastAccountId,
824
- lastThreadId: normalized.lastThreadId
825
- };
826
- }
827
- function normalizeSessionStore(store) {
828
- for (const [key, entry] of Object.entries(store)) {
829
- if (!entry) continue;
830
- const normalized = normalizeSessionEntryDelivery(normalizeSessionRuntimeModelFields(entry));
831
- if (normalized !== entry) store[key] = normalized;
832
- }
833
- }
834
- function loadSessionStore(storePath, opts = {}) {
835
- if (!opts.skipCache && isSessionStoreCacheEnabled()) {
836
- const currentFileStat = getFileStatSnapshot(storePath);
837
- const cached = readSessionStoreCache({
838
- storePath,
839
- mtimeMs: currentFileStat?.mtimeMs,
840
- sizeBytes: currentFileStat?.sizeBytes
841
- });
842
- if (cached) return cached;
843
- }
844
- let store = {};
845
- let fileStat = getFileStatSnapshot(storePath);
846
- let mtimeMs = fileStat?.mtimeMs;
847
- let serializedFromDisk;
848
- const maxReadAttempts = process.platform === "win32" ? 3 : 1;
849
- const retryBuf = maxReadAttempts > 1 ? new Int32Array(new SharedArrayBuffer(4)) : void 0;
850
- for (let attempt = 0; attempt < maxReadAttempts; attempt += 1) try {
851
- const raw = fs.readFileSync(storePath, "utf-8");
852
- if (raw.length === 0 && attempt < maxReadAttempts - 1) {
853
- Atomics.wait(retryBuf, 0, 0, 50);
854
- continue;
855
- }
856
- const parsed = JSON.parse(raw);
857
- if (isSessionStoreRecord(parsed)) {
858
- store = parsed;
859
- serializedFromDisk = raw;
860
- }
861
- fileStat = getFileStatSnapshot(storePath) ?? fileStat;
862
- mtimeMs = fileStat?.mtimeMs;
863
- break;
864
- } catch {
865
- if (attempt < maxReadAttempts - 1) {
866
- Atomics.wait(retryBuf, 0, 0, 50);
867
- continue;
868
- }
869
- }
870
- if (serializedFromDisk !== void 0) setSerializedSessionStore(storePath, serializedFromDisk);
871
- else setSerializedSessionStore(storePath, void 0);
872
- applySessionStoreMigrations(store);
873
- normalizeSessionStore(store);
874
- const maintenance = opts.maintenanceConfig ?? resolveMaintenanceConfigFromInput();
875
- if (maintenance.mode === "enforce" && Object.keys(store).length > maintenance.maxEntries) {
876
- const beforeCount = Object.keys(store).length;
877
- const pruned = pruneStaleEntries(store, maintenance.pruneAfterMs, { log: false });
878
- const capped = capEntryCount(store, maintenance.maxEntries, { log: false });
879
- const afterCount = Object.keys(store).length;
880
- if (pruned > 0 || capped > 0) {
881
- serializedFromDisk = void 0;
882
- setSerializedSessionStore(storePath, void 0);
883
- log$2.info("applied load-time maintenance to oversized session store", {
884
- storePath,
885
- before: beforeCount,
886
- after: afterCount,
887
- pruned,
888
- capped,
889
- maxEntries: maintenance.maxEntries
890
- });
891
- }
892
- }
893
- if (!opts.skipCache && isSessionStoreCacheEnabled()) writeSessionStoreCache({
894
- storePath,
895
- store,
896
- mtimeMs,
897
- sizeBytes: fileStat?.sizeBytes,
898
- serialized: serializedFromDisk
899
- });
900
- return structuredClone(store);
901
- }
902
- //#endregion
903
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/store-lock-state-DxRntb08.js
904
- const LOCK_QUEUES = /* @__PURE__ */ new Map();
905
- //#endregion
906
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/store-D_G4w--8.js
907
- const NOOP_LOGGER = {
908
- warn: () => {},
909
- info: () => {}
910
- };
911
- function canonicalizePathForComparison(filePath) {
912
- const resolved = path.resolve(filePath);
913
- try {
914
- return fs.realpathSync(resolved);
915
- } catch {
916
- return resolved;
917
- }
918
- }
919
- function measureStoreBytes(store) {
920
- return Buffer.byteLength(JSON.stringify(store, null, 2), "utf-8");
921
- }
922
- function measureStoreEntryChunkBytes(key, entry) {
923
- const singleEntryStore = JSON.stringify({ [key]: entry }, null, 2);
924
- if (!singleEntryStore.startsWith("{\n") || !singleEntryStore.endsWith("\n}")) return measureStoreBytes({ [key]: entry }) - 4;
925
- const chunk = singleEntryStore.slice(2, -2);
926
- return Buffer.byteLength(chunk, "utf-8");
927
- }
928
- function buildStoreEntryChunkSizeMap(store) {
929
- const out = /* @__PURE__ */ new Map();
930
- for (const [key, entry] of Object.entries(store)) out.set(key, measureStoreEntryChunkBytes(key, entry));
931
- return out;
932
- }
933
- function getEntryUpdatedAt(entry) {
934
- if (!entry) return 0;
935
- const updatedAt = entry.updatedAt;
936
- return Number.isFinite(updatedAt) ? updatedAt : 0;
937
- }
938
- function buildSessionIdRefCounts(store) {
939
- const counts = /* @__PURE__ */ new Map();
940
- for (const entry of Object.values(store)) {
941
- const sessionId = entry?.sessionId;
942
- if (!sessionId) continue;
943
- counts.set(sessionId, (counts.get(sessionId) ?? 0) + 1);
944
- }
945
- return counts;
946
- }
947
- function resolveSessionTranscriptPathForEntry(params) {
948
- if (!params.entry.sessionId) return null;
949
- try {
950
- const resolved = resolveSessionFilePath(params.entry.sessionId, params.entry, { sessionsDir: params.sessionsDir });
951
- const resolvedSessionsDir = canonicalizePathForComparison(params.sessionsDir);
952
- const resolvedPath = canonicalizePathForComparison(resolved);
953
- const relative = path.relative(resolvedSessionsDir, resolvedPath);
954
- if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return null;
955
- return resolvedPath;
956
- } catch {
957
- return null;
958
- }
959
- }
960
- function resolveReferencedSessionTranscriptPaths(params) {
961
- const referenced = /* @__PURE__ */ new Set();
962
- for (const entry of Object.values(params.store)) {
963
- const resolved = resolveSessionTranscriptPathForEntry({
964
- sessionsDir: params.sessionsDir,
965
- entry
966
- });
967
- if (resolved) referenced.add(canonicalizePathForComparison(resolved));
968
- }
969
- return referenced;
970
- }
971
- async function readSessionsDirFiles(sessionsDir) {
972
- const dirEntries = await fs.promises.readdir(sessionsDir, { withFileTypes: true }).catch(() => []);
973
- const files = [];
974
- for (const dirent of dirEntries) {
975
- if (!dirent.isFile()) continue;
976
- const filePath = path.join(sessionsDir, dirent.name);
977
- const stat = await fs.promises.stat(filePath).catch(() => null);
978
- if (!stat?.isFile()) continue;
979
- files.push({
980
- path: filePath,
981
- canonicalPath: canonicalizePathForComparison(filePath),
982
- name: dirent.name,
983
- size: stat.size,
984
- mtimeMs: stat.mtimeMs
985
- });
986
- }
987
- return files;
988
- }
989
- async function removeFileIfExists(filePath) {
990
- const stat = await fs.promises.stat(filePath).catch(() => null);
991
- if (!stat?.isFile()) return 0;
992
- await fs.promises.rm(filePath, { force: true }).catch(() => void 0);
993
- return stat.size;
994
- }
995
- async function removeFileForBudget(params) {
996
- const resolvedPath = path.resolve(params.filePath);
997
- const canonicalPath = params.canonicalPath ?? canonicalizePathForComparison(resolvedPath);
998
- if (params.dryRun) {
999
- if (params.simulatedRemovedPaths.has(canonicalPath)) return 0;
1000
- const size = params.fileSizesByPath.get(canonicalPath) ?? 0;
1001
- if (size <= 0) return 0;
1002
- params.simulatedRemovedPaths.add(canonicalPath);
1003
- return size;
1004
- }
1005
- return removeFileIfExists(resolvedPath);
1006
- }
1007
- async function enforceSessionDiskBudget(params) {
1008
- const maxBytes = params.maintenance.maxDiskBytes;
1009
- const highWaterBytes = params.maintenance.highWaterBytes;
1010
- if (maxBytes == null || highWaterBytes == null) return null;
1011
- const log = params.log ?? NOOP_LOGGER;
1012
- const dryRun = params.dryRun === true;
1013
- const sessionsDir = path.dirname(params.storePath);
1014
- const files = await readSessionsDirFiles(sessionsDir);
1015
- const fileSizesByPath = new Map(files.map((file) => [file.canonicalPath, file.size]));
1016
- const simulatedRemovedPaths = /* @__PURE__ */ new Set();
1017
- const resolvedStorePath = canonicalizePathForComparison(params.storePath);
1018
- const storeFile = files.find((file) => file.canonicalPath === resolvedStorePath);
1019
- let projectedStoreBytes = measureStoreBytes(params.store);
1020
- let total = files.reduce((sum, file) => sum + file.size, 0) - (storeFile?.size ?? 0) + projectedStoreBytes;
1021
- const totalBefore = total;
1022
- if (total <= maxBytes) return {
1023
- totalBytesBefore: totalBefore,
1024
- totalBytesAfter: total,
1025
- removedFiles: 0,
1026
- removedEntries: 0,
1027
- freedBytes: 0,
1028
- maxBytes,
1029
- highWaterBytes,
1030
- overBudget: false
1031
- };
1032
- if (params.warnOnly) {
1033
- log.warn("session disk budget exceeded (warn-only mode)", {
1034
- sessionsDir,
1035
- totalBytes: total,
1036
- maxBytes,
1037
- highWaterBytes
1038
- });
1039
- return {
1040
- totalBytesBefore: totalBefore,
1041
- totalBytesAfter: total,
1042
- removedFiles: 0,
1043
- removedEntries: 0,
1044
- freedBytes: 0,
1045
- maxBytes,
1046
- highWaterBytes,
1047
- overBudget: true
1048
- };
1049
- }
1050
- let removedFiles = 0;
1051
- let removedEntries = 0;
1052
- let freedBytes = 0;
1053
- const referencedPaths = resolveReferencedSessionTranscriptPaths({
1054
- sessionsDir,
1055
- store: params.store
1056
- });
1057
- const removableFileQueue = files.filter((file) => isSessionArchiveArtifactName(file.name) || isPrimarySessionTranscriptFileName(file.name) && !referencedPaths.has(file.canonicalPath)).toSorted((a, b) => a.mtimeMs - b.mtimeMs);
1058
- for (const file of removableFileQueue) {
1059
- if (total <= highWaterBytes) break;
1060
- const deletedBytes = await removeFileForBudget({
1061
- filePath: file.path,
1062
- canonicalPath: file.canonicalPath,
1063
- dryRun,
1064
- fileSizesByPath,
1065
- simulatedRemovedPaths
1066
- });
1067
- if (deletedBytes <= 0) continue;
1068
- total -= deletedBytes;
1069
- freedBytes += deletedBytes;
1070
- removedFiles += 1;
1071
- }
1072
- if (total > highWaterBytes) {
1073
- const activeSessionKey = normalizeOptionalLowercaseString(params.activeSessionKey);
1074
- const sessionIdRefCounts = buildSessionIdRefCounts(params.store);
1075
- const entryChunkBytesByKey = buildStoreEntryChunkSizeMap(params.store);
1076
- const keys = Object.keys(params.store).toSorted((a, b) => {
1077
- return getEntryUpdatedAt(params.store[a]) - getEntryUpdatedAt(params.store[b]);
1078
- });
1079
- for (const key of keys) {
1080
- if (total <= highWaterBytes) break;
1081
- if (activeSessionKey && normalizeLowercaseStringOrEmpty(key) === activeSessionKey) continue;
1082
- const entry = params.store[key];
1083
- if (!entry) continue;
1084
- const previousProjectedBytes = projectedStoreBytes;
1085
- delete params.store[key];
1086
- const chunkBytes = entryChunkBytesByKey.get(key);
1087
- entryChunkBytesByKey.delete(key);
1088
- if (typeof chunkBytes === "number" && Number.isFinite(chunkBytes) && chunkBytes >= 0) projectedStoreBytes = Math.max(2, projectedStoreBytes - (chunkBytes + 2));
1089
- else projectedStoreBytes = measureStoreBytes(params.store);
1090
- total += projectedStoreBytes - previousProjectedBytes;
1091
- removedEntries += 1;
1092
- const sessionId = entry.sessionId;
1093
- if (!sessionId) continue;
1094
- const nextRefCount = (sessionIdRefCounts.get(sessionId) ?? 1) - 1;
1095
- if (nextRefCount > 0) {
1096
- sessionIdRefCounts.set(sessionId, nextRefCount);
1097
- continue;
1098
- }
1099
- sessionIdRefCounts.delete(sessionId);
1100
- const transcriptPath = resolveSessionTranscriptPathForEntry({
1101
- sessionsDir,
1102
- entry
1103
- });
1104
- if (!transcriptPath) continue;
1105
- const deletedBytes = await removeFileForBudget({
1106
- filePath: transcriptPath,
1107
- dryRun,
1108
- fileSizesByPath,
1109
- simulatedRemovedPaths
1110
- });
1111
- if (deletedBytes <= 0) continue;
1112
- total -= deletedBytes;
1113
- freedBytes += deletedBytes;
1114
- removedFiles += 1;
1115
- }
1116
- }
1117
- if (!dryRun) {
1118
- if (total > highWaterBytes) log.warn("session disk budget still above high-water target after cleanup", {
1119
- sessionsDir,
1120
- totalBytes: total,
1121
- maxBytes,
1122
- highWaterBytes,
1123
- removedFiles,
1124
- removedEntries
1125
- });
1126
- else if (removedFiles > 0 || removedEntries > 0) log.info("applied session disk budget cleanup", {
1127
- sessionsDir,
1128
- totalBytesBefore: totalBefore,
1129
- totalBytesAfter: total,
1130
- maxBytes,
1131
- highWaterBytes,
1132
- removedFiles,
1133
- removedEntries
1134
- });
1135
- }
1136
- return {
1137
- totalBytesBefore: totalBefore,
1138
- totalBytesAfter: total,
1139
- removedFiles,
1140
- removedEntries,
1141
- freedBytes,
1142
- maxBytes,
1143
- highWaterBytes,
1144
- overBudget: true
1145
- };
1146
- }
1147
- function normalizeStoreSessionKey(sessionKey) {
1148
- return normalizeLowercaseStringOrEmpty(sessionKey);
1149
- }
1150
- function resolveMaintenanceConfig() {
1151
- let maintenance;
1152
- try {
1153
- maintenance = loadConfig().session?.maintenance;
1154
- } catch {}
1155
- return resolveMaintenanceConfigFromInput(maintenance);
1156
- }
1157
- const log = createSubsystemLogger("sessions/store");
1158
- let sessionArchiveRuntimePromise = null;
1159
- let sessionWriteLockAcquirerForTests = null;
1160
- function loadSessionArchiveRuntime() {
1161
- sessionArchiveRuntimePromise ??= import("./session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs");
1162
- return sessionArchiveRuntimePromise;
1163
- }
1164
- function updateSessionStoreWriteCaches(params) {
1165
- const fileStat = getFileStatSnapshot(params.storePath);
1166
- setSerializedSessionStore(params.storePath, params.serialized);
1167
- if (!isSessionStoreCacheEnabled()) {
1168
- dropSessionStoreObjectCache(params.storePath);
1169
- return;
1170
- }
1171
- writeSessionStoreCache({
1172
- storePath: params.storePath,
1173
- store: params.store,
1174
- mtimeMs: fileStat?.mtimeMs,
1175
- sizeBytes: fileStat?.sizeBytes,
1176
- serialized: params.serialized
1177
- });
1178
- }
1179
- function resolveMutableSessionStoreKey(store, sessionKey) {
1180
- const trimmed = sessionKey.trim();
1181
- if (!trimmed) return;
1182
- if (Object.prototype.hasOwnProperty.call(store, trimmed)) return trimmed;
1183
- const normalized = normalizeStoreSessionKey(trimmed);
1184
- if (Object.prototype.hasOwnProperty.call(store, normalized)) return normalized;
1185
- return Object.keys(store).find((key) => normalizeStoreSessionKey(key) === normalized);
1186
- }
1187
- function collectAcpMetadataSnapshot(store) {
1188
- const snapshot = /* @__PURE__ */ new Map();
1189
- for (const [sessionKey, entry] of Object.entries(store)) if (entry?.acp) snapshot.set(sessionKey, entry.acp);
1190
- return snapshot;
1191
- }
1192
- function preserveExistingAcpMetadata(params) {
1193
- const allowDrop = new Set((params.allowDropSessionKeys ?? []).map((key) => normalizeStoreSessionKey(key)));
1194
- for (const [previousKey, previousAcp] of params.previousAcpByKey.entries()) {
1195
- const normalizedKey = normalizeStoreSessionKey(previousKey);
1196
- if (allowDrop.has(normalizedKey)) continue;
1197
- const nextKey = resolveMutableSessionStoreKey(params.nextStore, previousKey);
1198
- if (!nextKey) continue;
1199
- const nextEntry = params.nextStore[nextKey];
1200
- if (!nextEntry || nextEntry.acp) continue;
1201
- params.nextStore[nextKey] = {
1202
- ...nextEntry,
1203
- acp: previousAcp
1204
- };
1205
- }
1206
- }
1207
- async function saveSessionStoreUnlocked(storePath, store, opts) {
1208
- normalizeSessionStore(store);
1209
- if (!opts?.skipMaintenance) {
1210
- const maintenance = opts?.maintenanceConfig ? {
1211
- ...opts.maintenanceConfig,
1212
- ...opts?.maintenanceOverride
1213
- } : {
1214
- ...resolveMaintenanceConfig(),
1215
- ...opts?.maintenanceOverride
1216
- };
1217
- const shouldWarnOnly = maintenance.mode === "warn";
1218
- const beforeCount = Object.keys(store).length;
1219
- if (shouldWarnOnly) {
1220
- const activeSessionKey = opts?.activeSessionKey?.trim();
1221
- if (activeSessionKey) {
1222
- const warning = getActiveSessionMaintenanceWarning({
1223
- store,
1224
- activeSessionKey,
1225
- pruneAfterMs: maintenance.pruneAfterMs,
1226
- maxEntries: maintenance.maxEntries
1227
- });
1228
- if (warning) {
1229
- log.warn("session maintenance would evict active session; skipping enforcement", {
1230
- activeSessionKey: warning.activeSessionKey,
1231
- wouldPrune: warning.wouldPrune,
1232
- wouldCap: warning.wouldCap,
1233
- pruneAfterMs: warning.pruneAfterMs,
1234
- maxEntries: warning.maxEntries
1235
- });
1236
- await opts?.onWarn?.(warning);
1237
- }
1238
- }
1239
- const diskBudget = await enforceSessionDiskBudget({
1240
- store,
1241
- storePath,
1242
- activeSessionKey: opts?.activeSessionKey,
1243
- maintenance,
1244
- warnOnly: true,
1245
- log
1246
- });
1247
- await opts?.onMaintenanceApplied?.({
1248
- mode: maintenance.mode,
1249
- beforeCount,
1250
- afterCount: Object.keys(store).length,
1251
- pruned: 0,
1252
- capped: 0,
1253
- diskBudget
1254
- });
1255
- } else {
1256
- const preserveSessionKeys = opts?.activeSessionKey ? new Set([opts.activeSessionKey]) : void 0;
1257
- const removedSessionFiles = /* @__PURE__ */ new Map();
1258
- const pruned = pruneStaleEntries(store, maintenance.pruneAfterMs, {
1259
- onPruned: ({ entry }) => {
1260
- rememberRemovedSessionFile(removedSessionFiles, entry);
1261
- },
1262
- preserveKeys: preserveSessionKeys
1263
- });
1264
- const capped = capEntryCount(store, maintenance.maxEntries, {
1265
- onCapped: ({ entry }) => {
1266
- rememberRemovedSessionFile(removedSessionFiles, entry);
1267
- },
1268
- preserveKeys: preserveSessionKeys
1269
- });
1270
- const archivedDirs = /* @__PURE__ */ new Set();
1271
- const archivedForDeletedSessions = await archiveRemovedSessionTranscripts({
1272
- removedSessionFiles,
1273
- referencedSessionIds: new Set(Object.values(store).map((entry) => entry?.sessionId).filter((id) => Boolean(id))),
1274
- storePath,
1275
- reason: "deleted",
1276
- restrictToStoreDir: true
1277
- });
1278
- for (const archivedDir of archivedForDeletedSessions) archivedDirs.add(archivedDir);
1279
- if (archivedDirs.size > 0 || maintenance.resetArchiveRetentionMs != null) {
1280
- const { cleanupArchivedSessionTranscripts } = await loadSessionArchiveRuntime();
1281
- const targetDirs = archivedDirs.size > 0 ? [...archivedDirs] : [path.dirname(path.resolve(storePath))];
1282
- await cleanupArchivedSessionTranscripts({
1283
- directories: targetDirs,
1284
- olderThanMs: maintenance.pruneAfterMs,
1285
- reason: "deleted"
1286
- });
1287
- if (maintenance.resetArchiveRetentionMs != null) await cleanupArchivedSessionTranscripts({
1288
- directories: targetDirs,
1289
- olderThanMs: maintenance.resetArchiveRetentionMs,
1290
- reason: "reset"
1291
- });
1292
- }
1293
- await rotateSessionFile(storePath, maintenance.rotateBytes);
1294
- const diskBudget = await enforceSessionDiskBudget({
1295
- store,
1296
- storePath,
1297
- activeSessionKey: opts?.activeSessionKey,
1298
- maintenance,
1299
- warnOnly: false,
1300
- log
1301
- });
1302
- await opts?.onMaintenanceApplied?.({
1303
- mode: maintenance.mode,
1304
- beforeCount,
1305
- afterCount: Object.keys(store).length,
1306
- pruned,
1307
- capped,
1308
- diskBudget
1309
- });
1310
- }
1311
- }
1312
- await fs.promises.mkdir(path.dirname(storePath), { recursive: true });
1313
- const json = JSON.stringify(store, null, 2);
1314
- if (getSerializedSessionStore(storePath) === json) {
1315
- updateSessionStoreWriteCaches({
1316
- storePath,
1317
- store,
1318
- serialized: json
1319
- });
1320
- return;
1321
- }
1322
- if (process.platform === "win32") {
1323
- for (let i = 0; i < 5; i++) try {
1324
- await writeSessionStoreAtomic({
1325
- storePath,
1326
- store,
1327
- serialized: json
1328
- });
1329
- return;
1330
- } catch (err) {
1331
- if (getErrorCode(err) === "ENOENT") return;
1332
- if (i < 4) {
1333
- await new Promise((r) => setTimeout(r, 50 * (i + 1)));
1334
- continue;
1335
- }
1336
- log.warn(`atomic write failed after 5 attempts: ${storePath}`);
1337
- }
1338
- return;
1339
- }
1340
- try {
1341
- await writeSessionStoreAtomic({
1342
- storePath,
1343
- store,
1344
- serialized: json
1345
- });
1346
- } catch (err) {
1347
- if (getErrorCode(err) === "ENOENT") {
1348
- try {
1349
- await writeSessionStoreAtomic({
1350
- storePath,
1351
- store,
1352
- serialized: json
1353
- });
1354
- } catch (err2) {
1355
- if (getErrorCode(err2) === "ENOENT") return;
1356
- throw err2;
1357
- }
1358
- return;
1359
- }
1360
- throw err;
1361
- }
1362
- }
1363
- async function updateSessionStore(storePath, mutator, opts) {
1364
- return await withSessionStoreLock(storePath, async () => {
1365
- const store = loadSessionStore(storePath, { skipCache: true });
1366
- const previousAcpByKey = collectAcpMetadataSnapshot(store);
1367
- const result = await mutator(store);
1368
- preserveExistingAcpMetadata({
1369
- previousAcpByKey,
1370
- nextStore: store,
1371
- allowDropSessionKeys: opts?.allowDropAcpMetaSessionKeys
1372
- });
1373
- await saveSessionStoreUnlocked(storePath, store, opts);
1374
- return result;
1375
- });
1376
- }
1377
- const SESSION_STORE_LOCK_MIN_HOLD_MS = 5e3;
1378
- const SESSION_STORE_LOCK_TIMEOUT_GRACE_MS = 5e3;
1379
- function getErrorCode(error) {
1380
- if (!error || typeof error !== "object" || !("code" in error)) return null;
1381
- return String(error.code);
1382
- }
1383
- function rememberRemovedSessionFile(removedSessionFiles, entry) {
1384
- if (!removedSessionFiles.has(entry.sessionId) || entry.sessionFile) removedSessionFiles.set(entry.sessionId, entry.sessionFile);
1385
- }
1386
- async function archiveRemovedSessionTranscripts(params) {
1387
- const { archiveSessionTranscripts } = await loadSessionArchiveRuntime();
1388
- const archivedDirs = /* @__PURE__ */ new Set();
1389
- for (const [sessionId, sessionFile] of params.removedSessionFiles) {
1390
- if (params.referencedSessionIds.has(sessionId)) continue;
1391
- const archived = archiveSessionTranscripts({
1392
- sessionId,
1393
- storePath: params.storePath,
1394
- sessionFile,
1395
- reason: params.reason,
1396
- restrictToStoreDir: params.restrictToStoreDir
1397
- });
1398
- for (const archivedPath of archived) archivedDirs.add(path.dirname(archivedPath));
1399
- }
1400
- return archivedDirs;
1401
- }
1402
- async function writeSessionStoreAtomic(params) {
1403
- await writeTextAtomic(params.storePath, params.serialized, { mode: 384 });
1404
- updateSessionStoreWriteCaches({
1405
- storePath: params.storePath,
1406
- store: params.store,
1407
- serialized: params.serialized
1408
- });
1409
- }
1410
- function lockTimeoutError(storePath) {
1411
- return /* @__PURE__ */ new Error(`timeout waiting for session store lock: ${storePath}`);
1412
- }
1413
- function resolveSessionStoreLockMaxHoldMs(timeoutMs) {
1414
- if (timeoutMs == null || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return;
1415
- return resolveSessionLockMaxHoldFromTimeout({
1416
- timeoutMs,
1417
- graceMs: SESSION_STORE_LOCK_TIMEOUT_GRACE_MS,
1418
- minMs: SESSION_STORE_LOCK_MIN_HOLD_MS
1419
- });
1420
- }
1421
- function getOrCreateLockQueue(storePath) {
1422
- const existing = LOCK_QUEUES.get(storePath);
1423
- if (existing) return existing;
1424
- const created = {
1425
- running: false,
1426
- pending: [],
1427
- drainPromise: null
1428
- };
1429
- LOCK_QUEUES.set(storePath, created);
1430
- return created;
1431
- }
1432
- async function drainSessionStoreLockQueue(storePath) {
1433
- const queue = LOCK_QUEUES.get(storePath);
1434
- if (!queue) return;
1435
- if (queue.drainPromise) {
1436
- await queue.drainPromise;
1437
- return;
1438
- }
1439
- queue.running = true;
1440
- queue.drainPromise = (async () => {
1441
- try {
1442
- while (queue.pending.length > 0) {
1443
- const task = queue.pending.shift();
1444
- if (!task) continue;
1445
- const remainingTimeoutMs = task.timeoutMs ?? Number.POSITIVE_INFINITY;
1446
- if (task.timeoutMs != null && remainingTimeoutMs <= 0) {
1447
- task.reject(lockTimeoutError(storePath));
1448
- continue;
1449
- }
1450
- let lock;
1451
- let result;
1452
- let failed;
1453
- let hasFailure = false;
1454
- try {
1455
- lock = await (sessionWriteLockAcquirerForTests ?? acquireSessionWriteLock)({
1456
- sessionFile: storePath,
1457
- timeoutMs: remainingTimeoutMs,
1458
- staleMs: task.staleMs,
1459
- maxHoldMs: resolveSessionStoreLockMaxHoldMs(task.timeoutMs)
1460
- });
1461
- result = await task.fn();
1462
- } catch (err) {
1463
- hasFailure = true;
1464
- failed = err;
1465
- } finally {
1466
- await lock?.release().catch(() => void 0);
1467
- }
1468
- if (hasFailure) {
1469
- task.reject(failed);
1470
- continue;
1471
- }
1472
- task.resolve(result);
1473
- }
1474
- } finally {
1475
- queue.running = false;
1476
- queue.drainPromise = null;
1477
- if (queue.pending.length === 0) LOCK_QUEUES.delete(storePath);
1478
- else queueMicrotask(() => {
1479
- drainSessionStoreLockQueue(storePath);
1480
- });
1481
- }
1482
- })();
1483
- await queue.drainPromise;
1484
- }
1485
- async function withSessionStoreLock(storePath, fn, opts = {}) {
1486
- if (!storePath || typeof storePath !== "string") throw new Error(`withSessionStoreLock: storePath must be a non-empty string, got ${JSON.stringify(storePath)}`);
1487
- const timeoutMs = opts.timeoutMs ?? 1e4;
1488
- const staleMs = opts.staleMs ?? 3e4;
1489
- opts.pollIntervalMs;
1490
- const hasTimeout = timeoutMs > 0 && Number.isFinite(timeoutMs);
1491
- const queue = getOrCreateLockQueue(storePath);
1492
- return await new Promise((resolve, reject) => {
1493
- const task = {
1494
- fn: async () => await fn(),
1495
- resolve: (value) => resolve(value),
1496
- reject,
1497
- timeoutMs: hasTimeout ? timeoutMs : void 0,
1498
- staleMs
1499
- };
1500
- queue.pending.push(task);
1501
- drainSessionStoreLockQueue(storePath);
1502
- });
1503
- }
1504
- //#endregion
1505
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/facade-runtime-DJ_ZWLEP.js
1506
- function createLazyFacadeValue(loadFacadeModule, key) {
1507
- return ((...args) => {
1508
- const value = loadFacadeModule()[key];
1509
- if (typeof value !== "function") return value;
1510
- return value(...args);
1511
- });
1512
- }
1513
- const OPENCLAW_PACKAGE_ROOT = resolveLoaderPackageRoot({
1514
- modulePath: fileURLToPath(import.meta.url),
1515
- moduleUrl: import.meta.url
1516
- }) ?? fileURLToPath(new URL("../..", import.meta.url));
1517
- const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
1518
- const OPENCLAW_SOURCE_EXTENSIONS_ROOT = path.resolve(OPENCLAW_PACKAGE_ROOT, "extensions");
1519
- const cachedFacadeModuleLocationsByKey = /* @__PURE__ */ new Map();
1520
- function createFacadeResolutionKey(params) {
1521
- const bundledPluginsDir = resolveBundledPluginsDir(params.env ?? process.env);
1522
- return createFacadeResolutionKey$1({
1523
- ...params,
1524
- bundledPluginsDir
1525
- });
1526
- }
1527
- function resolveRegistryPluginModuleLocation(params) {
1528
- return loadFacadeActivationCheckRuntime().resolveRegistryPluginModuleLocation({
1529
- ...params,
1530
- resolutionKey: createFacadeResolutionKey(params)
1531
- });
1532
- }
1533
- function resolveFacadeModuleLocationUncached(params) {
1534
- const bundledPluginsDir = resolveBundledPluginsDir(params.env ?? process.env);
1535
- const bundledLocation = resolveBundledFacadeModuleLocation({
1536
- ...params,
1537
- currentModulePath: CURRENT_MODULE_PATH,
1538
- packageRoot: OPENCLAW_PACKAGE_ROOT,
1539
- bundledPluginsDir
1540
- });
1541
- if (bundledLocation) return bundledLocation;
1542
- return resolveRegistryPluginModuleLocation(params);
1543
- }
1544
- function resolveFacadeModuleLocation(params) {
1545
- return resolveCachedFacadeModuleLocation({
1546
- cache: cachedFacadeModuleLocationsByKey,
1547
- key: createFacadeResolutionKey(params),
1548
- resolve: () => resolveFacadeModuleLocationUncached(params)
1549
- });
1550
- }
1551
- const nodeRequire = createRequire(import.meta.url);
1552
- const FACADE_ACTIVATION_CHECK_RUNTIME_CANDIDATES = ["./facade-activation-check.runtime.js", "./facade-activation-check.runtime.ts"];
1553
- let facadeActivationCheckRuntimeModule;
1554
- const facadeActivationCheckRuntimeJitiLoaders = /* @__PURE__ */ new Map();
1555
- function getFacadeActivationCheckRuntimeJiti(modulePath) {
1556
- return getCachedPluginJitiLoader({
1557
- cache: facadeActivationCheckRuntimeJitiLoaders,
1558
- modulePath,
1559
- importerUrl: import.meta.url,
1560
- jitiFilename: import.meta.url,
1561
- aliasMap: {},
1562
- tryNative: false
1563
- });
1564
- }
1565
- function loadFacadeActivationCheckRuntimeFromCandidates(loadCandidate) {
1566
- for (const candidate of FACADE_ACTIVATION_CHECK_RUNTIME_CANDIDATES) try {
1567
- return loadCandidate(candidate);
1568
- } catch {}
1569
- }
1570
- function loadFacadeActivationCheckRuntime() {
1571
- if (facadeActivationCheckRuntimeModule) return facadeActivationCheckRuntimeModule;
1572
- facadeActivationCheckRuntimeModule = loadFacadeActivationCheckRuntimeFromCandidates((candidate) => nodeRequire(candidate));
1573
- if (facadeActivationCheckRuntimeModule) return facadeActivationCheckRuntimeModule;
1574
- facadeActivationCheckRuntimeModule = loadFacadeActivationCheckRuntimeFromCandidates((candidate) => getFacadeActivationCheckRuntimeJiti(candidate)(candidate));
1575
- if (facadeActivationCheckRuntimeModule) return facadeActivationCheckRuntimeModule;
1576
- throw new Error("Unable to load facade activation check runtime");
1577
- }
1578
- function loadFacadeModuleAtLocationSync(params) {
1579
- return loadFacadeModuleAtLocationSync$1(params);
1580
- }
1581
- function buildFacadeActivationCheckParams(params, location = resolveFacadeModuleLocation(params)) {
1582
- return {
1583
- ...params,
1584
- location,
1585
- sourceExtensionsRoot: OPENCLAW_SOURCE_EXTENSIONS_ROOT,
1586
- resolutionKey: createFacadeResolutionKey(params)
1587
- };
1588
- }
1589
- function loadBundledPluginPublicSurfaceModuleSync(params) {
1590
- const location = resolveFacadeModuleLocation(params);
1591
- const trackedPluginId = () => loadFacadeActivationCheckRuntime().resolveTrackedFacadePluginId(buildFacadeActivationCheckParams(params, location));
1592
- if (!location) return loadBundledPluginPublicSurfaceModuleSync$1({
1593
- ...params,
1594
- trackedPluginId
1595
- });
1596
- return loadFacadeModuleAtLocationSync({
1597
- location,
1598
- trackedPluginId
1599
- });
1600
- }
1601
- function loadActivatedBundledPluginPublicSurfaceModuleSync(params) {
1602
- loadFacadeActivationCheckRuntime().resolveActivatedBundledPluginPublicSurfaceAccessOrThrow(buildFacadeActivationCheckParams(params));
1603
- return loadBundledPluginPublicSurfaceModuleSync(params);
1604
- }
1605
- function tryLoadActivatedBundledPluginPublicSurfaceModuleSync(params) {
1606
- if (!loadFacadeActivationCheckRuntime().resolveBundledPluginPublicSurfaceAccess(buildFacadeActivationCheckParams(params)).allowed) return null;
1607
- return loadBundledPluginPublicSurfaceModuleSync(params);
1608
- }
1609
- //#endregion
1610
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/session-conversation-DOWP59Dq.js
1611
- const SESSION_KEY_API_ARTIFACT_BASENAME = "session-key-api.js";
1612
- const bundledSessionConversationFallbackCache = /* @__PURE__ */ new Map();
1613
- function normalizeResolvedChannel(channel) {
1614
- return normalizeChannelId$1(channel) ?? normalizeChannelId(channel) ?? normalizeOptionalLowercaseString(channel) ?? "";
1615
- }
1616
- function getMessagingAdapter(channel) {
1617
- const normalizedChannel = normalizeResolvedChannel(channel);
1618
- try {
1619
- return getLoadedChannelPlugin(normalizedChannel)?.messaging;
1620
- } catch {
1621
- return;
1622
- }
1623
- }
1624
- function dedupeConversationIds(values) {
1625
- const seen = /* @__PURE__ */ new Set();
1626
- const resolved = [];
1627
- for (const value of values) {
1628
- if (typeof value !== "string") continue;
1629
- const trimmed = value.trim();
1630
- if (!trimmed || seen.has(trimmed)) continue;
1631
- seen.add(trimmed);
1632
- resolved.push(trimmed);
1633
- }
1634
- return resolved;
1635
- }
1636
- function buildGenericConversationResolution(rawId) {
1637
- const trimmed = rawId.trim();
1638
- if (!trimmed) return null;
1639
- const parsed = parseThreadSessionSuffix(trimmed);
1640
- const id = (parsed.baseSessionKey ?? trimmed).trim();
1641
- if (!id) return null;
1642
- return {
1643
- id,
1644
- threadId: parsed.threadId,
1645
- baseConversationId: id,
1646
- parentConversationCandidates: dedupeConversationIds(parsed.threadId ? [parsed.baseSessionKey] : [])
1647
- };
1648
- }
1649
- function normalizeSessionConversationResolution(resolved) {
1650
- if (!resolved?.id?.trim()) return null;
1651
- return {
1652
- id: resolved.id.trim(),
1653
- threadId: normalizeOptionalString(resolved.threadId),
1654
- baseConversationId: normalizeOptionalString(resolved.baseConversationId) ?? dedupeConversationIds(resolved.parentConversationCandidates ?? []).at(-1) ?? resolved.id.trim(),
1655
- parentConversationCandidates: dedupeConversationIds(resolved.parentConversationCandidates ?? []),
1656
- hasExplicitParentConversationCandidates: Object.hasOwn(resolved, "parentConversationCandidates")
1657
- };
1658
- }
1659
- function resolveBundledSessionConversationFallback(params) {
1660
- if (isBundledSessionConversationFallbackDisabled(params.channel)) return null;
1661
- const dirName = normalizeResolvedChannel(params.channel);
1662
- const version = getActivePluginChannelRegistryVersion();
1663
- let cached = bundledSessionConversationFallbackCache.get(dirName);
1664
- if (!cached || cached.version !== version) {
1665
- let resolveSessionConversation = null;
1666
- try {
1667
- const loaded = tryLoadActivatedBundledPluginPublicSurfaceModuleSync({
1668
- dirName,
1669
- artifactBasename: SESSION_KEY_API_ARTIFACT_BASENAME
1670
- });
1671
- resolveSessionConversation = typeof loaded?.resolveSessionConversation === "function" ? loaded.resolveSessionConversation : null;
1672
- } catch {
1673
- resolveSessionConversation = null;
1674
- }
1675
- cached = {
1676
- version,
1677
- resolveSessionConversation
1678
- };
1679
- bundledSessionConversationFallbackCache.set(dirName, cached);
1680
- }
1681
- if (typeof cached.resolveSessionConversation !== "function") return null;
1682
- return normalizeSessionConversationResolution(cached.resolveSessionConversation({
1683
- kind: params.kind,
1684
- rawId: params.rawId
1685
- }));
1686
- }
1687
- function isBundledSessionConversationFallbackDisabled(channel) {
1688
- const snapshot = getRuntimeConfigSnapshot();
1689
- if (!snapshot?.plugins) return false;
1690
- if (snapshot.plugins.enabled === false) return true;
1691
- const entry = snapshot.plugins.entries?.[normalizeResolvedChannel(channel)];
1692
- return !!entry && typeof entry === "object" && entry.enabled === false;
1693
- }
1694
- function shouldProbeBundledSessionConversationFallback(rawId) {
1695
- return rawId.includes(":");
1696
- }
1697
- function resolveSessionConversationResolution(params) {
1698
- const rawId = params.rawId.trim();
1699
- if (!rawId) return null;
1700
- const messaging = getMessagingAdapter(params.channel);
1701
- const pluginResolved = normalizeSessionConversationResolution(messaging?.resolveSessionConversation?.({
1702
- kind: params.kind,
1703
- rawId
1704
- }));
1705
- const shouldTryBundledFallback = params.bundledFallback !== false && !messaging && shouldProbeBundledSessionConversationFallback(rawId);
1706
- const resolved = pluginResolved ?? (shouldTryBundledFallback ? resolveBundledSessionConversationFallback({
1707
- channel: params.channel,
1708
- kind: params.kind,
1709
- rawId
1710
- }) : null) ?? buildGenericConversationResolution(rawId);
1711
- if (!resolved) return null;
1712
- const parentConversationCandidates = dedupeConversationIds(pluginResolved?.hasExplicitParentConversationCandidates ? resolved.parentConversationCandidates : messaging?.resolveParentConversationCandidates?.({
1713
- kind: params.kind,
1714
- rawId
1715
- }) ?? resolved.parentConversationCandidates);
1716
- const baseConversationId = parentConversationCandidates.at(-1) ?? resolved.baseConversationId ?? resolved.id;
1717
- return {
1718
- ...resolved,
1719
- baseConversationId,
1720
- parentConversationCandidates
1721
- };
1722
- }
1723
- function resolveSessionConversation(params) {
1724
- return resolveSessionConversationResolution(params);
1725
- }
1726
- //#endregion
1727
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/transcript-events-e-pVl4cn.js
1728
- const SESSION_TRANSCRIPT_LISTENERS = /* @__PURE__ */ new Set();
1729
- function emitSessionTranscriptUpdate(update) {
1730
- const normalized = typeof update === "string" ? { sessionFile: update } : {
1731
- sessionFile: update.sessionFile,
1732
- sessionKey: update.sessionKey,
1733
- message: update.message,
1734
- messageId: update.messageId
1735
- };
1736
- const trimmed = normalizeOptionalString(normalized.sessionFile);
1737
- if (!trimmed) return;
1738
- const nextUpdate = {
1739
- sessionFile: trimmed,
1740
- ...normalizeOptionalString(normalized.sessionKey) ? { sessionKey: normalizeOptionalString(normalized.sessionKey) } : {},
1741
- ...normalized.message !== void 0 ? { message: normalized.message } : {},
1742
- ...normalizeOptionalString(normalized.messageId) ? { messageId: normalizeOptionalString(normalized.messageId) } : {}
1743
- };
1744
- for (const listener of SESSION_TRANSCRIPT_LISTENERS) try {
1745
- listener(nextUpdate);
1746
- } catch {}
1747
- }
1748
- //#endregion
1749
- //#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/transcript-E_-ISOkD.js
1750
- async function resolveAndPersistSessionFile(params) {
1751
- const { sessionId, sessionKey, sessionStore, storePath } = params;
1752
- const baseEntry = params.sessionEntry ?? sessionStore[sessionKey] ?? {
1753
- sessionId,
1754
- updatedAt: Date.now()
1755
- };
1756
- const shouldReusePersistedSessionFile = baseEntry.sessionId === sessionId;
1757
- const fallbackSessionFile = params.fallbackSessionFile?.trim();
1758
- const sessionFile = resolveSessionFilePath(sessionId, !shouldReusePersistedSessionFile ? fallbackSessionFile ? {
1759
- ...baseEntry,
1760
- sessionFile: fallbackSessionFile
1761
- } : {
1762
- ...baseEntry,
1763
- sessionFile: void 0
1764
- } : !baseEntry.sessionFile && fallbackSessionFile ? {
1765
- ...baseEntry,
1766
- sessionFile: fallbackSessionFile
1767
- } : baseEntry, {
1768
- agentId: params.agentId,
1769
- sessionsDir: params.sessionsDir
1770
- });
1771
- const persistedEntry = {
1772
- ...baseEntry,
1773
- sessionId,
1774
- updatedAt: Date.now(),
1775
- sessionFile
1776
- };
1777
- if (baseEntry.sessionId !== sessionId || baseEntry.sessionFile !== sessionFile) {
1778
- sessionStore[sessionKey] = persistedEntry;
1779
- await updateSessionStore(storePath, (store) => {
1780
- store[sessionKey] = {
1781
- ...store[sessionKey],
1782
- ...persistedEntry
1783
- };
1784
- }, params.activeSessionKey || params.maintenanceConfig ? {
1785
- ...params.activeSessionKey ? { activeSessionKey: params.activeSessionKey } : {},
1786
- ...params.maintenanceConfig ? { maintenanceConfig: params.maintenanceConfig } : {}
1787
- } : void 0);
1788
- return {
1789
- sessionFile,
1790
- sessionEntry: persistedEntry
1791
- };
1792
- }
1793
- sessionStore[sessionKey] = persistedEntry;
1794
- return {
1795
- sessionFile,
1796
- sessionEntry: persistedEntry
1797
- };
1798
- }
1799
- function stripQuery(value) {
1800
- const noHash = value.split("#")[0] ?? value;
1801
- return noHash.split("?")[0] ?? noHash;
1802
- }
1803
- function extractFileNameFromMediaUrl(value) {
1804
- const trimmed = value.trim();
1805
- if (!trimmed) return null;
1806
- const cleaned = stripQuery(trimmed);
1807
- try {
1808
- const parsed = new URL(cleaned);
1809
- const base = path.basename(parsed.pathname);
1810
- if (!base) return null;
1811
- try {
1812
- return decodeURIComponent(base);
1813
- } catch {
1814
- return base;
1815
- }
1816
- } catch {
1817
- const base = path.basename(cleaned);
1818
- if (!base || base === "/" || base === ".") return null;
1819
- return base;
1820
- }
1821
- }
1822
- function resolveMirroredTranscriptText(params) {
1823
- const mediaUrls = params.mediaUrls?.filter((url) => url && url.trim()) ?? [];
1824
- if (mediaUrls.length > 0) {
1825
- const names = mediaUrls.map((url) => extractFileNameFromMediaUrl(url)).filter((name) => Boolean(name && name.trim()));
1826
- if (names.length > 0) return names.join(", ");
1827
- return "media";
1828
- }
1829
- const trimmed = (params.text ?? "").trim();
1830
- return trimmed ? trimmed : null;
1831
- }
1832
- async function ensureSessionHeader(params) {
1833
- if (fs.existsSync(params.sessionFile)) return;
1834
- await fs.promises.mkdir(path.dirname(params.sessionFile), { recursive: true });
1835
- const header = {
1836
- type: "session",
1837
- version: 3,
1838
- id: params.sessionId,
1839
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1840
- cwd: process.cwd()
1841
- };
1842
- await fs.promises.writeFile(params.sessionFile, `${JSON.stringify(header)}\n`, {
1843
- encoding: "utf-8",
1844
- mode: 384
1845
- });
1846
- }
1847
- async function appendAssistantMessageToSessionTranscript(params) {
1848
- const sessionKey = params.sessionKey.trim();
1849
- if (!sessionKey) return {
1850
- ok: false,
1851
- reason: "missing sessionKey"
1852
- };
1853
- const mirrorText = resolveMirroredTranscriptText({
1854
- text: params.text,
1855
- mediaUrls: params.mediaUrls
1856
- });
1857
- if (!mirrorText) return {
1858
- ok: false,
1859
- reason: "empty text"
1860
- };
1861
- return appendExactAssistantMessageToSessionTranscript({
1862
- agentId: params.agentId,
1863
- sessionKey,
1864
- storePath: params.storePath,
1865
- idempotencyKey: params.idempotencyKey,
1866
- updateMode: params.updateMode,
1867
- message: {
1868
- role: "assistant",
1869
- content: [{
1870
- type: "text",
1871
- text: mirrorText
1872
- }],
1873
- api: "openai-responses",
1874
- provider: "openclaw",
1875
- model: "delivery-mirror",
1876
- usage: {
1877
- input: 0,
1878
- output: 0,
1879
- cacheRead: 0,
1880
- cacheWrite: 0,
1881
- totalTokens: 0,
1882
- cost: {
1883
- input: 0,
1884
- output: 0,
1885
- cacheRead: 0,
1886
- cacheWrite: 0,
1887
- total: 0
1888
- }
1889
- },
1890
- stopReason: "stop",
1891
- timestamp: Date.now()
1892
- }
1893
- });
1894
- }
1895
- async function appendExactAssistantMessageToSessionTranscript(params) {
1896
- const sessionKey = params.sessionKey.trim();
1897
- if (!sessionKey) return {
1898
- ok: false,
1899
- reason: "missing sessionKey"
1900
- };
1901
- if (params.message.role !== "assistant") return {
1902
- ok: false,
1903
- reason: "message role must be assistant"
1904
- };
1905
- const storePath = params.storePath ?? resolveDefaultSessionStorePath(params.agentId);
1906
- const store = loadSessionStore(storePath, { skipCache: true });
1907
- const entry = store[normalizeStoreSessionKey(sessionKey)] ?? store[sessionKey];
1908
- if (!entry?.sessionId) return {
1909
- ok: false,
1910
- reason: `unknown sessionKey: ${sessionKey}`
1911
- };
1912
- let sessionFile;
1913
- try {
1914
- sessionFile = (await resolveAndPersistSessionFile({
1915
- sessionId: entry.sessionId,
1916
- sessionKey,
1917
- sessionStore: store,
1918
- storePath,
1919
- sessionEntry: entry,
1920
- agentId: params.agentId,
1921
- sessionsDir: path.dirname(storePath)
1922
- })).sessionFile;
1923
- } catch (err) {
1924
- return {
1925
- ok: false,
1926
- reason: formatErrorMessage(err)
1927
- };
1928
- }
1929
- await ensureSessionHeader({
1930
- sessionFile,
1931
- sessionId: entry.sessionId
1932
- });
1933
- const explicitIdempotencyKey = params.idempotencyKey ?? params.message.idempotencyKey;
1934
- const existingMessageId = explicitIdempotencyKey ? await transcriptHasIdempotencyKey(sessionFile, explicitIdempotencyKey) : void 0;
1935
- if (existingMessageId) return {
1936
- ok: true,
1937
- sessionFile,
1938
- messageId: existingMessageId
1939
- };
1940
- const latestEquivalentAssistantId = isRedundantDeliveryMirror(params.message) ? await findLatestEquivalentAssistantMessageId(sessionFile, params.message) : void 0;
1941
- if (latestEquivalentAssistantId) return {
1942
- ok: true,
1943
- sessionFile,
1944
- messageId: latestEquivalentAssistantId
1945
- };
1946
- const message = {
1947
- ...params.message,
1948
- ...explicitIdempotencyKey ? { idempotencyKey: explicitIdempotencyKey } : {}
1949
- };
1950
- const messageId = SessionManager.open(sessionFile).appendMessage(message);
1951
- switch (params.updateMode ?? "inline") {
1952
- case "inline":
1953
- emitSessionTranscriptUpdate({
1954
- sessionFile,
1955
- sessionKey,
1956
- message,
1957
- messageId
1958
- });
1959
- break;
1960
- case "file-only":
1961
- emitSessionTranscriptUpdate(sessionFile);
1962
- break;
1963
- case "none": break;
1964
- }
1965
- return {
1966
- ok: true,
1967
- sessionFile,
1968
- messageId
1969
- };
1970
- }
1971
- async function transcriptHasIdempotencyKey(transcriptPath, idempotencyKey) {
1972
- try {
1973
- const raw = await fs.promises.readFile(transcriptPath, "utf-8");
1974
- for (const line of raw.split(/\r?\n/)) {
1975
- if (!line.trim()) continue;
1976
- try {
1977
- const parsed = JSON.parse(line);
1978
- if (parsed.message?.idempotencyKey === idempotencyKey && typeof parsed.id === "string" && parsed.id) return parsed.id;
1979
- } catch {
1980
- continue;
1981
- }
1982
- }
1983
- } catch {
1984
- return;
1985
- }
1986
- }
1987
- function isRedundantDeliveryMirror(message) {
1988
- return message.provider === "openclaw" && message.model === "delivery-mirror";
1989
- }
1990
- function extractAssistantMessageText(message) {
1991
- if (!Array.isArray(message.content)) return null;
1992
- const parts = message.content.filter((part) => part.type === "text" && typeof part.text === "string" && part.text.trim().length > 0).map((part) => part.text.trim());
1993
- return parts.length > 0 ? parts.join("\n").trim() : null;
1994
- }
1995
- async function findLatestEquivalentAssistantMessageId(transcriptPath, message) {
1996
- const expectedText = extractAssistantMessageText(message);
1997
- if (!expectedText) return;
1998
- try {
1999
- const lines = (await fs.promises.readFile(transcriptPath, "utf-8")).split(/\r?\n/);
2000
- for (let index = lines.length - 1; index >= 0; index -= 1) {
2001
- const line = lines[index];
2002
- if (!line.trim()) continue;
2003
- try {
2004
- const parsed = JSON.parse(line);
2005
- const candidate = parsed.message;
2006
- if (!candidate || candidate.role !== "assistant") continue;
2007
- if (extractAssistantMessageText(candidate) !== expectedText) return;
2008
- if (typeof parsed.id === "string" && parsed.id) return parsed.id;
2009
- return;
2010
- } catch {
2011
- continue;
2012
- }
2013
- }
2014
- } catch {
2015
- return;
2016
- }
2017
- }
2018
- //#endregion
2019
- export { createLazyFacadeValue as a, loadSessionStore as c, resolveSessionConversation as i, appendExactAssistantMessageToSessionTranscript as n, loadActivatedBundledPluginPublicSurfaceModuleSync as o, resolveMirroredTranscriptText as r, updateSessionStore as s, appendAssistantMessageToSessionTranscript as t };