@gatanot/qualia_web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/build/client/_app/immutable/assets/0.BlmLthUu.css +1 -0
  2. package/build/client/_app/immutable/assets/0.BlmLthUu.css.br +0 -0
  3. package/build/client/_app/immutable/assets/0.BlmLthUu.css.gz +0 -0
  4. package/build/client/_app/immutable/assets/2.C6F1hpzI.css +1 -0
  5. package/build/client/_app/immutable/assets/2.C6F1hpzI.css.br +0 -0
  6. package/build/client/_app/immutable/assets/2.C6F1hpzI.css.gz +0 -0
  7. package/build/client/_app/immutable/assets/3.D8sLuVpx.css +1 -0
  8. package/build/client/_app/immutable/assets/3.D8sLuVpx.css.br +0 -0
  9. package/build/client/_app/immutable/assets/3.D8sLuVpx.css.gz +0 -0
  10. package/build/client/_app/immutable/assets/4.1xWrYHn4.css +1 -0
  11. package/build/client/_app/immutable/assets/4.1xWrYHn4.css.br +0 -0
  12. package/build/client/_app/immutable/assets/4.1xWrYHn4.css.gz +0 -0
  13. package/build/client/_app/immutable/assets/5.K6sy6bnZ.css +1 -0
  14. package/build/client/_app/immutable/assets/5.K6sy6bnZ.css.br +0 -0
  15. package/build/client/_app/immutable/assets/5.K6sy6bnZ.css.gz +0 -0
  16. package/build/client/_app/immutable/assets/ChatInput.CmxPxwkj.css +1 -0
  17. package/build/client/_app/immutable/assets/ChatInput.CmxPxwkj.css.br +0 -0
  18. package/build/client/_app/immutable/assets/ChatInput.CmxPxwkj.css.gz +0 -0
  19. package/build/client/_app/immutable/assets/KaTeX_AMS-Regular.BQhdFMY1.woff2 +0 -0
  20. package/build/client/_app/immutable/assets/KaTeX_AMS-Regular.DMm9YOAa.woff +0 -0
  21. package/build/client/_app/immutable/assets/KaTeX_AMS-Regular.DRggAlZN.ttf +0 -0
  22. package/build/client/_app/immutable/assets/KaTeX_Caligraphic-Bold.ATXxdsX0.ttf +0 -0
  23. package/build/client/_app/immutable/assets/KaTeX_Caligraphic-Bold.BEiXGLvX.woff +0 -0
  24. package/build/client/_app/immutable/assets/KaTeX_Caligraphic-Bold.Dq_IR9rO.woff2 +0 -0
  25. package/build/client/_app/immutable/assets/KaTeX_Caligraphic-Regular.CTRA-rTL.woff +0 -0
  26. package/build/client/_app/immutable/assets/KaTeX_Caligraphic-Regular.Di6jR-x-.woff2 +0 -0
  27. package/build/client/_app/immutable/assets/KaTeX_Caligraphic-Regular.wX97UBjC.ttf +0 -0
  28. package/build/client/_app/immutable/assets/KaTeX_Fraktur-Bold.BdnERNNW.ttf +0 -0
  29. package/build/client/_app/immutable/assets/KaTeX_Fraktur-Bold.BsDP51OF.woff +0 -0
  30. package/build/client/_app/immutable/assets/KaTeX_Fraktur-Bold.CL6g_b3V.woff2 +0 -0
  31. package/build/client/_app/immutable/assets/KaTeX_Fraktur-Regular.CB_wures.ttf +0 -0
  32. package/build/client/_app/immutable/assets/KaTeX_Fraktur-Regular.CTYiF6lA.woff2 +0 -0
  33. package/build/client/_app/immutable/assets/KaTeX_Fraktur-Regular.Dxdc4cR9.woff +0 -0
  34. package/build/client/_app/immutable/assets/KaTeX_Main-Bold.Cx986IdX.woff2 +0 -0
  35. package/build/client/_app/immutable/assets/KaTeX_Main-Bold.Jm3AIy58.woff +0 -0
  36. package/build/client/_app/immutable/assets/KaTeX_Main-Bold.waoOVXN0.ttf +0 -0
  37. package/build/client/_app/immutable/assets/KaTeX_Main-BoldItalic.DxDJ3AOS.woff2 +0 -0
  38. package/build/client/_app/immutable/assets/KaTeX_Main-BoldItalic.DzxPMmG6.ttf +0 -0
  39. package/build/client/_app/immutable/assets/KaTeX_Main-BoldItalic.SpSLRI95.woff +0 -0
  40. package/build/client/_app/immutable/assets/KaTeX_Main-Italic.3WenGoN9.ttf +0 -0
  41. package/build/client/_app/immutable/assets/KaTeX_Main-Italic.BMLOBm91.woff +0 -0
  42. package/build/client/_app/immutable/assets/KaTeX_Main-Italic.NWA7e6Wa.woff2 +0 -0
  43. package/build/client/_app/immutable/assets/KaTeX_Main-Regular.B22Nviop.woff2 +0 -0
  44. package/build/client/_app/immutable/assets/KaTeX_Main-Regular.Dr94JaBh.woff +0 -0
  45. package/build/client/_app/immutable/assets/KaTeX_Main-Regular.ypZvNtVU.ttf +0 -0
  46. package/build/client/_app/immutable/assets/KaTeX_Math-BoldItalic.B3XSjfu4.ttf +0 -0
  47. package/build/client/_app/immutable/assets/KaTeX_Math-BoldItalic.CZnvNsCZ.woff2 +0 -0
  48. package/build/client/_app/immutable/assets/KaTeX_Math-BoldItalic.iY-2wyZ7.woff +0 -0
  49. package/build/client/_app/immutable/assets/KaTeX_Math-Italic.DA0__PXp.woff +0 -0
  50. package/build/client/_app/immutable/assets/KaTeX_Math-Italic.flOr_0UB.ttf +0 -0
  51. package/build/client/_app/immutable/assets/KaTeX_Math-Italic.t53AETM-.woff2 +0 -0
  52. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Bold.CFMepnvq.ttf +0 -0
  53. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Bold.D1sUS0GD.woff2 +0 -0
  54. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Bold.DbIhKOiC.woff +0 -0
  55. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Italic.C3H0VqGB.woff2 +0 -0
  56. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Italic.DN2j7dab.woff +0 -0
  57. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Italic.YYjJ1zSn.ttf +0 -0
  58. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Regular.BNo7hRIc.ttf +0 -0
  59. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Regular.CS6fqUqJ.woff +0 -0
  60. package/build/client/_app/immutable/assets/KaTeX_SansSerif-Regular.DDBCnlJ7.woff2 +0 -0
  61. package/build/client/_app/immutable/assets/KaTeX_Script-Regular.C5JkGWo-.ttf +0 -0
  62. package/build/client/_app/immutable/assets/KaTeX_Script-Regular.D3wIWfF6.woff2 +0 -0
  63. package/build/client/_app/immutable/assets/KaTeX_Script-Regular.D5yQViql.woff +0 -0
  64. package/build/client/_app/immutable/assets/KaTeX_Size1-Regular.C195tn64.woff +0 -0
  65. package/build/client/_app/immutable/assets/KaTeX_Size1-Regular.Dbsnue_I.ttf +0 -0
  66. package/build/client/_app/immutable/assets/KaTeX_Size1-Regular.mCD8mA8B.woff2 +0 -0
  67. package/build/client/_app/immutable/assets/KaTeX_Size2-Regular.B7gKUWhC.ttf +0 -0
  68. package/build/client/_app/immutable/assets/KaTeX_Size2-Regular.Dy4dx90m.woff2 +0 -0
  69. package/build/client/_app/immutable/assets/KaTeX_Size2-Regular.oD1tc_U0.woff +0 -0
  70. package/build/client/_app/immutable/assets/KaTeX_Size3-Regular.CTq5MqoE.woff +0 -0
  71. package/build/client/_app/immutable/assets/KaTeX_Size3-Regular.DgpXs0kz.ttf +0 -0
  72. package/build/client/_app/immutable/assets/KaTeX_Size4-Regular.BF-4gkZK.woff +0 -0
  73. package/build/client/_app/immutable/assets/KaTeX_Size4-Regular.DWFBv043.ttf +0 -0
  74. package/build/client/_app/immutable/assets/KaTeX_Size4-Regular.Dl5lxZxV.woff2 +0 -0
  75. package/build/client/_app/immutable/assets/KaTeX_Typewriter-Regular.C0xS9mPB.woff +0 -0
  76. package/build/client/_app/immutable/assets/KaTeX_Typewriter-Regular.CO6r4hn1.woff2 +0 -0
  77. package/build/client/_app/immutable/assets/KaTeX_Typewriter-Regular.D3Ib7_Hf.ttf +0 -0
  78. package/build/client/_app/immutable/chunks/B39M1lOz.js +3 -0
  79. package/build/client/_app/immutable/chunks/B39M1lOz.js.br +0 -0
  80. package/build/client/_app/immutable/chunks/B39M1lOz.js.gz +0 -0
  81. package/build/client/_app/immutable/chunks/BMcRbUT8.js +3 -0
  82. package/build/client/_app/immutable/chunks/BMcRbUT8.js.br +0 -0
  83. package/build/client/_app/immutable/chunks/BMcRbUT8.js.gz +0 -0
  84. package/build/client/_app/immutable/chunks/BN2zEB6w.js +1 -0
  85. package/build/client/_app/immutable/chunks/BN2zEB6w.js.br +0 -0
  86. package/build/client/_app/immutable/chunks/BN2zEB6w.js.gz +0 -0
  87. package/build/client/_app/immutable/chunks/BVDlhZK_.js +1 -0
  88. package/build/client/_app/immutable/chunks/BVDlhZK_.js.br +2 -0
  89. package/build/client/_app/immutable/chunks/BVDlhZK_.js.gz +0 -0
  90. package/build/client/_app/immutable/chunks/CxmPiQW9.js +1 -0
  91. package/build/client/_app/immutable/chunks/CxmPiQW9.js.br +0 -0
  92. package/build/client/_app/immutable/chunks/CxmPiQW9.js.gz +0 -0
  93. package/build/client/_app/immutable/chunks/DAIlYrs_.js +1 -0
  94. package/build/client/_app/immutable/chunks/DAIlYrs_.js.br +0 -0
  95. package/build/client/_app/immutable/chunks/DAIlYrs_.js.gz +0 -0
  96. package/build/client/_app/immutable/chunks/Ir23lSxH.js +329 -0
  97. package/build/client/_app/immutable/chunks/Ir23lSxH.js.br +0 -0
  98. package/build/client/_app/immutable/chunks/Ir23lSxH.js.gz +0 -0
  99. package/build/client/_app/immutable/chunks/gZTJ0hjf.js +1 -0
  100. package/build/client/_app/immutable/chunks/gZTJ0hjf.js.br +0 -0
  101. package/build/client/_app/immutable/chunks/gZTJ0hjf.js.gz +0 -0
  102. package/build/client/_app/immutable/chunks/idCMFvY6.js +1 -0
  103. package/build/client/_app/immutable/chunks/idCMFvY6.js.br +2 -0
  104. package/build/client/_app/immutable/chunks/idCMFvY6.js.gz +0 -0
  105. package/build/client/_app/immutable/chunks/kNaey6uv.js +1 -0
  106. package/build/client/_app/immutable/chunks/kNaey6uv.js.br +0 -0
  107. package/build/client/_app/immutable/chunks/kNaey6uv.js.gz +0 -0
  108. package/build/client/_app/immutable/chunks/xihTtKlq.js +1 -0
  109. package/build/client/_app/immutable/chunks/xihTtKlq.js.br +1 -0
  110. package/build/client/_app/immutable/chunks/xihTtKlq.js.gz +0 -0
  111. package/build/client/_app/immutable/entry/app.CAKAEcgA.js +2 -0
  112. package/build/client/_app/immutable/entry/app.CAKAEcgA.js.br +0 -0
  113. package/build/client/_app/immutable/entry/app.CAKAEcgA.js.gz +0 -0
  114. package/build/client/_app/immutable/entry/start.BSM2k8tg.js +1 -0
  115. package/build/client/_app/immutable/entry/start.BSM2k8tg.js.br +0 -0
  116. package/build/client/_app/immutable/entry/start.BSM2k8tg.js.gz +0 -0
  117. package/build/client/_app/immutable/nodes/0.fnpvsEAN.js +1 -0
  118. package/build/client/_app/immutable/nodes/0.fnpvsEAN.js.br +0 -0
  119. package/build/client/_app/immutable/nodes/0.fnpvsEAN.js.gz +0 -0
  120. package/build/client/_app/immutable/nodes/1.CLtaTeie.js +1 -0
  121. package/build/client/_app/immutable/nodes/1.CLtaTeie.js.br +0 -0
  122. package/build/client/_app/immutable/nodes/1.CLtaTeie.js.gz +0 -0
  123. package/build/client/_app/immutable/nodes/2.BwxFyRtn.js +1 -0
  124. package/build/client/_app/immutable/nodes/2.BwxFyRtn.js.br +0 -0
  125. package/build/client/_app/immutable/nodes/2.BwxFyRtn.js.gz +0 -0
  126. package/build/client/_app/immutable/nodes/3.D2KZBL5g.js +4 -0
  127. package/build/client/_app/immutable/nodes/3.D2KZBL5g.js.br +0 -0
  128. package/build/client/_app/immutable/nodes/3.D2KZBL5g.js.gz +0 -0
  129. package/build/client/_app/immutable/nodes/4.B6LN5K9i.js +1 -0
  130. package/build/client/_app/immutable/nodes/4.B6LN5K9i.js.br +0 -0
  131. package/build/client/_app/immutable/nodes/4.B6LN5K9i.js.gz +0 -0
  132. package/build/client/_app/immutable/nodes/5.CVHYq0o4.js +10 -0
  133. package/build/client/_app/immutable/nodes/5.CVHYq0o4.js.br +0 -0
  134. package/build/client/_app/immutable/nodes/5.CVHYq0o4.js.gz +0 -0
  135. package/build/client/_app/version.json +1 -0
  136. package/build/client/_app/version.json.br +0 -0
  137. package/build/client/_app/version.json.gz +0 -0
  138. package/build/client/robots.txt +3 -0
  139. package/build/client/robots.txt.br +0 -0
  140. package/build/client/robots.txt.gz +0 -0
  141. package/build/env.js +70 -0
  142. package/build/env.js.map +1 -0
  143. package/build/handler.js +17 -0
  144. package/build/handler.js.map +1 -0
  145. package/build/index.js +140 -0
  146. package/build/index.js.map +1 -0
  147. package/build/server/chunks/0-CF_dr3E0.js +9 -0
  148. package/build/server/chunks/0-CF_dr3E0.js.map +1 -0
  149. package/build/server/chunks/1-CVoEVbhQ.js +9 -0
  150. package/build/server/chunks/1-CVoEVbhQ.js.map +1 -0
  151. package/build/server/chunks/2-BzhQC8cX.js +38 -0
  152. package/build/server/chunks/2-BzhQC8cX.js.map +1 -0
  153. package/build/server/chunks/3-CukYFw9L.js +9 -0
  154. package/build/server/chunks/3-CukYFw9L.js.map +1 -0
  155. package/build/server/chunks/4-4e_Gaah7.js +9 -0
  156. package/build/server/chunks/4-4e_Gaah7.js.map +1 -0
  157. package/build/server/chunks/5-B4fCEv4c.js +9 -0
  158. package/build/server/chunks/5-B4fCEv4c.js.map +1 -0
  159. package/build/server/chunks/ChatInput-GWTgCE1t.js +122 -0
  160. package/build/server/chunks/ChatInput-GWTgCE1t.js.map +1 -0
  161. package/build/server/chunks/_layout.svelte-MrMdtdjr.js +232 -0
  162. package/build/server/chunks/_layout.svelte-MrMdtdjr.js.map +1 -0
  163. package/build/server/chunks/_page.svelte-CfQFFres.js +64 -0
  164. package/build/server/chunks/_page.svelte-CfQFFres.js.map +1 -0
  165. package/build/server/chunks/_page.svelte-CgTaVEr0.js +189 -0
  166. package/build/server/chunks/_page.svelte-CgTaVEr0.js.map +1 -0
  167. package/build/server/chunks/_page.svelte-DEDJBB4D.js +602 -0
  168. package/build/server/chunks/_page.svelte-DEDJBB4D.js.map +1 -0
  169. package/build/server/chunks/_page.svelte-OC4xDCWu.js +67 -0
  170. package/build/server/chunks/_page.svelte-OC4xDCWu.js.map +1 -0
  171. package/build/server/chunks/_server.ts-BG3v883h.js +115 -0
  172. package/build/server/chunks/_server.ts-BG3v883h.js.map +1 -0
  173. package/build/server/chunks/_server.ts-C1hU_FnX.js +28 -0
  174. package/build/server/chunks/_server.ts-C1hU_FnX.js.map +1 -0
  175. package/build/server/chunks/_server.ts-CJOrsy4y.js +30 -0
  176. package/build/server/chunks/_server.ts-CJOrsy4y.js.map +1 -0
  177. package/build/server/chunks/_server.ts-Co2FAQm2.js +43 -0
  178. package/build/server/chunks/_server.ts-Co2FAQm2.js.map +1 -0
  179. package/build/server/chunks/_server.ts-D6NGuqud.js +106 -0
  180. package/build/server/chunks/_server.ts-D6NGuqud.js.map +1 -0
  181. package/build/server/chunks/_server.ts-DaHUgm60.js +26 -0
  182. package/build/server/chunks/_server.ts-DaHUgm60.js.map +1 -0
  183. package/build/server/chunks/_server.ts-DiHyx5ij.js +64 -0
  184. package/build/server/chunks/_server.ts-DiHyx5ij.js.map +1 -0
  185. package/build/server/chunks/_server.ts-GB-Qo389.js +73 -0
  186. package/build/server/chunks/_server.ts-GB-Qo389.js.map +1 -0
  187. package/build/server/chunks/_server.ts-K359HUPL.js +32 -0
  188. package/build/server/chunks/_server.ts-K359HUPL.js.map +1 -0
  189. package/build/server/chunks/_server.ts-e4VKCo3M.js +54 -0
  190. package/build/server/chunks/_server.ts-e4VKCo3M.js.map +1 -0
  191. package/build/server/chunks/_server.ts-nr6qwbTw.js +42 -0
  192. package/build/server/chunks/_server.ts-nr6qwbTw.js.map +1 -0
  193. package/build/server/chunks/chat-confirm-BW2aJ2qz.js +5 -0
  194. package/build/server/chunks/chat-confirm-BW2aJ2qz.js.map +1 -0
  195. package/build/server/chunks/chat-steering-DTefLITL.js +5 -0
  196. package/build/server/chunks/chat-steering-DTefLITL.js.map +1 -0
  197. package/build/server/chunks/client-BoLIct8q.js +69 -0
  198. package/build/server/chunks/client-BoLIct8q.js.map +1 -0
  199. package/build/server/chunks/config-d3FC8naq.js +4907 -0
  200. package/build/server/chunks/config-d3FC8naq.js.map +1 -0
  201. package/build/server/chunks/error.svelte-BpxjjtfZ.js +65 -0
  202. package/build/server/chunks/error.svelte-BpxjjtfZ.js.map +1 -0
  203. package/build/server/chunks/gateway-DWcUFfHo.js +478 -0
  204. package/build/server/chunks/gateway-DWcUFfHo.js.map +1 -0
  205. package/build/server/chunks/handler-BAQYBQgy.js +1454 -0
  206. package/build/server/chunks/handler-BAQYBQgy.js.map +1 -0
  207. package/build/server/chunks/hooks.server-C6heBR7o.js +35 -0
  208. package/build/server/chunks/hooks.server-C6heBR7o.js.map +1 -0
  209. package/build/server/chunks/index.js-N7Sh42pC.js +11584 -0
  210. package/build/server/chunks/index.js-N7Sh42pC.js.map +1 -0
  211. package/build/server/chunks/manifest.js-D2rH2GXr.js +143 -0
  212. package/build/server/chunks/manifest.js-D2rH2GXr.js.map +1 -0
  213. package/build/server/chunks/markdown-BYqQ8bKF.js +78593 -0
  214. package/build/server/chunks/markdown-BYqQ8bKF.js.map +1 -0
  215. package/build/server/chunks/prompts-tcGD1LCs.js +37 -0
  216. package/build/server/chunks/prompts-tcGD1LCs.js.map +1 -0
  217. package/build/server/chunks/session-store-B1Aop0Qn.js +50 -0
  218. package/build/server/chunks/session-store-B1Aop0Qn.js.map +1 -0
  219. package/build/server/chunks/stores-D_6JNTkz.js +36 -0
  220. package/build/server/chunks/stores-D_6JNTkz.js.map +1 -0
  221. package/build/shims.js +33 -0
  222. package/build/shims.js.map +1 -0
  223. package/handler.d.ts +8 -0
  224. package/package.json +46 -0
@@ -0,0 +1,4907 @@
1
+ import { p as pendingSteering } from './chat-steering-DTefLITL.js';
2
+ import { D as DEFAULT_SYSTEM_PROMPT, S as SYSTEM_CONTEXT } from './prompts-tcGD1LCs.js';
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
4
+ import { join, dirname, resolve, isAbsolute, sep } from 'node:path';
5
+ import { stat, readFile, mkdir, rm, writeFile, chmod, rename } from 'node:fs/promises';
6
+ import { randomUUID } from 'node:crypto';
7
+ import { spawn, execSync } from 'node:child_process';
8
+ import { homedir } from 'node:os';
9
+ import { g as getDefaultExportFromCjs } from './index.js-N7Sh42pC.js';
10
+ import require$$0 from 'fs';
11
+ import require$$1 from 'path';
12
+ import require$$2 from 'util';
13
+
14
+ var lib = {exports: {}};
15
+
16
+ function commonjsRequire(path) {
17
+ throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
18
+ }
19
+
20
+ var util = {};
21
+
22
+ var hasRequiredUtil;
23
+
24
+ function requireUtil () {
25
+ if (hasRequiredUtil) return util;
26
+ hasRequiredUtil = 1;
27
+
28
+ util.getBooleanOption = (options, key) => {
29
+ let value = false;
30
+ if (key in options && typeof (value = options[key]) !== 'boolean') {
31
+ throw new TypeError(`Expected the "${key}" option to be a boolean`);
32
+ }
33
+ return value;
34
+ };
35
+
36
+ util.cppdb = Symbol();
37
+ util.inspect = Symbol.for('nodejs.util.inspect.custom');
38
+ return util;
39
+ }
40
+
41
+ var sqliteError;
42
+ var hasRequiredSqliteError;
43
+
44
+ function requireSqliteError () {
45
+ if (hasRequiredSqliteError) return sqliteError;
46
+ hasRequiredSqliteError = 1;
47
+ const descriptor = { value: 'SqliteError', writable: true, enumerable: false, configurable: true };
48
+
49
+ function SqliteError(message, code) {
50
+ if (new.target !== SqliteError) {
51
+ return new SqliteError(message, code);
52
+ }
53
+ if (typeof code !== 'string') {
54
+ throw new TypeError('Expected second argument to be a string');
55
+ }
56
+ Error.call(this, message);
57
+ descriptor.value = '' + message;
58
+ Object.defineProperty(this, 'message', descriptor);
59
+ Error.captureStackTrace(this, SqliteError);
60
+ this.code = code;
61
+ }
62
+ Object.setPrototypeOf(SqliteError, Error);
63
+ Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
64
+ Object.defineProperty(SqliteError.prototype, 'name', descriptor);
65
+ sqliteError = SqliteError;
66
+ return sqliteError;
67
+ }
68
+
69
+ var bindings = {exports: {}};
70
+
71
+ var fileUriToPath_1;
72
+ var hasRequiredFileUriToPath;
73
+
74
+ function requireFileUriToPath () {
75
+ if (hasRequiredFileUriToPath) return fileUriToPath_1;
76
+ hasRequiredFileUriToPath = 1;
77
+ /**
78
+ * Module dependencies.
79
+ */
80
+
81
+ var sep = require$$1.sep || '/';
82
+
83
+ /**
84
+ * Module exports.
85
+ */
86
+
87
+ fileUriToPath_1 = fileUriToPath;
88
+
89
+ /**
90
+ * File URI to Path function.
91
+ *
92
+ * @param {String} uri
93
+ * @return {String} path
94
+ * @api public
95
+ */
96
+
97
+ function fileUriToPath (uri) {
98
+ if ('string' != typeof uri ||
99
+ uri.length <= 7 ||
100
+ 'file://' != uri.substring(0, 7)) {
101
+ throw new TypeError('must pass in a file:// URI to convert to a file path');
102
+ }
103
+
104
+ var rest = decodeURI(uri.substring(7));
105
+ var firstSlash = rest.indexOf('/');
106
+ var host = rest.substring(0, firstSlash);
107
+ var path = rest.substring(firstSlash + 1);
108
+
109
+ // 2. Scheme Definition
110
+ // As a special case, <host> can be the string "localhost" or the empty
111
+ // string; this is interpreted as "the machine from which the URL is
112
+ // being interpreted".
113
+ if ('localhost' == host) host = '';
114
+
115
+ if (host) {
116
+ host = sep + sep + host;
117
+ }
118
+
119
+ // 3.2 Drives, drive letters, mount points, file system root
120
+ // Drive letters are mapped into the top of a file URI in various ways,
121
+ // depending on the implementation; some applications substitute
122
+ // vertical bar ("|") for the colon after the drive letter, yielding
123
+ // "file:///c|/tmp/test.txt". In some cases, the colon is left
124
+ // unchanged, as in "file:///c:/tmp/test.txt". In other cases, the
125
+ // colon is simply omitted, as in "file:///c/tmp/test.txt".
126
+ path = path.replace(/^(.+)\|/, '$1:');
127
+
128
+ // for Windows, we need to invert the path separators from what a URI uses
129
+ if (sep == '\\') {
130
+ path = path.replace(/\//g, '\\');
131
+ }
132
+
133
+ if (/^.+\:/.test(path)) ; else {
134
+ // unix path…
135
+ path = sep + path;
136
+ }
137
+
138
+ return host + path;
139
+ }
140
+ return fileUriToPath_1;
141
+ }
142
+
143
+ /**
144
+ * Module dependencies.
145
+ */
146
+
147
+ var hasRequiredBindings;
148
+
149
+ function requireBindings () {
150
+ if (hasRequiredBindings) return bindings.exports;
151
+ hasRequiredBindings = 1;
152
+ (function (module, exports) {
153
+ var fs = require$$0,
154
+ path = require$$1,
155
+ fileURLToPath = requireFileUriToPath(),
156
+ join = path.join,
157
+ dirname = path.dirname,
158
+ exists =
159
+ (fs.accessSync &&
160
+ function(path) {
161
+ try {
162
+ fs.accessSync(path);
163
+ } catch (e) {
164
+ return false;
165
+ }
166
+ return true;
167
+ }) ||
168
+ fs.existsSync ||
169
+ path.existsSync,
170
+ defaults = {
171
+ arrow: process.env.NODE_BINDINGS_ARROW || ' → ',
172
+ compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled',
173
+ platform: process.platform,
174
+ arch: process.arch,
175
+ nodePreGyp:
176
+ 'node-v' +
177
+ process.versions.modules +
178
+ '-' +
179
+ process.platform +
180
+ '-' +
181
+ process.arch,
182
+ version: process.versions.node,
183
+ bindings: 'bindings.node',
184
+ try: [
185
+ // node-gyp's linked version in the "build" dir
186
+ ['module_root', 'build', 'bindings'],
187
+ // node-waf and gyp_addon (a.k.a node-gyp)
188
+ ['module_root', 'build', 'Debug', 'bindings'],
189
+ ['module_root', 'build', 'Release', 'bindings'],
190
+ // Debug files, for development (legacy behavior, remove for node v0.9)
191
+ ['module_root', 'out', 'Debug', 'bindings'],
192
+ ['module_root', 'Debug', 'bindings'],
193
+ // Release files, but manually compiled (legacy behavior, remove for node v0.9)
194
+ ['module_root', 'out', 'Release', 'bindings'],
195
+ ['module_root', 'Release', 'bindings'],
196
+ // Legacy from node-waf, node <= 0.4.x
197
+ ['module_root', 'build', 'default', 'bindings'],
198
+ // Production "Release" buildtype binary (meh...)
199
+ ['module_root', 'compiled', 'version', 'platform', 'arch', 'bindings'],
200
+ // node-qbs builds
201
+ ['module_root', 'addon-build', 'release', 'install-root', 'bindings'],
202
+ ['module_root', 'addon-build', 'debug', 'install-root', 'bindings'],
203
+ ['module_root', 'addon-build', 'default', 'install-root', 'bindings'],
204
+ // node-pre-gyp path ./lib/binding/{node_abi}-{platform}-{arch}
205
+ ['module_root', 'lib', 'binding', 'nodePreGyp', 'bindings']
206
+ ]
207
+ };
208
+
209
+ /**
210
+ * The main `bindings()` function loads the compiled bindings for a given module.
211
+ * It uses V8's Error API to determine the parent filename that this function is
212
+ * being invoked from, which is then used to find the root directory.
213
+ */
214
+
215
+ function bindings(opts) {
216
+ // Argument surgery
217
+ if (typeof opts == 'string') {
218
+ opts = { bindings: opts };
219
+ } else if (!opts) {
220
+ opts = {};
221
+ }
222
+
223
+ // maps `defaults` onto `opts` object
224
+ Object.keys(defaults).map(function(i) {
225
+ if (!(i in opts)) opts[i] = defaults[i];
226
+ });
227
+
228
+ // Get the module root
229
+ if (!opts.module_root) {
230
+ opts.module_root = exports.getRoot(exports.getFileName());
231
+ }
232
+
233
+ // Ensure the given bindings name ends with .node
234
+ if (path.extname(opts.bindings) != '.node') {
235
+ opts.bindings += '.node';
236
+ }
237
+
238
+ // https://github.com/webpack/webpack/issues/4175#issuecomment-342931035
239
+ var requireFunc =
240
+ typeof __webpack_require__ === 'function'
241
+ ? __non_webpack_require__
242
+ : commonjsRequire;
243
+
244
+ var tries = [],
245
+ i = 0,
246
+ l = opts.try.length,
247
+ n,
248
+ b,
249
+ err;
250
+
251
+ for (; i < l; i++) {
252
+ n = join.apply(
253
+ null,
254
+ opts.try[i].map(function(p) {
255
+ return opts[p] || p;
256
+ })
257
+ );
258
+ tries.push(n);
259
+ try {
260
+ b = opts.path ? requireFunc.resolve(n) : requireFunc(n);
261
+ if (!opts.path) {
262
+ b.path = n;
263
+ }
264
+ return b;
265
+ } catch (e) {
266
+ if (e.code !== 'MODULE_NOT_FOUND' &&
267
+ e.code !== 'QUALIFIED_PATH_RESOLUTION_FAILED' &&
268
+ !/not find/i.test(e.message)) {
269
+ throw e;
270
+ }
271
+ }
272
+ }
273
+
274
+ err = new Error(
275
+ 'Could not locate the bindings file. Tried:\n' +
276
+ tries
277
+ .map(function(a) {
278
+ return opts.arrow + a;
279
+ })
280
+ .join('\n')
281
+ );
282
+ err.tries = tries;
283
+ throw err;
284
+ }
285
+ module.exports = exports = bindings;
286
+
287
+ /**
288
+ * Gets the filename of the JavaScript file that invokes this function.
289
+ * Used to help find the root directory of a module.
290
+ * Optionally accepts an filename argument to skip when searching for the invoking filename
291
+ */
292
+
293
+ exports.getFileName = function getFileName(calling_file) {
294
+ var origPST = Error.prepareStackTrace,
295
+ origSTL = Error.stackTraceLimit,
296
+ dummy = {},
297
+ fileName;
298
+
299
+ Error.stackTraceLimit = 10;
300
+
301
+ Error.prepareStackTrace = function(e, st) {
302
+ for (var i = 0, l = st.length; i < l; i++) {
303
+ fileName = st[i].getFileName();
304
+ if (fileName !== __filename) {
305
+ if (calling_file) {
306
+ if (fileName !== calling_file) {
307
+ return;
308
+ }
309
+ } else {
310
+ return;
311
+ }
312
+ }
313
+ }
314
+ };
315
+
316
+ // run the 'prepareStackTrace' function above
317
+ Error.captureStackTrace(dummy);
318
+ dummy.stack;
319
+
320
+ // cleanup
321
+ Error.prepareStackTrace = origPST;
322
+ Error.stackTraceLimit = origSTL;
323
+
324
+ // handle filename that starts with "file://"
325
+ var fileSchema = 'file://';
326
+ if (fileName.indexOf(fileSchema) === 0) {
327
+ fileName = fileURLToPath(fileName);
328
+ }
329
+
330
+ return fileName;
331
+ };
332
+
333
+ /**
334
+ * Gets the root directory of a module, given an arbitrary filename
335
+ * somewhere in the module tree. The "root directory" is the directory
336
+ * containing the `package.json` file.
337
+ *
338
+ * In: /home/nate/node-native-module/lib/index.js
339
+ * Out: /home/nate/node-native-module
340
+ */
341
+
342
+ exports.getRoot = function getRoot(file) {
343
+ var dir = dirname(file),
344
+ prev;
345
+ while (true) {
346
+ if (dir === '.') {
347
+ // Avoids an infinite loop in rare cases, like the REPL
348
+ dir = process.cwd();
349
+ }
350
+ if (
351
+ exists(join(dir, 'package.json')) ||
352
+ exists(join(dir, 'node_modules'))
353
+ ) {
354
+ // Found the 'package.json' file or 'node_modules' dir; we're done
355
+ return dir;
356
+ }
357
+ if (prev === dir) {
358
+ // Got to the top
359
+ throw new Error(
360
+ 'Could not find module root given file: "' +
361
+ file +
362
+ '". Do you have a `package.json` file? '
363
+ );
364
+ }
365
+ // Try the parent dir next
366
+ prev = dir;
367
+ dir = join(dir, '..');
368
+ }
369
+ };
370
+ } (bindings, bindings.exports));
371
+ return bindings.exports;
372
+ }
373
+
374
+ var wrappers = {};
375
+
376
+ var hasRequiredWrappers;
377
+
378
+ function requireWrappers () {
379
+ if (hasRequiredWrappers) return wrappers;
380
+ hasRequiredWrappers = 1;
381
+ const { cppdb } = requireUtil();
382
+
383
+ wrappers.prepare = function prepare(sql) {
384
+ return this[cppdb].prepare(sql, this, false);
385
+ };
386
+
387
+ wrappers.exec = function exec(sql) {
388
+ this[cppdb].exec(sql);
389
+ return this;
390
+ };
391
+
392
+ wrappers.close = function close() {
393
+ this[cppdb].close();
394
+ return this;
395
+ };
396
+
397
+ wrappers.loadExtension = function loadExtension(...args) {
398
+ this[cppdb].loadExtension(...args);
399
+ return this;
400
+ };
401
+
402
+ wrappers.defaultSafeIntegers = function defaultSafeIntegers(...args) {
403
+ this[cppdb].defaultSafeIntegers(...args);
404
+ return this;
405
+ };
406
+
407
+ wrappers.unsafeMode = function unsafeMode(...args) {
408
+ this[cppdb].unsafeMode(...args);
409
+ return this;
410
+ };
411
+
412
+ wrappers.getters = {
413
+ name: {
414
+ get: function name() { return this[cppdb].name; },
415
+ enumerable: true,
416
+ },
417
+ open: {
418
+ get: function open() { return this[cppdb].open; },
419
+ enumerable: true,
420
+ },
421
+ inTransaction: {
422
+ get: function inTransaction() { return this[cppdb].inTransaction; },
423
+ enumerable: true,
424
+ },
425
+ readonly: {
426
+ get: function readonly() { return this[cppdb].readonly; },
427
+ enumerable: true,
428
+ },
429
+ memory: {
430
+ get: function memory() { return this[cppdb].memory; },
431
+ enumerable: true,
432
+ },
433
+ };
434
+ return wrappers;
435
+ }
436
+
437
+ var transaction;
438
+ var hasRequiredTransaction;
439
+
440
+ function requireTransaction () {
441
+ if (hasRequiredTransaction) return transaction;
442
+ hasRequiredTransaction = 1;
443
+ const { cppdb } = requireUtil();
444
+ const controllers = new WeakMap();
445
+
446
+ transaction = function transaction(fn) {
447
+ if (typeof fn !== 'function') throw new TypeError('Expected first argument to be a function');
448
+
449
+ const db = this[cppdb];
450
+ const controller = getController(db, this);
451
+ const { apply } = Function.prototype;
452
+
453
+ // Each version of the transaction function has these same properties
454
+ const properties = {
455
+ default: { value: wrapTransaction(apply, fn, db, controller.default) },
456
+ deferred: { value: wrapTransaction(apply, fn, db, controller.deferred) },
457
+ immediate: { value: wrapTransaction(apply, fn, db, controller.immediate) },
458
+ exclusive: { value: wrapTransaction(apply, fn, db, controller.exclusive) },
459
+ database: { value: this, enumerable: true },
460
+ };
461
+
462
+ Object.defineProperties(properties.default.value, properties);
463
+ Object.defineProperties(properties.deferred.value, properties);
464
+ Object.defineProperties(properties.immediate.value, properties);
465
+ Object.defineProperties(properties.exclusive.value, properties);
466
+
467
+ // Return the default version of the transaction function
468
+ return properties.default.value;
469
+ };
470
+
471
+ // Return the database's cached transaction controller, or create a new one
472
+ const getController = (db, self) => {
473
+ let controller = controllers.get(db);
474
+ if (!controller) {
475
+ const shared = {
476
+ commit: db.prepare('COMMIT', self, false),
477
+ rollback: db.prepare('ROLLBACK', self, false),
478
+ savepoint: db.prepare('SAVEPOINT `\t_bs3.\t`', self, false),
479
+ release: db.prepare('RELEASE `\t_bs3.\t`', self, false),
480
+ rollbackTo: db.prepare('ROLLBACK TO `\t_bs3.\t`', self, false),
481
+ };
482
+ controllers.set(db, controller = {
483
+ default: Object.assign({ begin: db.prepare('BEGIN', self, false) }, shared),
484
+ deferred: Object.assign({ begin: db.prepare('BEGIN DEFERRED', self, false) }, shared),
485
+ immediate: Object.assign({ begin: db.prepare('BEGIN IMMEDIATE', self, false) }, shared),
486
+ exclusive: Object.assign({ begin: db.prepare('BEGIN EXCLUSIVE', self, false) }, shared),
487
+ });
488
+ }
489
+ return controller;
490
+ };
491
+
492
+ // Return a new transaction function by wrapping the given function
493
+ const wrapTransaction = (apply, fn, db, { begin, commit, rollback, savepoint, release, rollbackTo }) => function sqliteTransaction() {
494
+ let before, after, undo;
495
+ if (db.inTransaction) {
496
+ before = savepoint;
497
+ after = release;
498
+ undo = rollbackTo;
499
+ } else {
500
+ before = begin;
501
+ after = commit;
502
+ undo = rollback;
503
+ }
504
+ before.run();
505
+ try {
506
+ const result = apply.call(fn, this, arguments);
507
+ if (result && typeof result.then === 'function') {
508
+ throw new TypeError('Transaction function cannot return a promise');
509
+ }
510
+ after.run();
511
+ return result;
512
+ } catch (ex) {
513
+ if (db.inTransaction) {
514
+ undo.run();
515
+ if (undo !== rollback) after.run();
516
+ }
517
+ throw ex;
518
+ }
519
+ };
520
+ return transaction;
521
+ }
522
+
523
+ var pragma;
524
+ var hasRequiredPragma;
525
+
526
+ function requirePragma () {
527
+ if (hasRequiredPragma) return pragma;
528
+ hasRequiredPragma = 1;
529
+ const { getBooleanOption, cppdb } = requireUtil();
530
+
531
+ pragma = function pragma(source, options) {
532
+ if (options == null) options = {};
533
+ if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string');
534
+ if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
535
+ const simple = getBooleanOption(options, 'simple');
536
+
537
+ const stmt = this[cppdb].prepare(`PRAGMA ${source}`, this, true);
538
+ return simple ? stmt.pluck().get() : stmt.all();
539
+ };
540
+ return pragma;
541
+ }
542
+
543
+ var backup;
544
+ var hasRequiredBackup;
545
+
546
+ function requireBackup () {
547
+ if (hasRequiredBackup) return backup;
548
+ hasRequiredBackup = 1;
549
+ const fs = require$$0;
550
+ const path = require$$1;
551
+ const { promisify } = require$$2;
552
+ const { cppdb } = requireUtil();
553
+ const fsAccess = promisify(fs.access);
554
+
555
+ backup = async function backup(filename, options) {
556
+ if (options == null) options = {};
557
+
558
+ // Validate arguments
559
+ if (typeof filename !== 'string') throw new TypeError('Expected first argument to be a string');
560
+ if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
561
+
562
+ // Interpret options
563
+ filename = filename.trim();
564
+ const attachedName = 'attached' in options ? options.attached : 'main';
565
+ const handler = 'progress' in options ? options.progress : null;
566
+
567
+ // Validate interpreted options
568
+ if (!filename) throw new TypeError('Backup filename cannot be an empty string');
569
+ if (filename === ':memory:') throw new TypeError('Invalid backup filename ":memory:"');
570
+ if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
571
+ if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
572
+ if (handler != null && typeof handler !== 'function') throw new TypeError('Expected the "progress" option to be a function');
573
+
574
+ // Make sure the specified directory exists
575
+ await fsAccess(path.dirname(filename)).catch(() => {
576
+ throw new TypeError('Cannot save backup because the directory does not exist');
577
+ });
578
+
579
+ const isNewFile = await fsAccess(filename).then(() => false, () => true);
580
+ return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null);
581
+ };
582
+
583
+ const runBackup = (backup, handler) => {
584
+ let rate = 0;
585
+ let useDefault = true;
586
+
587
+ return new Promise((resolve, reject) => {
588
+ setImmediate(function step() {
589
+ try {
590
+ const progress = backup.transfer(rate);
591
+ if (!progress.remainingPages) {
592
+ backup.close();
593
+ resolve(progress);
594
+ return;
595
+ }
596
+ if (useDefault) {
597
+ useDefault = false;
598
+ rate = 100;
599
+ }
600
+ if (handler) {
601
+ const ret = handler(progress);
602
+ if (ret !== undefined) {
603
+ if (typeof ret === 'number' && ret === ret) rate = Math.max(0, Math.min(0x7fffffff, Math.round(ret)));
604
+ else throw new TypeError('Expected progress callback to return a number or undefined');
605
+ }
606
+ }
607
+ setImmediate(step);
608
+ } catch (err) {
609
+ backup.close();
610
+ reject(err);
611
+ }
612
+ });
613
+ });
614
+ };
615
+ return backup;
616
+ }
617
+
618
+ var serialize;
619
+ var hasRequiredSerialize;
620
+
621
+ function requireSerialize () {
622
+ if (hasRequiredSerialize) return serialize;
623
+ hasRequiredSerialize = 1;
624
+ const { cppdb } = requireUtil();
625
+
626
+ serialize = function serialize(options) {
627
+ if (options == null) options = {};
628
+
629
+ // Validate arguments
630
+ if (typeof options !== 'object') throw new TypeError('Expected first argument to be an options object');
631
+
632
+ // Interpret and validate options
633
+ const attachedName = 'attached' in options ? options.attached : 'main';
634
+ if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
635
+ if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
636
+
637
+ return this[cppdb].serialize(attachedName);
638
+ };
639
+ return serialize;
640
+ }
641
+
642
+ var _function;
643
+ var hasRequired_function;
644
+
645
+ function require_function () {
646
+ if (hasRequired_function) return _function;
647
+ hasRequired_function = 1;
648
+ const { getBooleanOption, cppdb } = requireUtil();
649
+
650
+ _function = function defineFunction(name, options, fn) {
651
+ // Apply defaults
652
+ if (options == null) options = {};
653
+ if (typeof options === 'function') { fn = options; options = {}; }
654
+
655
+ // Validate arguments
656
+ if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
657
+ if (typeof fn !== 'function') throw new TypeError('Expected last argument to be a function');
658
+ if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
659
+ if (!name) throw new TypeError('User-defined function name cannot be an empty string');
660
+
661
+ // Interpret options
662
+ const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2;
663
+ const deterministic = getBooleanOption(options, 'deterministic');
664
+ const directOnly = getBooleanOption(options, 'directOnly');
665
+ const varargs = getBooleanOption(options, 'varargs');
666
+ let argCount = -1;
667
+
668
+ // Determine argument count
669
+ if (!varargs) {
670
+ argCount = fn.length;
671
+ if (!Number.isInteger(argCount) || argCount < 0) throw new TypeError('Expected function.length to be a positive integer');
672
+ if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments');
673
+ }
674
+
675
+ this[cppdb].function(fn, name, argCount, safeIntegers, deterministic, directOnly);
676
+ return this;
677
+ };
678
+ return _function;
679
+ }
680
+
681
+ var aggregate;
682
+ var hasRequiredAggregate;
683
+
684
+ function requireAggregate () {
685
+ if (hasRequiredAggregate) return aggregate;
686
+ hasRequiredAggregate = 1;
687
+ const { getBooleanOption, cppdb } = requireUtil();
688
+
689
+ aggregate = function defineAggregate(name, options) {
690
+ // Validate arguments
691
+ if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
692
+ if (typeof options !== 'object' || options === null) throw new TypeError('Expected second argument to be an options object');
693
+ if (!name) throw new TypeError('User-defined function name cannot be an empty string');
694
+
695
+ // Interpret options
696
+ const start = 'start' in options ? options.start : null;
697
+ const step = getFunctionOption(options, 'step', true);
698
+ const inverse = getFunctionOption(options, 'inverse', false);
699
+ const result = getFunctionOption(options, 'result', false);
700
+ const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2;
701
+ const deterministic = getBooleanOption(options, 'deterministic');
702
+ const directOnly = getBooleanOption(options, 'directOnly');
703
+ const varargs = getBooleanOption(options, 'varargs');
704
+ let argCount = -1;
705
+
706
+ // Determine argument count
707
+ if (!varargs) {
708
+ argCount = Math.max(getLength(step), inverse ? getLength(inverse) : 0);
709
+ if (argCount > 0) argCount -= 1;
710
+ if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments');
711
+ }
712
+
713
+ this[cppdb].aggregate(start, step, inverse, result, name, argCount, safeIntegers, deterministic, directOnly);
714
+ return this;
715
+ };
716
+
717
+ const getFunctionOption = (options, key, required) => {
718
+ const value = key in options ? options[key] : null;
719
+ if (typeof value === 'function') return value;
720
+ if (value != null) throw new TypeError(`Expected the "${key}" option to be a function`);
721
+ if (required) throw new TypeError(`Missing required option "${key}"`);
722
+ return null;
723
+ };
724
+
725
+ const getLength = ({ length }) => {
726
+ if (Number.isInteger(length) && length >= 0) return length;
727
+ throw new TypeError('Expected function.length to be a positive integer');
728
+ };
729
+ return aggregate;
730
+ }
731
+
732
+ var table;
733
+ var hasRequiredTable;
734
+
735
+ function requireTable () {
736
+ if (hasRequiredTable) return table;
737
+ hasRequiredTable = 1;
738
+ const { cppdb } = requireUtil();
739
+
740
+ table = function defineTable(name, factory) {
741
+ // Validate arguments
742
+ if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
743
+ if (!name) throw new TypeError('Virtual table module name cannot be an empty string');
744
+
745
+ // Determine whether the module is eponymous-only or not
746
+ let eponymous = false;
747
+ if (typeof factory === 'object' && factory !== null) {
748
+ eponymous = true;
749
+ factory = defer(parseTableDefinition(factory, 'used', name));
750
+ } else {
751
+ if (typeof factory !== 'function') throw new TypeError('Expected second argument to be a function or a table definition object');
752
+ factory = wrapFactory(factory);
753
+ }
754
+
755
+ this[cppdb].table(factory, name, eponymous);
756
+ return this;
757
+ };
758
+
759
+ function wrapFactory(factory) {
760
+ return function virtualTableFactory(moduleName, databaseName, tableName, ...args) {
761
+ const thisObject = {
762
+ module: moduleName,
763
+ database: databaseName,
764
+ table: tableName,
765
+ };
766
+
767
+ // Generate a new table definition by invoking the factory
768
+ const def = apply.call(factory, thisObject, args);
769
+ if (typeof def !== 'object' || def === null) {
770
+ throw new TypeError(`Virtual table module "${moduleName}" did not return a table definition object`);
771
+ }
772
+
773
+ return parseTableDefinition(def, 'returned', moduleName);
774
+ };
775
+ }
776
+
777
+ function parseTableDefinition(def, verb, moduleName) {
778
+ // Validate required properties
779
+ if (!hasOwnProperty.call(def, 'rows')) {
780
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "rows" property`);
781
+ }
782
+ if (!hasOwnProperty.call(def, 'columns')) {
783
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "columns" property`);
784
+ }
785
+
786
+ // Validate "rows" property
787
+ const rows = def.rows;
788
+ if (typeof rows !== 'function' || Object.getPrototypeOf(rows) !== GeneratorFunctionPrototype) {
789
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "rows" property (should be a generator function)`);
790
+ }
791
+
792
+ // Validate "columns" property
793
+ let columns = def.columns;
794
+ if (!Array.isArray(columns) || !(columns = [...columns]).every(x => typeof x === 'string')) {
795
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "columns" property (should be an array of strings)`);
796
+ }
797
+ if (columns.length !== new Set(columns).size) {
798
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate column names`);
799
+ }
800
+ if (!columns.length) {
801
+ throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with zero columns`);
802
+ }
803
+
804
+ // Validate "parameters" property
805
+ let parameters;
806
+ if (hasOwnProperty.call(def, 'parameters')) {
807
+ parameters = def.parameters;
808
+ if (!Array.isArray(parameters) || !(parameters = [...parameters]).every(x => typeof x === 'string')) {
809
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "parameters" property (should be an array of strings)`);
810
+ }
811
+ } else {
812
+ parameters = inferParameters(rows);
813
+ }
814
+ if (parameters.length !== new Set(parameters).size) {
815
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate parameter names`);
816
+ }
817
+ if (parameters.length > 32) {
818
+ throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with more than the maximum number of 32 parameters`);
819
+ }
820
+ for (const parameter of parameters) {
821
+ if (columns.includes(parameter)) {
822
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with column "${parameter}" which was ambiguously defined as both a column and parameter`);
823
+ }
824
+ }
825
+
826
+ // Validate "safeIntegers" option
827
+ let safeIntegers = 2;
828
+ if (hasOwnProperty.call(def, 'safeIntegers')) {
829
+ const bool = def.safeIntegers;
830
+ if (typeof bool !== 'boolean') {
831
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "safeIntegers" property (should be a boolean)`);
832
+ }
833
+ safeIntegers = +bool;
834
+ }
835
+
836
+ // Validate "directOnly" option
837
+ let directOnly = false;
838
+ if (hasOwnProperty.call(def, 'directOnly')) {
839
+ directOnly = def.directOnly;
840
+ if (typeof directOnly !== 'boolean') {
841
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "directOnly" property (should be a boolean)`);
842
+ }
843
+ }
844
+
845
+ // Generate SQL for the virtual table definition
846
+ const columnDefinitions = [
847
+ ...parameters.map(identifier).map(str => `${str} HIDDEN`),
848
+ ...columns.map(identifier),
849
+ ];
850
+ return [
851
+ `CREATE TABLE x(${columnDefinitions.join(', ')});`,
852
+ wrapGenerator(rows, new Map(columns.map((x, i) => [x, parameters.length + i])), moduleName),
853
+ parameters,
854
+ safeIntegers,
855
+ directOnly,
856
+ ];
857
+ }
858
+
859
+ function wrapGenerator(generator, columnMap, moduleName) {
860
+ return function* virtualTable(...args) {
861
+ /*
862
+ We must defensively clone any buffers in the arguments, because
863
+ otherwise the generator could mutate one of them, which would cause
864
+ us to return incorrect values for hidden columns, potentially
865
+ corrupting the database.
866
+ */
867
+ const output = args.map(x => Buffer.isBuffer(x) ? Buffer.from(x) : x);
868
+ for (let i = 0; i < columnMap.size; ++i) {
869
+ output.push(null); // Fill with nulls to prevent gaps in array (v8 optimization)
870
+ }
871
+ for (const row of generator(...args)) {
872
+ if (Array.isArray(row)) {
873
+ extractRowArray(row, output, columnMap.size, moduleName);
874
+ yield output;
875
+ } else if (typeof row === 'object' && row !== null) {
876
+ extractRowObject(row, output, columnMap, moduleName);
877
+ yield output;
878
+ } else {
879
+ throw new TypeError(`Virtual table module "${moduleName}" yielded something that isn't a valid row object`);
880
+ }
881
+ }
882
+ };
883
+ }
884
+
885
+ function extractRowArray(row, output, columnCount, moduleName) {
886
+ if (row.length !== columnCount) {
887
+ throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an incorrect number of columns`);
888
+ }
889
+ const offset = output.length - columnCount;
890
+ for (let i = 0; i < columnCount; ++i) {
891
+ output[i + offset] = row[i];
892
+ }
893
+ }
894
+
895
+ function extractRowObject(row, output, columnMap, moduleName) {
896
+ let count = 0;
897
+ for (const key of Object.keys(row)) {
898
+ const index = columnMap.get(key);
899
+ if (index === undefined) {
900
+ throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an undeclared column "${key}"`);
901
+ }
902
+ output[index] = row[key];
903
+ count += 1;
904
+ }
905
+ if (count !== columnMap.size) {
906
+ throw new TypeError(`Virtual table module "${moduleName}" yielded a row with missing columns`);
907
+ }
908
+ }
909
+
910
+ function inferParameters({ length }) {
911
+ if (!Number.isInteger(length) || length < 0) {
912
+ throw new TypeError('Expected function.length to be a positive integer');
913
+ }
914
+ const params = [];
915
+ for (let i = 0; i < length; ++i) {
916
+ params.push(`$${i + 1}`);
917
+ }
918
+ return params;
919
+ }
920
+
921
+ const { hasOwnProperty } = Object.prototype;
922
+ const { apply } = Function.prototype;
923
+ const GeneratorFunctionPrototype = Object.getPrototypeOf(function*(){});
924
+ const identifier = str => `"${str.replace(/"/g, '""')}"`;
925
+ const defer = x => () => x;
926
+ return table;
927
+ }
928
+
929
+ var inspect;
930
+ var hasRequiredInspect;
931
+
932
+ function requireInspect () {
933
+ if (hasRequiredInspect) return inspect;
934
+ hasRequiredInspect = 1;
935
+ const DatabaseInspection = function Database() {};
936
+
937
+ inspect = function inspect(depth, opts) {
938
+ return Object.assign(new DatabaseInspection(), this);
939
+ };
940
+ return inspect;
941
+ }
942
+
943
+ var database;
944
+ var hasRequiredDatabase;
945
+
946
+ function requireDatabase () {
947
+ if (hasRequiredDatabase) return database;
948
+ hasRequiredDatabase = 1;
949
+ const fs = require$$0;
950
+ const path = require$$1;
951
+ const util = requireUtil();
952
+ const SqliteError = requireSqliteError();
953
+
954
+ let DEFAULT_ADDON;
955
+
956
+ function Database(filenameGiven, options) {
957
+ if (new.target == null) {
958
+ return new Database(filenameGiven, options);
959
+ }
960
+
961
+ // Apply defaults
962
+ let buffer;
963
+ if (Buffer.isBuffer(filenameGiven)) {
964
+ buffer = filenameGiven;
965
+ filenameGiven = ':memory:';
966
+ }
967
+ if (filenameGiven == null) filenameGiven = '';
968
+ if (options == null) options = {};
969
+
970
+ // Validate arguments
971
+ if (typeof filenameGiven !== 'string') throw new TypeError('Expected first argument to be a string');
972
+ if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
973
+ if ('readOnly' in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"');
974
+ if ('memory' in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)');
975
+
976
+ // Interpret options
977
+ const filename = filenameGiven.trim();
978
+ const anonymous = filename === '' || filename === ':memory:';
979
+ const readonly = util.getBooleanOption(options, 'readonly');
980
+ const fileMustExist = util.getBooleanOption(options, 'fileMustExist');
981
+ const timeout = 'timeout' in options ? options.timeout : 5000;
982
+ const verbose = 'verbose' in options ? options.verbose : null;
983
+ const nativeBinding = 'nativeBinding' in options ? options.nativeBinding : null;
984
+
985
+ // Validate interpreted options
986
+ if (readonly && anonymous && !buffer) throw new TypeError('In-memory/temporary databases cannot be readonly');
987
+ if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer');
988
+ if (timeout > 0x7fffffff) throw new RangeError('Option "timeout" cannot be greater than 2147483647');
989
+ if (verbose != null && typeof verbose !== 'function') throw new TypeError('Expected the "verbose" option to be a function');
990
+ if (nativeBinding != null && typeof nativeBinding !== 'string' && typeof nativeBinding !== 'object') throw new TypeError('Expected the "nativeBinding" option to be a string or addon object');
991
+
992
+ // Load the native addon
993
+ let addon;
994
+ if (nativeBinding == null) {
995
+ addon = DEFAULT_ADDON || (DEFAULT_ADDON = requireBindings()('better_sqlite3.node'));
996
+ } else if (typeof nativeBinding === 'string') {
997
+ // See <https://webpack.js.org/api/module-variables/#__non_webpack_require__-webpack-specific>
998
+ const requireFunc = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire;
999
+ addon = requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, '.node'));
1000
+ } else {
1001
+ // See <https://github.com/WiseLibs/better-sqlite3/issues/972>
1002
+ addon = nativeBinding;
1003
+ }
1004
+
1005
+ if (!addon.isInitialized) {
1006
+ addon.setErrorConstructor(SqliteError);
1007
+ addon.isInitialized = true;
1008
+ }
1009
+
1010
+ // Make sure the specified directory exists
1011
+ if (!anonymous && !filename.startsWith('file:') && !fs.existsSync(path.dirname(filename))) {
1012
+ throw new TypeError('Cannot open database because the directory does not exist');
1013
+ }
1014
+
1015
+ Object.defineProperties(this, {
1016
+ [util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null) },
1017
+ ...wrappers.getters,
1018
+ });
1019
+ }
1020
+
1021
+ const wrappers = requireWrappers();
1022
+ Database.prototype.prepare = wrappers.prepare;
1023
+ Database.prototype.transaction = requireTransaction();
1024
+ Database.prototype.pragma = requirePragma();
1025
+ Database.prototype.backup = requireBackup();
1026
+ Database.prototype.serialize = requireSerialize();
1027
+ Database.prototype.function = require_function();
1028
+ Database.prototype.aggregate = requireAggregate();
1029
+ Database.prototype.table = requireTable();
1030
+ Database.prototype.loadExtension = wrappers.loadExtension;
1031
+ Database.prototype.exec = wrappers.exec;
1032
+ Database.prototype.close = wrappers.close;
1033
+ Database.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers;
1034
+ Database.prototype.unsafeMode = wrappers.unsafeMode;
1035
+ Database.prototype[util.inspect] = requireInspect();
1036
+
1037
+ database = Database;
1038
+ return database;
1039
+ }
1040
+
1041
+ var hasRequiredLib;
1042
+
1043
+ function requireLib () {
1044
+ if (hasRequiredLib) return lib.exports;
1045
+ hasRequiredLib = 1;
1046
+ lib.exports = requireDatabase();
1047
+ lib.exports.SqliteError = requireSqliteError();
1048
+ return lib.exports;
1049
+ }
1050
+
1051
+ var libExports = requireLib();
1052
+ var Database = /*@__PURE__*/getDefaultExportFromCjs(libExports);
1053
+
1054
+ //#region ../core/dist/ai/models.js
1055
+ var OPENAI_MODELS = [{
1056
+ id: "gpt-4o",
1057
+ name: "GPT-4o",
1058
+ contextWindow: 128e3,
1059
+ supportsReasoning: false,
1060
+ reasoningEffortValues: [],
1061
+ supportsVision: false
1062
+ }, {
1063
+ id: "gpt-4o-mini",
1064
+ name: "GPT-4o Mini",
1065
+ contextWindow: 128e3,
1066
+ supportsReasoning: false,
1067
+ reasoningEffortValues: [],
1068
+ supportsVision: false
1069
+ }];
1070
+ var DEEPSEEK_MODELS = [{
1071
+ id: "deepseek-v4-pro",
1072
+ name: "DeepSeek V4 Pro",
1073
+ contextWindow: 1048576,
1074
+ supportsReasoning: true,
1075
+ reasoningEffortValues: ["high", "max"],
1076
+ supportsVision: false
1077
+ }, {
1078
+ id: "deepseek-v4-flash",
1079
+ name: "DeepSeek V4 Flash",
1080
+ contextWindow: 1048576,
1081
+ supportsReasoning: true,
1082
+ reasoningEffortValues: ["high", "max"],
1083
+ supportsVision: false
1084
+ }];
1085
+ var XIAOMI_MODELS = [{
1086
+ id: "mimo-v2.5",
1087
+ name: "MiMo V2.5",
1088
+ contextWindow: 1048576,
1089
+ supportsReasoning: true,
1090
+ reasoningEffortValues: [],
1091
+ supportsVision: true
1092
+ }, {
1093
+ id: "mimo-v2.5-pro",
1094
+ name: "MiMo V2.5 Pro",
1095
+ contextWindow: 1048576,
1096
+ supportsReasoning: true,
1097
+ reasoningEffortValues: [],
1098
+ supportsVision: false
1099
+ }];
1100
+ function getDefaultModels(type) {
1101
+ switch (type) {
1102
+ case "openai": return [...OPENAI_MODELS];
1103
+ case "deepseek": return [...DEEPSEEK_MODELS];
1104
+ case "xiaomi": return [...XIAOMI_MODELS];
1105
+ default: return [];
1106
+ }
1107
+ }
1108
+ //#endregion
1109
+ //#region ../core/dist/ai/utils.js
1110
+ /**
1111
+ * 供应商请求错误
1112
+ */
1113
+ var ProviderError = class extends Error {
1114
+ status;
1115
+ body;
1116
+ constructor(message, status, body) {
1117
+ super(message);
1118
+ this.status = status;
1119
+ this.body = body;
1120
+ this.name = "ProviderError";
1121
+ }
1122
+ };
1123
+ /**
1124
+ * 异步延时
1125
+ * @param ms - 毫秒
1126
+ */
1127
+ function sleep(ms) {
1128
+ return new Promise((resolve) => setTimeout(resolve, ms));
1129
+ }
1130
+ /**
1131
+ * 带自动重试的 fetch 封装
1132
+ *
1133
+ * 仅对 5xx 错误和网络错误进行指数退避重试。
1134
+ * 4xx 错误直接抛出 ProviderError,不重试。
1135
+ *
1136
+ * @param fetchFn - fetch 调用工厂函数
1137
+ * @param maxRetries - 最大重试次数
1138
+ * @param baseDelayMs - 基础延迟(毫秒),每次重试延迟加倍
1139
+ * @returns Response
1140
+ * @throws ProviderError
1141
+ */
1142
+ async function fetchWithRetry(fetchFn, maxRetries, baseDelayMs = 1e3) {
1143
+ let lastError;
1144
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1145
+ try {
1146
+ const response = await fetchFn();
1147
+ if (response.ok) return response;
1148
+ if (response.status < 500 || attempt === maxRetries) {
1149
+ const body = await response.json().catch(() => null);
1150
+ throw new ProviderError(`API returned status ${response.status}`, response.status, body);
1151
+ }
1152
+ } catch (error) {
1153
+ if (error instanceof ProviderError) throw error;
1154
+ lastError = error;
1155
+ }
1156
+ if (attempt < maxRetries) await sleep(baseDelayMs * Math.pow(2, attempt));
1157
+ }
1158
+ throw lastError;
1159
+ }
1160
+ /**
1161
+ * 解析 SSE (Server-Sent Events) 流为 StreamChunk 异步生成器
1162
+ *
1163
+ * @param reader - ReadableStream reader
1164
+ * @returns AsyncGenerator<StreamChunk>
1165
+ */
1166
+ async function* parseSSEStream(reader) {
1167
+ const decoder = new TextDecoder();
1168
+ let buffer = "";
1169
+ try {
1170
+ while (true) {
1171
+ const { done, value } = await reader.read();
1172
+ if (done) break;
1173
+ buffer += decoder.decode(value, { stream: true });
1174
+ const lines = buffer.split("\n");
1175
+ buffer = lines.pop() || "";
1176
+ for (const line of lines) {
1177
+ const trimmed = line.trim();
1178
+ if (!trimmed || !trimmed.startsWith("data:")) continue;
1179
+ const data = trimmed.slice(5).trim();
1180
+ if (data === "[DONE]") return;
1181
+ try {
1182
+ const parsed = JSON.parse(data);
1183
+ const choice = parsed.choices?.[0];
1184
+ if (!choice) continue;
1185
+ const delta = choice.delta || {};
1186
+ const rawUsage = parsed.usage || choice.usage;
1187
+ yield {
1188
+ content: delta.content || "",
1189
+ reasoning_content: delta.reasoning_content || "",
1190
+ tool_calls: extractToolCalls(delta.tool_calls),
1191
+ finish_reason: choice.finish_reason || null,
1192
+ usage: rawUsage ? parseUsage(rawUsage) : void 0
1193
+ };
1194
+ } catch {}
1195
+ }
1196
+ }
1197
+ } finally {
1198
+ reader.releaseLock();
1199
+ }
1200
+ }
1201
+ function extractToolCalls(raw) {
1202
+ if (!Array.isArray(raw)) return [];
1203
+ return raw.map((tc) => ({
1204
+ index: tc.index ?? 0,
1205
+ id: tc.id,
1206
+ type: tc.type,
1207
+ function: tc.function ? {
1208
+ name: tc.function.name,
1209
+ arguments: tc.function.arguments
1210
+ } : void 0
1211
+ }));
1212
+ }
1213
+ /**
1214
+ * 将 API 返回的原始 usage 对象解析为类型化的 Usage
1215
+ *
1216
+ * @param raw - API 响应的 usage 字段
1217
+ */
1218
+ function parseUsage(raw) {
1219
+ return {
1220
+ prompt_tokens: raw.prompt_tokens ?? 0,
1221
+ completion_tokens: raw.completion_tokens ?? 0,
1222
+ total_tokens: raw.total_tokens ?? 0,
1223
+ prompt_cache_hit_tokens: raw.prompt_cache_hit_tokens,
1224
+ prompt_cache_miss_tokens: raw.prompt_cache_miss_tokens,
1225
+ completion_tokens_details: raw.completion_tokens_details ? { reasoning_tokens: raw.completion_tokens_details.reasoning_tokens ?? 0 } : void 0
1226
+ };
1227
+ }
1228
+ //#endregion
1229
+ //#region ../core/dist/ai/openai.js
1230
+ /**
1231
+ * OpenAI 兼容格式的 AI 供应商实现
1232
+ *
1233
+ * 封装 fetch 调用 /v1/chat/completions 端点,支持:
1234
+ * - 非流式调用(chat)
1235
+ * - SSE 流式调用(chatStream)
1236
+ * - 自动重试(仅 5xx 错误 + 网络错误,指数退避)
1237
+ * - 超时控制(AbortController)
1238
+ * - usage / reasoning_content 透传
1239
+ */
1240
+ var OpenAIProvider = class {
1241
+ apiKey;
1242
+ baseURL;
1243
+ model;
1244
+ timeout;
1245
+ maxRetries;
1246
+ constructor(config) {
1247
+ this.apiKey = config.apiKey;
1248
+ this.baseURL = config.baseURL.replace(/\/$/, "");
1249
+ this.model = config.model;
1250
+ this.timeout = config.timeout ?? 6e4;
1251
+ this.maxRetries = config.maxRetries ?? 2;
1252
+ }
1253
+ async chat(request) {
1254
+ const body = this.buildBody({
1255
+ ...request,
1256
+ stream: false
1257
+ });
1258
+ const json = await (await fetchWithRetry(() => this.doFetch(body), this.maxRetries)).json();
1259
+ return this.parseResponse(json);
1260
+ }
1261
+ async *chatStream(request) {
1262
+ const body = this.buildBody({
1263
+ ...request,
1264
+ stream: true
1265
+ });
1266
+ const response = await fetchWithRetry(() => this.doFetch(body), this.maxRetries);
1267
+ if (!response.body) throw new ProviderError("Response body is empty", 0, null);
1268
+ yield* parseSSEStream(response.body.getReader());
1269
+ }
1270
+ buildBodyObject(request) {
1271
+ return {
1272
+ model: request.model || this.model,
1273
+ messages: request.messages,
1274
+ tools: request.tools,
1275
+ tool_choice: request.tool_choice,
1276
+ max_tokens: request.max_tokens,
1277
+ temperature: request.temperature,
1278
+ stream: request.stream
1279
+ };
1280
+ }
1281
+ buildBody(request) {
1282
+ return JSON.stringify(this.buildBodyObject(request));
1283
+ }
1284
+ async doFetch(body) {
1285
+ const controller = new AbortController();
1286
+ const timer = setTimeout(() => controller.abort(), this.timeout);
1287
+ try {
1288
+ return await fetch(`${this.baseURL}/chat/completions`, {
1289
+ method: "POST",
1290
+ headers: {
1291
+ "Content-Type": "application/json",
1292
+ Authorization: `Bearer ${this.apiKey}`
1293
+ },
1294
+ body,
1295
+ signal: controller.signal
1296
+ });
1297
+ } finally {
1298
+ clearTimeout(timer);
1299
+ }
1300
+ }
1301
+ parseResponse(json) {
1302
+ const choice = json.choices?.[0];
1303
+ if (!choice) throw new ProviderError("No choices in response", 0, json);
1304
+ const message = choice.message;
1305
+ const usage = json.usage;
1306
+ return {
1307
+ content: message?.content || null,
1308
+ reasoning_content: message?.reasoning_content,
1309
+ tool_calls: message?.tool_calls || [],
1310
+ finish_reason: choice.finish_reason || "stop",
1311
+ usage: usage ? parseUsage(usage) : void 0,
1312
+ model: json.model || this.model
1313
+ };
1314
+ }
1315
+ };
1316
+ //#endregion
1317
+ //#region ../core/dist/ai/deepseek.js
1318
+ var DeepSeekProvider = class extends OpenAIProvider {
1319
+ reasoningEffort;
1320
+ supportsReasoning;
1321
+ constructor(config) {
1322
+ super(config);
1323
+ this.reasoningEffort = config.reasoningEffort;
1324
+ this.supportsReasoning = config.supportsReasoning || false;
1325
+ }
1326
+ buildBodyObject(request) {
1327
+ const body = super.buildBodyObject(request);
1328
+ if (this.supportsReasoning) if (this.reasoningEffort) {
1329
+ body.thinking = { type: "enabled" };
1330
+ body.reasoning_effort = this.reasoningEffort;
1331
+ } else body.thinking = { type: "disabled" };
1332
+ return body;
1333
+ }
1334
+ };
1335
+ //#endregion
1336
+ //#region ../core/dist/ai/xiaomi.js
1337
+ var XiaomiProvider = class extends OpenAIProvider {
1338
+ reasoningEffort;
1339
+ supportsReasoning;
1340
+ constructor(config) {
1341
+ super(config);
1342
+ this.reasoningEffort = config.reasoningEffort;
1343
+ this.supportsReasoning = config.supportsReasoning || false;
1344
+ }
1345
+ buildBodyObject(request) {
1346
+ const body = super.buildBodyObject(request);
1347
+ if (this.supportsReasoning) if (this.reasoningEffort) body.thinking = { type: "enabled" };
1348
+ else body.thinking = { type: "disabled" };
1349
+ return body;
1350
+ }
1351
+ };
1352
+ //#endregion
1353
+ //#region ../core/dist/ai/ollama.js
1354
+ var OllamaProvider = class extends OpenAIProvider {
1355
+ ollamaURL;
1356
+ constructor(config) {
1357
+ const baseURL = config.baseURL || `${config.ollamaURL || "http://localhost:11434"}/v1`;
1358
+ const normalizedBase = baseURL.endsWith("/v1") ? baseURL : baseURL.replace(/\/+$/, "") + "/v1";
1359
+ super({
1360
+ apiKey: config.apiKey || "ollama",
1361
+ baseURL: normalizedBase,
1362
+ model: config.model,
1363
+ timeout: config.timeout,
1364
+ maxRetries: config.maxRetries
1365
+ });
1366
+ this.ollamaURL = config.ollamaURL || "http://localhost:11434";
1367
+ }
1368
+ async listModels() {
1369
+ try {
1370
+ const res = await fetch(`${this.ollamaURL}/api/tags`);
1371
+ if (!res.ok) return [];
1372
+ return ((await res.json()).models || []).map((m) => ({
1373
+ id: m.name,
1374
+ name: m.name
1375
+ }));
1376
+ } catch {
1377
+ return [];
1378
+ }
1379
+ }
1380
+ };
1381
+ //#endregion
1382
+ //#region ../core/dist/ai/factory.js
1383
+ function createProvider(config) {
1384
+ const activeModel = config.activeModel || "";
1385
+ const supportsReasoning = getDefaultModels(config.type).find((m) => m.id === activeModel)?.supportsReasoning || false;
1386
+ switch (config.type) {
1387
+ case "openai": return new OpenAIProvider({
1388
+ apiKey: config.apiKey,
1389
+ baseURL: config.baseURL,
1390
+ model: activeModel,
1391
+ timeout: config.timeout,
1392
+ maxRetries: config.maxRetries ?? 5
1393
+ });
1394
+ case "deepseek": return new DeepSeekProvider({
1395
+ apiKey: config.apiKey,
1396
+ baseURL: config.baseURL,
1397
+ model: activeModel,
1398
+ timeout: config.timeout,
1399
+ maxRetries: config.maxRetries ?? 5,
1400
+ reasoningEffort: config.reasoningEffort,
1401
+ supportsReasoning
1402
+ });
1403
+ case "xiaomi": return new XiaomiProvider({
1404
+ apiKey: config.apiKey,
1405
+ baseURL: config.baseURL,
1406
+ model: activeModel,
1407
+ timeout: config.timeout,
1408
+ maxRetries: config.maxRetries ?? 5,
1409
+ reasoningEffort: config.reasoningEffort,
1410
+ supportsReasoning
1411
+ });
1412
+ case "ollama": return new OllamaProvider({
1413
+ apiKey: config.apiKey,
1414
+ baseURL: config.baseURL || "",
1415
+ model: activeModel,
1416
+ timeout: config.timeout,
1417
+ maxRetries: config.maxRetries ?? 3,
1418
+ ollamaURL: config.ollamaURL
1419
+ });
1420
+ default: throw new Error(`Unsupported provider type: ${config.type}`);
1421
+ }
1422
+ }
1423
+ //#endregion
1424
+ //#region ../core/dist/tool/registry.js
1425
+ /**
1426
+ * 工具注册表
1427
+ *
1428
+ * 管理工具的注册、查询和调度。
1429
+ * 提供 getDefinitions() 将已注册工具转为 OpenAI function calling 格式。
1430
+ * 支持 sourceId 追踪,可按来源批量卸载(为 extension 系统提供基础)。
1431
+ */
1432
+ var ToolRegistry = class {
1433
+ tools = /* @__PURE__ */ new Map();
1434
+ sources = /* @__PURE__ */ new Map();
1435
+ /**
1436
+ * 注册一个工具
1437
+ * @param tool - 工具定义
1438
+ * @param sourceId - 来源标识,默认为 'builtin'。用于批量卸载时按来源清理。
1439
+ */
1440
+ register(tool, sourceId = "builtin") {
1441
+ this.tools.set(tool.name, tool);
1442
+ if (!this.sources.has(sourceId)) this.sources.set(sourceId, /* @__PURE__ */ new Set());
1443
+ this.sources.get(sourceId).add(tool.name);
1444
+ }
1445
+ /** 注销一个工具 */
1446
+ unregister(name) {
1447
+ for (const [, names] of this.sources) names.delete(name);
1448
+ return this.tools.delete(name);
1449
+ }
1450
+ /**
1451
+ * 按来源批量注销工具
1452
+ * @param sourceId - 来源标识
1453
+ * @returns 被注销的工具数量
1454
+ */
1455
+ unregisterSource(sourceId) {
1456
+ const names = this.sources.get(sourceId);
1457
+ if (!names) return 0;
1458
+ let count = 0;
1459
+ for (const name of names) if (this.tools.delete(name)) count++;
1460
+ this.sources.delete(sourceId);
1461
+ return count;
1462
+ }
1463
+ /** 按名称获取工具 */
1464
+ get(name) {
1465
+ return this.tools.get(name);
1466
+ }
1467
+ /** 获取 OpenAI function calling 格式的工具定义列表 */
1468
+ getDefinitions() {
1469
+ return Array.from(this.tools.values()).map((tool) => ({
1470
+ type: "function",
1471
+ function: {
1472
+ name: tool.name,
1473
+ description: tool.description,
1474
+ parameters: tool.parameters
1475
+ }
1476
+ }));
1477
+ }
1478
+ /**
1479
+ * 按名称执行工具
1480
+ *
1481
+ * @param name - 工具名称
1482
+ * @param args - 调用参数,支持 __confirmed 标记跳过确认流程
1483
+ * @param ctx - 工具执行上下文
1484
+ * @returns 执行结果
1485
+ * @throws PendingConfirmation 需要用户确认时
1486
+ */
1487
+ async execute(name, args, ctx) {
1488
+ const tool = this.tools.get(name);
1489
+ if (!tool) return {
1490
+ success: false,
1491
+ output: "",
1492
+ error: `未知工具: ${name}`
1493
+ };
1494
+ return tool.execute(args, ctx);
1495
+ }
1496
+ };
1497
+ //#endregion
1498
+ //#region ../core/dist/tool/types.js
1499
+ /**
1500
+ * 待确认异常
1501
+ *
1502
+ * 工具执行时如需要用户确认,抛出此异常。
1503
+ * 上层 Agent Loop 捕获后通过 SSE 推送确认请求到前端,
1504
+ * 用户确认后以 __confirmed: true 重新调用工具。
1505
+ */
1506
+ var PendingConfirmation = class extends Error {
1507
+ toolName;
1508
+ args;
1509
+ reason;
1510
+ constructor(toolName, args, reason) {
1511
+ super(`Tool "${toolName}" requires confirmation: ${reason}`);
1512
+ this.toolName = toolName;
1513
+ this.args = args;
1514
+ this.reason = reason;
1515
+ this.name = "PendingConfirmation";
1516
+ }
1517
+ toJSON() {
1518
+ return {
1519
+ toolName: this.toolName,
1520
+ args: this.args,
1521
+ reason: this.reason
1522
+ };
1523
+ }
1524
+ };
1525
+ //#endregion
1526
+ //#region ../core/dist/tool/safeguard.js
1527
+ var READONLY_PATTERNS = [
1528
+ /^\s*(?:Get-ChildItem|dir|ls|Get-Content|cat|type|Get-Process|ps|Get-Service|Get-Location|pwd|gl|Get-Item|gi|Get-ItemProperty|gp|Get-Date|Get-Host|Get-Variable|gv|Get-Command|gcm|Get-Member|gm|Get-Alias|gal|Get-History|history|ghy|Select-String|sls|findstr|Test-Path|Measure-Object|measure|Sort-Object|sort|Group-Object|group|Select-Object|select|Format-List|fl|Format-Table|ft|Format-Wide|fw|Format-Hex|Write-Output|echo|write|Compare-Object|diff|compare|Where-Object|Join-Path|Split-Path|Resolve-Path|ConvertFrom-Json|ConvertFrom-Csv)\b/i,
1529
+ /^\s*(?:head|tail|less|more|grep|egrep|fgrep|rg|find|wc|sort|uniq|cut|tr|file|stat|df|du|which|whereis|command|whoami|id|groups|printf|uname|hostname|basename|dirname|readlink|realpath)\b/i,
1530
+ /^\s*git\s+(?:status|log|diff|show|branch|tag|stash\s+list|remote\s+(?:-v|show)|config\s+(?:--list|--get\b)|ls-files|rev-parse|rev-list|describe|shortlog|blame|grep|notes\s+list|reflog|cherry|for-each-ref|name-rev)\b/i,
1531
+ /^\s*npm\s+(?:ls|list|view|info|outdated|version|config\s+list)\b/i
1532
+ ];
1533
+ var DANGEROUS_PATTERNS = [
1534
+ /^\s*del\b/i,
1535
+ /^\s*rmdir\b/i,
1536
+ /^\s*Remove-Item\b/i,
1537
+ /\bformat\b/i,
1538
+ /\bdiskpart\b/i,
1539
+ /reg\s+(delete|add)/i,
1540
+ /Set-ExecutionPolicy/i,
1541
+ /\bshutdown\b/i,
1542
+ /Restart-Computer\b/i,
1543
+ /Stop-Process\s+.*(svchost|winlogon|lsass|csrss)/i,
1544
+ /Stop-Service\b/i,
1545
+ /\|\s*iex\b/i,
1546
+ /\|\s*Invoke-Expression\b/i,
1547
+ /\|\s*cmd\b/i,
1548
+ />\s*%SystemRoot%/i,
1549
+ />\s*C:\\Windows/i,
1550
+ /\brm\s+-rf?\b/,
1551
+ /\bfind\b.*\bdelete\b/,
1552
+ /\bdd\s+if=/,
1553
+ /\bmkfs\./,
1554
+ /\bchmod\s+777\s+\//,
1555
+ /\bshutdown\b/,
1556
+ /\breboot\b/,
1557
+ /\binit\s+[06]/,
1558
+ />\s*\/etc\//,
1559
+ />\s*\/bin\//,
1560
+ />\s*\/boot\//,
1561
+ /\|\s*(ba)?sh\b/,
1562
+ /\|\s*zsh\b/,
1563
+ /\bdrop\s+table\b/i,
1564
+ /\bdrop\s+database\b/i,
1565
+ /\bgit\s+push\s+--force\b/i,
1566
+ /\bgit\s+reset\s+--hard\b/i
1567
+ ];
1568
+ var SYSTEM_DIRS = [
1569
+ "C:\\Windows",
1570
+ "C:\\Program Files",
1571
+ "C:\\Program Files (x86)",
1572
+ "/etc",
1573
+ "/bin",
1574
+ "/sbin",
1575
+ "/usr/bin",
1576
+ "/usr/sbin",
1577
+ "/boot",
1578
+ "/sys",
1579
+ "/dev",
1580
+ "/proc"
1581
+ ];
1582
+ function isDangerousCommand(command) {
1583
+ if (DANGEROUS_PATTERNS.some((pattern) => pattern.test(command))) return true;
1584
+ for (const segment of command.split("|")) if (DANGEROUS_PATTERNS.some((pattern) => pattern.test(segment))) return true;
1585
+ return false;
1586
+ }
1587
+ function isReadonlyCommand(command) {
1588
+ for (const segment of command.split("|")) if (!READONLY_PATTERNS.some((pattern) => pattern.test(segment))) return false;
1589
+ return true;
1590
+ }
1591
+ function isPathInWorkspace(targetPath, workspaceRoot) {
1592
+ const resolved = normalizePath(targetPath, workspaceRoot);
1593
+ const normalizedRoot = resolve(workspaceRoot).toLowerCase();
1594
+ return resolve(resolved).toLowerCase().startsWith(normalizedRoot + sep);
1595
+ }
1596
+ function isSystemPath(targetPath, workspaceRoot) {
1597
+ const normalized = resolve(normalizePath(targetPath, workspaceRoot)).toLowerCase();
1598
+ return SYSTEM_DIRS.some((sysDir) => normalized.startsWith(sysDir.toLowerCase()));
1599
+ }
1600
+ function expandEnvVars(command) {
1601
+ let result = command.replace(/%(\w+)%/g, (_, name) => {
1602
+ return process.env[name] ?? `%${name}%`;
1603
+ });
1604
+ result = result.replace(/\$\{(\w+)\}/g, (_, name) => {
1605
+ return process.env[name] ?? `\$\{${name}\}`;
1606
+ });
1607
+ result = result.replace(/\$([A-Za-z_]\w*)/g, (_, name) => {
1608
+ return process.env[name] ?? `$${name}`;
1609
+ });
1610
+ return result;
1611
+ }
1612
+ function collectPaths(source, paths) {
1613
+ const winAbsRe = /[A-Za-z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*/g;
1614
+ let match;
1615
+ while ((match = winAbsRe.exec(source)) !== null) paths.push(match[0]);
1616
+ const unixAbsRe = /(?<!\w)\/(?:[^\s'"]+)/g;
1617
+ while ((match = unixAbsRe.exec(source)) !== null) {
1618
+ const p = match[0];
1619
+ if (p.length > 1 && !/^\/\d/.test(p) && !/\/$/.test(p)) paths.push(p);
1620
+ }
1621
+ const tildeRe = /(?<!\w)~\/(?:[^\s'"]+)/g;
1622
+ while ((match = tildeRe.exec(source)) !== null) paths.push(match[0]);
1623
+ }
1624
+ function extractPaths(command) {
1625
+ const paths = [];
1626
+ collectPaths(command, paths);
1627
+ const expanded = expandEnvVars(command);
1628
+ if (expanded !== command) collectPaths(expanded, paths);
1629
+ const winRelRe = /(?:\.\.\\)+(?:[^\s'"]+)/g;
1630
+ let match;
1631
+ while ((match = winRelRe.exec(command)) !== null) paths.push(match[0]);
1632
+ const unixRelRe = /(?<!\w)(?:\.\.\/)+(?:[^\s'"]+)/g;
1633
+ while ((match = unixRelRe.exec(command)) !== null) {
1634
+ const p = match[0];
1635
+ if (p.length > 1 && !/\/$/.test(p)) paths.push(p);
1636
+ }
1637
+ return paths;
1638
+ }
1639
+ /**
1640
+ * 分类命令的安全性
1641
+ *
1642
+ * 判定顺序:
1643
+ * 1. reject — 明确禁止(format, diskpart)
1644
+ * 2. confirm — 命中危险模式(删除、系统修改、管道注入等)
1645
+ * 3. safe — 只读命令,无需后续路径检查
1646
+ * 4. confirm — 路径在工作区外或系统目录
1647
+ * 5. safe — 其余放行
1648
+ *
1649
+ * @returns 'safe' 可直接执行 / 'confirm' 需用户确认 / 'reject' 拒绝执行
1650
+ */
1651
+ function classifyCommand(command, workspaceRoot) {
1652
+ if (/^\s*(format|diskpart)\b/i.test(command.trim())) return "reject";
1653
+ if (isDangerousCommand(command)) return "confirm";
1654
+ if (isReadonlyCommand(command)) return "safe";
1655
+ const paths = extractPaths(command);
1656
+ for (const p of paths) {
1657
+ if (isSystemPath(p, workspaceRoot)) return "confirm";
1658
+ if (!isPathInWorkspace(p, workspaceRoot)) return "confirm";
1659
+ }
1660
+ return "safe";
1661
+ }
1662
+ /**
1663
+ * 分类文件路径的安全性
1664
+ *
1665
+ * @returns 'safe' 可直接操作 / 'confirm' 需用户确认
1666
+ */
1667
+ function classifyFilePath(targetPath, workspaceRoot) {
1668
+ const normalized = normalizePath(targetPath, workspaceRoot);
1669
+ if (isSystemPath(normalized, workspaceRoot)) return "reject";
1670
+ if (!isPathInWorkspace(normalized, workspaceRoot)) return "confirm";
1671
+ return "safe";
1672
+ }
1673
+ function normalizePath(targetPath, workspaceRoot) {
1674
+ let resolved = targetPath;
1675
+ if (resolved.startsWith("~")) {
1676
+ const home = process.env.HOME || process.env.USERPROFILE || "";
1677
+ resolved = resolved.replace(/^~/, home);
1678
+ }
1679
+ if (isAbsolute(resolved)) return resolved;
1680
+ return resolve(workspaceRoot, resolved);
1681
+ }
1682
+ //#endregion
1683
+ //#region ../core/dist/tool/env.js
1684
+ /**
1685
+ * ToolContext — 工具执行上下文
1686
+ *
1687
+ * 封装工作区根目录、路径解析和安全检查。
1688
+ * 替换原来分散在工具中的 resolve() + classifyFilePath/classifyCommand 模式。
1689
+ */
1690
+ var ToolContext = class {
1691
+ root;
1692
+ onUpdate;
1693
+ constructor(root) {
1694
+ this.root = root;
1695
+ }
1696
+ /** 解析用户输入的路径,同时做安全检查 */
1697
+ resolvePath(userPath) {
1698
+ const resolved = resolve(this.root, userPath);
1699
+ return {
1700
+ path: resolved,
1701
+ classification: classifyFilePath(resolved, this.root)
1702
+ };
1703
+ }
1704
+ /** 分类终端命令的安全性 */
1705
+ classifyCommand(command) {
1706
+ return classifyCommand(command, this.root);
1707
+ }
1708
+ };
1709
+ //#endregion
1710
+ //#region ../core/dist/tool/tools/file-utils.js
1711
+ var BOM = "";
1712
+ function stripBom(content) {
1713
+ if (content.startsWith(BOM)) return content.slice(1);
1714
+ return content;
1715
+ }
1716
+ function detectLineEnding(content) {
1717
+ if (content.includes("\r\n")) return "CRLF";
1718
+ return "LF";
1719
+ }
1720
+ function detectMeta(content) {
1721
+ return {
1722
+ bom: content.startsWith(BOM),
1723
+ lineEnding: detectLineEnding(content)
1724
+ };
1725
+ }
1726
+ function normalizeLineEndings(content, target) {
1727
+ if (target === "CRLF") return content.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n");
1728
+ return content.replace(/\r\n/g, "\n");
1729
+ }
1730
+ function normalizeToLF(content) {
1731
+ return content.replace(/\r\n/g, "\n");
1732
+ }
1733
+ function applyMeta(content, meta) {
1734
+ let result = normalizeLineEndings(content, meta.lineEnding);
1735
+ if (meta.bom && !result.startsWith(BOM)) result = BOM + result;
1736
+ else if (!meta.bom && result.startsWith(BOM)) result = result.slice(1);
1737
+ return result;
1738
+ }
1739
+ async function atomicWrite(filePath, content, meta) {
1740
+ let finalContent = content;
1741
+ let targetMode = null;
1742
+ try {
1743
+ const info = await stat(filePath);
1744
+ if (info.isFile()) targetMode = info.mode;
1745
+ } catch {}
1746
+ if (meta) finalContent = applyMeta(content, meta);
1747
+ dirname(filePath);
1748
+ const tmpPath = filePath + "." + randomUUID() + ".tmp";
1749
+ await writeFile(tmpPath, finalContent, "utf-8");
1750
+ if (targetMode !== null) await chmod(tmpPath, targetMode);
1751
+ await rename(tmpPath, filePath);
1752
+ }
1753
+ //#endregion
1754
+ //#region ../core/dist/tool/tools/read-file.js
1755
+ var MAX_FILE_SIZE = 1024 * 1024;
1756
+ var DEFAULT_OFFSET = 1;
1757
+ var DEFAULT_LIMIT = 500;
1758
+ function validateParam(name, value) {
1759
+ if (value === void 0 || value === null) return NaN;
1760
+ const n = Number(value);
1761
+ if (!Number.isInteger(n)) return NaN;
1762
+ if (n < 1) return NaN;
1763
+ return n;
1764
+ }
1765
+ /**
1766
+ * read_file — 读取文件内容
1767
+ *
1768
+ * 工作区内文件直接读取;工作区外文件需用户确认。
1769
+ * 文件大小限制 1 MB,超限返回错误。
1770
+ * 支持 offset / limit 按行翻页,不指定时默认读前 500 行。
1771
+ */
1772
+ var readFileTool = {
1773
+ name: "read_file",
1774
+ description: "Read file contents. Supports offset/limit for paginated line-by-line reading. Use for viewing code, config, docs, etc.",
1775
+ parameters: {
1776
+ type: "object",
1777
+ properties: {
1778
+ path: {
1779
+ type: "string",
1780
+ description: "File path (relative to workspace or absolute)"
1781
+ },
1782
+ offset: {
1783
+ type: "integer",
1784
+ description: "Starting line number (1-based), default 1"
1785
+ },
1786
+ limit: {
1787
+ type: "integer",
1788
+ description: "Max lines to read, default 500"
1789
+ }
1790
+ },
1791
+ required: ["path"]
1792
+ },
1793
+ async execute(args, ctx) {
1794
+ const userPath = args.path;
1795
+ if (!userPath) return {
1796
+ success: false,
1797
+ output: "",
1798
+ error: "缺少参数: path"
1799
+ };
1800
+ let offset = DEFAULT_OFFSET;
1801
+ let limit = DEFAULT_LIMIT;
1802
+ if ("offset" in args && args.offset !== void 0 && args.offset !== null) {
1803
+ const parsed = validateParam("offset", args.offset);
1804
+ if (isNaN(parsed)) return {
1805
+ success: false,
1806
+ output: "",
1807
+ error: "offset 必须是大于等于 1 的整数"
1808
+ };
1809
+ offset = parsed;
1810
+ }
1811
+ if ("limit" in args && args.limit !== void 0 && args.limit !== null) {
1812
+ const parsed = validateParam("limit", args.limit);
1813
+ if (isNaN(parsed)) return {
1814
+ success: false,
1815
+ output: "",
1816
+ error: "limit 必须是大于等于 1 的整数"
1817
+ };
1818
+ limit = parsed;
1819
+ }
1820
+ const { path: filePath, classification } = ctx.resolvePath(userPath);
1821
+ if (!args.__confirmed) {
1822
+ if (classification === "reject") return {
1823
+ success: false,
1824
+ output: "",
1825
+ error: `拒绝读取系统路径: ${userPath}`
1826
+ };
1827
+ if (classification === "confirm") throw new PendingConfirmation("read_file", {
1828
+ path: userPath,
1829
+ offset,
1830
+ limit
1831
+ }, `文件 "${userPath}" 在工作区之外,确认读取?`);
1832
+ }
1833
+ try {
1834
+ const info = await stat(filePath);
1835
+ if (!info.isFile()) return {
1836
+ success: false,
1837
+ output: "",
1838
+ error: `路径不是文件: ${userPath}`
1839
+ };
1840
+ if (info.size > MAX_FILE_SIZE) return {
1841
+ success: false,
1842
+ output: "",
1843
+ error: `文件过大 (${(info.size / 1024 / 1024).toFixed(1)} MB),最大支持 1 MB`
1844
+ };
1845
+ const lines = stripBom(await readFile(filePath, "utf-8")).split("\n");
1846
+ const totalLines = lines.length;
1847
+ const startIdx = offset - 1;
1848
+ if (startIdx >= totalLines) return {
1849
+ success: true,
1850
+ output: `=== ${userPath} (第 ${offset}-${offset + limit - 1} 行 / 共 ${totalLines} 行) ===\n\n(起始行号超出文件末尾)`
1851
+ };
1852
+ const endIdx = Math.min(startIdx + limit, totalLines);
1853
+ const slice = lines.slice(startIdx, endIdx);
1854
+ const atEnd = endIdx >= totalLines;
1855
+ return {
1856
+ success: true,
1857
+ output: `=== ${userPath} ${`(第 ${offset}-${startIdx + slice.length} 行 / 共 ${totalLines} 行${atEnd ? ",已达文件末尾" : ""})`} ===\n${slice.join("\n")}`
1858
+ };
1859
+ } catch (error) {
1860
+ if (error.code === "ENOENT") return {
1861
+ success: false,
1862
+ output: "",
1863
+ error: `文件不存在: ${userPath}`
1864
+ };
1865
+ return {
1866
+ success: false,
1867
+ output: "",
1868
+ error: `读取失败: ${error.message}`
1869
+ };
1870
+ }
1871
+ }
1872
+ };
1873
+ //#endregion
1874
+ //#region ../core/dist/tool/tools/write-file.js
1875
+ /**
1876
+ * write_file — 写入文件内容
1877
+ *
1878
+ * 自动创建不存在的父目录。覆盖已有文件。
1879
+ * 使用原子写入(临时文件 + rename),崩溃时不留残缺文件。
1880
+ * 覆盖已有文件时自动保留原文件的 BOM 和行尾格式(CRLF/LF)。
1881
+ * 工作区内文件直接写入;工作区外需用户确认。
1882
+ */
1883
+ var writeFileTool = {
1884
+ name: "write_file",
1885
+ description: "Write content to a file (overwrites). Creates missing parent directories automatically. Preserves existing file encoding (BOM, line endings) when overwriting.",
1886
+ parameters: {
1887
+ type: "object",
1888
+ properties: {
1889
+ path: {
1890
+ type: "string",
1891
+ description: "File path (relative to workspace or absolute)"
1892
+ },
1893
+ content: {
1894
+ type: "string",
1895
+ description: "Complete file content to write"
1896
+ }
1897
+ },
1898
+ required: ["path", "content"]
1899
+ },
1900
+ async execute(args, ctx) {
1901
+ const userPath = args.path;
1902
+ const content = args.content;
1903
+ if (!userPath) return {
1904
+ success: false,
1905
+ output: "",
1906
+ error: "缺少参数: path"
1907
+ };
1908
+ if (content === void 0 || content === null) return {
1909
+ success: false,
1910
+ output: "",
1911
+ error: "缺少参数: content"
1912
+ };
1913
+ const { path: filePath, classification } = ctx.resolvePath(userPath);
1914
+ if (!args.__confirmed) {
1915
+ if (classification === "reject") return {
1916
+ success: false,
1917
+ output: "",
1918
+ error: `拒绝写入系统路径: ${userPath}`
1919
+ };
1920
+ if (classification === "confirm") throw new PendingConfirmation("write_file", {
1921
+ path: userPath,
1922
+ content
1923
+ }, `文件 "${userPath}" 在工作区之外,确认写入?`);
1924
+ }
1925
+ try {
1926
+ await mkdir(dirname(filePath), { recursive: true });
1927
+ let existed = false;
1928
+ let meta = void 0;
1929
+ try {
1930
+ existed = (await stat(filePath)).isFile();
1931
+ if (existed) meta = detectMeta(await readFile(filePath, "utf-8"));
1932
+ } catch {}
1933
+ await atomicWrite(filePath, content, meta);
1934
+ return {
1935
+ success: true,
1936
+ output: `${existed ? "已更新" : "已创建"}文件: ${userPath} (${content.split("\n").length} 行, ${Buffer.byteLength(content, "utf-8")} 字节${meta?.bom ? " (已保留 BOM)" : ""})`
1937
+ };
1938
+ } catch (error) {
1939
+ return {
1940
+ success: false,
1941
+ output: "",
1942
+ error: `写入失败: ${error.message}`
1943
+ };
1944
+ }
1945
+ }
1946
+ };
1947
+ //#endregion
1948
+ //#region ../core/dist/tool/tools/delete-file.js
1949
+ /**
1950
+ * delete_file — 删除文件
1951
+ *
1952
+ * 删除操作始终需要用户确认(不可逆)。
1953
+ * 仅支持删除文件,不支持删除目录。
1954
+ * 系统路径始终拒绝。
1955
+ */
1956
+ var deleteFileTool = {
1957
+ name: "delete_file",
1958
+ description: "Delete a file. Always requires user confirmation.",
1959
+ parameters: {
1960
+ type: "object",
1961
+ properties: { path: {
1962
+ type: "string",
1963
+ description: "File path (relative to workspace or absolute)"
1964
+ } },
1965
+ required: ["path"]
1966
+ },
1967
+ async execute(args, ctx) {
1968
+ const userPath = args.path;
1969
+ if (!userPath) return {
1970
+ success: false,
1971
+ output: "",
1972
+ error: "缺少参数: path"
1973
+ };
1974
+ const { path: filePath, classification } = ctx.resolvePath(userPath);
1975
+ if (!args.__confirmed) throw new PendingConfirmation("delete_file", { path: userPath }, `确认删除 "${userPath}"?此操作不可恢复。`);
1976
+ if (classification === "reject") return {
1977
+ success: false,
1978
+ output: "",
1979
+ error: `拒绝删除系统路径: ${userPath}`
1980
+ };
1981
+ try {
1982
+ if ((await stat(filePath)).isDirectory()) return {
1983
+ success: false,
1984
+ output: "",
1985
+ error: `目标是目录而非文件: ${userPath}`
1986
+ };
1987
+ await rm(filePath);
1988
+ return {
1989
+ success: true,
1990
+ output: `已删除文件: ${userPath}`
1991
+ };
1992
+ } catch (error) {
1993
+ if (error.code === "ENOENT") return {
1994
+ success: false,
1995
+ output: "",
1996
+ error: `路径不存在: ${userPath}`
1997
+ };
1998
+ return {
1999
+ success: false,
2000
+ output: "",
2001
+ error: `删除失败: ${error.message}`
2002
+ };
2003
+ }
2004
+ }
2005
+ };
2006
+ //#endregion
2007
+ //#region ../core/dist/tool/tools/edit.js
2008
+ function escapeNewlines(s) {
2009
+ return s.replace(/\r/g, "\\r").replace(/\n/g, "\\n");
2010
+ }
2011
+ function formatDiff(original, replacement) {
2012
+ return `- ${escapeNewlines(original)}\n+ ${escapeNewlines(replacement)}`;
2013
+ }
2014
+ function countOccurrences(haystack, needle) {
2015
+ if (!needle) return 0;
2016
+ let count = 0;
2017
+ let pos = 0;
2018
+ while (true) {
2019
+ pos = haystack.indexOf(needle, pos);
2020
+ if (pos === -1) break;
2021
+ count++;
2022
+ pos += needle.length;
2023
+ }
2024
+ return count;
2025
+ }
2026
+ /**
2027
+ * edit — 精确字符串替换编辑文件
2028
+ *
2029
+ * 在文件中查找 oldString 并替换为 newString。
2030
+ * 使用原子写入,自动保留原文件的 BOM 和行尾格式。
2031
+ * 非 replaceAll 模式下,oldString 必须在文件中恰好出现一次。
2032
+ */
2033
+ var editTool = {
2034
+ name: "edit",
2035
+ description: "Perform exact string replacement in a file. Find oldString and replace with newString. In non-replaceAll mode, oldString must appear exactly once (prevents accidental changes). Preserves BOM and line endings (CRLF/LF).",
2036
+ parameters: {
2037
+ type: "object",
2038
+ properties: {
2039
+ path: {
2040
+ type: "string",
2041
+ description: "File path (relative to workspace or absolute)"
2042
+ },
2043
+ oldString: {
2044
+ type: "string",
2045
+ description: "Original text to replace (must match file content exactly, including indentation and blank lines)"
2046
+ },
2047
+ newString: {
2048
+ type: "string",
2049
+ description: "Replacement text"
2050
+ },
2051
+ replaceAll: {
2052
+ type: "boolean",
2053
+ description: "Replace all occurrences. Default false — oldString must appear exactly once in the file."
2054
+ }
2055
+ },
2056
+ required: [
2057
+ "path",
2058
+ "oldString",
2059
+ "newString"
2060
+ ]
2061
+ },
2062
+ async execute(args, ctx) {
2063
+ const userPath = args.path;
2064
+ const oldString = args.oldString;
2065
+ const newString = args.newString;
2066
+ const replaceAll = args.replaceAll === true;
2067
+ if (!userPath) return {
2068
+ success: false,
2069
+ output: "",
2070
+ error: "缺少参数: path"
2071
+ };
2072
+ if (oldString === void 0 || oldString === null) return {
2073
+ success: false,
2074
+ output: "",
2075
+ error: "缺少参数: oldString"
2076
+ };
2077
+ if (newString === void 0 || newString === null) return {
2078
+ success: false,
2079
+ output: "",
2080
+ error: "缺少参数: newString"
2081
+ };
2082
+ if (oldString === "") return {
2083
+ success: false,
2084
+ output: "",
2085
+ error: "oldString 不能为空"
2086
+ };
2087
+ if (oldString === newString) return {
2088
+ success: false,
2089
+ output: "",
2090
+ error: "oldString 与 newString 相同,无需替换"
2091
+ };
2092
+ const { path: filePath, classification } = ctx.resolvePath(userPath);
2093
+ if (!args.__confirmed) {
2094
+ if (classification === "reject") return {
2095
+ success: false,
2096
+ output: "",
2097
+ error: `拒绝编辑系统路径: ${userPath}`
2098
+ };
2099
+ if (classification === "confirm") throw new PendingConfirmation("edit", {
2100
+ path: userPath,
2101
+ oldString,
2102
+ newString,
2103
+ replaceAll
2104
+ }, `文件 "${userPath}" 在工作区之外,确认编辑?`);
2105
+ }
2106
+ try {
2107
+ const raw = await readFile(filePath, "utf-8");
2108
+ const meta = detectMeta(raw);
2109
+ const content = stripBom(raw);
2110
+ let matchCount = countOccurrences(content, oldString);
2111
+ if (matchCount === 0) {
2112
+ const lfContent = normalizeToLF(content);
2113
+ const lfOld = normalizeToLF(oldString);
2114
+ const lfCount = countOccurrences(lfContent, lfOld);
2115
+ if (lfCount > 0) {
2116
+ matchCount = lfCount;
2117
+ const lfNew = normalizeToLF(newString);
2118
+ let result;
2119
+ if (replaceAll) result = lfContent.split(lfOld).join(lfNew);
2120
+ else result = lfContent.replace(lfOld, lfNew);
2121
+ if (meta.lineEnding === "CRLF") result = result.replace(/\n/g, "\r\n");
2122
+ await atomicWrite(filePath, result, meta);
2123
+ return {
2124
+ success: true,
2125
+ output: `已编辑: ${userPath}\n替换 ${replaceAll ? matchCount : 1} 处:\n${formatDiff(oldString, newString)}`
2126
+ };
2127
+ }
2128
+ }
2129
+ if (matchCount === 0) return {
2130
+ success: false,
2131
+ output: "",
2132
+ error: `未在文件中找到 oldString。请确保 oldString 与文件内容完全一致(包括缩进和空行)。\n文件路径: ${userPath}\noldString: ${escapeNewlines(oldString.slice(0, 200))}`
2133
+ };
2134
+ if (!replaceAll && matchCount > 1) return {
2135
+ success: false,
2136
+ output: "",
2137
+ error: `oldString 在文件中出现了 ${matchCount} 次。请提供更多上下文使匹配唯一,或设置 replaceAll: true 替换全部。`
2138
+ };
2139
+ await atomicWrite(filePath, replaceAll ? content.split(oldString).join(newString) : content.replace(oldString, newString), meta);
2140
+ return {
2141
+ success: true,
2142
+ output: `已编辑: ${userPath}\n替换 ${replaceAll ? matchCount : 1} 处:\n${formatDiff(oldString, newString)}`
2143
+ };
2144
+ } catch (error) {
2145
+ if (error.code === "ENOENT") return {
2146
+ success: false,
2147
+ output: "",
2148
+ error: `文件不存在: ${userPath}`
2149
+ };
2150
+ if (error instanceof PendingConfirmation) throw error;
2151
+ return {
2152
+ success: false,
2153
+ output: "",
2154
+ error: `编辑失败: ${error.message}`
2155
+ };
2156
+ }
2157
+ }
2158
+ };
2159
+ //#endregion
2160
+ //#region ../core/dist/tool/tools/exec.js
2161
+ var DEFAULT_TIMEOUT = 3e5;
2162
+ var MAX_ALLOWED_TIMEOUT = 36e5;
2163
+ var MAX_OUTPUT = 5e4;
2164
+ var IS_WINDOWS = process.platform === "win32";
2165
+ function killProcessTree(pid) {
2166
+ if (pid == null) return false;
2167
+ if (IS_WINDOWS) try {
2168
+ execSync(`taskkill /F /T /PID ${pid}`, { stdio: "ignore" });
2169
+ return true;
2170
+ } catch {
2171
+ return false;
2172
+ }
2173
+ try {
2174
+ process.kill(pid, "SIGKILL");
2175
+ return true;
2176
+ } catch {
2177
+ return false;
2178
+ }
2179
+ }
2180
+ /**
2181
+ * execute_command — 执行终端命令
2182
+ *
2183
+ * 安全策略:
2184
+ * - 安全命令 + 工作区路径 → 直接执行
2185
+ * - 危险命令 → 需用户确认
2186
+ * - format/diskpart → 拒绝
2187
+ * - 默认超时 5 分钟,输出上限 50KB
2188
+ */
2189
+ var execTool = {
2190
+ name: "execute_command",
2191
+ description: "Execute a terminal command in the workspace directory and return output. For development tasks only, non-interactive. Default timeout 5 minutes.",
2192
+ parameters: {
2193
+ type: "object",
2194
+ properties: {
2195
+ command: {
2196
+ type: "string",
2197
+ description: "The terminal command to execute"
2198
+ },
2199
+ timeout: {
2200
+ type: "number",
2201
+ description: "Timeout in seconds, default 300 (5 min), max 3600 (1 hour)"
2202
+ }
2203
+ },
2204
+ required: ["command"]
2205
+ },
2206
+ async execute(args, ctx) {
2207
+ const command = args.command;
2208
+ if (!command) return {
2209
+ success: false,
2210
+ output: "",
2211
+ error: "缺少参数: command"
2212
+ };
2213
+ let timeoutSec = typeof args.timeout === "number" && args.timeout > 0 ? args.timeout : DEFAULT_TIMEOUT / 1e3;
2214
+ if (timeoutSec > MAX_ALLOWED_TIMEOUT / 1e3) timeoutSec = MAX_ALLOWED_TIMEOUT / 1e3;
2215
+ const timeoutMs = timeoutSec * 1e3;
2216
+ const classification = ctx.classifyCommand(command);
2217
+ if (classification === "reject") return {
2218
+ success: false,
2219
+ output: "",
2220
+ error: `拒绝执行危险命令: ${command.slice(0, 80)}`
2221
+ };
2222
+ if (classification === "confirm" && !args.__confirmed) throw new PendingConfirmation("execute_command", { ...args }, `需要确认执行命令:\n${command}`);
2223
+ if (args.__confirmed) {
2224
+ if (ctx.classifyCommand(command) === "reject") return {
2225
+ success: false,
2226
+ output: "",
2227
+ error: `拒绝执行危险命令: ${command.slice(0, 80)}`
2228
+ };
2229
+ }
2230
+ return new Promise((resolve) => {
2231
+ const stdoutChunks = [];
2232
+ const stderrChunks = [];
2233
+ let resolved = false;
2234
+ let totalOutput = 0;
2235
+ const resolveResult = (success, error) => {
2236
+ if (resolved) return;
2237
+ resolved = true;
2238
+ clearTimeout(timer);
2239
+ const out = Buffer.concat(stdoutChunks).toString();
2240
+ const err = Buffer.concat(stderrChunks).toString();
2241
+ resolve({
2242
+ success,
2243
+ output: [out, err ? `\n[stderr]\n${err}` : ""].filter(Boolean).join("").slice(0, MAX_OUTPUT) || "(无输出)",
2244
+ error
2245
+ });
2246
+ };
2247
+ const timer = setTimeout(() => {
2248
+ if (!resolved) {
2249
+ if (!killProcessTree(child.pid)) try {
2250
+ child.kill();
2251
+ } catch {}
2252
+ resolveResult(false, `命令执行超时 (${timeoutSec} 秒)`);
2253
+ }
2254
+ }, timeoutMs);
2255
+ const child = spawn(command, [], {
2256
+ cwd: ctx.root,
2257
+ shell: IS_WINDOWS ? "powershell.exe" : "/bin/bash",
2258
+ stdio: [
2259
+ "ignore",
2260
+ "pipe",
2261
+ "pipe"
2262
+ ]
2263
+ });
2264
+ child.stdout?.on("data", (data) => {
2265
+ stdoutChunks.push(data);
2266
+ totalOutput += data.length;
2267
+ if (totalOutput > MAX_OUTPUT) {
2268
+ if (!resolved) {
2269
+ if (!killProcessTree(child.pid)) try {
2270
+ child.kill();
2271
+ } catch {}
2272
+ resolveResult(false, "命令输出超过上限 (50KB)");
2273
+ }
2274
+ } else ctx.onUpdate?.(data.toString());
2275
+ });
2276
+ child.stderr?.on("data", (data) => {
2277
+ stderrChunks.push(data);
2278
+ totalOutput += data.length;
2279
+ if (totalOutput > MAX_OUTPUT) {
2280
+ if (!resolved) {
2281
+ if (!killProcessTree(child.pid)) try {
2282
+ child.kill();
2283
+ } catch {}
2284
+ resolveResult(false, "命令输出超过上限 (50KB)");
2285
+ }
2286
+ } else ctx.onUpdate?.(data.toString());
2287
+ });
2288
+ child.on("close", (code) => {
2289
+ if (resolved) return;
2290
+ resolveResult(code === 0, code !== 0 ? `命令退出码: ${code}` : void 0);
2291
+ });
2292
+ child.on("error", (err) => {
2293
+ if (resolved) return;
2294
+ resolveResult(false, err.message);
2295
+ });
2296
+ });
2297
+ }
2298
+ };
2299
+ //#endregion
2300
+ //#region ../core/dist/tool/tools/web-search.js
2301
+ async function searchSearXNG(query, num, baseURL) {
2302
+ const url = `${baseURL.replace(/\/+$/, "")}/search?format=json&q=${encodeURIComponent(query)}`;
2303
+ const res = await fetch(url);
2304
+ if (!res.ok) throw new Error(`SearXNG returned ${res.status}`);
2305
+ return ((await res.json()).results || []).slice(0, num).map((r) => ({
2306
+ title: r.title,
2307
+ url: r.url,
2308
+ snippet: r.content || ""
2309
+ }));
2310
+ }
2311
+ async function searchTavily(query, num, apiKey) {
2312
+ const res = await fetch("https://api.tavily.com/search", {
2313
+ method: "POST",
2314
+ headers: {
2315
+ "Content-Type": "application/json",
2316
+ Authorization: `Bearer ${apiKey}`
2317
+ },
2318
+ body: JSON.stringify({
2319
+ query,
2320
+ max_results: num,
2321
+ include_answer: false
2322
+ })
2323
+ });
2324
+ if (!res.ok) throw new Error(`Tavily returned ${res.status}`);
2325
+ return ((await res.json()).results || []).slice(0, num).map((r) => ({
2326
+ title: r.title,
2327
+ url: r.url,
2328
+ snippet: r.content || ""
2329
+ }));
2330
+ }
2331
+ var webSearchTool = {
2332
+ name: "web_search",
2333
+ description: "Search the internet for information. Use for latest news, documentation lookup, fact verification, etc. Only use when real-time or external knowledge is needed. Results include title, URL, and snippet.",
2334
+ parameters: {
2335
+ type: "object",
2336
+ properties: {
2337
+ query: {
2338
+ type: "string",
2339
+ description: "Search query (keyword or question)"
2340
+ },
2341
+ num: {
2342
+ type: "integer",
2343
+ description: "Number of results, default 5, max 10"
2344
+ }
2345
+ },
2346
+ required: ["query"]
2347
+ },
2348
+ async execute(args, _ctx) {
2349
+ const query = args.query?.trim();
2350
+ if (!query) return {
2351
+ success: false,
2352
+ output: "",
2353
+ error: "缺少参数: query"
2354
+ };
2355
+ const num = Math.min(Math.max(typeof args.num === "number" ? args.num : 5, 1), 10);
2356
+ const config = readConfig();
2357
+ if (!config.searchEnabled) return {
2358
+ success: false,
2359
+ output: "",
2360
+ error: "搜索功能未启用,请在设置中开启"
2361
+ };
2362
+ const provider = config.searchProvider || "searxng";
2363
+ try {
2364
+ let results;
2365
+ if (provider === "tavily") {
2366
+ if (!config.tavilyApiKey) return {
2367
+ success: false,
2368
+ output: "",
2369
+ error: "未配置 Tavily API Key,请在设置中填写"
2370
+ };
2371
+ results = await searchTavily(query, num, config.tavilyApiKey);
2372
+ } else results = await searchSearXNG(query, num, config.searxngURL || "http://localhost:8080");
2373
+ if (results.length === 0) return {
2374
+ success: true,
2375
+ output: `未找到与「${query}」相关的结果。`
2376
+ };
2377
+ const formatted = results.map((r, i) => `${i + 1}. **[${r.title}](${r.url})**\n ${r.snippet}`).join("\n\n");
2378
+ return {
2379
+ success: true,
2380
+ output: `搜索「${query}」的结果(共 ${results.length} 条):\n\n${formatted}`
2381
+ };
2382
+ } catch (error) {
2383
+ return {
2384
+ success: false,
2385
+ output: "",
2386
+ error: `搜索失败: ${error.message}`
2387
+ };
2388
+ }
2389
+ }
2390
+ };
2391
+ //#endregion
2392
+ //#region ../core/dist/paths.js
2393
+ var QUALIA_HOME = join(homedir(), ".qualia");
2394
+ var DATA_DIR = join(QUALIA_HOME, "data");
2395
+ function getDataDir() {
2396
+ return DATA_DIR;
2397
+ }
2398
+ function getDataPath(...segments) {
2399
+ return join(DATA_DIR, ...segments);
2400
+ }
2401
+ function getConfigPath() {
2402
+ return join(QUALIA_HOME, "config.json");
2403
+ }
2404
+ //#endregion
2405
+ //#region ../core/dist/tool/tools/read-memory.js
2406
+ var MEMORY_PATH$2 = getDataPath("memory.md");
2407
+ var readMemoryTool = {
2408
+ name: "read_memory",
2409
+ description: "Read long-term memory (data/memory.md). Optionally pass a query for keyword search — returns matching lines with their category headers. Without query, returns the full memory content. Use when you need to recall previously stored information about users, yourself, or important events. Note: the memory snapshot taken at session creation may be stale; this tool always returns the latest.",
2410
+ parameters: {
2411
+ type: "object",
2412
+ properties: { query: {
2413
+ type: "string",
2414
+ description: "Optional. Search keyword (case-insensitive). Returns matching lines with their category headers. Omit to return all memory."
2415
+ } },
2416
+ required: []
2417
+ },
2418
+ async execute(args, _ctx) {
2419
+ try {
2420
+ if (!existsSync(MEMORY_PATH$2)) return {
2421
+ success: true,
2422
+ output: "(暂无记忆内容)"
2423
+ };
2424
+ const content = readFileSync(MEMORY_PATH$2, "utf-8");
2425
+ if (!content.trim()) return {
2426
+ success: true,
2427
+ output: "(暂无记忆内容)"
2428
+ };
2429
+ const query = args.query;
2430
+ if (!query?.trim()) return {
2431
+ success: true,
2432
+ output: content
2433
+ };
2434
+ const lines = content.split("\n");
2435
+ const lowerQuery = query.trim().toLowerCase();
2436
+ const resultLines = [];
2437
+ let lastHeader = "";
2438
+ for (const line of lines) {
2439
+ if (line.startsWith("## ")) lastHeader = line;
2440
+ if (line.trim() !== "" && !line.startsWith("## ") && line.toLowerCase().includes(lowerQuery)) {
2441
+ if (lastHeader && !resultLines.includes(lastHeader)) {
2442
+ resultLines.push(lastHeader);
2443
+ resultLines.push("");
2444
+ }
2445
+ resultLines.push(line);
2446
+ }
2447
+ }
2448
+ if (resultLines.length === 0) return {
2449
+ success: true,
2450
+ output: `(记忆中没有找到与 "${query.trim()}" 相关的内容)`
2451
+ };
2452
+ return {
2453
+ success: true,
2454
+ output: resultLines.join("\n")
2455
+ };
2456
+ } catch (error) {
2457
+ return {
2458
+ success: false,
2459
+ output: "",
2460
+ error: `读取记忆失败: ${error.message}`
2461
+ };
2462
+ }
2463
+ }
2464
+ };
2465
+ //#endregion
2466
+ //#region ../core/dist/tool/tools/write-memory.js
2467
+ var SECTION_META = `
2468
+ ## 关于我自己 (Qualia)
2469
+ 我是一个运行在本地环境中的 AI 伴侣,帮助用户完成开发工作和日常任务。
2470
+
2471
+ ## 关于用户
2472
+ (待记录)
2473
+
2474
+ ## 重要事件
2475
+ (待记录)
2476
+ `;
2477
+ var MEMORY_PATH$1 = getDataPath("memory.md");
2478
+ function ensureMemoryFile() {
2479
+ const dir = getDataDir();
2480
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
2481
+ if (!existsSync(MEMORY_PATH$1) || !readFileSync(MEMORY_PATH$1, "utf-8").includes("## 关于用户")) writeFileSync(MEMORY_PATH$1, SECTION_META.trim().replace(/\r/g, "") + "\n", "utf-8");
2482
+ }
2483
+ var CATEGORY_HEADERS = {
2484
+ self: "## 关于我自己 (Qualia)",
2485
+ user: "## 关于用户",
2486
+ event: "## 重要事件"
2487
+ };
2488
+ function updateSection(current, category, content) {
2489
+ const header = CATEGORY_HEADERS[category];
2490
+ if (!header) return current;
2491
+ let result = "";
2492
+ let inTarget = false;
2493
+ let done = false;
2494
+ for (const line of current.split("\n")) {
2495
+ if (line.startsWith("## ")) {
2496
+ if (inTarget) {
2497
+ result += content + "\n\n";
2498
+ done = true;
2499
+ }
2500
+ inTarget = line === header;
2501
+ } else if (inTarget && !done) continue;
2502
+ result += line + "\n";
2503
+ }
2504
+ if (inTarget && !done) result += content;
2505
+ return result.trim() + "\n";
2506
+ }
2507
+ var writeMemoryTool = {
2508
+ name: "write_memory",
2509
+ description: "Write important information to long-term memory (memory.md). Only use for information worth remembering long-term. Content is automatically injected into the system prompt of future sessions. Three categories: self (about yourself), user (about the user), event (important milestones). Each call overwrites the entire content of the given category.",
2510
+ parameters: {
2511
+ type: "object",
2512
+ properties: {
2513
+ category: {
2514
+ type: "string",
2515
+ description: "Memory category: self (about yourself), user (about the user), event (important events)",
2516
+ enum: [
2517
+ "self",
2518
+ "user",
2519
+ "event"
2520
+ ]
2521
+ },
2522
+ content: {
2523
+ type: "string",
2524
+ description: "New content for this category (replaces existing). Write in Chinese, concise and brief, one item per line."
2525
+ }
2526
+ },
2527
+ required: ["category", "content"]
2528
+ },
2529
+ async execute(args, _ctx) {
2530
+ const category = args.category;
2531
+ const content = args.content;
2532
+ if (!category || !CATEGORY_HEADERS[category]) return {
2533
+ success: false,
2534
+ output: "",
2535
+ error: `无效的类别: ${category},可选: self, user, event`
2536
+ };
2537
+ if (!content?.trim()) return {
2538
+ success: false,
2539
+ output: "",
2540
+ error: "content 不能为空"
2541
+ };
2542
+ try {
2543
+ ensureMemoryFile();
2544
+ writeFileSync(MEMORY_PATH$1, updateSection(readFileSync(MEMORY_PATH$1, "utf-8").replace(/\r/g, ""), category, content.trim()), "utf-8");
2545
+ return {
2546
+ success: true,
2547
+ output: `已更新记忆: ${CATEGORY_HEADERS[category]}\n${content}`
2548
+ };
2549
+ } catch (error) {
2550
+ return {
2551
+ success: false,
2552
+ output: "",
2553
+ error: `写入失败: ${error.message}`
2554
+ };
2555
+ }
2556
+ }
2557
+ };
2558
+ //#endregion
2559
+ //#region ../core/dist/concurrency/file-mutex.js
2560
+ var FileMutex = class {
2561
+ locks = /* @__PURE__ */ new Map();
2562
+ async run(key, fn) {
2563
+ await this.acquire(key);
2564
+ try {
2565
+ return await fn();
2566
+ } finally {
2567
+ this.release(key);
2568
+ }
2569
+ }
2570
+ acquire(key) {
2571
+ let entry = this.locks.get(key);
2572
+ if (!entry) {
2573
+ entry = {
2574
+ locked: false,
2575
+ waiters: []
2576
+ };
2577
+ this.locks.set(key, entry);
2578
+ }
2579
+ if (!entry.locked) {
2580
+ entry.locked = true;
2581
+ return Promise.resolve();
2582
+ }
2583
+ return new Promise((resolve, reject) => {
2584
+ entry.waiters.push({
2585
+ resolve,
2586
+ reject
2587
+ });
2588
+ });
2589
+ }
2590
+ release(key) {
2591
+ const entry = this.locks.get(key);
2592
+ if (!entry) return;
2593
+ const next = entry.waiters.shift();
2594
+ if (next) next.resolve();
2595
+ else {
2596
+ entry.locked = false;
2597
+ this.locks.delete(key);
2598
+ }
2599
+ }
2600
+ };
2601
+ var fileMutex = new FileMutex();
2602
+ //#endregion
2603
+ //#region ../core/dist/concurrency/background-worker.js
2604
+ var BackgroundWorker = class {
2605
+ tasks = /* @__PURE__ */ new Map();
2606
+ states = /* @__PURE__ */ new Map();
2607
+ started = false;
2608
+ schedule(name, intervalMs, fn) {
2609
+ if (this.tasks.has(name)) throw new Error(`BackgroundWorker: task "${name}" already registered`);
2610
+ this.tasks.set(name, {
2611
+ name,
2612
+ intervalMs,
2613
+ fn
2614
+ });
2615
+ this.states.set(name, {
2616
+ running: false,
2617
+ timerId: null
2618
+ });
2619
+ if (this.started) this.scheduleNext(name);
2620
+ }
2621
+ start() {
2622
+ if (this.started) return;
2623
+ this.started = true;
2624
+ for (const name of this.tasks.keys()) this.scheduleNext(name);
2625
+ }
2626
+ stop() {
2627
+ this.started = false;
2628
+ for (const [name, state] of this.states) {
2629
+ if (state.timerId) {
2630
+ clearTimeout(state.timerId);
2631
+ state.timerId = null;
2632
+ }
2633
+ state.running = false;
2634
+ }
2635
+ }
2636
+ scheduleNext(name) {
2637
+ const task = this.tasks.get(name);
2638
+ const state = this.states.get(name);
2639
+ if (!task || !state) return;
2640
+ state.timerId = setTimeout(() => this.execute(name), task.intervalMs);
2641
+ }
2642
+ async execute(name) {
2643
+ const task = this.tasks.get(name);
2644
+ const state = this.states.get(name);
2645
+ if (!task || !state) return;
2646
+ if (state.running) return;
2647
+ state.running = true;
2648
+ try {
2649
+ await task.fn();
2650
+ } catch (e) {
2651
+ console.error(`[BackgroundWorker] task "${name}" error:`, e.message);
2652
+ } finally {
2653
+ state.running = false;
2654
+ if (this.started) this.scheduleNext(name);
2655
+ }
2656
+ }
2657
+ };
2658
+ //#endregion
2659
+ //#region ../core/dist/concurrency/session-lock.js
2660
+ var SessionLock = class {
2661
+ sessions = /* @__PURE__ */ new Map();
2662
+ createRelease(sessionId) {
2663
+ let released = false;
2664
+ return () => {
2665
+ if (released) throw new Error(`SessionLock: session "${sessionId}" already released`);
2666
+ released = true;
2667
+ this.release(sessionId);
2668
+ };
2669
+ }
2670
+ async acquire(sessionId) {
2671
+ let entry = this.sessions.get(sessionId);
2672
+ if (!entry) {
2673
+ entry = {
2674
+ locked: false,
2675
+ waiters: []
2676
+ };
2677
+ this.sessions.set(sessionId, entry);
2678
+ }
2679
+ if (!entry.locked) {
2680
+ entry.locked = true;
2681
+ return this.createRelease(sessionId);
2682
+ }
2683
+ return new Promise((resolve, reject) => {
2684
+ entry.waiters.push({
2685
+ resolve,
2686
+ reject
2687
+ });
2688
+ });
2689
+ }
2690
+ release(sessionId) {
2691
+ const entry = this.sessions.get(sessionId);
2692
+ if (!entry) return;
2693
+ const next = entry.waiters.shift();
2694
+ if (next) next.resolve(this.createRelease(sessionId));
2695
+ else {
2696
+ entry.locked = false;
2697
+ this.sessions.delete(sessionId);
2698
+ }
2699
+ }
2700
+ };
2701
+ var sessionLock = new SessionLock();
2702
+ //#endregion
2703
+ //#region ../core/dist/task/store.js
2704
+ var MAX_AGE_MS = 10080 * 60 * 1e3;
2705
+ function getPath() {
2706
+ return getDataPath("tasks.json");
2707
+ }
2708
+ function readAll() {
2709
+ const path = getPath();
2710
+ if (!existsSync(path)) return [];
2711
+ try {
2712
+ const raw = readFileSync(path, "utf-8");
2713
+ const parsed = JSON.parse(raw);
2714
+ if (!Array.isArray(parsed)) return [];
2715
+ return parsed;
2716
+ } catch {
2717
+ return [];
2718
+ }
2719
+ }
2720
+ function writeAll(tasks) {
2721
+ const path = getPath();
2722
+ const dir = getDataDir();
2723
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
2724
+ const now = Date.now();
2725
+ const pruned = tasks.filter((t) => t.status === "pending" || t.status === "running" || t.status === "paused" || now - t.createdAt < MAX_AGE_MS).slice(-100);
2726
+ const tmpPath = path + ".tmp";
2727
+ writeFileSync(tmpPath, JSON.stringify(pruned, null, " "), "utf-8");
2728
+ renameSync(tmpPath, path);
2729
+ }
2730
+ var TASKS_MUTEX_KEY = "tasks.json";
2731
+ async function createTask(name, prompt, scheduledAt) {
2732
+ return fileMutex.run(TASKS_MUTEX_KEY, async () => {
2733
+ const task = {
2734
+ id: crypto.randomUUID(),
2735
+ name,
2736
+ prompt,
2737
+ createdAt: Date.now(),
2738
+ scheduledAt,
2739
+ status: "pending"
2740
+ };
2741
+ const all = readAll();
2742
+ all.push(task);
2743
+ writeAll(all);
2744
+ return task;
2745
+ });
2746
+ }
2747
+ function getAllTasks() {
2748
+ return readAll().sort((a, b) => b.createdAt - a.createdAt);
2749
+ }
2750
+ function getPendingTasks() {
2751
+ return readAll().filter((t) => t.status === "pending" && t.scheduledAt <= Date.now());
2752
+ }
2753
+ async function updateTaskStatus(id, status, extra) {
2754
+ return fileMutex.run(TASKS_MUTEX_KEY, async () => {
2755
+ const all = readAll();
2756
+ const task = all.find((t) => t.id === id);
2757
+ if (!task) return false;
2758
+ if (!{
2759
+ pending: ["running", "paused"],
2760
+ running: ["completed", "failed"],
2761
+ completed: [],
2762
+ failed: [],
2763
+ paused: ["pending"]
2764
+ }[status].includes(task.status)) return false;
2765
+ task.status = status;
2766
+ if (status === "completed") {
2767
+ task.completedAt = Date.now();
2768
+ task.result = extra?.result;
2769
+ }
2770
+ if (status === "failed") {
2771
+ task.completedAt = Date.now();
2772
+ task.error = extra?.error;
2773
+ }
2774
+ writeAll(all);
2775
+ return true;
2776
+ });
2777
+ }
2778
+ async function pauseTask(id) {
2779
+ return fileMutex.run(TASKS_MUTEX_KEY, async () => {
2780
+ const all = readAll();
2781
+ const task = all.find((t) => t.id === id);
2782
+ if (!task || task.status !== "pending") return false;
2783
+ task.status = "paused";
2784
+ writeAll(all);
2785
+ return true;
2786
+ });
2787
+ }
2788
+ async function resumeTask(id) {
2789
+ return fileMutex.run(TASKS_MUTEX_KEY, async () => {
2790
+ const all = readAll();
2791
+ const task = all.find((t) => t.id === id);
2792
+ if (!task || task.status !== "paused") return false;
2793
+ task.status = "pending";
2794
+ writeAll(all);
2795
+ return true;
2796
+ });
2797
+ }
2798
+ async function deleteTask(id) {
2799
+ return fileMutex.run(TASKS_MUTEX_KEY, async () => {
2800
+ const all = readAll();
2801
+ const idx = all.findIndex((t) => t.id === id);
2802
+ if (idx === -1) return false;
2803
+ all.splice(idx, 1);
2804
+ writeAll(all);
2805
+ return true;
2806
+ });
2807
+ }
2808
+ function formatTasksForAI(tasks) {
2809
+ if (tasks.length === 0) return "暂无任务。";
2810
+ const statusLabel = {
2811
+ pending: "等待中",
2812
+ running: "执行中",
2813
+ completed: "已完成",
2814
+ failed: "失败",
2815
+ paused: "已暂停"
2816
+ };
2817
+ return tasks.map((t) => {
2818
+ const created = new Date(t.createdAt).toISOString().replace("T", " ").slice(0, 19);
2819
+ const scheduled = new Date(t.scheduledAt).toISOString().replace("T", " ").slice(0, 19);
2820
+ let entry = `## ${t.name}\n`;
2821
+ entry += `- ID: ${t.id.slice(0, 8)}\n`;
2822
+ entry += `- 状态: ${statusLabel[t.status] || t.status}\n`;
2823
+ entry += `- 创建时间: ${created}\n`;
2824
+ entry += `- 计划执行: ${scheduled}\n`;
2825
+ if (t.prompt) entry += `- 任务描述: ${t.prompt.slice(0, 200)}${t.prompt.length > 200 ? "..." : ""}\n`;
2826
+ if (t.result) entry += `- 执行结果: ${t.result.slice(0, 500)}${t.result.length > 500 ? "..." : ""}\n`;
2827
+ if (t.error) entry += `- 错误: ${t.error.slice(0, 200)}\n`;
2828
+ if (t.completedAt) {
2829
+ const comp = new Date(t.completedAt).toISOString().replace("T", " ").slice(0, 19);
2830
+ entry += `- 完成时间: ${comp}\n`;
2831
+ }
2832
+ return entry;
2833
+ }).join("\n");
2834
+ }
2835
+ //#endregion
2836
+ //#region ../core/dist/storage/utils.js
2837
+ function formatSessionTitle(today, count) {
2838
+ return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}-${String(count).padStart(2, "0")}`;
2839
+ }
2840
+ //#endregion
2841
+ //#region ../core/dist/storage/memory.js
2842
+ /**
2843
+ * MemoryStorage — 基于内存 Map 的存储实现
2844
+ *
2845
+ * 所有数据存储在内存中,进程重启后数据丢失。
2846
+ * 适用于开发测试或关闭持久化时使用。
2847
+ */
2848
+ var MemoryStorage = class {
2849
+ sessions = /* @__PURE__ */ new Map();
2850
+ messages = /* @__PURE__ */ new Map();
2851
+ messageById = /* @__PURE__ */ new Map();
2852
+ seqCounter = /* @__PURE__ */ new Map();
2853
+ async createSession(title, memorySnapshot, workspace) {
2854
+ const id = crypto.randomUUID();
2855
+ const now = Date.now();
2856
+ const today = new Date(now);
2857
+ const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
2858
+ let count = 0;
2859
+ for (const s of this.sessions.values()) if (s.created_at >= startOfDay) count++;
2860
+ const session = {
2861
+ id,
2862
+ title: title || formatSessionTitle(today, count + 1),
2863
+ created_at: now,
2864
+ updated_at: now,
2865
+ parent_id: null,
2866
+ status: "active",
2867
+ token_count: 0,
2868
+ summary: "",
2869
+ last_summarized_at: null,
2870
+ memory_snapshot: memorySnapshot || "",
2871
+ workspace: workspace || ""
2872
+ };
2873
+ this.sessions.set(id, session);
2874
+ this.messages.set(id, []);
2875
+ this.seqCounter.set(id, 0);
2876
+ return session;
2877
+ }
2878
+ async getSession(id) {
2879
+ return this.sessions.get(id) || null;
2880
+ }
2881
+ async listSessions() {
2882
+ return Array.from(this.sessions.values()).sort((a, b) => b.updated_at - a.updated_at);
2883
+ }
2884
+ async deleteSession(id) {
2885
+ this.sessions.delete(id);
2886
+ const msgs = this.messages.get(id) || [];
2887
+ for (const msg of msgs) this.messageById.delete(msg.id);
2888
+ this.messages.delete(id);
2889
+ this.seqCounter.delete(id);
2890
+ }
2891
+ async archiveSession(id) {
2892
+ const session = this.sessions.get(id);
2893
+ if (session) {
2894
+ session.status = "archived";
2895
+ session.updated_at = Date.now();
2896
+ }
2897
+ }
2898
+ async forkSession(id) {
2899
+ const parent = this.sessions.get(id);
2900
+ if (!parent) throw new Error(`会话不存在: ${id}`);
2901
+ const newSession = await this.createSession(`[分叉] ${parent.title}`, parent.memory_snapshot);
2902
+ newSession.parent_id = id;
2903
+ newSession.token_count = parent.token_count;
2904
+ this.sessions.set(newSession.id, newSession);
2905
+ const parentMessages = this.messages.get(id) || [];
2906
+ const copiedMsgs = [];
2907
+ let seq = 0;
2908
+ for (const msg of parentMessages) {
2909
+ seq++;
2910
+ const copy = {
2911
+ ...msg,
2912
+ id: crypto.randomUUID(),
2913
+ session_id: newSession.id,
2914
+ seq
2915
+ };
2916
+ copiedMsgs.push(copy);
2917
+ this.messageById.set(copy.id, copy);
2918
+ }
2919
+ this.messages.set(newSession.id, copiedMsgs);
2920
+ this.seqCounter.set(newSession.id, seq);
2921
+ return newSession;
2922
+ }
2923
+ async addMessage(sessionId, message) {
2924
+ const session = this.sessions.get(sessionId);
2925
+ if (!session) throw new Error(`会话不存在: ${sessionId}`);
2926
+ const seq = (this.seqCounter.get(sessionId) || 0) + 1;
2927
+ this.seqCounter.set(sessionId, seq);
2928
+ const record = {
2929
+ ...message,
2930
+ id: message.id || crypto.randomUUID(),
2931
+ created_at: Date.now(),
2932
+ seq
2933
+ };
2934
+ const list = this.messages.get(sessionId) || [];
2935
+ list.push(record);
2936
+ this.messages.set(sessionId, list);
2937
+ this.messageById.set(record.id, record);
2938
+ session.updated_at = Date.now();
2939
+ return record;
2940
+ }
2941
+ async getMessages(sessionId, options) {
2942
+ let list = this.messages.get(sessionId) || [];
2943
+ if (options?.before !== void 0) list = list.filter((m) => m.seq < options.before);
2944
+ if (options?.limit !== void 0) list = list.slice(-options.limit);
2945
+ return list;
2946
+ }
2947
+ async getMessage(id) {
2948
+ return this.messageById.get(id) || null;
2949
+ }
2950
+ async deleteMessage(id) {
2951
+ const msg = this.messageById.get(id);
2952
+ if (!msg) return;
2953
+ this.messageById.delete(id);
2954
+ const list = this.messages.get(msg.session_id);
2955
+ if (list) {
2956
+ const idx = list.findIndex((m) => m.id === id);
2957
+ if (idx !== -1) list.splice(idx, 1);
2958
+ }
2959
+ }
2960
+ async deleteMessagesFrom(sessionId, messageId) {
2961
+ const list = this.messages.get(sessionId);
2962
+ if (!list) return;
2963
+ const idx = list.findIndex((m) => m.id === messageId);
2964
+ if (idx === -1) return;
2965
+ const toDelete = list.splice(idx);
2966
+ for (const msg of toDelete) this.messageById.delete(msg.id);
2967
+ }
2968
+ async getTokenCount(sessionId) {
2969
+ return this.sessions.get(sessionId)?.token_count || 0;
2970
+ }
2971
+ async updateTokenCount(sessionId, count) {
2972
+ const session = this.sessions.get(sessionId);
2973
+ if (session) session.token_count = count;
2974
+ }
2975
+ async setSessionTitle(sessionId, title) {
2976
+ const session = this.sessions.get(sessionId);
2977
+ if (session) session.title = title;
2978
+ }
2979
+ async getStaleSessions(idleMs) {
2980
+ const now = Date.now();
2981
+ const result = [];
2982
+ for (const s of this.sessions.values()) {
2983
+ if (s.status !== "active") continue;
2984
+ if (idleMs !== null && now - s.updated_at <= idleMs) continue;
2985
+ if (s.last_summarized_at !== null && s.last_summarized_at >= s.updated_at) continue;
2986
+ const msgs = this.messages.get(s.id);
2987
+ if (!msgs || msgs.length === 0) continue;
2988
+ result.push(s);
2989
+ }
2990
+ result.sort((a, b) => a.updated_at - b.updated_at);
2991
+ return result;
2992
+ }
2993
+ async getMessagesSinceSeq(sessionId, seq) {
2994
+ return (this.messages.get(sessionId) || []).filter((m) => m.seq > seq);
2995
+ }
2996
+ async updateSummary(sessionId, summary) {
2997
+ const session = this.sessions.get(sessionId);
2998
+ if (session) {
2999
+ session.summary = summary;
3000
+ session.last_summarized_at = Date.now();
3001
+ }
3002
+ }
3003
+ async getTodayUpdatedSessions() {
3004
+ const now = /* @__PURE__ */ new Date();
3005
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
3006
+ const endOfDay = startOfDay + 864e5;
3007
+ const result = [];
3008
+ for (const s of this.sessions.values()) if (s.summary && s.last_summarized_at && s.last_summarized_at >= startOfDay && s.last_summarized_at < endOfDay) result.push(s);
3009
+ result.sort((a, b) => (a.last_summarized_at || 0) - (b.last_summarized_at || 0));
3010
+ return result;
3011
+ }
3012
+ async setMemorySnapshot(sessionId, snapshot) {
3013
+ const session = this.sessions.get(sessionId);
3014
+ if (session) session.memory_snapshot = snapshot;
3015
+ }
3016
+ async searchMessages(query, sessionId, limit = 10) {
3017
+ const lowerQuery = query.toLowerCase();
3018
+ const results = [];
3019
+ for (const [sid, msgs] of this.messages) {
3020
+ if (sessionId && sid !== sessionId) continue;
3021
+ const session = this.sessions.get(sid);
3022
+ for (const msg of msgs) {
3023
+ if (!msg.content.toLowerCase().includes(lowerQuery)) continue;
3024
+ results.push({
3025
+ sessionId: sid,
3026
+ sessionTitle: session?.title || "",
3027
+ messageId: msg.id,
3028
+ role: msg.role,
3029
+ content: msg.content,
3030
+ createdAt: msg.created_at
3031
+ });
3032
+ }
3033
+ }
3034
+ results.sort((a, b) => b.createdAt - a.createdAt);
3035
+ return results.slice(0, limit);
3036
+ }
3037
+ async setAudioPath(messageId, path) {
3038
+ const msg = this.messageById.get(messageId);
3039
+ if (msg) msg.audio_path = path;
3040
+ }
3041
+ async getMostRecentSession() {
3042
+ for (const s of this.sessions.values()) if (s.status === "active") return s;
3043
+ return null;
3044
+ }
3045
+ async listWorkspaces() {
3046
+ const workspaces = /* @__PURE__ */ new Set();
3047
+ for (const s of this.sessions.values()) if (s.status === "active" && s.workspace) workspaces.add(s.workspace);
3048
+ return Array.from(workspaces).sort();
3049
+ }
3050
+ };
3051
+ //#endregion
3052
+ //#region ../core/dist/storage/sqlite.js
3053
+ /**
3054
+ * SQLiteStorage — 基于 better-sqlite3 的持久化存储
3055
+ *
3056
+ * 使用 WAL 模式,支持外键约束。
3057
+ * 自动建表,联合索引 (session_id, seq)。
3058
+ */
3059
+ var SQLiteStorage = class {
3060
+ db;
3061
+ stmts;
3062
+ constructor(dbPath) {
3063
+ this.db = new Database(dbPath);
3064
+ this.db.pragma("journal_mode = WAL");
3065
+ this.db.pragma("foreign_keys = ON");
3066
+ this.initTables();
3067
+ this.stmts = this.prepareStatements();
3068
+ }
3069
+ initTables() {
3070
+ this.db.exec(`
3071
+ CREATE TABLE IF NOT EXISTS sessions (
3072
+ id TEXT PRIMARY KEY,
3073
+ title TEXT NOT NULL DEFAULT '',
3074
+ created_at INTEGER NOT NULL,
3075
+ updated_at INTEGER NOT NULL,
3076
+ parent_id TEXT,
3077
+ status TEXT NOT NULL DEFAULT 'active',
3078
+ token_count INTEGER NOT NULL DEFAULT 0,
3079
+ summary TEXT NOT NULL DEFAULT '',
3080
+ last_summarized_at INTEGER,
3081
+ memory_snapshot TEXT NOT NULL DEFAULT '',
3082
+ workspace TEXT NOT NULL DEFAULT ''
3083
+ );
3084
+ CREATE TABLE IF NOT EXISTS messages (
3085
+ id TEXT PRIMARY KEY,
3086
+ session_id TEXT NOT NULL,
3087
+ role TEXT NOT NULL,
3088
+ content TEXT NOT NULL DEFAULT '',
3089
+ reasoning_content TEXT,
3090
+ tool_calls TEXT,
3091
+ tool_call_id TEXT,
3092
+ name TEXT,
3093
+ usage TEXT,
3094
+ audio_path TEXT,
3095
+ created_at INTEGER NOT NULL,
3096
+ seq INTEGER NOT NULL,
3097
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
3098
+ );
3099
+ CREATE INDEX IF NOT EXISTS idx_messages_session_seq
3100
+ ON messages(session_id, seq);
3101
+ `);
3102
+ this.migrate();
3103
+ }
3104
+ migrate() {
3105
+ const cols = this.db.pragma("table_info(sessions)");
3106
+ const columnNames = new Set(cols.map((c) => c.name));
3107
+ if (!columnNames.has("summary")) this.db.exec(`ALTER TABLE sessions ADD COLUMN summary TEXT NOT NULL DEFAULT ''`);
3108
+ if (!columnNames.has("last_summarized_at")) this.db.exec(`ALTER TABLE sessions ADD COLUMN last_summarized_at INTEGER`);
3109
+ if (!columnNames.has("memory_snapshot")) this.db.exec(`ALTER TABLE sessions ADD COLUMN memory_snapshot TEXT NOT NULL DEFAULT ''`);
3110
+ if (!columnNames.has("workspace")) this.db.exec(`ALTER TABLE sessions ADD COLUMN workspace TEXT NOT NULL DEFAULT ''`);
3111
+ }
3112
+ prepareStatements() {
3113
+ return {
3114
+ createSession: this.db.prepare(`INSERT INTO sessions (id, title, created_at, updated_at, parent_id, status, token_count, summary, last_summarized_at, memory_snapshot, workspace) VALUES (?, ?, ?, ?, ?, ?, ?, '', NULL, ?, ?)`),
3115
+ getSession: this.db.prepare(`SELECT * FROM sessions WHERE id = ?`),
3116
+ listAllSessions: this.db.prepare(`SELECT * FROM sessions ORDER BY updated_at DESC`),
3117
+ deleteSession: this.db.prepare(`DELETE FROM sessions WHERE id = ?`),
3118
+ updateSessionStatus: this.db.prepare(`UPDATE sessions SET status = ?, updated_at = ? WHERE id = ?`),
3119
+ updateSession: this.db.prepare(`UPDATE sessions SET title = ?, updated_at = ?, token_count = ? WHERE id = ?`),
3120
+ insertMessage: this.db.prepare(`INSERT INTO messages (id, session_id, role, content, reasoning_content, tool_calls, tool_call_id, name, usage, audio_path, created_at, seq) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
3121
+ getMessages: this.db.prepare(`SELECT * FROM messages WHERE session_id = ? AND (? IS NULL OR seq < ?) ORDER BY seq ASC`),
3122
+ getMessagesSinceSeq: this.db.prepare(`SELECT * FROM messages WHERE session_id = ? AND seq > ? ORDER BY seq ASC`),
3123
+ getMessage: this.db.prepare(`SELECT * FROM messages WHERE id = ?`),
3124
+ deleteMessage: this.db.prepare(`DELETE FROM messages WHERE id = ?`),
3125
+ getMaxSeq: this.db.prepare(`SELECT COALESCE(MAX(seq), 0) as max_seq FROM messages WHERE session_id = ?`),
3126
+ updateAudioPath: this.db.prepare(`UPDATE messages SET audio_path = ? WHERE id = ?`),
3127
+ deleteFromSeq: this.db.prepare(`DELETE FROM messages WHERE session_id = ? AND seq >= ?`),
3128
+ setTitle: this.db.prepare(`UPDATE sessions SET title = ? WHERE id = ?`),
3129
+ updateSummary: this.db.prepare(`UPDATE sessions SET summary = ?, last_summarized_at = ? WHERE id = ?`),
3130
+ getStaleSessions: this.db.prepare(`SELECT * FROM sessions WHERE status = 'active' AND (? - updated_at > ?) AND (last_summarized_at IS NULL OR last_summarized_at < updated_at) AND id IN (SELECT DISTINCT session_id FROM messages) ORDER BY updated_at ASC`),
3131
+ getAllUnsummarized: this.db.prepare(`SELECT * FROM sessions WHERE status = 'active' AND (last_summarized_at IS NULL OR last_summarized_at < updated_at) AND id IN (SELECT DISTINCT session_id FROM messages) ORDER BY updated_at ASC`),
3132
+ getTodayUpdated: this.db.prepare(`SELECT * FROM sessions WHERE summary != '' AND last_summarized_at >= ? AND last_summarized_at < ? ORDER BY last_summarized_at ASC`),
3133
+ setMemorySnapshot: this.db.prepare(`UPDATE sessions SET memory_snapshot = ? WHERE id = ?`),
3134
+ countToday: this.db.prepare(`SELECT COUNT(*) as cnt FROM sessions WHERE created_at >= ? AND created_at < ?`),
3135
+ searchMessages: this.db.prepare(`SELECT m.id as messageId, m.session_id as sessionId, m.role, m.content, m.created_at as createdAt, s.title as sessionTitle FROM messages m JOIN sessions s ON m.session_id = s.id WHERE m.content LIKE ? AND (? IS NULL OR m.session_id = ?) ORDER BY m.created_at DESC LIMIT ?`)
3136
+ };
3137
+ }
3138
+ async createSession(title, memorySnapshot, workspace) {
3139
+ const id = crypto.randomUUID();
3140
+ const now = Date.now();
3141
+ const effectiveTitle = title || this.generateDefaultTitle(now);
3142
+ this.stmts.createSession.run(id, effectiveTitle, now, now, null, "active", 0, memorySnapshot || "", workspace || "");
3143
+ return await this.getSession(id);
3144
+ }
3145
+ generateDefaultTitle(now) {
3146
+ const today = new Date(now);
3147
+ const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
3148
+ const endOfDay = startOfDay + 864e5;
3149
+ const { cnt } = this.stmts.countToday.get(startOfDay, endOfDay);
3150
+ return formatSessionTitle(today, cnt + 1);
3151
+ }
3152
+ async getSession(id) {
3153
+ const row = this.stmts.getSession.get(id);
3154
+ return row ? this.rowToSession(row) : null;
3155
+ }
3156
+ async listSessions() {
3157
+ return this.stmts.listAllSessions.all().map((row) => this.rowToSession(row));
3158
+ }
3159
+ async deleteSession(id) {
3160
+ this.stmts.deleteSession.run(id);
3161
+ }
3162
+ async archiveSession(id) {
3163
+ this.stmts.updateSessionStatus.run("archived", Date.now(), id);
3164
+ }
3165
+ async forkSession(id) {
3166
+ const parent = await this.getSession(id);
3167
+ if (!parent) throw new Error(`会话不存在: ${id}`);
3168
+ const newSession = await this.createSession(`[分叉] ${parent.title}`, parent.memory_snapshot);
3169
+ const now = Date.now();
3170
+ this.db.prepare("UPDATE sessions SET parent_id = ? WHERE id = ?").run(id, newSession.id);
3171
+ const parentMessages = await this.getMessages(id);
3172
+ let seq = 0;
3173
+ for (const msg of parentMessages) {
3174
+ seq++;
3175
+ this.stmts.insertMessage.run(crypto.randomUUID(), newSession.id, msg.role, msg.content, msg.reasoning_content || null, msg.tool_calls ? JSON.stringify(msg.tool_calls) : null, msg.tool_call_id || null, msg.name || null, msg.usage ? JSON.stringify(msg.usage) : null, msg.audio_path || null, msg.created_at, seq);
3176
+ }
3177
+ this.db.prepare("UPDATE sessions SET token_count = ?, updated_at = ? WHERE id = ?").run(parent.token_count, now, newSession.id);
3178
+ return await this.getSession(newSession.id);
3179
+ }
3180
+ async addMessage(sessionId, message) {
3181
+ const session = await this.getSession(sessionId);
3182
+ if (!session) throw new Error(`会话不存在: ${sessionId}`);
3183
+ const { max_seq } = this.stmts.getMaxSeq.get(sessionId);
3184
+ const seq = max_seq + 1;
3185
+ const id = message.id || crypto.randomUUID();
3186
+ const now = Date.now();
3187
+ this.stmts.insertMessage.run(id, sessionId, message.role, message.content, message.reasoning_content || null, message.tool_calls ? JSON.stringify(message.tool_calls) : null, message.tool_call_id || null, message.name || null, message.usage ? JSON.stringify(message.usage) : null, message.audio_path || null, now, seq);
3188
+ this.stmts.updateSession.run(session.title, now, session.token_count, sessionId);
3189
+ return await this.getMessage(id);
3190
+ }
3191
+ async getMessages(sessionId, options) {
3192
+ const before = options?.before ?? null;
3193
+ let result = this.stmts.getMessages.all(sessionId, before, before).map((row) => this.rowToMessage(row));
3194
+ if (options?.limit !== void 0) result = result.slice(-options.limit);
3195
+ return result;
3196
+ }
3197
+ async getMessage(id) {
3198
+ const row = this.stmts.getMessage.get(id);
3199
+ return row ? this.rowToMessage(row) : null;
3200
+ }
3201
+ async deleteMessage(id) {
3202
+ this.stmts.deleteMessage.run(id);
3203
+ }
3204
+ async deleteMessagesFrom(sessionId, messageId) {
3205
+ const msg = this.stmts.getMessage.get(messageId);
3206
+ if (!msg) return;
3207
+ this.stmts.deleteFromSeq.run(sessionId, msg.seq);
3208
+ }
3209
+ async getTokenCount(sessionId) {
3210
+ return (await this.getSession(sessionId))?.token_count || 0;
3211
+ }
3212
+ async updateTokenCount(sessionId, count) {
3213
+ const session = await this.getSession(sessionId);
3214
+ if (session) this.stmts.updateSession.run(session.title, Date.now(), count, sessionId);
3215
+ }
3216
+ async setSessionTitle(sessionId, title) {
3217
+ this.stmts.setTitle.run(title, sessionId);
3218
+ }
3219
+ async searchMessages(query, sessionId, limit = 10) {
3220
+ const pattern = `%${query}%`;
3221
+ return this.stmts.searchMessages.all(pattern, sessionId || null, sessionId || null, limit).map((r) => ({
3222
+ sessionId: r.sessionId,
3223
+ sessionTitle: r.sessionTitle,
3224
+ messageId: r.messageId,
3225
+ role: r.role,
3226
+ content: r.content,
3227
+ createdAt: r.createdAt
3228
+ }));
3229
+ }
3230
+ async setAudioPath(messageId, path) {
3231
+ this.stmts.updateAudioPath.run(path, messageId);
3232
+ }
3233
+ async getMostRecentSession() {
3234
+ const rows = this.stmts.listAllSessions.all();
3235
+ for (const row of rows) if (row.status === "active") return this.rowToSession(row);
3236
+ return null;
3237
+ }
3238
+ async listWorkspaces() {
3239
+ return this.db.prepare(`SELECT DISTINCT workspace FROM sessions WHERE status = 'active' AND workspace != '' ORDER BY workspace ASC`).all().map((r) => r.workspace);
3240
+ }
3241
+ async getStaleSessions(idleMs) {
3242
+ let rows;
3243
+ if (idleMs === null) rows = this.stmts.getAllUnsummarized.all();
3244
+ else {
3245
+ const now = Date.now();
3246
+ rows = this.stmts.getStaleSessions.all(now, idleMs);
3247
+ }
3248
+ return rows.map((row) => this.rowToSession(row));
3249
+ }
3250
+ async getMessagesSinceSeq(sessionId, seq) {
3251
+ return this.stmts.getMessagesSinceSeq.all(sessionId, seq).map((row) => this.rowToMessage(row));
3252
+ }
3253
+ async updateSummary(sessionId, summary) {
3254
+ this.stmts.updateSummary.run(summary, Date.now(), sessionId);
3255
+ }
3256
+ async getTodayUpdatedSessions() {
3257
+ const now = /* @__PURE__ */ new Date();
3258
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
3259
+ const endOfDay = startOfDay + 864e5;
3260
+ return this.stmts.getTodayUpdated.all(startOfDay, endOfDay).map((row) => this.rowToSession(row));
3261
+ }
3262
+ async setMemorySnapshot(sessionId, snapshot) {
3263
+ this.stmts.setMemorySnapshot.run(snapshot, sessionId);
3264
+ }
3265
+ rowToSession(row) {
3266
+ return {
3267
+ id: row.id,
3268
+ title: row.title,
3269
+ created_at: row.created_at,
3270
+ updated_at: row.updated_at,
3271
+ parent_id: row.parent_id,
3272
+ status: row.status,
3273
+ token_count: row.token_count,
3274
+ summary: row.summary || "",
3275
+ last_summarized_at: row.last_summarized_at ?? null,
3276
+ memory_snapshot: row.memory_snapshot || "",
3277
+ workspace: row.workspace || ""
3278
+ };
3279
+ }
3280
+ rowToMessage(row) {
3281
+ return {
3282
+ id: row.id,
3283
+ session_id: row.session_id,
3284
+ role: row.role,
3285
+ content: row.content,
3286
+ reasoning_content: row.reasoning_content || void 0,
3287
+ tool_calls: row.tool_calls ? JSON.parse(row.tool_calls) : void 0,
3288
+ tool_call_id: row.tool_call_id || void 0,
3289
+ name: row.name || void 0,
3290
+ usage: row.usage ? JSON.parse(row.usage) : void 0,
3291
+ audio_path: row.audio_path || void 0,
3292
+ created_at: row.created_at,
3293
+ seq: row.seq
3294
+ };
3295
+ }
3296
+ };
3297
+ //#endregion
3298
+ //#region ../core/dist/storage/index.js
3299
+ var _memory = null;
3300
+ var _sqlite = null;
3301
+ function createStorage(config) {
3302
+ if (config.enabled) {
3303
+ if (!_sqlite) _sqlite = new SQLiteStorage(config.dbPath || getDataPath("db.sqlite"));
3304
+ return _sqlite;
3305
+ }
3306
+ if (!_memory) _memory = new MemoryStorage();
3307
+ return _memory;
3308
+ }
3309
+ //#endregion
3310
+ //#region ../core/dist/task/executor.js
3311
+ var TASK_TIMEOUT_MS = 600 * 1e3;
3312
+ async function executeTask(task, onComplete) {
3313
+ if (!await updateTaskStatus(task.id, "running")) return;
3314
+ let result = "";
3315
+ let error;
3316
+ try {
3317
+ const config = readConfig();
3318
+ if (!config.activeModel) throw new Error("未选择模型");
3319
+ const providerConfig = getProviderForModel(config.activeModel);
3320
+ if (!providerConfig) throw new Error("未找到供应商配置");
3321
+ const model = getActiveModel();
3322
+ const provider = createProvider({
3323
+ ...providerConfig,
3324
+ activeModel: model?.id || config.activeModel,
3325
+ contextWindow: model?.contextWindow || 1048576
3326
+ });
3327
+ const storage = createStorage({ enabled: false });
3328
+ const registry = new ToolRegistry();
3329
+ for (const t of CORE_TOOLS) if (t.name !== "write_memory") registry.register(t);
3330
+ registry.register(createSearchHistoryTool(storage));
3331
+ const abortController = new AbortController();
3332
+ const timeout = setTimeout(() => abortController.abort(), TASK_TIMEOUT_MS);
3333
+ try {
3334
+ const buildResult = {
3335
+ messages: [{
3336
+ role: "system",
3337
+ content: `You are a background automation agent. Execute the task description strictly and output a concise result summary in Chinese.
3338
+ Do not ask the user any questions. Do not wait for confirmation. Do not create new scheduled tasks.
3339
+ If an operation requires confirmation, skip it and explain why.`
3340
+ }, {
3341
+ role: "user",
3342
+ content: task.prompt
3343
+ }],
3344
+ contextWindow: getContextWindow()
3345
+ };
3346
+ const agent = new AgentLoop(provider, storage, registry, async () => false, abortController.signal, new AgentLogger(`task-${task.id.slice(0, 8)}`), config.compressionMode, config.compressionThreshold);
3347
+ const sid = (await storage.createSession(void 0, void 0, process.cwd())).id;
3348
+ for await (const event of agent.run(sid, task.prompt, buildResult)) if (event.type === "content") result += event.text;
3349
+ else if (event.type === "error") error = event.message;
3350
+ else if (event.type === "retry_exhausted") error = event.message;
3351
+ } finally {
3352
+ clearTimeout(timeout);
3353
+ }
3354
+ if (error) await updateTaskStatus(task.id, "failed", { error });
3355
+ else {
3356
+ result = result.trim();
3357
+ await updateTaskStatus(task.id, "completed", { result });
3358
+ }
3359
+ await onComplete(result, error);
3360
+ } catch (e) {
3361
+ error = e.message;
3362
+ await updateTaskStatus(task.id, "failed", { error });
3363
+ await onComplete("", error);
3364
+ }
3365
+ }
3366
+ //#endregion
3367
+ //#region ../core/dist/task/scheduler.js
3368
+ var SCAN_INTERVAL_MS = 15e3;
3369
+ var worker = null;
3370
+ var notificationCallback = null;
3371
+ function setTaskNotificationHandler(fn) {
3372
+ notificationCallback = fn;
3373
+ }
3374
+ async function tick() {
3375
+ const pending = getPendingTasks();
3376
+ for (const task of pending) await executeTask(task, async (result, error) => {
3377
+ if (notificationCallback) if (error) await notificationCallback({
3378
+ title: `任务失败: ${task.name}`,
3379
+ body: error,
3380
+ type: "error"
3381
+ });
3382
+ else {
3383
+ const preview = result.slice(0, 300) + (result.length > 300 ? "..." : "");
3384
+ await notificationCallback({
3385
+ title: `任务完成: ${task.name}`,
3386
+ body: preview,
3387
+ type: "task_complete"
3388
+ });
3389
+ }
3390
+ });
3391
+ }
3392
+ function startScheduler() {
3393
+ if (worker) return;
3394
+ worker = new BackgroundWorker();
3395
+ worker.schedule("task-tick", SCAN_INTERVAL_MS, tick);
3396
+ worker.start();
3397
+ }
3398
+ //#endregion
3399
+ //#region ../core/dist/tool/tools/schedule-task.js
3400
+ var scheduleTaskTool = {
3401
+ name: "schedule_task",
3402
+ description: "Create a scheduled one-shot task. The task runs automatically at the specified future time (no conversation context) and the user is notified on completion. Before using, run exec to get the current system time to ensure scheduledAt is in the future.",
3403
+ parameters: {
3404
+ type: "object",
3405
+ properties: {
3406
+ name: {
3407
+ type: "string",
3408
+ description: "Task name (short description, e.g. \"Data processing\")"
3409
+ },
3410
+ prompt: {
3411
+ type: "string",
3412
+ description: "Task description — this is the sole instruction the model receives when executing in the background with no conversation context. Must be self-contained: what to do, expected output format, any necessary details"
3413
+ },
3414
+ scheduledAt: {
3415
+ type: "string",
3416
+ description: "ISO 8601 datetime string (e.g. 2026-06-16T14:30:00Z). Must be in the future. Use exec to get current system time first."
3417
+ }
3418
+ },
3419
+ required: [
3420
+ "name",
3421
+ "prompt",
3422
+ "scheduledAt"
3423
+ ]
3424
+ },
3425
+ execute: async (args) => {
3426
+ const name = args.name;
3427
+ const prompt = args.prompt;
3428
+ const scheduledAtStr = args.scheduledAt;
3429
+ if (!name?.trim() || !prompt?.trim() || !scheduledAtStr?.trim()) return {
3430
+ success: false,
3431
+ output: "",
3432
+ error: "参数不完整:name、prompt、scheduledAt 均为必填"
3433
+ };
3434
+ const scheduledAt = new Date(scheduledAtStr).getTime();
3435
+ if (isNaN(scheduledAt)) return {
3436
+ success: false,
3437
+ output: "",
3438
+ error: `无法解析时间 "${scheduledAtStr}",请使用 ISO 8601 格式,如 2026-06-16T14:30:00Z`
3439
+ };
3440
+ const now = Date.now();
3441
+ if (scheduledAt <= now) return {
3442
+ success: false,
3443
+ output: "",
3444
+ error: `计划执行时间 ${scheduledAtStr} 已过期。当前时间是 ${new Date(now).toISOString()},请设置一个未来的时间`
3445
+ };
3446
+ if (scheduledAt > now + 720 * 60 * 60 * 1e3) return {
3447
+ success: false,
3448
+ output: "",
3449
+ error: `计划执行时间不能超过 30 天后`
3450
+ };
3451
+ const task = await createTask(name.trim(), prompt.trim(), scheduledAt);
3452
+ const formatted = new Date(scheduledAt).toISOString().replace("T", " ").slice(0, 19);
3453
+ return {
3454
+ success: true,
3455
+ output: `任务已创建:\n- ID: ${task.id.slice(0, 8)}\n- 名称: ${task.name}\n- 计划执行: ${formatted}\n\n任务将在指定时间自动执行,完成后通过 Email 通知你。`
3456
+ };
3457
+ }
3458
+ };
3459
+ //#endregion
3460
+ //#region ../core/dist/tool/tools/read-tasks.js
3461
+ var readTasksTool = {
3462
+ name: "read_tasks",
3463
+ description: "Query scheduled task list and results. View all tasks (pending, running, completed, failed, paused) or filter by status. The AI is NOT automatically notified of completions — you must manually call this tool to check.",
3464
+ parameters: {
3465
+ type: "object",
3466
+ properties: { status: {
3467
+ type: "string",
3468
+ description: "Filter by status: pending, running, completed, failed, paused. Omit to return all."
3469
+ } },
3470
+ required: []
3471
+ },
3472
+ execute: async (args) => {
3473
+ const statusFilter = args.status?.trim();
3474
+ let tasks = getAllTasks();
3475
+ if (statusFilter) {
3476
+ const valid = [
3477
+ "pending",
3478
+ "running",
3479
+ "completed",
3480
+ "failed",
3481
+ "paused"
3482
+ ];
3483
+ if (!valid.includes(statusFilter)) return {
3484
+ success: false,
3485
+ output: "",
3486
+ error: `无效的状态值 "${statusFilter}",可选: ${valid.join(", ")}`
3487
+ };
3488
+ tasks = tasks.filter((t) => t.status === statusFilter);
3489
+ }
3490
+ return {
3491
+ success: true,
3492
+ output: formatTasksForAI(tasks)
3493
+ };
3494
+ }
3495
+ };
3496
+ //#endregion
3497
+ //#region ../core/dist/tool/tools/search-history.js
3498
+ function formatResults(results, query) {
3499
+ if (results.length === 0) return `(未在历史对话中找到与 "${query}" 相关的内容)`;
3500
+ const lines = [`找到 ${results.length} 条与 "${query}" 相关的结果:`];
3501
+ let lastSession = "";
3502
+ for (const r of results) {
3503
+ if (r.sessionTitle !== lastSession) {
3504
+ lastSession = r.sessionTitle;
3505
+ lines.push("", `--- ${r.sessionTitle} ---`);
3506
+ }
3507
+ const date = new Date(r.createdAt).toLocaleString("zh-CN");
3508
+ const roleLabel = r.role === "user" ? "用户" : r.role === "assistant" ? "AI" : r.role;
3509
+ const snippet = r.content.length > 200 ? r.content.slice(0, 200) + "..." : r.content;
3510
+ lines.push(`[${date}] ${roleLabel}: ${snippet}`);
3511
+ }
3512
+ return lines.join("\n");
3513
+ }
3514
+ function createSearchHistoryTool(storage) {
3515
+ return {
3516
+ name: "search_history",
3517
+ description: "Search conversation history across all sessions with fuzzy text matching. Use when you need to recall what the user discussed before. Note: this searches chat records, not long-term memory (use read_memory for that).",
3518
+ parameters: {
3519
+ type: "object",
3520
+ properties: {
3521
+ query: {
3522
+ type: "string",
3523
+ description: "Search keyword or phrase (case-insensitive). Matches content field of all messages."
3524
+ },
3525
+ session_id: {
3526
+ type: "string",
3527
+ description: "Optional. Limit search to a specific session. Omit to search all sessions."
3528
+ },
3529
+ limit: {
3530
+ type: "number",
3531
+ description: "Optional. Max results, default 10."
3532
+ }
3533
+ },
3534
+ required: ["query"]
3535
+ },
3536
+ async execute(args, _ctx) {
3537
+ const query = args.query;
3538
+ const sessionId = args.session_id;
3539
+ const limit = args.limit || 10;
3540
+ if (!query?.trim()) return {
3541
+ success: false,
3542
+ output: "",
3543
+ error: "query 不能为空"
3544
+ };
3545
+ try {
3546
+ return {
3547
+ success: true,
3548
+ output: formatResults(await storage.searchMessages(query.trim(), sessionId || void 0, limit), query.trim())
3549
+ };
3550
+ } catch (error) {
3551
+ return {
3552
+ success: false,
3553
+ output: "",
3554
+ error: `搜索失败: ${error.message}`
3555
+ };
3556
+ }
3557
+ }
3558
+ };
3559
+ }
3560
+ //#endregion
3561
+ //#region ../core/dist/tool/index.js
3562
+ /** 核心工具集:文件操作 + 搜索 + 记忆(Chat / Gateway 使用,再拼接 SCHEDULING_TOOLS 即为全量) */
3563
+ var CORE_TOOLS = [
3564
+ readFileTool,
3565
+ writeFileTool,
3566
+ deleteFileTool,
3567
+ editTool,
3568
+ execTool,
3569
+ webSearchTool,
3570
+ readMemoryTool,
3571
+ writeMemoryTool
3572
+ ];
3573
+ /** 调度工具集 */
3574
+ var SCHEDULING_TOOLS = [scheduleTaskTool, readTasksTool];
3575
+ //#endregion
3576
+ //#region ../core/dist/agent/types.js
3577
+ /**
3578
+ * AgentLoop 状态机状态枚举
3579
+ *
3580
+ * 每个状态对应循环中的一个确定阶段,状态转换时触发对应的 LoopHooks 回调。
3581
+ */
3582
+ var AgentState;
3583
+ (function(AgentState) {
3584
+ AgentState["INIT"] = "INIT";
3585
+ AgentState["PRE_LLM"] = "PRE_LLM";
3586
+ AgentState["LLM_STREAMING"] = "LLM_STREAMING";
3587
+ AgentState["POST_LLM"] = "POST_LLM";
3588
+ AgentState["LLM_RETRY_WAIT"] = "LLM_RETRY_WAIT";
3589
+ AgentState["PRE_TOOL"] = "PRE_TOOL";
3590
+ AgentState["TOOL_EXECUTING"] = "TOOL_EXECUTING";
3591
+ AgentState["AWAIT_CONFIRM"] = "AWAIT_CONFIRM";
3592
+ AgentState["POST_TOOL"] = "POST_TOOL";
3593
+ AgentState["PERSIST_TURN"] = "PERSIST_TURN";
3594
+ AgentState["DONE"] = "DONE";
3595
+ AgentState["ERROR"] = "ERROR";
3596
+ })(AgentState || (AgentState = {}));
3597
+ //#endregion
3598
+ //#region ../core/dist/agent/message-sanitizer.js
3599
+ function extractTextContent$1(content) {
3600
+ if (typeof content === "string") return content;
3601
+ return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
3602
+ }
3603
+ function mergeContent(a, b) {
3604
+ return extractTextContent$1(a) + "\n\n" + extractTextContent$1(b);
3605
+ }
3606
+ var SURROGATE_RE = /[\uD800-\uDFFF]/g;
3607
+ function stripSurrogates(text) {
3608
+ return text.replace(SURROGATE_RE, "�");
3609
+ }
3610
+ function cleanContent(content) {
3611
+ if (typeof content === "string") return stripSurrogates(content);
3612
+ return content.map((part) => {
3613
+ if (part.type === "text") return {
3614
+ ...part,
3615
+ text: stripSurrogates(part.text)
3616
+ };
3617
+ return part;
3618
+ });
3619
+ }
3620
+ /**
3621
+ * 修复相邻相同角色消息:
3622
+ * - 连续 user → 合并为一条(内容拼接)
3623
+ * - 连续 assistant(不含 tool_calls)→ 合并
3624
+ * - 连续 assistant 其中之一有 tool_calls → 保留两者(tool_calls 不能合并)
3625
+ */
3626
+ function repairRoleAlternation(messages) {
3627
+ if (messages.length <= 1) return messages;
3628
+ const result = [messages[0]];
3629
+ for (let i = 1; i < messages.length; i++) {
3630
+ const prev = result[result.length - 1];
3631
+ const curr = messages[i];
3632
+ if (prev.role === curr.role && curr.role === "user") result[result.length - 1] = {
3633
+ role: "user",
3634
+ content: mergeContent(prev.content, curr.content)
3635
+ };
3636
+ else if (prev.role === curr.role && curr.role === "assistant") if (prev.tool_calls || curr.tool_calls) result.push(curr);
3637
+ else {
3638
+ const merged = {
3639
+ role: "assistant",
3640
+ content: mergeContent(prev.content, curr.content)
3641
+ };
3642
+ if (prev.reasoning_content || curr.reasoning_content) merged.reasoning_content = [prev.reasoning_content, curr.reasoning_content].filter(Boolean).join("\n\n");
3643
+ if (prev.name) merged.name = prev.name;
3644
+ result[result.length - 1] = merged;
3645
+ }
3646
+ else result.push(curr);
3647
+ }
3648
+ return result;
3649
+ }
3650
+ /**
3651
+ * 移除孤儿 tool 结果:
3652
+ * tool role 消息的 tool_call_id 必须在前面的 assistant.tool_calls 中存在。
3653
+ */
3654
+ function stripOrphanToolResults(messages) {
3655
+ const activeToolIds = /* @__PURE__ */ new Set();
3656
+ for (const msg of messages) if (msg.role === "assistant" && msg.tool_calls) for (const tc of msg.tool_calls) activeToolIds.add(tc.id);
3657
+ return messages.filter((msg) => {
3658
+ if (msg.role !== "tool") return true;
3659
+ if (!msg.tool_call_id) return false;
3660
+ return activeToolIds.has(msg.tool_call_id);
3661
+ });
3662
+ }
3663
+ function stripEmptyMessages(messages) {
3664
+ return messages.filter((msg) => {
3665
+ if (extractTextContent$1(msg.content).trim() === "" && !msg.tool_calls && msg.role !== "tool") return false;
3666
+ return true;
3667
+ });
3668
+ }
3669
+ /**
3670
+ * 消息清洗管道
3671
+ *
3672
+ * 1. 移除空消息(无内容且无 tool_calls)
3673
+ * 2. 清除 Unicode surrogate(\uD800-\uDFFF)
3674
+ * 3. 修复角色交替(合并连续 user/assistant)
3675
+ * 4. 移除孤儿 tool 结果(无匹配 tool_call_id)
3676
+ *
3677
+ * 返回新的 Message 数组,不修改原数组。
3678
+ */
3679
+ function sanitizeMessages(messages) {
3680
+ let result = stripEmptyMessages(messages);
3681
+ result = result.map((msg) => {
3682
+ const cleaned = {
3683
+ role: msg.role,
3684
+ content: cleanContent(msg.content)
3685
+ };
3686
+ if (msg.name) cleaned.name = stripSurrogates(msg.name);
3687
+ if (msg.tool_call_id) cleaned.tool_call_id = stripSurrogates(msg.tool_call_id);
3688
+ if (msg.reasoning_content) cleaned.reasoning_content = stripSurrogates(msg.reasoning_content);
3689
+ if (msg.tool_calls) cleaned.tool_calls = msg.tool_calls.map((tc) => ({
3690
+ ...tc,
3691
+ function: {
3692
+ name: stripSurrogates(tc.function.name),
3693
+ arguments: stripSurrogates(tc.function.arguments)
3694
+ }
3695
+ }));
3696
+ return cleaned;
3697
+ });
3698
+ result = repairRoleAlternation(result);
3699
+ result = stripOrphanToolResults(result);
3700
+ return result;
3701
+ }
3702
+ //#endregion
3703
+ //#region ../core/dist/agent/loop.js
3704
+ function extractTextContent(content) {
3705
+ if (typeof content === "string") return content;
3706
+ return content.filter((p) => p.type === "text" && "text" in p).map((p) => p.text).join("\n");
3707
+ }
3708
+ var MAX_LLM_RETRIES = 5;
3709
+ var RETRY_BASE_DELAY = 1e3;
3710
+ var CONTEXT_WINDOW_DEFAULT = 1048576;
3711
+ var CONTINUE_THRESHOLD = 2e4;
3712
+ var MAX_TOOL_ITERATIONS$1 = 50;
3713
+ var COMPRESSION_THRESHOLD_DEFAULT = 256e3;
3714
+ function buildSummaryContent(messages, initialSystem) {
3715
+ const relevant = messages.filter((m) => m.role !== "system").filter((m) => m.role !== "tool");
3716
+ let header = "";
3717
+ if (initialSystem) header = `原始系统提示词摘要: ${initialSystem.slice(0, 200)}\n\n`;
3718
+ const lines = [];
3719
+ for (const m of relevant) {
3720
+ const role = m.role === "user" ? "用户" : "AI";
3721
+ const text = extractTextContent(m.content);
3722
+ lines.push(`[${role}] ${text.slice(0, 2e3)}`);
3723
+ }
3724
+ return header + lines.join("\n");
3725
+ }
3726
+ var AgentLoop = class {
3727
+ provider;
3728
+ storage;
3729
+ registry;
3730
+ onConfirm;
3731
+ signal;
3732
+ hooks;
3733
+ state = AgentState.INIT;
3734
+ effectiveSessionId = "";
3735
+ contextWindow = CONTEXT_WINDOW_DEFAULT;
3736
+ buildResult;
3737
+ userMsg;
3738
+ messages = [];
3739
+ tools = [];
3740
+ totalUsage;
3741
+ iteration = 0;
3742
+ fullContent = "";
3743
+ fullReasoning = "";
3744
+ collectedToolCalls = /* @__PURE__ */ new Map();
3745
+ chunkUsage;
3746
+ attempt = 0;
3747
+ resolvedToolCalls = [];
3748
+ toolIndex = 0;
3749
+ toolResultMsgs = [];
3750
+ currentToolCall;
3751
+ currentArgs = {};
3752
+ pendingConfirmation;
3753
+ toolContext;
3754
+ compressionMode;
3755
+ compressionThreshold;
3756
+ constructor(provider, storage, registry, onConfirm, signal, hooks = {}, compressionMode = "auto", compressionThreshold = COMPRESSION_THRESHOLD_DEFAULT) {
3757
+ this.provider = provider;
3758
+ this.storage = storage;
3759
+ this.registry = registry;
3760
+ this.onConfirm = onConfirm;
3761
+ this.signal = signal;
3762
+ this.hooks = hooks;
3763
+ this.toolContext = new ToolContext(process.cwd());
3764
+ this.compressionMode = compressionMode;
3765
+ this.compressionThreshold = compressionThreshold;
3766
+ }
3767
+ async *run(sessionId, userMessage, buildResult, userMessageId) {
3768
+ this.effectiveSessionId = sessionId;
3769
+ this.contextWindow = buildResult.contextWindow || CONTEXT_WINDOW_DEFAULT;
3770
+ this.buildResult = buildResult;
3771
+ this.messages = [...buildResult.messages];
3772
+ this.tools = this.registry.getDefinitions();
3773
+ this.totalUsage = void 0;
3774
+ this.iteration = 0;
3775
+ this.state = AgentState.INIT;
3776
+ const session = await this.storage.getSession(sessionId);
3777
+ if (session?.workspace) this.toolContext = new ToolContext(session.workspace);
3778
+ pendingSteering.delete(sessionId);
3779
+ try {
3780
+ while (true) {
3781
+ if (this.state === AgentState.DONE || this.state === AgentState.ERROR) break;
3782
+ switch (this.state) {
3783
+ case AgentState.INIT:
3784
+ yield* this.doInit(userMessage, userMessageId);
3785
+ break;
3786
+ case AgentState.PRE_LLM:
3787
+ yield* this.doPreLlm();
3788
+ break;
3789
+ case AgentState.LLM_STREAMING:
3790
+ yield* this.doLlmStreaming();
3791
+ break;
3792
+ case AgentState.POST_LLM:
3793
+ yield* this.doPostLlm();
3794
+ break;
3795
+ case AgentState.LLM_RETRY_WAIT:
3796
+ yield* this.doLlmRetryWait();
3797
+ break;
3798
+ case AgentState.PRE_TOOL:
3799
+ yield* this.doPreTool();
3800
+ break;
3801
+ case AgentState.TOOL_EXECUTING:
3802
+ yield* this.doToolExecuting();
3803
+ break;
3804
+ case AgentState.AWAIT_CONFIRM:
3805
+ yield* this.doAwaitConfirm();
3806
+ break;
3807
+ case AgentState.POST_TOOL:
3808
+ yield* this.doPostTool();
3809
+ break;
3810
+ case AgentState.PERSIST_TURN:
3811
+ yield* this.doPersistTurn();
3812
+ break;
3813
+ case AgentState.DONE:
3814
+ case AgentState.ERROR: break;
3815
+ }
3816
+ }
3817
+ } catch (error) {
3818
+ yield {
3819
+ type: "error",
3820
+ message: error.message || "未知错误"
3821
+ };
3822
+ }
3823
+ }
3824
+ async *doInit(userMessage, userMessageId) {
3825
+ this.userMsg = await this.storage.addMessage(this.effectiveSessionId, {
3826
+ id: userMessageId,
3827
+ session_id: this.effectiveSessionId,
3828
+ role: "user",
3829
+ content: userMessage
3830
+ });
3831
+ this.state = AgentState.PRE_LLM;
3832
+ }
3833
+ async *doPreLlm() {
3834
+ if (this.signal?.aborted) {
3835
+ this.state = AgentState.DONE;
3836
+ return;
3837
+ }
3838
+ if (this.iteration >= MAX_TOOL_ITERATIONS$1) {
3839
+ yield {
3840
+ type: "error",
3841
+ message: `达到最大工具调用次数限制(${MAX_TOOL_ITERATIONS$1}次),请简化任务后重试`
3842
+ };
3843
+ this.state = AgentState.ERROR;
3844
+ return;
3845
+ }
3846
+ this.fullContent = "";
3847
+ this.fullReasoning = "";
3848
+ this.collectedToolCalls.clear();
3849
+ this.chunkUsage = void 0;
3850
+ this.attempt = 0;
3851
+ yield* this.consumeSteering();
3852
+ const modified = await this.hooks.beforeLlmCall?.(this.messages);
3853
+ if (modified) this.messages = modified;
3854
+ this.state = AgentState.LLM_STREAMING;
3855
+ }
3856
+ async *consumeSteering() {
3857
+ const steering = pendingSteering.get(this.effectiveSessionId);
3858
+ if (!steering || steering.length === 0) return;
3859
+ const drained = steering.splice(0);
3860
+ for (const s of drained) {
3861
+ await this.storage.addMessage(this.effectiveSessionId, {
3862
+ session_id: this.effectiveSessionId,
3863
+ role: "user",
3864
+ content: s.text
3865
+ });
3866
+ this.messages.push({
3867
+ role: "user",
3868
+ content: s.text
3869
+ });
3870
+ yield {
3871
+ type: "steering_consumed",
3872
+ messageId: s.messageId
3873
+ };
3874
+ }
3875
+ }
3876
+ async *doLlmStreaming() {
3877
+ try {
3878
+ const apiMessages = sanitizeMessages(this.messages);
3879
+ const stream = this.provider.chatStream({
3880
+ messages: apiMessages,
3881
+ tools: this.tools.length > 0 ? this.tools : void 0
3882
+ });
3883
+ for await (const chunk of stream) {
3884
+ if (chunk.reasoning_content) {
3885
+ this.fullReasoning += chunk.reasoning_content;
3886
+ yield {
3887
+ type: "reasoning",
3888
+ text: chunk.reasoning_content
3889
+ };
3890
+ }
3891
+ if (chunk.content) {
3892
+ this.fullContent += chunk.content;
3893
+ yield {
3894
+ type: "content",
3895
+ text: chunk.content
3896
+ };
3897
+ }
3898
+ if (chunk.tool_calls) for (const tc of chunk.tool_calls) {
3899
+ const existing = this.collectedToolCalls.get(tc.index);
3900
+ if (existing) {
3901
+ if (tc.function?.arguments) existing.function.arguments += tc.function.arguments;
3902
+ } else if (tc.id) {
3903
+ const newTc = {
3904
+ id: tc.id,
3905
+ type: "function",
3906
+ function: {
3907
+ name: tc.function?.name || "",
3908
+ arguments: tc.function?.arguments || ""
3909
+ }
3910
+ };
3911
+ this.collectedToolCalls.set(tc.index, newTc);
3912
+ }
3913
+ }
3914
+ if (chunk.usage) this.chunkUsage = chunk.usage;
3915
+ }
3916
+ this.state = AgentState.POST_LLM;
3917
+ } catch (llmError) {
3918
+ this.fullContent = "";
3919
+ this.collectedToolCalls.clear();
3920
+ this.chunkUsage = void 0;
3921
+ if (this.attempt >= MAX_LLM_RETRIES) {
3922
+ const errorMessage = `[连接失败] ${llmError.message || "多次重试后仍无法连接"}`;
3923
+ await this.storage.addMessage(this.effectiveSessionId, {
3924
+ session_id: this.effectiveSessionId,
3925
+ role: "assistant",
3926
+ content: errorMessage
3927
+ });
3928
+ yield {
3929
+ type: "retry_exhausted",
3930
+ message: llmError.message || "连接失败",
3931
+ partialContent: true
3932
+ };
3933
+ this.state = AgentState.ERROR;
3934
+ return;
3935
+ }
3936
+ this.state = AgentState.LLM_RETRY_WAIT;
3937
+ }
3938
+ }
3939
+ async *doLlmRetryWait() {
3940
+ await this.hooks.onLlmRetry?.(this.attempt + 1, MAX_LLM_RETRIES, /* @__PURE__ */ new Error("LLM call failed"));
3941
+ yield {
3942
+ type: "retrying",
3943
+ attempt: this.attempt + 1,
3944
+ maxRetries: MAX_LLM_RETRIES
3945
+ };
3946
+ await sleep(RETRY_BASE_DELAY * Math.pow(2, this.attempt));
3947
+ this.attempt++;
3948
+ this.state = AgentState.LLM_STREAMING;
3949
+ }
3950
+ async *doPostLlm() {
3951
+ if (this.chunkUsage) {
3952
+ const cu = this.chunkUsage;
3953
+ this.totalUsage = this.totalUsage ? {
3954
+ prompt_tokens: (this.totalUsage.prompt_tokens || 0) + (cu.prompt_tokens || 0),
3955
+ completion_tokens: (this.totalUsage.completion_tokens || 0) + (cu.completion_tokens || 0),
3956
+ total_tokens: (this.totalUsage.total_tokens || 0) + (cu.total_tokens || 0)
3957
+ } : { ...cu };
3958
+ }
3959
+ await this.hooks.afterLlmCall?.(this.totalUsage);
3960
+ this.resolvedToolCalls = Array.from(this.collectedToolCalls.values());
3961
+ if (this.resolvedToolCalls.length === 0) {
3962
+ await this.storage.addMessage(this.effectiveSessionId, {
3963
+ session_id: this.effectiveSessionId,
3964
+ role: "assistant",
3965
+ content: this.fullContent,
3966
+ reasoning_content: this.fullReasoning || void 0,
3967
+ usage: this.totalUsage
3968
+ });
3969
+ if (this.totalUsage) await this.storage.updateTokenCount(this.effectiveSessionId, this.totalUsage.total_tokens);
3970
+ yield* this.tryForkIfWindowLow();
3971
+ yield {
3972
+ type: "done",
3973
+ messageId: crypto.randomUUID(),
3974
+ usage: this.totalUsage,
3975
+ contextWindow: this.contextWindow
3976
+ };
3977
+ this.state = AgentState.DONE;
3978
+ return;
3979
+ }
3980
+ this.messages.push({
3981
+ role: "assistant",
3982
+ content: this.fullContent || "",
3983
+ tool_calls: this.resolvedToolCalls,
3984
+ reasoning_content: this.fullReasoning || void 0
3985
+ });
3986
+ yield* this.tryForkIfWindowLow();
3987
+ this.toolResultMsgs = [];
3988
+ this.toolIndex = 0;
3989
+ this.state = AgentState.PRE_TOOL;
3990
+ }
3991
+ async *doPreTool() {
3992
+ if (this.signal?.aborted) {
3993
+ this.state = AgentState.DONE;
3994
+ return;
3995
+ }
3996
+ if (this.toolIndex >= this.resolvedToolCalls.length) {
3997
+ this.state = AgentState.PERSIST_TURN;
3998
+ return;
3999
+ }
4000
+ this.currentToolCall = this.resolvedToolCalls[this.toolIndex];
4001
+ this.currentArgs = {};
4002
+ try {
4003
+ this.currentArgs = JSON.parse(this.currentToolCall.function.arguments);
4004
+ } catch {}
4005
+ const modifiedArgs = await this.hooks.beforeToolExecution?.(this.currentToolCall.function.name, this.currentArgs);
4006
+ if (modifiedArgs) this.currentArgs = modifiedArgs;
4007
+ yield {
4008
+ type: "tool_call",
4009
+ name: this.currentToolCall.function.name,
4010
+ args: this.currentArgs
4011
+ };
4012
+ this.state = AgentState.TOOL_EXECUTING;
4013
+ }
4014
+ async *doToolExecuting() {
4015
+ const tc = this.currentToolCall;
4016
+ const name = tc.function.name;
4017
+ const updateQueue = [];
4018
+ let toolDone = false;
4019
+ let toolResult;
4020
+ let toolError;
4021
+ let wakeUp = null;
4022
+ this.toolContext.onUpdate = (chunk) => {
4023
+ if (!toolDone) {
4024
+ updateQueue.push(chunk);
4025
+ wakeUp?.();
4026
+ }
4027
+ };
4028
+ this.registry.execute(name, this.currentArgs, this.toolContext).then((r) => {
4029
+ toolResult = r;
4030
+ }).catch((e) => {
4031
+ toolError = e;
4032
+ }).finally(() => {
4033
+ this.toolContext.onUpdate = void 0;
4034
+ toolDone = true;
4035
+ wakeUp?.();
4036
+ });
4037
+ while (!toolDone) if (updateQueue.length > 0) while (updateQueue.length > 0) yield {
4038
+ type: "tool_execution_update",
4039
+ name,
4040
+ text: updateQueue.shift()
4041
+ };
4042
+ else await new Promise((resolve) => {
4043
+ wakeUp = resolve;
4044
+ });
4045
+ if (toolError) {
4046
+ if (toolError instanceof PendingConfirmation) {
4047
+ this.pendingConfirmation = toolError;
4048
+ this.state = AgentState.AWAIT_CONFIRM;
4049
+ return;
4050
+ }
4051
+ const errMsg = toolError.message;
4052
+ yield {
4053
+ type: "tool_result",
4054
+ name,
4055
+ success: false,
4056
+ output: errMsg
4057
+ };
4058
+ this.toolResultMsgs.push({
4059
+ role: "tool",
4060
+ content: `工具执行异常: ${errMsg}`,
4061
+ tool_call_id: tc.id,
4062
+ name
4063
+ });
4064
+ this.messages.push({
4065
+ role: "tool",
4066
+ content: `工具执行异常: ${errMsg}`,
4067
+ tool_call_id: tc.id,
4068
+ name
4069
+ });
4070
+ this.state = AgentState.POST_TOOL;
4071
+ return;
4072
+ }
4073
+ const result = toolResult;
4074
+ yield {
4075
+ type: "tool_result",
4076
+ name,
4077
+ success: result.success,
4078
+ output: result.output
4079
+ };
4080
+ const content = result.output || result.error || "";
4081
+ this.toolResultMsgs.push({
4082
+ role: "tool",
4083
+ content,
4084
+ tool_call_id: tc.id,
4085
+ name
4086
+ });
4087
+ this.messages.push({
4088
+ role: "tool",
4089
+ content,
4090
+ tool_call_id: tc.id,
4091
+ name
4092
+ });
4093
+ await this.hooks.afterToolExecution?.(name, {
4094
+ success: result.success,
4095
+ output: result.output
4096
+ });
4097
+ this.state = AgentState.POST_TOOL;
4098
+ }
4099
+ async *doAwaitConfirm() {
4100
+ const error = this.pendingConfirmation;
4101
+ const tc = this.currentToolCall;
4102
+ const confirmId = crypto.randomUUID();
4103
+ await this.hooks.onConfirmRequired?.(error, confirmId);
4104
+ yield {
4105
+ type: "confirm_required",
4106
+ confirmId,
4107
+ confirmation: error
4108
+ };
4109
+ let abortCleanup;
4110
+ const approved = await Promise.race([this.onConfirm(error, confirmId), new Promise((resolve) => {
4111
+ if (this.signal) {
4112
+ const onAbort = () => resolve(false);
4113
+ this.signal.addEventListener("abort", onAbort, { once: true });
4114
+ abortCleanup = () => this.signal?.removeEventListener("abort", onAbort);
4115
+ }
4116
+ })]);
4117
+ abortCleanup?.();
4118
+ if (approved) try {
4119
+ const retryResult = await this.registry.execute(error.toolName, {
4120
+ ...error.args,
4121
+ __confirmed: true
4122
+ }, this.toolContext);
4123
+ yield {
4124
+ type: "tool_result",
4125
+ name: error.toolName,
4126
+ success: retryResult.success,
4127
+ output: retryResult.output
4128
+ };
4129
+ const content = retryResult.output || retryResult.error || "";
4130
+ this.toolResultMsgs.push({
4131
+ role: "tool",
4132
+ content,
4133
+ tool_call_id: tc.id,
4134
+ name: error.toolName
4135
+ });
4136
+ this.messages.push({
4137
+ role: "tool",
4138
+ content,
4139
+ tool_call_id: tc.id,
4140
+ name: error.toolName
4141
+ });
4142
+ } catch (retryError) {
4143
+ const errMsg = retryError.message;
4144
+ yield {
4145
+ type: "tool_result",
4146
+ name: error.toolName,
4147
+ success: false,
4148
+ output: errMsg
4149
+ };
4150
+ this.toolResultMsgs.push({
4151
+ role: "tool",
4152
+ content: `执行失败: ${errMsg}`,
4153
+ tool_call_id: tc.id,
4154
+ name: error.toolName
4155
+ });
4156
+ this.messages.push({
4157
+ role: "tool",
4158
+ content: `执行失败: ${errMsg}`,
4159
+ tool_call_id: tc.id,
4160
+ name: error.toolName
4161
+ });
4162
+ }
4163
+ else {
4164
+ const cancelMsg = "用户取消了此操作";
4165
+ yield {
4166
+ type: "tool_result",
4167
+ name: error.toolName,
4168
+ success: false,
4169
+ output: cancelMsg
4170
+ };
4171
+ this.toolResultMsgs.push({
4172
+ role: "tool",
4173
+ content: cancelMsg,
4174
+ tool_call_id: tc.id,
4175
+ name: error.toolName
4176
+ });
4177
+ this.messages.push({
4178
+ role: "tool",
4179
+ content: cancelMsg,
4180
+ tool_call_id: tc.id,
4181
+ name: error.toolName
4182
+ });
4183
+ }
4184
+ this.pendingConfirmation = void 0;
4185
+ this.state = AgentState.POST_TOOL;
4186
+ }
4187
+ async *doPostTool() {
4188
+ this.toolIndex++;
4189
+ this.state = AgentState.PRE_TOOL;
4190
+ }
4191
+ async *doPersistTurn() {
4192
+ await this.hooks.afterTurn?.(this.iteration);
4193
+ await this.storage.addMessage(this.effectiveSessionId, {
4194
+ session_id: this.effectiveSessionId,
4195
+ role: "assistant",
4196
+ content: this.fullContent || "",
4197
+ reasoning_content: this.fullReasoning || void 0,
4198
+ tool_calls: this.resolvedToolCalls,
4199
+ usage: this.totalUsage
4200
+ });
4201
+ if (this.totalUsage) await this.storage.updateTokenCount(this.effectiveSessionId, this.totalUsage.total_tokens);
4202
+ for (const t of this.toolResultMsgs) await this.storage.addMessage(this.effectiveSessionId, {
4203
+ session_id: this.effectiveSessionId,
4204
+ role: "tool",
4205
+ content: t.content,
4206
+ tool_call_id: t.tool_call_id,
4207
+ name: t.name
4208
+ });
4209
+ if (this.signal?.aborted) {
4210
+ this.state = AgentState.DONE;
4211
+ return;
4212
+ }
4213
+ this.iteration++;
4214
+ this.state = AgentState.PRE_LLM;
4215
+ }
4216
+ async *tryForkIfWindowLow() {
4217
+ const tokensUsed = this.totalUsage?.total_tokens || 0;
4218
+ if (tokensUsed <= 0) return;
4219
+ if (this.compressionMode === "custom" ? tokensUsed > this.compressionThreshold : this.contextWindow - tokensUsed < CONTINUE_THRESHOLD) {
4220
+ const newId = await this.createContinuation(this.effectiveSessionId, this.userMsg, this.messages, typeof this.buildResult.messages[0]?.content === "string" ? this.buildResult.messages[0]?.content : void 0);
4221
+ if (newId) yield {
4222
+ type: "forked",
4223
+ newSessionId: newId
4224
+ };
4225
+ }
4226
+ }
4227
+ extractPriorCompression(messages) {
4228
+ const systemMsg = messages.find((m) => m.role === "system");
4229
+ if (!systemMsg) return void 0;
4230
+ const content = extractTextContent(systemMsg.content);
4231
+ const idx = content.indexOf("[此对话延续自");
4232
+ if (idx === -1) return void 0;
4233
+ return content.slice(idx);
4234
+ }
4235
+ async createContinuation(sessionId, userMsg, allMessages, systemPrompt) {
4236
+ try {
4237
+ const parentSession = await this.storage.getSession(sessionId);
4238
+ if (!parentSession) return null;
4239
+ const rawContent = buildSummaryContent(allMessages, systemPrompt);
4240
+ let compression = "";
4241
+ const priorCompression = this.extractPriorCompression(allMessages);
4242
+ try {
4243
+ let prompt = `The following is a conversation history that needs compression due to context length. Extract the **key information needed to continue the current task**, output in Chinese using the format below:
4244
+
4245
+ ## 目标
4246
+ - Core task the user wants to accomplish (1 sentence)
4247
+
4248
+ ## 进度
4249
+ - 已完成: <completed items>
4250
+ - 进行中: <in progress>
4251
+ - 阻塞: <blocked items, omit if none>
4252
+
4253
+ ## 关键决策
4254
+ - <key technical decisions, tool choices, approaches taken>
4255
+
4256
+ ## 用户偏好与约束
4257
+ - <user habits, preferences, explicit constraints>
4258
+
4259
+ ## 关键上下文
4260
+ - <file paths, key parameters, environment info>
4261
+
4262
+ ## 下一步
4263
+ - <next steps, ordered by priority>
4264
+
4265
+ Conversation:
4266
+ ${rawContent}`;
4267
+ if (priorCompression) prompt += `\n\nBelow is an existing compression summary. Update it by preserving ALL existing information and adding new developments:\n${priorCompression}`;
4268
+ compression = (await this.provider.chat({
4269
+ messages: [{
4270
+ role: "user",
4271
+ content: prompt
4272
+ }],
4273
+ max_tokens: 2e3,
4274
+ temperature: .3
4275
+ })).content || "";
4276
+ } catch {
4277
+ compression = rawContent.slice(0, 2e3);
4278
+ }
4279
+ if (!compression) return null;
4280
+ const newTitle = `[延续] ${parentSession.title}`;
4281
+ const newSession = await this.storage.createSession(newTitle, parentSession.memory_snapshot, parentSession.workspace);
4282
+ await this.storage.addMessage(newSession.id, {
4283
+ session_id: newSession.id,
4284
+ role: "system",
4285
+ content: `[此对话延续自会话「${parentSession.title || sessionId}」,以下为上下文压缩]\n\n${compression}`
4286
+ });
4287
+ await this.storage.addMessage(newSession.id, {
4288
+ session_id: newSession.id,
4289
+ role: "user",
4290
+ content: userMsg.content
4291
+ });
4292
+ const recentMessages = await this.storage.getMessagesSinceSeq(sessionId, userMsg.seq);
4293
+ for (const msg of recentMessages) await this.storage.addMessage(newSession.id, {
4294
+ session_id: newSession.id,
4295
+ role: msg.role,
4296
+ content: msg.content,
4297
+ reasoning_content: msg.reasoning_content,
4298
+ tool_calls: msg.tool_calls,
4299
+ tool_call_id: msg.tool_call_id,
4300
+ name: msg.name,
4301
+ usage: msg.usage
4302
+ });
4303
+ return newSession.id;
4304
+ } catch {
4305
+ return null;
4306
+ }
4307
+ }
4308
+ };
4309
+ //#endregion
4310
+ //#region ../core/dist/agent/context-builder.js
4311
+ var DEFAULT_CONTEXT_WINDOW$1 = 1048576;
4312
+ var MEMORY_PATH = getDataPath("memory.md");
4313
+ function readMemoryFile() {
4314
+ try {
4315
+ if (existsSync(MEMORY_PATH)) return readFileSync(MEMORY_PATH, "utf-8").replace(/\r/g, "").trim();
4316
+ } catch {}
4317
+ return "";
4318
+ }
4319
+ function formatMemorySection(content) {
4320
+ if (!content) return "";
4321
+ return `\n\n## 用户信息\n\n以下是关于你和用户的已知信息,请据此调整你的行为:\n\n${content}`;
4322
+ }
4323
+ /**
4324
+ * ContextBuilder — 上下文构建器
4325
+ *
4326
+ * 负责拼装发给 LLM 的 messages 数组:
4327
+ * 1. 系统提示词(用户自定义 + 环境信息 + memory 快照)
4328
+ * 2. 会话历史消息
4329
+ * 3. 当前用户输入
4330
+ *
4331
+ * 工具描述通过 API 的 tools 参数传递,不写入 system prompt 文本。
4332
+ * memory 在会话首次构建时从 memory.md 读取并存入 session.memory_snapshot,
4333
+ * 后续构建直接使用快照,保证 system 消息稳定。
4334
+ */
4335
+ var ContextBuilder = class {
4336
+ async build(sessionId, userMessage, images, storage, contextWindow, systemPrompt) {
4337
+ return {
4338
+ messages: await this.buildMessages(sessionId, userMessage, images, storage, systemPrompt),
4339
+ contextWindow: contextWindow || DEFAULT_CONTEXT_WINDOW$1
4340
+ };
4341
+ }
4342
+ async resolveMemory(sessionId, storage) {
4343
+ const session = await storage.getSession(sessionId);
4344
+ if (session?.memory_snapshot) return session.memory_snapshot;
4345
+ const content = readMemoryFile();
4346
+ if (session) await storage.setMemorySnapshot(sessionId, content);
4347
+ return content;
4348
+ }
4349
+ parseStoredContent(content) {
4350
+ if (content.startsWith("[")) try {
4351
+ return JSON.parse(content);
4352
+ } catch {}
4353
+ return content;
4354
+ }
4355
+ buildUserContent(text, images) {
4356
+ if (images.length === 0) return text;
4357
+ return [{
4358
+ type: "text",
4359
+ text
4360
+ }, ...images];
4361
+ }
4362
+ async buildMessages(sessionId, userMessage, images, storage, systemPrompt) {
4363
+ const messages = [];
4364
+ let systemContent = systemPrompt || DEFAULT_SYSTEM_PROMPT;
4365
+ systemContent += SYSTEM_CONTEXT;
4366
+ const memoryContent = await this.resolveMemory(sessionId, storage);
4367
+ systemContent += formatMemorySection(memoryContent);
4368
+ const history = await storage.getMessages(sessionId);
4369
+ for (const msg of history) if (msg.role === "system") systemContent += "\n\n" + (typeof msg.content === "string" ? msg.content : "");
4370
+ messages.push({
4371
+ role: "system",
4372
+ content: systemContent
4373
+ });
4374
+ for (const msg of history) {
4375
+ if (msg.role === "system") continue;
4376
+ const m = {
4377
+ role: msg.role,
4378
+ content: this.parseStoredContent(msg.content)
4379
+ };
4380
+ if (msg.tool_calls) m.tool_calls = msg.tool_calls;
4381
+ if (msg.tool_call_id) m.tool_call_id = msg.tool_call_id;
4382
+ if (msg.name) m.name = msg.name;
4383
+ messages.push(m);
4384
+ }
4385
+ messages.push({
4386
+ role: "user",
4387
+ content: this.buildUserContent(userMessage, images)
4388
+ });
4389
+ return messages;
4390
+ }
4391
+ };
4392
+ //#endregion
4393
+ //#region ../core/dist/agent/summarizer.js
4394
+ function parseStoredContent(content) {
4395
+ if (content.startsWith("[")) try {
4396
+ return JSON.parse(content);
4397
+ } catch {}
4398
+ return content;
4399
+ }
4400
+ var _registry = new ToolRegistry();
4401
+ for (const t of CORE_TOOLS) {
4402
+ if (t.name === "edit" || t.name === "read_memory") continue;
4403
+ _registry.register(t);
4404
+ }
4405
+ var _toolContext = new ToolContext(process.cwd());
4406
+ var _toolDefs = _registry.getDefinitions();
4407
+ function buildSystemMessage() {
4408
+ let content = readConfig().systemPrompt || DEFAULT_SYSTEM_PROMPT;
4409
+ content += SYSTEM_CONTEXT;
4410
+ return {
4411
+ role: "system",
4412
+ content
4413
+ };
4414
+ }
4415
+ var MAX_TOOL_ITERATIONS = 10;
4416
+ async function completeWithToolLoop(provider, messages, maxTokens, temperature) {
4417
+ const tools = _toolDefs;
4418
+ for (let i = 0; i < MAX_TOOL_ITERATIONS; i++) {
4419
+ const response = await provider.chat({
4420
+ messages,
4421
+ tools: tools.length > 0 ? tools : void 0,
4422
+ max_tokens: maxTokens,
4423
+ temperature
4424
+ });
4425
+ if (!response.tool_calls || response.tool_calls.length === 0) return {
4426
+ content: response.content || "",
4427
+ usage: response.usage
4428
+ };
4429
+ messages.push({
4430
+ role: "assistant",
4431
+ content: response.content || "",
4432
+ tool_calls: response.tool_calls
4433
+ });
4434
+ for (const tc of response.tool_calls) {
4435
+ let args = {};
4436
+ try {
4437
+ args = JSON.parse(tc.function.arguments);
4438
+ } catch {}
4439
+ try {
4440
+ const result = await _registry.execute(tc.function.name, args, _toolContext);
4441
+ messages.push({
4442
+ role: "tool",
4443
+ content: result.output || result.error || "",
4444
+ tool_call_id: tc.id,
4445
+ name: tc.function.name
4446
+ });
4447
+ } catch (error) {
4448
+ if (error instanceof PendingConfirmation) messages.push({
4449
+ role: "tool",
4450
+ content: `后台任务无法执行需确认的操作: ${error.reason}`,
4451
+ tool_call_id: tc.id,
4452
+ name: error.toolName
4453
+ });
4454
+ else {
4455
+ const errMsg = error.message;
4456
+ messages.push({
4457
+ role: "tool",
4458
+ content: `工具执行异常: ${errMsg}`,
4459
+ tool_call_id: tc.id,
4460
+ name: tc.function.name
4461
+ });
4462
+ }
4463
+ }
4464
+ }
4465
+ }
4466
+ return { content: "" };
4467
+ }
4468
+ async function generateSummary(provider, storage, sessionId, existingSummary) {
4469
+ const records = await storage.getMessages(sessionId);
4470
+ if (records.length === 0) return "";
4471
+ const messages = [buildSystemMessage()];
4472
+ for (const r of records) {
4473
+ if (r.role === "system") continue;
4474
+ const m = {
4475
+ role: r.role,
4476
+ content: parseStoredContent(r.content)
4477
+ };
4478
+ if (r.tool_calls) m.tool_calls = r.tool_calls;
4479
+ if (r.tool_call_id) m.tool_call_id = r.tool_call_id;
4480
+ if (r.name) m.name = r.name;
4481
+ messages.push(m);
4482
+ }
4483
+ let userInstruction = `Please summarize the conversation above. Output in Chinese using the structured format below:
4484
+
4485
+ ## 目标
4486
+ - The user's current main goal
4487
+
4488
+ ## 进度
4489
+ - 已完成: <completed items>
4490
+ - 进行中: <in progress>
4491
+ - 阻塞: <blocked items, omit if none>
4492
+
4493
+ ## 关键决策
4494
+ - <key decisions or choices made>
4495
+
4496
+ ## 用户偏好
4497
+ - <user habits, preferences, constraints>
4498
+
4499
+ ## 情感上下文
4500
+ - <user mood, attitude, and other context helpful for continuing the conversation>`;
4501
+ if (existingSummary) userInstruction += `\n\nBelow is the existing summary. Update it by preserving all existing information and appending new developments:\n${existingSummary}`;
4502
+ messages.push({
4503
+ role: "user",
4504
+ content: userInstruction
4505
+ });
4506
+ const { content, usage } = await completeWithToolLoop(provider, messages, 2e3, .3);
4507
+ if (usage) {
4508
+ const hit = usage.prompt_cache_hit_tokens ?? 0;
4509
+ const miss = usage.prompt_cache_miss_tokens ?? 0;
4510
+ console.log(`[summarize] session=${sessionId} messages=${records.length} hit=${hit} miss=${miss} total_tokens=${usage.total_tokens}`);
4511
+ }
4512
+ return content || "";
4513
+ }
4514
+ //#endregion
4515
+ //#region ../core/dist/agent/diary.js
4516
+ var DIARY_DIR = join(getDataPath("diary"));
4517
+ var MAX_RECENT_DAYS = 7;
4518
+ function getTodayDate() {
4519
+ const now = /* @__PURE__ */ new Date();
4520
+ let date = new Date(now.getFullYear(), now.getMonth(), now.getDate());
4521
+ if (now.getHours() < 8) date = /* @__PURE__ */ new Date(date.getTime() - 864e5);
4522
+ const y = date.getFullYear();
4523
+ const m = String(date.getMonth() + 1).padStart(2, "0");
4524
+ const d = String(date.getDate()).padStart(2, "0");
4525
+ return {
4526
+ date,
4527
+ y,
4528
+ m,
4529
+ d
4530
+ };
4531
+ }
4532
+ function formatDatePath(y, m, d) {
4533
+ return `data/diary/${y}-${m}-${d}.md`;
4534
+ }
4535
+ function getTodayFile() {
4536
+ const { y, m, d } = getTodayDate();
4537
+ return formatDatePath(y, m, d);
4538
+ }
4539
+ function readRecentDiaries(targetDate) {
4540
+ const parts = [];
4541
+ const cursor = new Date(targetDate);
4542
+ for (let i = 1; i <= MAX_RECENT_DAYS; i++) {
4543
+ cursor.setDate(cursor.getDate() - 1);
4544
+ const y = cursor.getFullYear();
4545
+ const m = String(cursor.getMonth() + 1).padStart(2, "0");
4546
+ const d = String(cursor.getDate()).padStart(2, "0");
4547
+ const filePath = join(DIARY_DIR, `${y}-${m}-${d}.md`);
4548
+ if (existsSync(filePath)) {
4549
+ const content = readFileSync(filePath, "utf-8").trim();
4550
+ parts.push(`### ${y}-${m}-${d}\n${content.slice(0, 2e3)}`);
4551
+ }
4552
+ }
4553
+ return parts.join("\n\n");
4554
+ }
4555
+ async function generateDiary(provider, storage) {
4556
+ const sessions = await storage.getTodayUpdatedSessions();
4557
+ if (sessions.length === 0) return;
4558
+ const summaries = [];
4559
+ for (const s of sessions) if (s.summary) summaries.push(`### ${s.title}\n${s.summary}`);
4560
+ if (summaries.length === 0) return;
4561
+ const { date } = getTodayDate();
4562
+ const filePath = getTodayFile();
4563
+ const recentDiaries = readRecentDiaries(date);
4564
+ let userContent = `以下是今天各会话的摘要,请据此撰写一篇日记,记录当天和我一起完成了什么、有哪些重要交流。\n\n${summaries.join("\n\n")}`;
4565
+ if (recentDiaries) userContent += `\n\n以下是前几天的日记内容,请参考以保持日记的连贯性和叙事感:\n\n${recentDiaries}`;
4566
+ userContent += `\n\n请使用 write_file 工具将日记写入以下文件:${filePath}`;
4567
+ await completeWithToolLoop(provider, [buildSystemMessage(), {
4568
+ role: "user",
4569
+ content: userContent
4570
+ }], 2e3, .5);
4571
+ }
4572
+ //#endregion
4573
+ //#region ../core/dist/agent/background.js
4574
+ async function runSummarizeJob(force, idleMs) {
4575
+ const config = readConfig();
4576
+ if (!config.storageEnabled) throw new Error("对话存储未开启");
4577
+ const providerConfig = getFirstProvider();
4578
+ if (!providerConfig?.apiKey) throw new Error("未配置 AI 供应商");
4579
+ const model = getActiveModel() || getDefaultModels(providerConfig.type)[0];
4580
+ if (!model) throw new Error("未选择模型");
4581
+ const provider = createProvider({
4582
+ ...providerConfig,
4583
+ activeModel: model.id,
4584
+ contextWindow: model.contextWindow
4585
+ });
4586
+ const storage = createStorage({ enabled: true });
4587
+ let effectiveIdleMs;
4588
+ if (force) effectiveIdleMs = -1;
4589
+ else if (idleMs !== void 0) effectiveIdleMs = idleMs;
4590
+ else effectiveIdleMs = (config.summaryIdleHours || 8) * 60 * 60 * 1e3;
4591
+ const staleSessions = await storage.getStaleSessions(effectiveIdleMs);
4592
+ let summarized = 0;
4593
+ for (const session of staleSessions) try {
4594
+ const summary = await generateSummary(provider, storage, session.id, session.summary || void 0);
4595
+ if (summary) {
4596
+ await storage.updateSummary(session.id, summary);
4597
+ summarized++;
4598
+ }
4599
+ } catch (e) {
4600
+ console.error(`[summarize] session=${session.id} failed:`, e.message);
4601
+ }
4602
+ let diary = false;
4603
+ if (summarized > 0) try {
4604
+ await generateDiary(provider, storage);
4605
+ diary = true;
4606
+ } catch (e) {
4607
+ console.error("[diary] failed:", e.message);
4608
+ }
4609
+ return {
4610
+ summarized,
4611
+ diary
4612
+ };
4613
+ }
4614
+ //#endregion
4615
+ //#region ../core/dist/agent/logger.js
4616
+ var AgentLogger = class {
4617
+ sessionId;
4618
+ turn = 0;
4619
+ llmStart = 0;
4620
+ turnLog = null;
4621
+ constructor(sessionId) {
4622
+ this.sessionId = sessionId;
4623
+ }
4624
+ async beforeLlmCall(messages) {
4625
+ this.llmStart = Date.now();
4626
+ this.turn++;
4627
+ this.turnLog = {
4628
+ turn: this.turn,
4629
+ toolCalls: 0,
4630
+ inputTokens: 0,
4631
+ outputTokens: 0,
4632
+ errors: 0
4633
+ };
4634
+ const msgCount = messages.length;
4635
+ const lastRole = messages.length > 0 ? messages[messages.length - 1].role : "none";
4636
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} LLM call (${msgCount} msgs, last=${lastRole})`);
4637
+ return messages;
4638
+ }
4639
+ async afterLlmCall(usage) {
4640
+ const latency = Date.now() - this.llmStart;
4641
+ if (this.turnLog) this.turnLog.llmLatencyMs = latency;
4642
+ if (usage) {
4643
+ if (this.turnLog) {
4644
+ this.turnLog.inputTokens = usage.prompt_tokens;
4645
+ this.turnLog.outputTokens = usage.completion_tokens;
4646
+ }
4647
+ const cache = usage.prompt_cache_hit_tokens != null ? ` cache=${usage.prompt_cache_hit_tokens}+${usage.prompt_cache_miss_tokens}` : "";
4648
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} done — latency=${latency}ms tokens=${usage.total_tokens} (${usage.prompt_tokens}+${usage.completion_tokens})${cache}`);
4649
+ } else console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} done — latency=${latency}ms`);
4650
+ }
4651
+ async onLlmRetry(attempt, maxRetries, error) {
4652
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} retry ${attempt}/${maxRetries}: ${error.message}`);
4653
+ if (this.turnLog) this.turnLog.errors++;
4654
+ }
4655
+ async beforeToolExecution(name, args) {
4656
+ const preview = JSON.stringify(args).slice(0, 120);
4657
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} tool: ${name}(${preview}${JSON.stringify(args).length > 120 ? "..." : ""})`);
4658
+ return args;
4659
+ }
4660
+ async afterToolExecution(name, result) {
4661
+ const outLen = result.output.length;
4662
+ if (this.turnLog) this.turnLog.toolCalls++;
4663
+ const status = result.success ? "OK" : "FAIL";
4664
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} tool ${name} → ${status} (${outLen} chars)`);
4665
+ }
4666
+ async onConfirmRequired(confirmation, confirmId) {
4667
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} confirm: ${confirmation.toolName} — ${confirmation.reason.slice(0, 80)}`);
4668
+ }
4669
+ async afterTurn(_iteration) {
4670
+ if (this.turnLog) {
4671
+ const t = this.turnLog;
4672
+ console.log(`[agent ${this.sessionId.slice(0, 8)}] turn ${this.turn} summary — tools=${t.toolCalls} tokens=${t.inputTokens}+${t.outputTokens} latency=${t.llmLatencyMs}ms errors=${t.errors}`);
4673
+ }
4674
+ }
4675
+ };
4676
+ //#endregion
4677
+ //#region ../core/dist/agent/summarize-worker.js
4678
+ function getToday() {
4679
+ const d = /* @__PURE__ */ new Date();
4680
+ return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
4681
+ }
4682
+ function createSummarizeWorker(notify) {
4683
+ let worker = null;
4684
+ let lastScheduledDate = "";
4685
+ async function tick() {
4686
+ const config = readConfig();
4687
+ if (!config.autoSummarize || !config.storageEnabled) return;
4688
+ let result;
4689
+ if (config.summaryMode === "scheduled") {
4690
+ const now = /* @__PURE__ */ new Date();
4691
+ const today = getToday();
4692
+ if (now.getHours() >= (config.summaryScheduleHour || 2) && today !== lastScheduledDate) {
4693
+ lastScheduledDate = today;
4694
+ result = await runSummarizeJob(false, null);
4695
+ }
4696
+ } else result = await runSummarizeJob();
4697
+ if (result) {
4698
+ const { summarized, diary } = result;
4699
+ if (summarized > 0 || diary) {
4700
+ const parts = [];
4701
+ if (summarized > 0) parts.push(`已为 ${summarized} 个对话生成摘要`);
4702
+ if (diary) parts.push("已生成日记条目");
4703
+ await notify({
4704
+ title: "Qualia 任务完成",
4705
+ body: parts.join("\n"),
4706
+ type: "task_complete"
4707
+ });
4708
+ }
4709
+ }
4710
+ }
4711
+ return {
4712
+ start() {
4713
+ const config = readConfig();
4714
+ if (!config.autoSummarize || !config.storageEnabled) return;
4715
+ const intervalMin = config.summaryIntervalMin || 30;
4716
+ worker = new BackgroundWorker();
4717
+ worker.schedule("summarize", intervalMin * 60 * 1e3, tick);
4718
+ worker.start();
4719
+ tick();
4720
+ },
4721
+ stop() {
4722
+ if (worker) {
4723
+ worker.stop();
4724
+ worker = null;
4725
+ }
4726
+ }
4727
+ };
4728
+ }
4729
+ //#endregion
4730
+ //#region ../core/dist/config/store.js
4731
+ var DEFAULT_CONTEXT_WINDOW = 1048576;
4732
+ function ensureDataDir() {
4733
+ const dir = getDataDir();
4734
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
4735
+ }
4736
+ var defaultConfig = {
4737
+ providers: [],
4738
+ activeModel: "",
4739
+ storageEnabled: false,
4740
+ systemPrompt: DEFAULT_SYSTEM_PROMPT,
4741
+ customBrandIcon: false,
4742
+ autoSummarize: true,
4743
+ summaryMode: "idle",
4744
+ summaryIdleHours: 8,
4745
+ summaryScheduleHour: 2,
4746
+ summaryIntervalMin: 30,
4747
+ compressionMode: "auto",
4748
+ compressionThreshold: 256e3,
4749
+ searchEnabled: false,
4750
+ searchProvider: "searxng",
4751
+ searxngURL: "http://localhost:8080",
4752
+ tavilyApiKey: "",
4753
+ emailNotifications: false,
4754
+ emailSmtpHost: "",
4755
+ emailSmtpPort: 465,
4756
+ emailSmtpSecure: true,
4757
+ emailSmtpUser: "",
4758
+ emailSmtpPass: "",
4759
+ emailFrom: "",
4760
+ emailTo: "",
4761
+ telegramEnabled: false,
4762
+ telegramBotToken: "",
4763
+ telegramAllowedUsers: ""
4764
+ };
4765
+ function normalizeProvider(p) {
4766
+ return {
4767
+ type: p.type || "openai",
4768
+ name: p.name || "",
4769
+ apiKey: p.apiKey || "",
4770
+ baseURL: p.baseURL || "",
4771
+ reasoningEffort: p.reasoningEffort,
4772
+ timeout: p.timeout,
4773
+ maxRetries: p.maxRetries,
4774
+ ollamaURL: p.ollamaURL || "http://localhost:11434"
4775
+ };
4776
+ }
4777
+ function readConfig() {
4778
+ const path = getConfigPath();
4779
+ if (!existsSync(path)) return structuredClone(defaultConfig);
4780
+ try {
4781
+ const raw = readFileSync(path, "utf-8");
4782
+ const parsed = JSON.parse(raw);
4783
+ return {
4784
+ providers: Array.isArray(parsed.providers) ? parsed.providers.map((p) => normalizeProvider(p)) : [],
4785
+ activeModel: parsed.activeModel || "",
4786
+ storageEnabled: parsed.storageEnabled === true,
4787
+ systemPrompt: parsed.systemPrompt || DEFAULT_SYSTEM_PROMPT,
4788
+ customBrandIcon: parsed.customBrandIcon === true,
4789
+ autoSummarize: parsed.autoSummarize !== false,
4790
+ summaryMode: parsed.summaryMode === "scheduled" ? "scheduled" : "idle",
4791
+ summaryIdleHours: typeof parsed.summaryIdleHours === "number" ? parsed.summaryIdleHours : 8,
4792
+ summaryScheduleHour: typeof parsed.summaryScheduleHour === "number" ? parsed.summaryScheduleHour : 2,
4793
+ summaryIntervalMin: typeof parsed.summaryIntervalMin === "number" ? parsed.summaryIntervalMin : 30,
4794
+ compressionMode: parsed.compressionMode === "custom" ? "custom" : "auto",
4795
+ compressionThreshold: typeof parsed.compressionThreshold === "number" ? parsed.compressionThreshold : 256e3,
4796
+ searchEnabled: parsed.searchEnabled === true,
4797
+ searchProvider: parsed.searchProvider === "searxng" || parsed.searchProvider === "tavily" ? parsed.searchProvider : "searxng",
4798
+ searxngURL: typeof parsed.searxngURL === "string" ? parsed.searxngURL : "http://localhost:8080",
4799
+ tavilyApiKey: typeof parsed.tavilyApiKey === "string" ? parsed.tavilyApiKey : "",
4800
+ emailNotifications: parsed.emailNotifications === true,
4801
+ emailSmtpHost: typeof parsed.emailSmtpHost === "string" ? parsed.emailSmtpHost : "",
4802
+ emailSmtpPort: typeof parsed.emailSmtpPort === "number" ? parsed.emailSmtpPort : 465,
4803
+ emailSmtpSecure: parsed.emailSmtpSecure !== false,
4804
+ emailSmtpUser: typeof parsed.emailSmtpUser === "string" ? parsed.emailSmtpUser : "",
4805
+ emailSmtpPass: typeof parsed.emailSmtpPass === "string" ? parsed.emailSmtpPass : "",
4806
+ emailFrom: typeof parsed.emailFrom === "string" ? parsed.emailFrom : "",
4807
+ emailTo: typeof parsed.emailTo === "string" ? parsed.emailTo : "",
4808
+ telegramEnabled: parsed.telegramEnabled === true,
4809
+ telegramBotToken: typeof parsed.telegramBotToken === "string" ? parsed.telegramBotToken : "",
4810
+ telegramAllowedUsers: typeof parsed.telegramAllowedUsers === "string" ? parsed.telegramAllowedUsers : ""
4811
+ };
4812
+ } catch {
4813
+ return structuredClone(defaultConfig);
4814
+ }
4815
+ }
4816
+ function writeConfig(config) {
4817
+ const path = getConfigPath();
4818
+ ensureDataDir();
4819
+ const tmpPath = path + ".tmp";
4820
+ writeFileSync(tmpPath, JSON.stringify(config, null, " "), "utf-8");
4821
+ renameSync(tmpPath, path);
4822
+ }
4823
+ function addProvider(provider) {
4824
+ const config = readConfig();
4825
+ const existing = config.providers.findIndex((p) => p.name === provider.name);
4826
+ if (existing !== -1) config.providers[existing] = provider;
4827
+ else config.providers.push(provider);
4828
+ if (!config.activeModel) config.activeModel = getDefaultModels(provider.type)[0]?.id || "";
4829
+ writeConfig(config);
4830
+ return config;
4831
+ }
4832
+ function removeProvider(name) {
4833
+ const config = readConfig();
4834
+ config.providers = config.providers.filter((p) => p.name !== name);
4835
+ if (!getProviderForModel(config.activeModel)) {
4836
+ const first = config.providers[0];
4837
+ config.activeModel = first ? getDefaultModels(first.type)[0]?.id || "" : "";
4838
+ }
4839
+ writeConfig(config);
4840
+ return config;
4841
+ }
4842
+ function setActiveModel(modelId) {
4843
+ const config = readConfig();
4844
+ config.activeModel = modelId;
4845
+ for (const provider of config.providers) {
4846
+ const models = getDefaultModels(provider.type);
4847
+ if (models.length > 0) {
4848
+ const model = models.find((m) => m.id === modelId);
4849
+ if (model && !model.supportsReasoning) provider.reasoningEffort = void 0;
4850
+ } else if (provider.type === "ollama") provider.reasoningEffort = void 0;
4851
+ }
4852
+ writeConfig(config);
4853
+ return config;
4854
+ }
4855
+ function setReasoningEffort(value) {
4856
+ const config = readConfig();
4857
+ const provider = config.providers.find((p) => {
4858
+ const models = getDefaultModels(p.type);
4859
+ if (models.length > 0) return models.some((m) => m.id === config.activeModel);
4860
+ return p.type === "ollama" && !!config.activeModel;
4861
+ });
4862
+ if (provider) {
4863
+ provider.reasoningEffort = value || void 0;
4864
+ writeConfig(config);
4865
+ }
4866
+ return config;
4867
+ }
4868
+ function getProviderForModel(modelId) {
4869
+ const config = readConfig();
4870
+ for (const provider of config.providers) if (getDefaultModels(provider.type).some((m) => m.id === modelId)) return provider;
4871
+ const ollama = config.providers.find((p) => p.type === "ollama");
4872
+ if (ollama) return ollama;
4873
+ }
4874
+ function getAllAvailableModels() {
4875
+ const config = readConfig();
4876
+ const result = [];
4877
+ for (const provider of config.providers) for (const model of getDefaultModels(provider.type)) result.push({
4878
+ model,
4879
+ providerName: provider.name
4880
+ });
4881
+ return result;
4882
+ }
4883
+ function getFirstProvider() {
4884
+ return readConfig().providers.find((p) => p.apiKey);
4885
+ }
4886
+ function getActiveModel() {
4887
+ const config = readConfig();
4888
+ if (!config.activeModel) return void 0;
4889
+ for (const provider of config.providers) {
4890
+ const model = getDefaultModels(provider.type).find((m) => m.id === config.activeModel);
4891
+ if (model) return model;
4892
+ }
4893
+ if (config.providers.some((p) => p.type === "ollama")) return {
4894
+ id: config.activeModel,
4895
+ name: config.activeModel,
4896
+ contextWindow: 128e3,
4897
+ supportsReasoning: false,
4898
+ reasoningEffortValues: [],
4899
+ supportsVision: false
4900
+ };
4901
+ }
4902
+ function getContextWindow() {
4903
+ return getActiveModel()?.contextWindow || DEFAULT_CONTEXT_WINDOW;
4904
+ }
4905
+
4906
+ export { AgentLoop as A, CORE_TOOLS as C, SCHEDULING_TOOLS as S, ToolRegistry as T, getDataPath as a, getProviderForModel as b, createStorage as c, getActiveModel as d, createProvider as e, getContextWindow as f, getDataDir as g, createSearchHistoryTool as h, ContextBuilder as i, AgentLogger as j, setReasoningEffort as k, setActiveModel as l, removeProvider as m, addProvider as n, getAllAvailableModels as o, runSummarizeJob as p, getAllTasks as q, readConfig as r, sessionLock as s, deleteTask as t, resumeTask as u, pauseTask as v, writeConfig as w, startScheduler as x, createSummarizeWorker as y, setTaskNotificationHandler as z };
4907
+ //# sourceMappingURL=config-d3FC8naq.js.map