@xopcai/xopcbot 0.1.3 → 0.2.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 (292) hide show
  1. package/README.md +57 -52
  2. package/README.zh-CN.md +56 -49
  3. package/dist/agent/__tests__/media-processing.test.d.ts +6 -0
  4. package/dist/agent/__tests__/media-processing.test.js +385 -0
  5. package/dist/agent/__tests__/media-processing.test.js.map +1 -0
  6. package/dist/agent/fallback/__tests__/index.test.js +16 -5
  7. package/dist/agent/fallback/__tests__/index.test.js.map +1 -1
  8. package/dist/agent/fallback/candidates.d.ts +2 -4
  9. package/dist/agent/fallback/candidates.js +19 -26
  10. package/dist/agent/fallback/candidates.js.map +1 -1
  11. package/dist/agent/helpers.d.ts +1 -0
  12. package/dist/agent/helpers.js.map +1 -1
  13. package/dist/agent/index.d.ts +6 -1
  14. package/dist/agent/index.js +10 -1
  15. package/dist/agent/index.js.map +1 -1
  16. package/dist/agent/models/compat.d.ts +35 -0
  17. package/dist/agent/models/compat.js +110 -0
  18. package/dist/agent/models/compat.js.map +1 -0
  19. package/dist/agent/models/fallback.d.ts +38 -0
  20. package/dist/agent/models/fallback.js +133 -0
  21. package/dist/agent/models/fallback.js.map +1 -0
  22. package/dist/agent/models/index.d.ts +10 -0
  23. package/dist/agent/models/index.js +11 -0
  24. package/dist/agent/models/index.js.map +1 -0
  25. package/dist/agent/{model-manager.d.ts → models/manager.d.ts} +2 -8
  26. package/dist/agent/{model-manager.js → models/manager.js} +38 -24
  27. package/dist/agent/models/manager.js.map +1 -0
  28. package/dist/agent/models/scan.d.ts +46 -0
  29. package/dist/agent/models/scan.js +177 -0
  30. package/dist/agent/models/scan.js.map +1 -0
  31. package/dist/agent/models/selection.d.ts +44 -0
  32. package/dist/agent/models/selection.js +141 -0
  33. package/dist/agent/models/selection.js.map +1 -0
  34. package/dist/agent/prompt/index.js +1 -1
  35. package/dist/agent/prompt/index.js.map +1 -1
  36. package/dist/agent/service.js +34 -16
  37. package/dist/agent/service.js.map +1 -1
  38. package/dist/agent/skills/__tests__/test-framework.test.js +15 -7
  39. package/dist/agent/skills/__tests__/test-framework.test.js.map +1 -1
  40. package/dist/agent/skills/config.d.ts +1 -1
  41. package/dist/agent/skills/config.js +2 -2
  42. package/dist/agent/skills/config.js.map +1 -1
  43. package/dist/agent/skills/index.js +15 -28
  44. package/dist/agent/skills/index.js.map +1 -1
  45. package/dist/agent/skills/installer.d.ts +1 -1
  46. package/dist/agent/skills/installer.js +1 -1
  47. package/dist/agent/skills/scanner.d.ts +1 -1
  48. package/dist/agent/skills/scanner.js +1 -1
  49. package/dist/agent/skills/test-framework.js +24 -23
  50. package/dist/agent/skills/test-framework.js.map +1 -1
  51. package/dist/agent/skills/types.d.ts +3 -3
  52. package/dist/agent/skills/types.js +1 -1
  53. package/dist/agent/skills/watcher.d.ts +1 -1
  54. package/dist/agent/skills/watcher.js +1 -1
  55. package/dist/agent/system-prompt.d.ts +67 -0
  56. package/dist/agent/system-prompt.js +351 -0
  57. package/dist/agent/system-prompt.js.map +1 -0
  58. package/dist/agent/tools/__tests__/send-media.test.d.ts +6 -0
  59. package/dist/agent/tools/__tests__/send-media.test.js +251 -0
  60. package/dist/agent/tools/__tests__/send-media.test.js.map +1 -0
  61. package/dist/agent/types.agent-defaults.d.ts +48 -0
  62. package/dist/agent/types.agent-defaults.js +5 -0
  63. package/dist/agent/types.agent-defaults.js.map +1 -0
  64. package/dist/agent/types.d.ts +14 -6
  65. package/dist/agent/types.js +5 -0
  66. package/dist/agent/types.js.map +1 -1
  67. package/dist/agent/workspace.d.ts +94 -0
  68. package/dist/agent/workspace.js +625 -0
  69. package/dist/agent/workspace.js.map +1 -0
  70. package/dist/auth/index.js +1 -1
  71. package/dist/auth/index.js.map +1 -1
  72. package/dist/auth/oauth/index.d.ts +1 -0
  73. package/dist/auth/oauth/index.js +1 -0
  74. package/dist/auth/oauth/index.js.map +1 -1
  75. package/dist/auth/oauth/kimi.d.ts +2 -1
  76. package/dist/auth/oauth/kimi.js +51 -48
  77. package/dist/auth/oauth/kimi.js.map +1 -1
  78. package/dist/auth/oauth/minimax-cn.d.ts +12 -0
  79. package/dist/auth/oauth/minimax-cn.js +111 -0
  80. package/dist/auth/oauth/minimax-cn.js.map +1 -0
  81. package/dist/auth/oauth/qwen.d.ts +5 -0
  82. package/dist/auth/oauth/qwen.js +54 -84
  83. package/dist/auth/oauth/qwen.js.map +1 -1
  84. package/dist/auth/profiles/index.d.ts +0 -2
  85. package/dist/auth/profiles/index.js +0 -2
  86. package/dist/auth/profiles/index.js.map +1 -1
  87. package/dist/auth/storage.js +7 -1
  88. package/dist/auth/storage.js.map +1 -1
  89. package/dist/channels/__tests__/media-integration.test.d.ts +6 -0
  90. package/dist/channels/__tests__/media-integration.test.js +398 -0
  91. package/dist/channels/__tests__/media-integration.test.js.map +1 -0
  92. package/dist/channels/__tests__/media.test.d.ts +6 -0
  93. package/dist/channels/__tests__/media.test.js +251 -0
  94. package/dist/channels/__tests__/media.test.js.map +1 -0
  95. package/dist/channels/access-control.d.ts +1 -1
  96. package/dist/channels/access-control.js +1 -1
  97. package/dist/channels/draft-stream.d.ts +1 -1
  98. package/dist/channels/draft-stream.js +1 -1
  99. package/dist/channels/format.d.ts +1 -1
  100. package/dist/channels/format.js +1 -1
  101. package/dist/channels/telegram/command-handler.js +15 -48
  102. package/dist/channels/telegram/command-handler.js.map +1 -1
  103. package/dist/channels/telegram/plugin.js +3 -2
  104. package/dist/channels/telegram/plugin.js.map +1 -1
  105. package/dist/channels/telegram/webhook.d.ts +1 -1
  106. package/dist/channels/telegram/webhook.js +1 -1
  107. package/dist/channels/types.d.ts +1 -1
  108. package/dist/channels/types.js +1 -1
  109. package/dist/channels/update-offset-store.d.ts +1 -1
  110. package/dist/channels/update-offset-store.js +1 -1
  111. package/dist/cli/commands/auth.js +8 -23
  112. package/dist/cli/commands/auth.js.map +1 -1
  113. package/dist/cli/commands/gateway.js +9 -1
  114. package/dist/cli/commands/gateway.js.map +1 -1
  115. package/dist/cli/commands/models.js +35 -29
  116. package/dist/cli/commands/models.js.map +1 -1
  117. package/dist/cli/commands/onboard.js +166 -115
  118. package/dist/cli/commands/onboard.js.map +1 -1
  119. package/dist/cli/commands/setup.js +123 -0
  120. package/dist/cli/commands/setup.js.map +1 -0
  121. package/dist/cli/commands/skills.js +6 -6
  122. package/dist/cli/commands/skills.js.map +1 -1
  123. package/dist/cli/index.d.ts +1 -1
  124. package/dist/cli/index.js +1 -1
  125. package/dist/cli/index.js.map +1 -1
  126. package/dist/cli/templates.d.ts +2 -0
  127. package/dist/cli/templates.js +1 -1
  128. package/dist/cli/templates.js.map +1 -1
  129. package/dist/config/defaults.d.ts +19 -0
  130. package/dist/config/defaults.js +168 -0
  131. package/dist/config/defaults.js.map +1 -0
  132. package/dist/config/index.d.ts +5 -0
  133. package/dist/config/index.js +4 -0
  134. package/dist/config/index.js.map +1 -1
  135. package/dist/config/integration.d.ts +12 -0
  136. package/dist/config/integration.js +14 -0
  137. package/dist/config/integration.js.map +1 -0
  138. package/dist/config/models-json.d.ts +454 -0
  139. package/dist/config/models-json.js +323 -0
  140. package/dist/config/models-json.js.map +1 -0
  141. package/dist/config/paths.d.ts +2 -0
  142. package/dist/config/paths.js +4 -0
  143. package/dist/config/paths.js.map +1 -1
  144. package/dist/config/reload.d.ts +1 -1
  145. package/dist/config/reload.js +3 -3
  146. package/dist/config/reload.js.map +1 -1
  147. package/dist/config/resolve-config-value.d.ts +36 -0
  148. package/dist/config/resolve-config-value.js +218 -0
  149. package/dist/config/resolve-config-value.js.map +1 -0
  150. package/dist/config/rules.js +3 -2
  151. package/dist/config/rules.js.map +1 -1
  152. package/dist/config/schema.d.ts +17 -884
  153. package/dist/config/schema.js +36 -312
  154. package/dist/config/schema.js.map +1 -1
  155. package/dist/config/types.models.d.ts +54 -0
  156. package/dist/config/types.models.js +2 -0
  157. package/dist/config/types.models.js.map +1 -0
  158. package/dist/cron/validation.d.ts +4 -4
  159. package/dist/gateway/hono/app.js +232 -78
  160. package/dist/gateway/hono/app.js.map +1 -1
  161. package/dist/gateway/hono/oauth-async.d.ts +14 -0
  162. package/dist/gateway/hono/oauth-async.js +285 -0
  163. package/dist/gateway/hono/oauth-async.js.map +1 -0
  164. package/dist/gateway/hono/oauth.d.ts +9 -0
  165. package/dist/gateway/hono/oauth.js +157 -0
  166. package/dist/gateway/hono/oauth.js.map +1 -0
  167. package/dist/gateway/hono/sse.js +5 -2
  168. package/dist/gateway/hono/sse.js.map +1 -1
  169. package/dist/gateway/process-manager.js +12 -10
  170. package/dist/gateway/process-manager.js.map +1 -1
  171. package/dist/gateway/service.d.ts +6 -2
  172. package/dist/gateway/service.js +20 -6
  173. package/dist/gateway/service.js.map +1 -1
  174. package/dist/gateway/static/root/assets/flow-BqIEBwW6.js +2 -0
  175. package/dist/gateway/static/root/assets/flow-BqIEBwW6.js.map +1 -0
  176. package/dist/gateway/static/root/assets/main-Br2tw-87.js +5168 -0
  177. package/dist/gateway/static/root/assets/main-Br2tw-87.js.map +1 -0
  178. package/dist/gateway/static/root/assets/main-DwlbPf8Z.css +1 -0
  179. package/dist/gateway/static/root/index.html +2 -2
  180. package/dist/plugins/index.d.ts +0 -2
  181. package/dist/plugins/index.js +0 -2
  182. package/dist/plugins/index.js.map +1 -1
  183. package/dist/plugins/types.d.ts +0 -2
  184. package/dist/plugins/types.js +0 -2
  185. package/dist/plugins/types.js.map +1 -1
  186. package/dist/providers/index.d.ts +50 -22
  187. package/dist/providers/index.js +276 -50
  188. package/dist/providers/index.js.map +1 -1
  189. package/dist/providers/model-registry.d.ts +84 -0
  190. package/dist/providers/model-registry.js +385 -0
  191. package/dist/providers/model-registry.js.map +1 -0
  192. package/dist/types/providers.d.ts +2 -63
  193. package/dist/types/providers.js +1 -1
  194. package/dist/utils/__tests__/frontmatter.test.d.ts +4 -0
  195. package/dist/utils/__tests__/frontmatter.test.js +150 -0
  196. package/dist/utils/__tests__/frontmatter.test.js.map +1 -0
  197. package/dist/utils/diagnostic-events.d.ts +230 -0
  198. package/dist/utils/diagnostic-events.js +189 -0
  199. package/dist/utils/diagnostic-events.js.map +1 -0
  200. package/dist/utils/frontmatter.d.ts +0 -1
  201. package/dist/utils/frontmatter.js +15 -79
  202. package/dist/utils/frontmatter.js.map +1 -1
  203. package/dist/utils/log-stream.d.ts +95 -0
  204. package/dist/utils/log-stream.js +229 -0
  205. package/dist/utils/log-stream.js.map +1 -0
  206. package/dist/utils/logger.d.ts +5 -0
  207. package/dist/utils/logger.js +25 -0
  208. package/dist/utils/logger.js.map +1 -1
  209. package/dist/utils/redact.d.ts +73 -0
  210. package/dist/utils/redact.js +245 -0
  211. package/dist/utils/redact.js.map +1 -0
  212. package/package.json +6 -4
  213. package/skills/find-skills/SKILL.md +0 -9
  214. package/dist/__tests__/core.test.js +0 -72
  215. package/dist/__tests__/core.test.js.map +0 -1
  216. package/dist/agent/model-manager.js.map +0 -1
  217. package/dist/cli/commands/configure.d.ts +0 -1
  218. package/dist/cli/commands/configure.js +0 -173
  219. package/dist/cli/commands/configure.js.map +0 -1
  220. package/dist/cli/commands/gateway-daemon.d.ts +0 -1
  221. package/dist/cli/commands/gateway-daemon.js +0 -141
  222. package/dist/cli/commands/gateway-daemon.js.map +0 -1
  223. package/dist/config/__tests__/diff.test.d.ts +0 -1
  224. package/dist/config/__tests__/diff.test.js +0 -192
  225. package/dist/config/__tests__/diff.test.js.map +0 -1
  226. package/dist/config/__tests__/loader.test.d.ts +0 -1
  227. package/dist/config/__tests__/loader.test.js +0 -356
  228. package/dist/config/__tests__/loader.test.js.map +0 -1
  229. package/dist/config/__tests__/paths.test.d.ts +0 -1
  230. package/dist/config/__tests__/paths.test.js +0 -192
  231. package/dist/config/__tests__/paths.test.js.map +0 -1
  232. package/dist/config/__tests__/reload.test.d.ts +0 -1
  233. package/dist/config/__tests__/reload.test.js +0 -374
  234. package/dist/config/__tests__/reload.test.js.map +0 -1
  235. package/dist/config/__tests__/rules.test.d.ts +0 -1
  236. package/dist/config/__tests__/rules.test.js +0 -204
  237. package/dist/config/__tests__/rules.test.js.map +0 -1
  238. package/dist/config/__tests__/schema.test.d.ts +0 -1
  239. package/dist/config/__tests__/schema.test.js +0 -672
  240. package/dist/config/__tests__/schema.test.js.map +0 -1
  241. package/dist/daemon/background-start.d.ts +0 -33
  242. package/dist/daemon/background-start.js +0 -89
  243. package/dist/daemon/background-start.js.map +0 -1
  244. package/dist/daemon/gateway-manager.d.ts +0 -87
  245. package/dist/daemon/gateway-manager.js +0 -324
  246. package/dist/daemon/gateway-manager.js.map +0 -1
  247. package/dist/daemon/index.d.ts +0 -5
  248. package/dist/daemon/index.js +0 -6
  249. package/dist/daemon/index.js.map +0 -1
  250. package/dist/gateway/static/root/assets/main-DevbZW9K.js +0 -2227
  251. package/dist/gateway/static/root/assets/main-DevbZW9K.js.map +0 -1
  252. package/dist/gateway/static/root/assets/main-DxZg1Nmz.css +0 -1
  253. package/dist/providers/__tests__/registry.test.d.ts +0 -1
  254. package/dist/providers/__tests__/registry.test.js +0 -110
  255. package/dist/providers/__tests__/registry.test.js.map +0 -1
  256. package/dist/providers/api-strategies.d.ts +0 -15
  257. package/dist/providers/api-strategies.js +0 -96
  258. package/dist/providers/api-strategies.js.map +0 -1
  259. package/dist/providers/auto-discovery.d.ts +0 -84
  260. package/dist/providers/auto-discovery.js +0 -236
  261. package/dist/providers/auto-discovery.js.map +0 -1
  262. package/dist/providers/config.d.ts +0 -25
  263. package/dist/providers/config.js +0 -42
  264. package/dist/providers/config.js.map +0 -1
  265. package/dist/providers/model-catalog.d.ts +0 -205
  266. package/dist/providers/model-catalog.js +0 -1071
  267. package/dist/providers/model-catalog.js.map +0 -1
  268. package/dist/providers/models-dev-data.d.ts +0 -11
  269. package/dist/providers/models-dev-data.js +0 -1035
  270. package/dist/providers/models-dev-data.js.map +0 -1
  271. package/dist/providers/models-dev.d.ts +0 -30
  272. package/dist/providers/models-dev.js +0 -42
  273. package/dist/providers/models-dev.js.map +0 -1
  274. package/dist/providers/pi-ai.d.ts +0 -62
  275. package/dist/providers/pi-ai.js +0 -221
  276. package/dist/providers/pi-ai.js.map +0 -1
  277. package/dist/providers/provider-catalog.d.ts +0 -173
  278. package/dist/providers/provider-catalog.js +0 -834
  279. package/dist/providers/provider-catalog.js.map +0 -1
  280. package/dist/providers/registry.d.ts +0 -155
  281. package/dist/providers/registry.js +0 -524
  282. package/dist/providers/registry.js.map +0 -1
  283. package/dist/providers/types.d.ts +0 -95
  284. package/dist/providers/types.js +0 -7
  285. package/dist/providers/types.js.map +0 -1
  286. package/dist/session/chat-manager.d.ts +0 -49
  287. package/dist/session/chat-manager.js +0 -167
  288. package/dist/session/chat-manager.js.map +0 -1
  289. package/dist/session/chat-types.d.ts +0 -53
  290. package/dist/session/chat-types.js +0 -63
  291. package/dist/session/chat-types.js.map +0 -1
  292. /package/dist/{__tests__/core.test.d.ts → cli/commands/setup.d.ts} +0 -0
@@ -1,2227 +0,0 @@
1
- (function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const a of n)if(a.type==="childList")for(const l of a.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&i(l)}).observe(document,{childList:!0,subtree:!0});function s(n){const a={};return n.integrity&&(a.integrity=n.integrity),n.referrerPolicy&&(a.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?a.credentials="include":n.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(n){if(n.ep)return;n.ep=!0;const a=s(n);fetch(n.href,a)}})();const $e=globalThis,Be=$e.ShadowRoot&&($e.ShadyCSS===void 0||$e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,rt=Symbol(),qe=new WeakMap;let $t=class{constructor(t,s,i){if(this._$cssResult$=!0,i!==rt)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=s}get styleSheet(){let t=this.o;const s=this.t;if(Be&&t===void 0){const i=s!==void 0&&s.length===1;i&&(t=qe.get(s)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),i&&qe.set(s,t))}return t}toString(){return this.cssText}};const kt=e=>new $t(typeof e=="string"?e:e+"",void 0,rt),xt=(e,t)=>{if(Be)e.adoptedStyleSheets=t.map(s=>s instanceof CSSStyleSheet?s:s.styleSheet);else for(const s of t){const i=document.createElement("style"),n=$e.litNonce;n!==void 0&&i.setAttribute("nonce",n),i.textContent=s.cssText,e.appendChild(i)}},Je=Be?e=>e:e=>e instanceof CSSStyleSheet?(t=>{let s="";for(const i of t.cssRules)s+=i.cssText;return kt(s)})(e):e;const{is:St,defineProperty:At,getOwnPropertyDescriptor:Ct,getOwnPropertyNames:Tt,getOwnPropertySymbols:Mt,getPrototypeOf:Et}=Object,Te=globalThis,Ge=Te.trustedTypes,Pt=Ge?Ge.emptyScript:"",Ft=Te.reactiveElementPolyfillSupport,ue=(e,t)=>e,ke={toAttribute(e,t){switch(t){case Boolean:e=e?Pt:null;break;case Object:case Array:e=e==null?e:JSON.stringify(e)}return e},fromAttribute(e,t){let s=e;switch(t){case Boolean:s=e!==null;break;case Number:s=e===null?null:Number(e);break;case Object:case Array:try{s=JSON.parse(e)}catch{s=null}}return s}},Ke=(e,t)=>!St(e,t),We={attribute:!0,type:String,converter:ke,reflect:!1,useDefault:!1,hasChanged:Ke};Symbol.metadata??=Symbol("metadata"),Te.litPropertyMetadata??=new WeakMap;let se=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=We){if(s.state&&(s.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=!0),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(t,i,s);n!==void 0&&At(this.prototype,t,n)}}static getPropertyDescriptor(t,s,i){const{get:n,set:a}=Ct(this.prototype,t)??{get(){return this[s]},set(l){this[s]=l}};return{get:n,set(l){const h=n?.call(this);a?.call(this,l),this.requestUpdate(t,h,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??We}static _$Ei(){if(this.hasOwnProperty(ue("elementProperties")))return;const t=Et(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(ue("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ue("properties"))){const s=this.properties,i=[...Tt(s),...Mt(s)];for(const n of i)this.createProperty(n,s[n])}const t=this[Symbol.metadata];if(t!==null){const s=litPropertyMetadata.get(t);if(s!==void 0)for(const[i,n]of s)this.elementProperties.set(i,n)}this._$Eh=new Map;for(const[s,i]of this.elementProperties){const n=this._$Eu(s,i);n!==void 0&&this._$Eh.set(n,s)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const s=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const n of i)s.unshift(Je(n))}else t!==void 0&&s.push(Je(t));return s}static _$Eu(t,s){const i=s.attribute;return i===!1?void 0:typeof i=="string"?i:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return xt(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,s,i){this._$AK(t,i)}_$ET(t,s){const i=this.constructor.elementProperties.get(t),n=this.constructor._$Eu(t,i);if(n!==void 0&&i.reflect===!0){const a=(i.converter?.toAttribute!==void 0?i.converter:ke).toAttribute(s,i.type);this._$Em=t,a==null?this.removeAttribute(n):this.setAttribute(n,a),this._$Em=null}}_$AK(t,s){const i=this.constructor,n=i._$Eh.get(t);if(n!==void 0&&this._$Em!==n){const a=i.getPropertyOptions(n),l=typeof a.converter=="function"?{fromAttribute:a.converter}:a.converter?.fromAttribute!==void 0?a.converter:ke;this._$Em=n;const h=l.fromAttribute(s,a.type);this[n]=h??this._$Ej?.get(n)??h,this._$Em=null}}requestUpdate(t,s,i,n=!1,a){if(t!==void 0){const l=this.constructor;if(n===!1&&(a=this[t]),i??=l.getPropertyOptions(t),!((i.hasChanged??Ke)(a,s)||i.useDefault&&i.reflect&&a===this._$Ej?.get(t)&&!this.hasAttribute(l._$Eu(t,i))))return;this.C(t,s,i)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,s,{useDefault:i,reflect:n,wrapped:a},l){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,l??s??this[t]),a!==!0||l!==void 0)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),n===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(s){Promise.reject(s)}const t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[n,a]of this._$Ep)this[n]=a;this._$Ep=void 0}const i=this.constructor.elementProperties;if(i.size>0)for(const[n,a]of i){const{wrapped:l}=a,h=this[n];l!==!0||this._$AL.has(n)||h===void 0||this.C(n,void 0,a,h)}}let t=!1;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach(i=>i.hostUpdate?.()),this.update(s)):this._$EM()}catch(i){throw t=!1,this._$EM(),i}t&&this._$AE(s)}willUpdate(t){}_$AE(t){this._$EO?.forEach(s=>s.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(s=>this._$ET(s,this[s])),this._$EM()}updated(t){}firstUpdated(t){}};se.elementStyles=[],se.shadowRootOptions={mode:"open"},se[ue("elementProperties")]=new Map,se[ue("finalized")]=new Map,Ft?.({ReactiveElement:se}),(Te.reactiveElementVersions??=[]).push("2.1.2");const je=globalThis,Ve=e=>e,xe=je.trustedTypes,Qe=xe?xe.createPolicy("lit-html",{createHTML:e=>e}):void 0,lt="$lit$",B=`lit$${Math.random().toFixed(9).slice(2)}$`,ct="?"+B,Lt=`<${ct}>`,G=document,_e=()=>G.createComment(""),me=e=>e===null||typeof e!="object"&&typeof e!="function",Ue=Array.isArray,Dt=e=>Ue(e)||typeof e?.[Symbol.iterator]=="function",Fe=`[
2
- \f\r]`,ce=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Xe=/-->/g,Ye=/>/g,N=RegExp(`>|${Fe}(?:([^\\s"'>=/]+)(${Fe}*=${Fe}*(?:[^
3
- \f\r"'\`<>=]|("|')|))|$)`,"g"),Ze=/'/g,et=/"/g,ht=/^(?:script|style|textarea|title)$/i,It=e=>(t,...s)=>({_$litType$:e,strings:t,values:s}),o=It(1),W=Symbol.for("lit-noChange"),_=Symbol.for("lit-nothing"),tt=new WeakMap,q=G.createTreeWalker(G,129);function dt(e,t){if(!Ue(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return Qe!==void 0?Qe.createHTML(t):t}const Ot=(e,t)=>{const s=e.length-1,i=[];let n,a=t===2?"<svg>":t===3?"<math>":"",l=ce;for(let h=0;h<s;h++){const p=e[h];let g,S,f=-1,F=0;for(;F<p.length&&(l.lastIndex=F,S=l.exec(p),S!==null);)F=l.lastIndex,l===ce?S[1]==="!--"?l=Xe:S[1]!==void 0?l=Ye:S[2]!==void 0?(ht.test(S[2])&&(n=RegExp("</"+S[2],"g")),l=N):S[3]!==void 0&&(l=N):l===N?S[0]===">"?(l=n??ce,f=-1):S[1]===void 0?f=-2:(f=l.lastIndex-S[2].length,g=S[1],l=S[3]===void 0?N:S[3]==='"'?et:Ze):l===et||l===Ze?l=N:l===Xe||l===Ye?l=ce:(l=N,n=void 0);const I=l===N&&e[h+1].startsWith("/>")?" ":"";a+=l===ce?p+Lt:f>=0?(i.push(g),p.slice(0,f)+lt+p.slice(f)+B+I):p+B+(f===-2?h:I)}return[dt(e,a+(e[s]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),i]};class ve{constructor({strings:t,_$litType$:s},i){let n;this.parts=[];let a=0,l=0;const h=t.length-1,p=this.parts,[g,S]=Ot(t,s);if(this.el=ve.createElement(g,i),q.currentNode=this.el.content,s===2||s===3){const f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(n=q.nextNode())!==null&&p.length<h;){if(n.nodeType===1){if(n.hasAttributes())for(const f of n.getAttributeNames())if(f.endsWith(lt)){const F=S[l++],I=n.getAttribute(f).split(B),we=/([.?@])?(.*)/.exec(F);p.push({type:1,index:a,name:we[2],strings:I,ctor:we[1]==="."?Bt:we[1]==="?"?Kt:we[1]==="@"?jt:Me}),n.removeAttribute(f)}else f.startsWith(B)&&(p.push({type:6,index:a}),n.removeAttribute(f));if(ht.test(n.tagName)){const f=n.textContent.split(B),F=f.length-1;if(F>0){n.textContent=xe?xe.emptyScript:"";for(let I=0;I<F;I++)n.append(f[I],_e()),q.nextNode(),p.push({type:2,index:++a});n.append(f[F],_e())}}}else if(n.nodeType===8)if(n.data===ct)p.push({type:2,index:a});else{let f=-1;for(;(f=n.data.indexOf(B,f+1))!==-1;)p.push({type:7,index:a}),f+=B.length-1}a++}}static createElement(t,s){const i=G.createElement("template");return i.innerHTML=t,i}}function ne(e,t,s=e,i){if(t===W)return t;let n=i!==void 0?s._$Co?.[i]:s._$Cl;const a=me(t)?void 0:t._$litDirective$;return n?.constructor!==a&&(n?._$AO?.(!1),a===void 0?n=void 0:(n=new a(e),n._$AT(e,s,i)),i!==void 0?(s._$Co??=[])[i]=n:s._$Cl=n),n!==void 0&&(t=ne(e,n._$AS(e,t.values),n,i)),t}class Rt{constructor(t,s){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=s}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:s},parts:i}=this._$AD,n=(t?.creationScope??G).importNode(s,!0);q.currentNode=n;let a=q.nextNode(),l=0,h=0,p=i[0];for(;p!==void 0;){if(l===p.index){let g;p.type===2?g=new ye(a,a.nextSibling,this,t):p.type===1?g=new p.ctor(a,p.name,p.strings,this,t):p.type===6&&(g=new Ut(a,this,t)),this._$AV.push(g),p=i[++h]}l!==p?.index&&(a=q.nextNode(),l++)}return q.currentNode=G,n}p(t){let s=0;for(const i of this._$AV)i!==void 0&&(i.strings!==void 0?(i._$AI(t,i,s),s+=i.strings.length-2):i._$AI(t[s])),s++}}class ye{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,s,i,n){this.type=2,this._$AH=_,this._$AN=void 0,this._$AA=t,this._$AB=s,this._$AM=i,this.options=n,this._$Cv=n?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const s=this._$AM;return s!==void 0&&t?.nodeType===11&&(t=s.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,s=this){t=ne(this,t,s),me(t)?t===_||t==null||t===""?(this._$AH!==_&&this._$AR(),this._$AH=_):t!==this._$AH&&t!==W&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):Dt(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==_&&me(this._$AH)?this._$AA.nextSibling.data=t:this.T(G.createTextNode(t)),this._$AH=t}$(t){const{values:s,_$litType$:i}=t,n=typeof i=="number"?this._$AC(t):(i.el===void 0&&(i.el=ve.createElement(dt(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(s);else{const a=new Rt(n,this),l=a.u(this.options);a.p(s),this.T(l),this._$AH=a}}_$AC(t){let s=tt.get(t.strings);return s===void 0&&tt.set(t.strings,s=new ve(t)),s}k(t){Ue(this._$AH)||(this._$AH=[],this._$AR());const s=this._$AH;let i,n=0;for(const a of t)n===s.length?s.push(i=new ye(this.O(_e()),this.O(_e()),this,this.options)):i=s[n],i._$AI(a),n++;n<s.length&&(this._$AR(i&&i._$AB.nextSibling,n),s.length=n)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const i=Ve(t).nextSibling;Ve(t).remove(),t=i}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}}class Me{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,s,i,n,a){this.type=1,this._$AH=_,this._$AN=void 0,this.element=t,this.name=s,this._$AM=n,this.options=a,i.length>2||i[0]!==""||i[1]!==""?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=_}_$AI(t,s=this,i,n){const a=this.strings;let l=!1;if(a===void 0)t=ne(this,t,s,0),l=!me(t)||t!==this._$AH&&t!==W,l&&(this._$AH=t);else{const h=t;let p,g;for(t=a[0],p=0;p<a.length-1;p++)g=ne(this,h[i+p],s,p),g===W&&(g=this._$AH[p]),l||=!me(g)||g!==this._$AH[p],g===_?t=_:t!==_&&(t+=(g??"")+a[p+1]),this._$AH[p]=g}l&&!n&&this.j(t)}j(t){t===_?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}}class Bt extends Me{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===_?void 0:t}}class Kt extends Me{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==_)}}class jt extends Me{constructor(t,s,i,n,a){super(t,s,i,n,a),this.type=5}_$AI(t,s=this){if((t=ne(this,t,s,0)??_)===W)return;const i=this._$AH,n=t===_&&i!==_||t.capture!==i.capture||t.once!==i.once||t.passive!==i.passive,a=t!==_&&(i===_||n);n&&this.element.removeEventListener(this.name,this,i),a&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class Ut{constructor(t,s,i){this.element=t,this.type=6,this._$AN=void 0,this._$AM=s,this.options=i}get _$AU(){return this._$AM._$AU}_$AI(t){ne(this,t)}}const Ht=je.litHtmlPolyfillSupport;Ht?.(ve,ye),(je.litHtmlVersions??=[]).push("3.3.2");const Nt=(e,t,s)=>{const i=s?.renderBefore??t;let n=i._$litPart$;if(n===void 0){const a=s?.renderBefore??null;i._$litPart$=n=new ye(t.insertBefore(_e(),a),a,void 0,s??{})}return n._$AI(e),n};const He=globalThis;let y=class extends se{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const s=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=Nt(s,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return W}};y._$litElement$=!0,y.finalized=!0,He.litElementHydrateSupport?.({LitElement:y});const zt=He.litElementPolyfillSupport;zt?.({LitElement:y});(He.litElementVersions??=[]).push("4.2.2");const k=e=>(t,s)=>{s!==void 0?s.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};const qt={attribute:!0,type:String,converter:ke,reflect:!1,hasChanged:Ke},Jt=(e=qt,t,s)=>{const{kind:i,metadata:n}=s;let a=globalThis.litPropertyMetadata.get(n);if(a===void 0&&globalThis.litPropertyMetadata.set(n,a=new Map),i==="setter"&&((e=Object.create(e)).wrapped=!0),a.set(s.name,e),i==="accessor"){const{name:l}=s;return{set(h){const p=t.get.call(this);t.set.call(this,h),this.requestUpdate(l,p,e,!0,h)},init(h){return h!==void 0&&this.C(l,void 0,e,h),h}}}if(i==="setter"){const{name:l}=s;return function(h){const p=this[l];t.call(this,h),this.requestUpdate(l,p,e,!0,h)}}throw Error("Unsupported decorator location: "+i)};function u(e){return(t,s)=>typeof s=="object"?Jt(e,t,s):((i,n,a)=>{const l=n.hasOwnProperty(a);return n.constructor.createProperty(a,i),l?Object.getOwnPropertyDescriptor(n,a):void 0})(e,t,s)}function c(e){return u({...e,state:!0,attribute:!1})}const Gt=(e,t,s)=>(s.configurable=!0,s.enumerable=!0,Reflect.decorate&&typeof t!="object"&&Object.defineProperty(e,t,s),s);function oe(e,t){return(s,i,n)=>{const a=l=>l.renderRoot?.querySelector(e)??null;return Gt(s,i,{get(){return a(this)}})}}const Wt=e=>e.strings===void 0;const pt={CHILD:2},ut=e=>(...t)=>({_$litDirective$:e,values:t});class gt{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,s,i){this._$Ct=t,this._$AM=s,this._$Ci=i}_$AS(t,s){return this.update(t,s)}update(t,s){return this.render(...s)}}const ge=(e,t)=>{const s=e._$AN;if(s===void 0)return!1;for(const i of s)i._$AO?.(t,!1),ge(i,t);return!0},Se=e=>{let t,s;do{if((t=e._$AM)===void 0)break;s=t._$AN,s.delete(e),e=t}while(s?.size===0)},_t=e=>{for(let t;t=e._$AM;e=t){let s=t._$AN;if(s===void 0)t._$AN=s=new Set;else if(s.has(e))break;s.add(e),Xt(t)}};function Vt(e){this._$AN!==void 0?(Se(this),this._$AM=e,_t(this)):this._$AM=e}function Qt(e,t=!1,s=0){const i=this._$AH,n=this._$AN;if(n!==void 0&&n.size!==0)if(t)if(Array.isArray(i))for(let a=s;a<i.length;a++)ge(i[a],!1),Se(i[a]);else i!=null&&(ge(i,!1),Se(i));else ge(this,e)}const Xt=e=>{e.type==pt.CHILD&&(e._$AP??=Qt,e._$AQ??=Vt)};class Yt extends gt{constructor(){super(...arguments),this._$AN=void 0}_$AT(t,s,i){super._$AT(t,s,i),_t(this),this.isConnected=t._$AU}_$AO(t,s=!0){t!==this.isConnected&&(this.isConnected=t,t?this.reconnected?.():this.disconnected?.()),s&&(ge(this,t),Se(this))}setValue(t){if(Wt(this._$Ct))this._$Ct._$AI(t,this);else{const s=[...this._$Ct._$AH];s[this._$Ci]=t,this._$Ct._$AI(s,this,0)}}disconnected(){}reconnected(){}}const st=()=>new Zt;class Zt{}const Le=new WeakMap,it=ut(class extends Yt{render(e){return _}update(e,[t]){const s=t!==this.G;return s&&this.G!==void 0&&this.rt(void 0),(s||this.lt!==this.ct)&&(this.G=t,this.ht=e.options?.host,this.rt(this.ct=e.element)),_}rt(e){if(this.isConnected||(e=void 0),typeof this.G=="function"){const t=this.ht??globalThis;let s=Le.get(t);s===void 0&&(s=new WeakMap,Le.set(t,s)),s.get(this.G)!==void 0&&this.G.call(this.ht,void 0),s.set(this.G,e),e!==void 0&&this.G.call(this.ht,e)}else this.G.value=e}get lt(){return typeof this.G=="function"?Le.get(this.ht??globalThis)?.get(this.G):this.G?.value}disconnected(){this.lt===this.ct&&this.rt(void 0)}reconnected(){this.rt(this.ct)}});class De extends gt{constructor(t){if(super(t),this.it=_,t.type!==pt.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(t){if(t===_||t==null)return this._t=void 0,this.it=t;if(t===W)return t;if(typeof t!="string")throw Error(this.constructor.directiveName+"() called with a non-string value");if(t===this.it)return this._t;this.it=t;const s=[t];return s.raw=s,this._t={_$litType$:this.constructor.resultType,strings:s,values:[]}}}De.directiveName="unsafeHTML",De.resultType=1;const he=ut(De);const Ee={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const es=["svg",Ee,[["path",{d:"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"}]]];const ts=["svg",Ee,[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"}],["path",{d:"m21.854 2.147-10.94 10.939"}]]];const ss=["svg",Ee,[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}]]];const is=["svg",Ee,[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]]],ns={title:"XOPCBOT Gateway",brand:"XOPCBOT"},os={chat:"Chat",sessions:"Sessions",cron:"Cron Jobs",logs:"Logs",settings:"Settings",management:"Management"},as={title:"XopcBot",newSession:"New Chat",welcomeTitle:"Welcome to xopcbot",welcomeDescription:"Send a message to get started",emptyState:"No messages yet",emptyStateDescription:"Start a conversation by typing a message below",you:"You",assistant:"Assistant",tool:"Tool",thinking:"thinking...",typeMessage:"Type a message...",attachFile:"Attach file",sendMessage:"Send message",abort:"Abort",retry:"Retry",reasoning:"Reasoning",thinkingLevelNone:"None",thinkingLevel1:"Level 1",thinkingLevel2:"Level 2",thinkingLevel3:"Level 3",thinkingLevel4:"Level 4",connecting:"Connecting...",disconnected:"Disconnected",connectionError:"Connection error",reconnecting:"Reconnecting...",online:"Online",offline:"Offline"},rs={title:"Settings",save:"Save",cancel:"Cancel",close:"Close",loading:"Loading settings...",unsaved:"{{count}} unsaved",saveChanges:"Save Changes",saving:"Saving...",noSection:"No section selected",enableFeature:"Enable this feature",required:"{{field}} is required",invalidFormat:"Invalid format",unsavedChanges:"Unsaved changes",sections:{agent:"Agent",providers:"Providers",channels:"Channels",gateway:"Gateway"},descriptions:{agent:"Configure your agent settings",providers:"Configure your provider API keys",channels:"Configure messaging channels",gateway:"Configure gateway settings"},fields:{model:"Model",workspace:"Workspace",maxTokens:"Max Tokens",temperature:"Temperature",maxToolIterations:"Max Tool Iterations",openaiApiKey:"OpenAI API Key",anthropicApiKey:"Anthropic API Key",googleApiKey:"Google API Key",qwenApiKey:"Qwen API Key",kimiApiKey:"Kimi API Key",minimaxApiKey:"MiniMax API Key",deepseekApiKey:"DeepSeek API Key",grokApiKey:"Grok API Key",openrouterApiKey:"OpenRouter API Key",telegramEnabled:"Telegram",telegramToken:"Telegram Token",telegramApiRoot:"API Root (Optional)",telegramAllowFrom:"Allow From (Optional)",telegramDebug:"Debug Mode",whatsappEnabled:"WhatsApp",whatsappBridgeUrl:"Bridge URL",whatsappAllowFrom:"Allow From (Optional)",heartbeatEnabled:"Heartbeat",heartbeatIntervalMs:"Heartbeat Interval (ms)",gatewayToken:"Gateway Token"},descriptionsFields:{model:"Default AI model to use",workspace:"Working directory for agent files",maxTokens:"Maximum tokens in response",temperature:"Randomness in responses (0-2)",maxToolIterations:"Maximum tool calls per message",openaiApiKey:"API key for OpenAI models",anthropicApiKey:"API key for Claude models",googleApiKey:"API key for Gemini models",qwenApiKey:"API key for Qwen models",kimiApiKey:"API key for Kimi models",minimaxApiKey:"API key for MiniMax models",deepseekApiKey:"API key for DeepSeek models",grokApiKey:"API key for Grok models",openrouterApiKey:"API key for OpenRouter models",telegramEnabled:"Enable Telegram bot",telegramToken:"Bot API token from @BotFather",telegramApiRoot:"Custom Telegram API root URL",telegramAllowFrom:"Allowed user IDs, comma separated",telegramDebug:"Enable debug logging for Telegram",whatsappEnabled:"Enable WhatsApp bridge",whatsappBridgeUrl:"WhatsApp bridge WebSocket URL",whatsappAllowFrom:"Allowed phone numbers, comma separated",heartbeatEnabled:"Enable heartbeat monitoring",heartbeatIntervalMs:"Heartbeat check interval in milliseconds",gatewayToken:"Authentication token for gateway API access"},placeholders:{workspace:"~/.xopcbot/workspace",openaiApiKey:"sk-...",anthropicApiKey:"sk-ant-...",googleApiKey:"AIzaSy...",qwenApiKey:"sk-...",kimiApiKey:"sk-kimi-...",minimaxApiKey:"sk-cp-...",deepseekApiKey:"sk-...",openrouterApiKey:"sk-or-...",telegramToken:"1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",telegramApiRoot:"https://api.telegram.org",telegramAllowFrom:"123456789, 987654321",whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"+1234567890, +0987654321",gatewayToken:"Enter your gateway authentication token"},connection:{title:"Connection",gatewayUrl:"Gateway URL",gatewayUrlDesc:"WebSocket URL for the gateway server",authToken:"Auth Token",authTokenDesc:"Optional authentication token"},appearance:{title:"Appearance",theme:"Theme",themeDesc:"Choose your preferred color scheme",themeSystem:"System",themeLight:"Light",themeDark:"Dark"},chat:{title:"Chat",enableAttachments:"Enable Attachments",enableAttachmentsDesc:"Allow file attachments in chat",showModelSelector:"Show Model Selector",showModelSelectorDesc:"Display model selection dropdown",showThinkingSelector:"Show Thinking Selector",showThinkingSelectorDesc:"Display thinking level selection"}},ls={noSession:"No session available",noAgent:"No agent set",noModel:"No model set",requestTimeout:"Request timeout",sendFailed:"Failed to send message",invalidFileType:"Invalid file type",fileTooLarge:"File too large (max {{size}})",readFileFailed:"Failed to read file"},cs={dropHere:"Drop files here",dragDrop:"Drag and drop files here",image:"Image",document:"Document",pdf:"PDF",word:"Word",excel:"Excel",powerpoint:"PowerPoint",text:"Text",code:"Code",archive:"Archive",unknown:"Unknown"},hs={settings:"Open settings"},ds={title:"Configuration",save:"Save Configuration",noResult:"No result",artifacts:"Artifacts",showArtifacts:"Show artifacts"},ps={title:"Logs",refresh:"Refresh",clear:"Clear",totalLogs:"Total Logs",pause:"Pause",autoRefresh:"Auto Refresh",level:"Level",search:"Search",searchPlaceholder:"Search logs...",time:"Time",message:"Message",module:"Module",noLogs:"No logs found",noLogsDescription:"Try adjusting your filters or check back later.",details:"Log Details"},us={title:"Sessions",newSession:"New Session",searchPlaceholder:"Search sessions...",totalSessions:"Total Sessions",activeSessions:"Active Sessions",pinnedSessions:"Pinned Sessions",archivedSessions:"Archived Sessions",noSessions:"No sessions",delete:"Delete",archive:"Archive",pin:"Pin",unpin:"Unpin",confirmDelete:"Are you sure you want to delete this session?"},gs={title:"Cron Jobs",addJob:"Add Cron Job",editJob:"Edit Job",name:"Name (optional)",namePlaceholder:"My scheduled task",schedule:"Schedule (cron expression) *",scheduleHint:"e.g., */5 * * * * (every 5 minutes), 0 9 * * * (daily at 9am)",message:"Message *",messagePlaceholder:"What should the assistant do?",create:"Create Job",runNow:"Run Now",delete:"Delete",edit:"Edit",enable:"Enable",disable:"Disable",enabled:"Enabled",disabled:"Disabled",running:"Running",lastRun:"Last Run",nextRun:"Next Run",status:"Status",history:"History",actions:"Actions",noJobs:"No cron jobs",confirmDelete:"Are you sure you want to delete this cron job?",confirmRun:"Run this cron job now?",success:"Success",failed:"Failed",scheduleLabel:"Schedule",messageLabel:"Message",confirm:"Confirm",cancel:"Cancel",total:"Total",schedulePresets:{custom:"-- Custom (enter below) --",everyMinute:"Every minute",every5Minutes:"Every 5 minutes (default)",every10Minutes:"Every 10 minutes",every15Minutes:"Every 15 minutes",every30Minutes:"Every 30 minutes",everyHour:"Every hour",every2Hours:"Every 2 hours",every4Hours:"Every 4 hours",every6Hours:"Every 6 hours",every12Hours:"Every 12 hours",everyDayMidnight:"Every day at midnight",everyDay9AM:"Every day at 9:00 AM",everyDay9PM:"Every day at 9:00 PM"},scheduleHintPreset:"Select a preset or enter custom cron expression",mode:"Mode",modeDirect:"Send message directly to the channel without AI processing",modeAgent:"Use AI agent to process the message, then send the response",modeDirectOption:"Direct (send message directly)",modeAgentOption:"AI Agent (process with AI then send)",model:"Model",noConfiguredModels:"No configured models",save:"Save",failedToLoadJobs:"Failed to load jobs",scheduleRequired:"Schedule and message are required",chatIdRequired:"Chat ID is required",failedToJob:"Failed to {{mode}} job",failedToToggleJob:"Failed to toggle job",actionFailed:"Action failed",enterManuallyOrSelect:"Enter manually or select from recent chats",noRecentChats:"No recent chats found. Enter chat ID manually (e.g., 123456789 for Telegram)",timeLabels:{lessThanMinute:"Less than a minute",minutes:"{{count}} min",hours:"{{count}} hours",overdue:"Overdue"},lastActiveLabels:{justNow:"just now",minutesAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",daysAgo:"{{count}}d ago"}},_s={save:"Save",cancel:"Cancel",confirm:"Confirm",close:"Close",loading:"Loading...",error:"Error",success:"Success",noData:"No data"},ms={app:ns,nav:os,chat:as,settings:rs,errors:ls,fileUpload:cs,shortcuts:hs,config:ds,logs:ps,sessions:us,cron:gs,common:_s},vs={title:"XOPCBOT 网关",brand:"XOPCBOT"},fs={chat:"对话",sessions:"会话",cron:"定时任务",logs:"日志",settings:"设置",management:"管理"},ys={title:"XopcBot",newSession:"新建对话",welcomeTitle:"欢迎使用 xopcbot",welcomeDescription:"发送消息开始对话",emptyState:"暂无消息",emptyStateDescription:"在下方输入消息开始对话",you:"你",assistant:"助手",tool:"工具",thinking:"思考中...",typeMessage:"输入消息...",attachFile:"附加文件",sendMessage:"发送消息",abort:"中止",retry:"重试",reasoning:"推理",thinkingLevelNone:"无",thinkingLevel1:"级别 1",thinkingLevel2:"级别 2",thinkingLevel3:"级别 3",thinkingLevel4:"级别 4",connecting:"连接中...",disconnected:"已断开",connectionError:"连接错误",reconnecting:"重新连接中...",online:"在线",offline:"离线"},ws={title:"设置",save:"保存",cancel:"取消",close:"关闭",loading:"加载设置中...",unsaved:"{{count}} 个未保存",saveChanges:"保存更改",saving:"保存中...",noSection:"未选择部分",enableFeature:"启用此功能",required:"{{field}} 为必填项",invalidFormat:"格式无效",unsavedChanges:"未保存的更改",sections:{agent:"代理",providers:"提供商",channels:"渠道",gateway:"网关"},descriptions:{agent:"配置代理设置",providers:"配置提供商 API 密钥",channels:"配置消息渠道",gateway:"配置网关设置"},fields:{model:"模型",workspace:"工作区",maxTokens:"最大 Token 数",temperature:"温度",maxToolIterations:"最大工具调用次数",openaiApiKey:"OpenAI API 密钥",anthropicApiKey:"Anthropic API 密钥",googleApiKey:"Google API 密钥",qwenApiKey:"Qwen API 密钥",kimiApiKey:"Kimi API 密钥",minimaxApiKey:"MiniMax API 密钥",deepseekApiKey:"DeepSeek API 密钥",grokApiKey:"Grok API 密钥",openrouterApiKey:"OpenRouter API 密钥",telegramEnabled:"Telegram",telegramToken:"Telegram 令牌",telegramApiRoot:"API 根地址(可选)",telegramAllowFrom:"允许来源(可选)",telegramDebug:"调试模式",whatsappEnabled:"WhatsApp",whatsappBridgeUrl:"桥接地址",whatsappAllowFrom:"允许来源(可选)",heartbeatEnabled:"心跳",heartbeatIntervalMs:"心跳间隔(毫秒)",gatewayToken:"网关令牌"},descriptionsFields:{model:"默认使用的 AI 模型",workspace:"代理文件的工作目录",maxTokens:"响应中的最大 token 数",temperature:"响应随机性(0-2)",maxToolIterations:"每条消息的最大工具调用次数",openaiApiKey:"OpenAI 模型的 API 密钥",anthropicApiKey:"Claude 模型的 API 密钥",googleApiKey:"Gemini 模型的 API 密钥",qwenApiKey:"Qwen 模型的 API 密钥",kimiApiKey:"Kimi 模型的 API 密钥",minimaxApiKey:"MiniMax 模型的 API 密钥",deepseekApiKey:"DeepSeek 模型的 API 密钥",grokApiKey:"Grok 模型的 API 密钥",openrouterApiKey:"OpenRouter 模型的 API 密钥",telegramEnabled:"启用 Telegram 机器人",telegramToken:"@BotFather 获取的机器人 API 令牌",telegramApiRoot:"自定义 Telegram API 根地址",telegramAllowFrom:"允许的用户 ID,逗号分隔",telegramDebug:"启用 Telegram 调试日志",whatsappEnabled:"启用 WhatsApp 桥接",whatsappBridgeUrl:"WhatsApp 桥接 WebSocket 地址",whatsappAllowFrom:"允许的电话号码,逗号分隔",heartbeatEnabled:"启用心跳监控",heartbeatIntervalMs:"心跳检查间隔(毫秒)",gatewayToken:"网关 API 访问认证令牌"},placeholders:{workspace:"~/.xopcbot/workspace",openaiApiKey:"sk-...",anthropicApiKey:"sk-ant-...",googleApiKey:"AIzaSy...",qwenApiKey:"sk-...",kimiApiKey:"sk-kimi-...",minimaxApiKey:"sk-cp-...",deepseekApiKey:"sk-...",openrouterApiKey:"sk-or-...",telegramToken:"1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",telegramApiRoot:"https://api.telegram.org",telegramAllowFrom:"123456789, 987654321",whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"+1234567890, +0987654321",gatewayToken:"输入网关认证令牌"},connection:{title:"连接",gatewayUrl:"网关地址",gatewayUrlDesc:"网关服务器的 WebSocket 地址",authToken:"认证令牌",authTokenDesc:"可选的认证令牌"},appearance:{title:"外观",theme:"主题",themeDesc:"选择你喜欢的配色方案",themeSystem:"跟随系统",themeLight:"浅色",themeDark:"深色"},chat:{title:"对话",enableAttachments:"启用附件",enableAttachmentsDesc:"允许在对话中附加文件",showModelSelector:"显示模型选择器",showModelSelectorDesc:"显示模型选择下拉框",showThinkingSelector:"显示思考选择器",showThinkingSelectorDesc:"显示思考级别选择"}},bs={noSession:"无可用会话",noAgent:"未设置代理",noModel:"未设置模型",requestTimeout:"请求超时",sendFailed:"发送消息失败",invalidFileType:"无效的文件类型",fileTooLarge:"文件过大(最大 {{size}})",readFileFailed:"读取文件失败"},$s={dropHere:"拖放文件到此处",dragDrop:"拖放文件到此处",image:"图片",document:"文档",pdf:"PDF",word:"Word",excel:"Excel",powerpoint:"PowerPoint",text:"文本",code:"代码",archive:"压缩包",unknown:"未知"},ks={settings:"打开设置"},xs={title:"配置",save:"保存配置",noResult:"无结果",artifacts:"产物",showArtifacts:"显示产物"},Ss={title:"日志",refresh:"刷新",clear:"清空",totalLogs:"总日志数",pause:"暂停",autoRefresh:"自动刷新",level:"级别",search:"搜索",searchPlaceholder:"搜索日志...",time:"时间",message:"消息",module:"模块",noLogs:"暂无日志",noLogsDescription:"尝试调整筛选条件或稍后再查看。",details:"日志详情"},As={title:"会话",newSession:"新建会话",searchPlaceholder:"搜索会话...",totalSessions:"总会话数",activeSessions:"活跃会话",pinnedSessions:"固定会话",archivedSessions:"归档会话",noSessions:"暂无会话",delete:"删除",archive:"归档",pin:"固定",unpin:"取消固定",confirmDelete:"确定要删除此会话吗?"},Cs={title:"定时任务",addJob:"添加定时任务",editJob:"编辑任务",name:"名称(可选)",namePlaceholder:"我的定时任务",schedule:"计划表达式 *",scheduleHint:"例如:*/5 * * * *(每5分钟),0 9 * * *(每天9点)",message:"消息 *",messagePlaceholder:"助手应该做什么?",create:"创建任务",runNow:"立即执行",delete:"删除",edit:"编辑",enable:"启用",disable:"禁用",enabled:"已启用",disabled:"已禁用",running:"运行中",lastRun:"上次执行",nextRun:"下次执行",status:"状态",history:"历史记录",actions:"操作",noJobs:"暂无定时任务",confirmDelete:"确定要删除此定时任务吗?",confirmRun:"立即执行此定时任务?",success:"成功",failed:"失败",scheduleLabel:"计划",messageLabel:"消息",confirm:"确认",cancel:"取消",total:"总计",schedulePresets:{custom:"-- 自定义(在下方输入) --",everyMinute:"每分钟",every5Minutes:"每 5 分钟(默认)",every10Minutes:"每 10 分钟",every15Minutes:"每 15 分钟",every30Minutes:"每 30 分钟",everyHour:"每小时",every2Hours:"每 2 小时",every4Hours:"每 4 小时",every6Hours:"每 6 小时",every12Hours:"每 12 小时",everyDayMidnight:"每天午夜",everyDay9AM:"每天早上 9 点",everyDay9PM:"每天晚上 9 点"},scheduleHintPreset:"选择预设或输入自定义 cron 表达式",mode:"模式",modeDirect:"直接发送消息到渠道,不经过 AI 处理",modeAgent:"使用 AI 代理处理消息,然后发送回复",modeDirectOption:"直接发送(直接发送到渠道)",modeAgentOption:"AI 代理(经过 AI 处理后发送)",model:"模型",noConfiguredModels:"未配置模型",save:"保存",failedToLoadJobs:"加载任务失败",scheduleRequired:"计划表达式和消息为必填项",chatIdRequired:"Chat ID 为必填项",failedToJob:"{{mode}} 任务失败",failedToToggleJob:"切换任务状态失败",actionFailed:"操作失败",enterManuallyOrSelect:"手动输入或从最近聊天中选择",noRecentChats:"未找到最近聊天。请手动输入 chat ID(例如:Telegram 为 123456789)",timeLabels:{lessThanMinute:"不到 1 分钟",minutes:"{{count}} 分钟",hours:"{{count}} 小时",overdue:"已过期"},lastActiveLabels:{justNow:"刚刚",minutesAgo:"{{count}} 分钟前",hoursAgo:"{{count}} 小时前",daysAgo:"{{count}} 天前"}},Ts={save:"保存",cancel:"取消",confirm:"确认",close:"关闭",loading:"加载中...",error:"错误",success:"成功",noData:"暂无数据"},Ms={app:vs,nav:fs,chat:ys,settings:ws,errors:bs,fileUpload:$s,shortcuts:ks,config:xs,logs:Ss,sessions:As,cron:Cs,common:Ts},mt={en:ms,zh:Ms},K=new Map;K.set("en",mt.en);K.set("zh",mt.zh);let J="en";function r(e,t){const s=K.get(J);if(!s)return e;const i=e.split(".");let n=s;for(const a of i)if(n&&typeof n=="object"&&a in n)n=n[a];else{const l=K.get("en");if(l&&J!=="en"){let h=l;for(const p of i)if(h&&typeof h=="object"&&p in h)h=h[p];else return e;n=h}else return e}return typeof n!="string"?e:t?n.replace(/\{\{(\w+)\}\}/g,(a,l)=>{const h=t[l];return h!==void 0?String(h):`{{${l}}}`}):n}async function Es(e){if(K.has(e)){J=e;return}try{const t=await fetch(`/src/i18n/${e}.json`);if(!t.ok)throw new Error(`Failed to load ${e} translations`);const s=await t.json();K.set(e,s),J=e,window.dispatchEvent(new CustomEvent("languagechange",{detail:{language:e}}))}catch(t){console.error(`Failed to load ${e} translations:`,t),e!=="en"&&K.has("en")&&(J="en")}}function nt(e){K.has(e)?(J=e,window.dispatchEvent(new CustomEvent("languagechange",{detail:{language:e}}))):Es(e)}function Ps(e="en"){J=e}const Fs={"Type a message...":"chat.typeMessage","Attach file":"chat.attachFile","Send message":"chat.sendMessage",Abort:"chat.abort","No session available":"errors.noSession","No agent set":"errors.noAgent",Configuration:"config.title",Cancel:"settings.cancel",Save:"settings.save","No result":"config.noResult",Artifacts:"config.artifacts","Show artifacts":"config.showArtifacts"};function ie(e){const t=Fs[e];return r(t||e)}var Ls=Object.defineProperty,Ds=Object.getOwnPropertyDescriptor,M=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ds(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ls(t,s,n),n};function de(e,t=""){if(!e||!Array.isArray(e))return"";const[s,i,n]=e,a=Object.entries(i||{}).map(([p,g])=>`${p}="${g}"`).join(" "),l=Array.isArray(n)?n.map(p=>{if(Array.isArray(p)){const[g,S]=p,f=Object.entries(S||{}).map(([F,I])=>`${F}="${I}"`).join(" ");return`<${g} ${f} />`}return""}).join(""):"";return`<svg ${t?`${a} class="${t}"`:a}>${l}</svg>`}let T=class extends y{constructor(){super(...arguments),this.value="",this.attachments=[],this.isStreaming=!1,this.showAttachmentButton=!0,this.showModelSelector=!0,this._isComposing=!1,this._isDragging=!1,this._processingFiles=!1,this._isSending=!1,this.textareaRef=st(),this.fileInputRef=st(),this.maxFileSize=20*1024*1024,this.acceptedTypes="image/*,application/pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml,.zip",this._handleDocumentDragOver=e=>{e.dataTransfer?.types.includes("Files")&&(e.preventDefault(),this._isDragging=!0)},this._handleDocumentDragLeave=e=>{e.relatedTarget===null&&(this._isDragging=!1)},this._handleDocumentDrop=async e=>{e.preventDefault(),this._isDragging=!1;const t=e.dataTransfer?.files;t&&t.length>0&&await this._processFiles(Array.from(t))},this._handleInput=e=>{const t=e.target;this.value=t.value,this._adjustTextareaHeight()},this._handleKeydown=e=>{e.key==="Enter"&&!e.shiftKey&&!this._isComposing&&(e.preventDefault(),this._send())},this._handlePaste=async e=>{const t=e.clipboardData?.items;if(!t)return;const s=[];for(const i of Array.from(t))if(i.type.startsWith("image/")){const n=i.getAsFile();n&&s.push(n)}s.length>0&&(e.preventDefault(),await this._processFiles(s))},this._handleFileInputChange=async e=>{const t=e.target,s=t.files;s&&(await this._processFiles(Array.from(s)),t.value="")}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),document.addEventListener("dragover",this._handleDocumentDragOver),document.addEventListener("drop",this._handleDocumentDrop),document.addEventListener("dragleave",this._handleDocumentDragLeave),document.addEventListener("click",this._handleOutsideClick)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("dragover",this._handleDocumentDragOver),document.removeEventListener("drop",this._handleDocumentDrop),document.removeEventListener("dragleave",this._handleDocumentDragLeave),document.removeEventListener("click",this._handleOutsideClick)}render(){return o`
4
- <div class="editor-container">
5
- ${this.attachments.length>0?this._renderAttachments():""}
6
-
7
- <div class="input-row ${this._isDragging?"dragging":""}">
8
- ${this.showAttachmentButton?this._renderAttachmentButton():""}
9
-
10
- <textarea
11
- ${it(this.textareaRef)}
12
- class="text-input"
13
- placeholder=${ie("Type a message...")}
14
- .value=${this.value}
15
- @input=${this._handleInput}
16
- @keydown=${this._handleKeydown}
17
- @compositionstart=${()=>this._isComposing=!0}
18
- @compositionend=${()=>this._isComposing=!1}
19
- @paste=${this._handlePaste}
20
- rows="1"
21
- ></textarea>
22
-
23
- <div class="input-actions">
24
- ${this._renderSendButton()}
25
- </div>
26
- </div>
27
-
28
- ${this._isDragging?this._renderDropOverlay():""}
29
- </div>
30
- `}_renderAttachments(){return o`
31
- <div class="attachments-row">
32
- ${this.attachments.map((e,t)=>o`
33
- <div class="attachment-chip">
34
- <div class="attachment-preview">
35
- ${e.mimeType.startsWith("image/")?o`
36
- <img src="${e.content}" alt="${e.name}" />
37
- `:o`
38
- ${he(de(FileText,"w-4 h-4"))}
39
- `}
40
- </div>
41
- <span class="attachment-name">${e.name}</span>
42
- <button type="button" class="attachment-remove" @click=${()=>this._removeAttachment(t)}>
43
- ${he(de(is,"w-3 h-3"))}
44
- </button>
45
- </div>
46
- `)}
47
- </div>
48
- `}_renderAttachmentButton(){return o`
49
- <button type="button" class="attach-btn" @click=${()=>this._triggerFileSelect("all")} title=${ie("Attach file")}>
50
- ${he(de(es,"w-4 h-4"))}
51
- </button>
52
-
53
- <input
54
- ${it(this.fileInputRef)}
55
- type="file"
56
- multiple
57
- accept=${this.acceptedTypes}
58
- class="hidden"
59
- @change=${this._handleFileInputChange}
60
- />
61
- `}_renderSendButton(){const e=this.value.trim()||this.attachments.length>0;return this.isStreaming?o`
62
- <button type="button" class="stop-btn" @click=${()=>this.onAbort?.()} title=${ie("Abort")}>
63
- ${he(de(ss,"w-4 h-4"))}
64
- </button>
65
- `:o`
66
- <button
67
- type="button"
68
- class="send-btn ${e?"active":""}"
69
- ?disabled=${!e}
70
- @click=${this._send}
71
- title=${ie("Send message")}
72
- >
73
- ${he(de(ts,"w-4 h-4"))}
74
- </button>
75
- `}_renderDropOverlay(){return o`
76
- <div class="drop-overlay">
77
- <span>Drop files here to attach</span>
78
- </div>
79
- `}_triggerFileSelect(e){let t=this.fileInputRef.value;if(t||(t=this.querySelector('input[type="file"]')),!t){console.warn("File input not found");return}e==="image"?t.accept="image/*":e==="document"?t.accept=".pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml,.zip":t.accept=this.acceptedTypes,t.click()}_adjustTextareaHeight(){const e=this.textareaRef.value;e&&(e.style.height="auto",e.style.height=Math.min(e.scrollHeight,200)+"px")}_send(){if(this._isSending||this.isStreaming||!this.value.trim()&&this.attachments.length===0)return;this._isSending=!0;const e=[...this.attachments];this.onSend?.(this.value,e),this.value="",this.attachments=[],requestAnimationFrame(()=>{this._adjustTextareaHeight(),setTimeout(()=>{this._isSending=!1},500)})}async _processFiles(e){this._processingFiles=!0;try{for(const t of e){if(t.size>this.maxFileSize){console.warn(`File ${t.name} exceeds max size of ${this.maxFileSize} bytes`);continue}const s=await this._loadAttachment(t);this.attachments=[...this.attachments,s]}}finally{this._processingFiles=!1}}async _loadAttachment(e){const t=await this._readFileAsBase64(e),s=e.type.startsWith("image/");return{id:crypto.randomUUID(),name:e.name,type:s?"image":"document",mimeType:e.type,size:e.size,content:t}}_readFileAsBase64(e){return new Promise((t,s)=>{const i=new FileReader;i.onload=()=>t(i.result),i.onerror=()=>s(i.error),i.readAsDataURL(e)})}_removeAttachment(e){this.attachments=this.attachments.filter((t,s)=>s!==e)}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}};M([oe("textarea")],T.prototype,"textarea",2);M([u({type:String})],T.prototype,"value",2);M([u({type:Array})],T.prototype,"attachments",2);M([u({type:Boolean})],T.prototype,"isStreaming",2);M([u({type:Boolean})],T.prototype,"showAttachmentButton",2);M([u({type:Boolean})],T.prototype,"showModelSelector",2);M([u({attribute:!1})],T.prototype,"currentModel",2);M([u({attribute:!1})],T.prototype,"onSend",2);M([u({attribute:!1})],T.prototype,"onAbort",2);M([u({attribute:!1})],T.prototype,"onModelSelect",2);M([c()],T.prototype,"_isComposing",2);M([c()],T.prototype,"_isDragging",2);M([c()],T.prototype,"_processingFiles",2);M([c()],T.prototype,"_isSending",2);T=M([k("message-editor")],T);function d(e){return Ie[e]||Ie.helpCircle}const Ie={messageSquare:o`
80
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
81
- <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
82
- </svg>
83
- `,settings:o`
84
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
85
- <circle cx="12" cy="12" r="3"></circle>
86
- <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
87
- </svg>
88
- `,menu:o`
89
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
90
- <line x1="3" y1="12" x2="21" y2="12"></line>
91
- <line x1="3" y1="6" x2="21" y2="6"></line>
92
- <line x1="3" y1="18" x2="21" y2="18"></line>
93
- </svg>
94
- `,chevronDown:o`
95
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
96
- <polyline points="6 9 12 15 18 9"></polyline>
97
- </svg>
98
- `,sun:o`
99
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
100
- <circle cx="12" cy="12" r="5"></circle>
101
- <line x1="12" y1="1" x2="12" y2="3"></line>
102
- <line x1="12" y1="21" x2="12" y2="23"></line>
103
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
104
- <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
105
- <line x1="1" y1="12" x2="3" y2="12"></line>
106
- <line x1="21" y1="12" x2="23" y2="12"></line>
107
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
108
- <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
109
- </svg>
110
- `,moon:o`
111
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
112
- <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
113
- </svg>
114
- `,monitor:o`
115
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
116
- <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
117
- <line x1="8" y1="21" x2="16" y2="21"></line>
118
- <line x1="12" y1="17" x2="12" y2="21"></line>
119
- </svg>
120
- `,send:o`
121
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
122
- <line x1="22" y1="2" x2="11" y2="13"></line>
123
- <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
124
- </svg>
125
- `,paperclip:o`
126
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
127
- <path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path>
128
- </svg>
129
- `,x:o`
130
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
131
- <line x1="18" y1="6" x2="6" y2="18"></line>
132
- <line x1="6" y1="6" x2="18" y2="18"></line>
133
- </svg>
134
- `,fileText:o`
135
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
136
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
137
- <polyline points="14 2 14 8 20 8"></polyline>
138
- <line x1="16" y1="13" x2="8" y2="13"></line>
139
- <line x1="16" y1="17" x2="8" y2="17"></line>
140
- <polyline points="10 9 9 9 8 9"></polyline>
141
- </svg>
142
- `,image:o`
143
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
144
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
145
- <circle cx="8.5" cy="8.5" r="1.5"></circle>
146
- <polyline points="21 15 16 10 5 21"></polyline>
147
- </svg>
148
- `,file:o`
149
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
150
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
151
- <polyline points="14 2 14 8 20 8"></polyline>
152
- </svg>
153
- `,plug:o`
154
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
155
- <path d="M12 22v-5"></path>
156
- <path d="M15 8V2"></path>
157
- <path d="M9 8V2"></path>
158
- <path d="M15 8a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3v-5a3 3 0 0 1 3-3h6z"></path>
159
- </svg>
160
- `,palette:o`
161
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
162
- <circle cx="13.5" cy="6.5" r=".5"></circle>
163
- <circle cx="17.5" cy="10.5" r=".5"></circle>
164
- <circle cx="8.5" cy="7.5" r=".5"></circle>
165
- <circle cx="6.5" cy="12.5" r=".5"></circle>
166
- <path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.01 17.461 2 12 2z"></path>
167
- </svg>
168
- `,alertCircle:o`
169
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
170
- <circle cx="12" cy="12" r="10"></circle>
171
- <line x1="12" y1="8" x2="12" y2="12"></line>
172
- <line x1="12" y1="16" x2="12.01" y2="16"></line>
173
- </svg>
174
- `,check:o`
175
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
176
- <polyline points="20 6 9 17 4 12"></polyline>
177
- </svg>
178
- `,chevronRight:o`
179
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
180
- <polyline points="9 18 15 12 9 6"></polyline>
181
- </svg>
182
- `,arrowLeft:o`
183
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
184
- <line x1="19" y1="12" x2="5" y2="12"></line>
185
- <polyline points="12 19 5 12 12 5"></polyline>
186
- </svg>
187
- `,bot:o`
188
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
189
- <rect x="3" y="11" width="18" height="10" rx="2"></rect>
190
- <circle cx="12" cy="5" r="2"></circle>
191
- <path d="M12 7v4"></path>
192
- <line x1="8" y1="16" x2="8" y2="16.01"></line>
193
- <line x1="16" y1="16" x2="16" y2="16.01"></line>
194
- </svg>
195
- `,helpCircle:o`
196
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
197
- <circle cx="12" cy="12" r="10"></circle>
198
- <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
199
- <line x1="12" y1="17" x2="12.01" y2="17"></line>
200
- </svg>
201
- `,rotateCcw:o`
202
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
203
- <polyline points="1 4 1 10 7 10"></polyline>
204
- <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path>
205
- </svg>
206
- `,square:o`
207
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
208
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
209
- </svg>
210
- `,moreHorizontal:o`
211
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
212
- <circle cx="12" cy="12" r="1"></circle>
213
- <circle cx="19" cy="12" r="1"></circle>
214
- <circle cx="5" cy="12" r="1"></circle>
215
- </svg>
216
- `,copy:o`
217
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
218
- <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
219
- <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
220
- </svg>
221
- `,download:o`
222
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
223
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
224
- <polyline points="7 10 12 15 17 10"></polyline>
225
- <line x1="12" y1="15" x2="12" y2="3"></line>
226
- </svg>
227
- `,folderOpen:o`
228
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
229
- <path d="M6 17h12a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3.5"></path>
230
- <path d="M2 17V5a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v1"></path>
231
- </svg>
232
- `,phone:o`
233
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
234
- <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
235
- </svg>
236
- `,globe:o`
237
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
238
- <circle cx="12" cy="12" r="10"></circle>
239
- <line x1="2" y1="12" x2="22" y2="12"></line>
240
- <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
241
- </svg>
242
- `,terminal:o`
243
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
244
- <polyline points="4 17 10 11 4 5"></polyline>
245
- <line x1="12" y1="19" x2="20" y2="19"></line>
246
- </svg>
247
- `,zap:o`
248
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
249
- <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>
250
- </svg>
251
- `,pin:o`
252
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
253
- <line x1="12" y1="17" x2="12" y2="22"></line>
254
- <path d="M5 17h14v-3a2 2 0 0 0-2-2h-3.5"></path>
255
- <path d="M5 12V7a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v5"></path>
256
- <circle cx="12" cy="7" r="1"></circle>
257
- </svg>
258
- `,pinOff:o`
259
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
260
- <line x1="2" y1="2" x2="22" y2="22"></line>
261
- <line x1="12" y1="17" x2="12" y2="22"></line>
262
- <path d="M5 17h14v-3a2 2 0 0 0-2-2h-3.5"></path>
263
- <path d="M5 12V7a2 2 0 0 1 2-2h1"></path>
264
- </svg>
265
- `,archive:o`
266
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
267
- <polyline points="21 8 21 21 3 21 3 8"></polyline>
268
- <rect x="1" y="3" width="22" height="5"></rect>
269
- <line x1="10" y1="12" x2="14" y2="12"></line>
270
- </svg>
271
- `,archiveRestore:o`
272
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
273
- <polyline points="21 8 21 21 3 21 3 8"></polyline>
274
- <rect x="1" y="3" width="22" height="5"></rect>
275
- <polyline points="10 12 14 12 14 8"></polyline>
276
- </svg>
277
- `,trash:o`
278
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
279
- <polyline points="3 6 5 6 21 6"></polyline>
280
- <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
281
- </svg>
282
- `,grid:o`
283
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
284
- <rect x="3" y="3" width="7" height="7"></rect>
285
- <rect x="14" y="3" width="7" height="7"></rect>
286
- <rect x="14" y="14" width="7" height="7"></rect>
287
- <rect x="3" y="14" width="7" height="7"></rect>
288
- </svg>
289
- `,list:o`
290
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
291
- <line x1="8" y1="6" x2="21" y2="6"></line>
292
- <line x1="8" y1="12" x2="21" y2="12"></line>
293
- <line x1="8" y1="18" x2="21" y2="18"></line>
294
- <line x1="3" y1="6" x2="3.01" y2="6"></line>
295
- <line x1="3" y1="12" x2="3.01" y2="12"></line>
296
- <line x1="3" y1="18" x2="3.01" y2="18"></line>
297
- </svg>
298
- `,layers:o`
299
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
300
- <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
301
- <polyline points="2 17 12 22 22 17"></polyline>
302
- <polyline points="2 12 12 17 22 12"></polyline>
303
- </svg>
304
- `,circle:o`
305
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
306
- <circle cx="12" cy="12" r="10"></circle>
307
- </svg>
308
- `,search:o`
309
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
310
- <circle cx="11" cy="11" r="8"></circle>
311
- <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
312
- </svg>
313
- `,chevronUp:o`
314
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
315
- <polyline points="18 15 12 9 6 15"></polyline>
316
- </svg>
317
- `,alertTriangle:o`
318
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
319
- <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
320
- <line x1="12" y1="9" x2="12" y2="13"></line>
321
- <line x1="12" y1="17" x2="12.01" y2="17"></line>
322
- </svg>
323
- `,info:o`
324
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
325
- <circle cx="12" cy="12" r="10"></circle>
326
- <line x1="12" y1="16" x2="12" y2="12"></line>
327
- <line x1="12" y1="8" x2="12.01" y2="8"></line>
328
- </svg>
329
- `,folder:o`
330
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
331
- <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
332
- </svg>
333
- `,clock:o`
334
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
335
- <circle cx="12" cy="12" r="10"></circle>
336
- <polyline points="12 6 12 12 16 14"></polyline>
337
- </svg>
338
- `,plus:o`
339
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
340
- <line x1="12" y1="5" x2="12" y2="19"></line>
341
- <line x1="5" y1="12" x2="19" y2="12"></line>
342
- </svg>
343
- `,refresh:o`
344
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
345
- <polyline points="23 4 23 10 17 10"></polyline>
346
- <polyline points="1 20 1 14 7 14"></polyline>
347
- <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
348
- </svg>
349
- `,play:o`
350
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
351
- <polygon points="5 3 19 12 5 21 5 3"></polygon>
352
- </svg>
353
- `,edit:o`
354
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
355
- <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
356
- <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
357
- </svg>
358
- `,pause:o`
359
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
360
- <rect x="6" y="4" width="4" height="16"></rect>
361
- <rect x="14" y="4" width="4" height="16"></rect>
362
- </svg>
363
- `,refreshCw:o`
364
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
365
- <polyline points="23 4 23 10 17 10"></polyline>
366
- <polyline points="1 20 1 14 7 14"></polyline>
367
- <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
368
- </svg>
369
- `,checkCircle:o`
370
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
371
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
372
- <polyline points="22 4 12 14.01 9 11.01"></polyline>
373
- </svg>
374
- `,xCircle:o`
375
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
376
- <circle cx="12" cy="12" r="10"></circle>
377
- <line x1="15" y1="9" x2="9" y2="15"></line>
378
- <line x1="9" y1="9" x2="15" y2="15"></line>
379
- </svg>
380
- `,loader:o`
381
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
382
- <line x1="12" y1="2" x2="12" y2="6"></line>
383
- <line x1="12" y1="18" x2="12" y2="22"></line>
384
- <line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
385
- <line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
386
- <line x1="2" y1="12" x2="6" y2="12"></line>
387
- <line x1="18" y1="12" x2="22" y2="12"></line>
388
- <line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
389
- <line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
390
- </svg>
391
- `,slash:o`
392
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
393
- <circle cx="12" cy="12" r="10"></circle>
394
- <line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>
395
- </svg>
396
- `};function Is(e){return e.includes("pdf")?o`
397
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2">
398
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
399
- <polyline points="14,2 14,8 20,8"/>
400
- </svg>
401
- `:e.includes("word")||e.includes("document")?o`
402
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2">
403
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
404
- <polyline points="14,2 14,8 20,8"/>
405
- </svg>
406
- `:e.includes("sheet")||e.includes("excel")?o`
407
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2">
408
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
409
- <polyline points="14,2 14,8 20,8"/>
410
- </svg>
411
- `:e.includes("presentation")||e.includes("powerpoint")?o`
412
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2">
413
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
414
- <polyline points="14,2 14,8 20,8"/>
415
- </svg>
416
- `:Ie.file}var Os=Object.defineProperty,Rs=Object.getOwnPropertyDescriptor,vt=(e,t,s,i)=>{for(var n=i>1?void 0:i?Rs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Os(t,s,n),n};let Oe=class extends y{constructor(){super(...arguments),this.attachments=[]}createRenderRoot(){return this}render(){if(!this.attachments?.length)return null;const e=this.attachments.filter(s=>s.type==="image"||s.mimeType?.startsWith("image/")),t=this.attachments.filter(s=>s.type!=="image"&&!s.mimeType?.startsWith("image/"));return o`
417
- <div class="flex flex-col gap-2 mt-2">
418
- ${e.length>0?this._renderImageGallery(e):""}
419
- ${t.length>0?this._renderDocumentList(t):""}
420
- </div>
421
- `}_renderImageGallery(e){const t=e.length;let s="single";return t===2?s="double":t===3?s="triple":t>=4&&(s="quad"),o`
422
- <div class="image-gallery ${s}">
423
- ${e.map(i=>o`
424
- <img
425
- src="${i.data||i.content}"
426
- alt="${i.name||r("fileUpload.image")}"
427
- @click=${()=>this._handleImageClick(i)}
428
- />
429
- `)}
430
- </div>
431
- `}_renderDocumentList(e){return o`
432
- <div class="flex flex-col gap-2">
433
- ${e.map(t=>this._renderDocumentPreview(t))}
434
- </div>
435
- `}_renderDocumentPreview(e){const t=e.name||r("fileUpload.document"),s=e.size?this._formatFileSize(e.size):"";return o`
436
- <div class="document-preview" @click=${()=>this._handleDocumentClick(e)}>
437
- <div class="icon">${Is(e.mimeType||"")}</div>
438
- <div class="info">
439
- <div class="name">${t}</div>
440
- <div class="meta">${s||e.mimeType||r("fileUpload.unknown")}</div>
441
- </div>
442
- </div>
443
- `}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}_handleImageClick(e){this.dispatchEvent(new CustomEvent("image-click",{detail:e,bubbles:!0,composed:!0}))}_handleDocumentClick(e){this.dispatchEvent(new CustomEvent("document-click",{detail:e,bubbles:!0,composed:!0}))}};vt([u({attribute:!1})],Oe.prototype,"attachments",2);Oe=vt([k("attachment-renderer")],Oe);var Bs=Object.defineProperty,Ks=Object.getOwnPropertyDescriptor,ft=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ks(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Bs(t,s,n),n};let Re=class extends y{createRenderRoot(){return this}render(){if(!this.usage)return null;const e=[];return this.usage.totalTokens!==void 0?e.push(`${this.usage.totalTokens} tokens`):this.usage.inputTokens!==void 0&&this.usage.outputTokens!==void 0&&e.push(`${this.usage.inputTokens+this.usage.outputTokens} tokens`),this.usage.cost!==void 0&&this.usage.cost>0&&e.push(`$${this.usage.cost.toFixed(4)}`),e.length===0?null:o`
444
- <span class="usage-badge">
445
- ${e.join(" · ")}
446
- </span>
447
- `}};ft([u({attribute:!1})],Re.prototype,"usage",2);Re=ft([k("usage-badge")],Re);var js=Object.defineProperty,Us=Object.getOwnPropertyDescriptor,Ne=(e,t,s,i)=>{for(var n=i>1?void 0:i?Us(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&js(t,s,n),n};let Ae=class extends y{constructor(){super(...arguments),this.isStreaming=!1}createRenderRoot(){return this}render(){const e=this.message.role==="user"||this.message.role==="user-with-attachments",t=this.message.role==="assistant";this.message.role==="tool"||this.message.role;const s=r(e?"chat.you":t?"chat.assistant":"chat.tool"),i=s.charAt(0);return o`
448
- <div class="message-item ${e?"flex-row-reverse":""}">
449
- <div class="avatar ${e?"user":t?"assistant":"tool"}">
450
- ${i}
451
- </div>
452
-
453
- <div class="flex flex-col gap-1 max-w-[85%]">
454
- <div class="flex items-center gap-2 text-xs text-muted">
455
- <span class="font-medium">${s}</span>
456
- <span>·</span>
457
- <span>${this._formatTime(this.message.timestamp)}</span>
458
- ${this.isStreaming?o`<span class="text-primary animate-pulse">${r("chat.thinking")}</span>`:""}
459
- </div>
460
-
461
- <div class="message-bubble ${e?"bg-primary-light":"bg-secondary"}">
462
- ${this._renderContent(this.message.content)}
463
- ${this.message.attachments?.length?o`
464
- <attachment-renderer .attachments=${this.message.attachments}></attachment-renderer>
465
- `:""}
466
- </div>
467
-
468
- ${t&&this.message.usage?o`
469
- <usage-badge .usage=${this.message.usage}></usage-badge>
470
- `:""}
471
- </div>
472
- </div>
473
- `}_renderContent(e){return!e||e.length===0?this.isStreaming?o`<span class="streaming-cursor"></span>`:null:o`
474
- <div class="markdown-content">
475
- ${e.map(t=>this._renderContentBlock(t))}
476
- ${this.isStreaming?o`<span class="streaming-cursor"></span>`:""}
477
- </div>
478
- `}_renderContentBlock(e){switch(e.type){case"text":if(e.text)return o`<p class="whitespace-pre-wrap">${e.text}</p>`;break;case"image":if(e.source?.data)return o`<img src="${e.source.data}" class="rounded-lg max-w-full" />`;break;case"tool_use":case"tool_result":return this._renderToolCall(e);default:if(e.text)return o`<p class="whitespace-pre-wrap">${e.text}</p>`}return null}_renderToolCall(e){const t=e.is_error||e.error,s=e.name||e.function?.name||"Tool",i=e.input||e.function?.arguments;return o`
479
- <div class="tool-call ${t?"tool-call--error":""}">
480
- <div class="tool-call-header">
481
- <span>🔧 ${s}</span>
482
- ${t?o`<span class="text-red-500 text-xs">Error</span>`:""}
483
- </div>
484
- ${i?o`
485
- <pre class="tool-call-content">${JSON.stringify(i,null,2)}</pre>
486
- `:""}
487
- ${e.content?o`
488
- <div class="tool-call-result">${JSON.stringify(e.content)}</div>
489
- `:""}
490
- </div>
491
- `}_formatTime(e){return e?new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):""}};Ne([u({attribute:!1})],Ae.prototype,"message",2);Ne([u({type:Boolean})],Ae.prototype,"isStreaming",2);Ae=Ne([k("message-bubble")],Ae);var Hs=Object.defineProperty,Ns=Object.getOwnPropertyDescriptor,Pe=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ns(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Hs(t,s,n),n};let fe=class extends y{constructor(){super(...arguments),this.messages=[],this.isStreaming=!1,this.useVirtualScroll=!1}createRenderRoot(){return this}render(){return!this.messages||this.messages.length===0?this._renderEmptyState():o`
492
- <div class="flex flex-col gap-4 pb-4">
493
- ${this.messages.map((e,t)=>o`
494
- <message-bubble
495
- .message=${e}
496
- .isStreaming=${this.isStreaming&&t===this.messages.length-1}
497
- ></message-bubble>
498
- `)}
499
- </div>
500
- `}_renderEmptyState(){return o`
501
- <div class="empty-state">
502
- <div class="icon">💬</div>
503
- <div class="title">${r("chat.emptyState")}</div>
504
- <div class="description">${r("chat.emptyStateDescription")}</div>
505
- </div>
506
- `}scrollToBottom(){const e=this.closest(".overflow-y-auto");e&&(e.scrollTop=e.scrollHeight)}isNearBottom(e=100){const t=this.closest(".overflow-y-auto");if(!t)return!0;const{scrollTop:s,scrollHeight:i,clientHeight:n}=t;return i-s-n<e}};Pe([u({attribute:!1})],fe.prototype,"messages",2);Pe([u({type:Boolean})],fe.prototype,"isStreaming",2);Pe([u({type:Boolean})],fe.prototype,"useVirtualScroll",2);fe=Pe([k("message-list")],fe);var zs=Object.defineProperty,qs=Object.getOwnPropertyDescriptor,ae=(e,t,s,i)=>{for(var n=i>1?void 0:i?qs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&zs(t,s,n),n};let V=class extends y{constructor(){super(...arguments),this.tools=new Map,this.pendingToolCalls=new Set,this.isStreaming=!1,this._currentMessage=null,this._isComplete=!1}createRenderRoot(){return this}setMessage(e,t){this._currentMessage=e,this._isComplete=t}render(){return this._currentMessage?o`
507
- <div class="flex gap-3 message-item">
508
- <div class="avatar assistant">
509
- AI
510
- </div>
511
-
512
- <div class="flex flex-col gap-1 max-w-[85%]">
513
- <div class="flex items-center gap-2 text-xs text-muted">
514
- <span class="font-medium">Assistant</span>
515
- <span>·</span>
516
- <span class="text-accent animate-pulse">thinking...</span>
517
- </div>
518
-
519
- <div class="rounded-xl p-3 bg-secondary">
520
- ${this.renderStreamingContent()}
521
- </div>
522
- </div>
523
- </div>
524
- `:null}renderStreamingContent(){const e=this._currentMessage?.content||[];return o`
525
- <div class="markdown-content">
526
- ${e.map(t=>t.type==="text"?o`<p class="whitespace-pre-wrap">${this._escapeHtml(t.text||"")}<span class="streaming-cursor"></span></p>`:t.type==="tool_use"?this.renderToolUse(t):"")}
527
- ${this.isStreaming&&(!e.length||e[e.length-1]?.type!=="text")?o`<span class="streaming-cursor"></span>`:""}
528
- </div>
529
- `}renderToolUse(e){const t=e.name||e.function?.name,s=e.input||e.function?.arguments||{},i=typeof s=="string"?s:JSON.stringify(s,null,2);return o`
530
- <div class="tool-call">
531
- <div class="name">
532
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
533
- <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
534
- </svg>
535
- <span>${t}</span>
536
- </div>
537
- <pre class="input">${i}</pre>
538
- </div>
539
- `}_escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}};ae([u({attribute:!1})],V.prototype,"tools",2);ae([u({attribute:!1})],V.prototype,"pendingToolCalls",2);ae([u({type:Boolean})],V.prototype,"isStreaming",2);ae([c()],V.prototype,"_currentMessage",2);ae([c()],V.prototype,"_isComplete",2);V=ae([k("streaming-message-container")],V);var Js=Object.defineProperty,Gs=Object.getOwnPropertyDescriptor,x=(e,t,s,i)=>{for(var n=i>1?void 0:i?Gs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Js(t,s,n),n};function Ws(){return window.location.origin}function te(e){return`${Ws()}${e}`}function pe(e){const t={"Content-Type":"application/json"};return e&&(t.Authorization=`Bearer ${e}`),t}let w=class extends y{constructor(){super(...arguments),this.enableAttachments=!0,this.enableModelSelector=!0,this._connectionState="disconnected",this._error=null,this._messages=[],this._isStreaming=!1,this._streamingContent="",this._streamingMessage=null,this._reconnectCount=0,this._isAtBottom=!0,this._currentSessionKey=null,this._sessions=[],this._hasMoreMessages=!0,this._isLoadingMore=!1,this._shouldReconnect=!0,this._isSending=!1,this._lastLoadedSessionKey=null,this._handleScroll=()=>{if(!this._chatMessages)return;const{scrollTop:e,scrollHeight:t,clientHeight:s}=this._chatMessages,i=t-e-s<50;i!==this._isAtBottom&&(this._isAtBottom=i),e<100&&!this._isAtBottom&&this._hasMoreMessages&&!this._isLoadingMore&&this._loadMoreMessages()},this._handleSend=(e,t)=>{const s=t?.map(i=>({type:i.type||"file",mimeType:i.mimeType,data:i.content,name:i.name,size:i.size}));this.sendMessage(e,s)}}get _maxReconnectAttempts(){return this.config?.maxReconnectAttempts??10}get _autoReconnect(){return this.config?.autoReconnect??!0}createRenderRoot(){return this}async connectedCallback(){super.connectedCallback(),this.classList.add("chat-container"),await Ps("en")}firstUpdated(){this._chatMessages&&this._chatMessages.addEventListener("scroll",this._handleScroll),this._handleRouteChange()}updated(e){super.updated(e),e.has("config")&&this.config&&this._connectionState==="disconnected"&&this.connect(),e.has("route")&&this.route&&this._handleRouteChange()}async _handleRouteChange(){const e=this.route;if(!e)return;let t=null;switch(e.type){case"recent":this._lastLoadedSessionKey=null,await this._loadSessions();return;case"session":t=e.sessionKey;break;case"new":await this._createNewSession();return}t&&t!==this._lastLoadedSessionKey&&(await this._loadSession(t,0),this._lastLoadedSessionKey=t)}async _loadSession(e,t=0){if(this.config)try{const s=te(`/api/sessions/${encodeURIComponent(e)}?offset=${t}&limit=50`),i=pe(this.config.token),n=await fetch(s,{headers:i});if(!n.ok)throw new Error(`HTTP ${n.status}`);const l=(await n.json()).session;this._currentSessionKey=e;const h=l.messages||[],p=h.filter(g=>g.role==="user"||g.role==="assistant").map(g=>({role:g.role,content:typeof g.content=="string"?[{type:"text",text:g.content}]:g.content||[],attachments:g.attachments,timestamp:g.timestamp?new Date(g.timestamp).getTime():Date.now()}));t>0?this._messages=[...p,...this._messages]:this._messages=p,this._hasMoreMessages=h.length>=50,t===0&&this._scrollToBottom(!1),this.requestUpdate()}catch(s){console.error("[GatewayChat] Failed to load session:",s)}}async _loadMoreMessages(){if(!this._currentSessionKey||this._isLoadingMore||!this._hasMoreMessages)return;this._isLoadingMore=!0;const e=this._messages.length;try{await this._loadSession(this._currentSessionKey,e)}finally{this._isLoadingMore=!1}}disconnectedCallback(){super.disconnectedCallback(),this._shouldReconnect=!1,this.disconnect(),this._chatMessages&&this._chatMessages.removeEventListener("scroll",this._handleScroll)}_scrollToBottom(e=!0){this.updateComplete.then(()=>{this._chatMessages&&this._chatMessages.scrollTo({top:this._chatMessages.scrollHeight,behavior:e?"smooth":"auto"})})}connect(){if(!(!this.config||this._connectionState==="connecting")){this._connectionState="connecting",this._error=null,this.requestUpdate();try{const e=te("/api/events"),t=new URL(e);this.config.token&&t.searchParams.set("token",this.config.token),this._eventSource=new EventSource(t.toString()),this._eventSource.onopen=()=>{this._connectionState="connected",this._error=null,this._reconnectCount=0,this.requestUpdate(),this._lastLoadedSessionKey||this._loadSessions()},this._eventSource.addEventListener("connected",()=>{this._connectionState="connected",this._error=null,this.requestUpdate()}),this._eventSource.addEventListener("config.reload",s=>{try{const i=JSON.parse(s.data);this.dispatchEvent(new CustomEvent("config-reload",{detail:i}))}catch{}}),this._eventSource.addEventListener("channels.status",s=>{try{const i=JSON.parse(s.data);this.dispatchEvent(new CustomEvent("channels-status",{detail:i}))}catch{}}),this._eventSource.addEventListener("message.sent",s=>{try{const i=JSON.parse(s.data);this.dispatchEvent(new CustomEvent("message-sent",{detail:i}))}catch{}}),this._eventSource.onerror=()=>{this._eventSource?.readyState===EventSource.CLOSED?(this._connectionState="disconnected",this._handlePermanentDisconnect()):this._connectionState="reconnecting",this.requestUpdate()}}catch(e){console.error("[GatewayChat] Failed to create EventSource:",e),this._connectionState="error",this._error=r("errors.connectionError"),this.requestUpdate()}}}_handlePermanentDisconnect(){this._isStreaming&&(this._isStreaming=!1,this._isSending=!1,this._streamingContent="",this._streamingMessage=null),this._shouldReconnect&&this._autoReconnect&&(this._reconnectCount++,this._reconnectCount>this._maxReconnectAttempts&&(this._error=r("errors.connectionError"),this._connectionState="error"))}disconnect(){this._shouldReconnect=!1,this._eventSource?.close(),this._eventSource=void 0,this._agentAbort?.abort(),this._agentAbort=void 0,this._connectionState="disconnected"}reconnect(){this._shouldReconnect=!0,this._reconnectCount=0,this.disconnect(),setTimeout(()=>this.connect(),100)}async _loadSessions(){if(this.config)try{const e=te("/api/sessions?limit=20"),t=pe(this.config.token),s=await fetch(e,{headers:t});if(!s.ok)throw new Error(`HTTP ${s.status}`);const a=((await s.json()).items||[]).filter(h=>h.key.startsWith("gateway:")).sort((h,p)=>new Date(p.updatedAt).getTime()-new Date(h.updatedAt).getTime());this._sessions=a;const l=a.filter(h=>h.messageCount>0);if(l.length>0){const h=l[0].key;await this._loadSession(h,0),this._lastLoadedSessionKey=h,this._updateUrlWithSession(h)}else if(a.length>0){const h=a[0];this._currentSessionKey=h.key,this._messages=[],this._lastLoadedSessionKey=h.key,this._updateUrlWithSession(h.key)}else await this._createNewSession()}catch(e){console.error("[GatewayChat] Failed to load sessions:",e)}}_updateUrlWithSession(e){const t=`#/chat/${encodeURIComponent(e)}`;location.hash!==t&&history.replaceState(null,"",t)}async _createNewSession(){if(!this.config)return;const e=this._sessions.find(t=>t.messageCount===0);if(e){this._currentSessionKey=e.key,this._messages=[],this._lastLoadedSessionKey=e.key,this._updateUrlWithSession(e.key);return}try{const t=te("/api/sessions"),s={...pe(this.config.token),"Content-Type":"application/json"},i=await fetch(t,{method:"POST",headers:s,body:JSON.stringify({channel:"gateway"})});if(!i.ok)throw new Error(`HTTP ${i.status}`);const a=(await i.json()).session;this._currentSessionKey=a.key,this._messages=[],this._sessions=[{key:a.key,name:a.name,updatedAt:a.updatedAt},...this._sessions],this._currentSessionKey=a.key,this._lastLoadedSessionKey=a.key,this._updateUrlWithSession(a.key),this._scrollToBottom(),this.requestUpdate()}catch(t){console.error("[GatewayChat] Failed to create new session:",t)}}async sendMessage(e,t){if(!(this._isSending||this._isStreaming)&&!(!e.trim()&&!t?.length)&&this.config){this._isSending=!0,this._messages=[...this._messages,{role:"user",content:e?[{type:"text",text:e}]:[],attachments:t,timestamp:Date.now()}],this._scrollToBottom(),this.requestUpdate();try{this._agentAbort=new AbortController;const s=te("/api/agent"),i={...pe(this.config.token),Accept:"text/event-stream"},n=this._currentSessionKey?this._currentSessionKey.replace("gateway:",""):"default",a=await fetch(s,{method:"POST",headers:i,body:JSON.stringify({message:e,channel:"gateway",chatId:n,attachments:t}),signal:this._agentAbort.signal});if(!a.ok){const h=await a.json().catch(()=>({}));throw new Error(h.error?.message||`HTTP ${a.status}`)}if((a.headers.get("Content-Type")||"").includes("text/event-stream")&&a.body)await this._consumeSSEStream(a.body);else{const h=await a.json();h.ok&&h.payload?.content&&(this._updateStreamingMessage(h.payload.content),this._finalizeMessage())}}catch(s){if(s.name==="AbortError")return;this._error=s instanceof Error?s.message:r("errors.sendFailed"),this._isStreaming=!1,this._isSending=!1,this._streamingMessage=null,this.requestUpdate()}finally{this._agentAbort=void 0,this._isSending=!1}}}async _consumeSSEStream(e){const t=e.pipeThrough(new TextDecoderStream).getReader();let s="",i="",n="";try{for(;;){const{done:a,value:l}=await t.read();if(a)break;for(s+=l;s.includes(`
540
- `);){const h=s.indexOf(`
541
- `),p=s.slice(0,h);s=s.slice(h+1),p.startsWith("event:")?i=p.slice(6).trim():p.startsWith("data:")?n+=(n?`
542
- `:"")+p.slice(5).trim():p===""&&n&&(this._handleSSEEvent(i||"message",n),i="",n="")}}if(s.trim()||n){if(s.trim()){const a=s.split(`
543
- `);for(const l of a)l.startsWith("event:")?i=l.slice(6).trim():l.startsWith("data:")?n+=(n?`
544
- `:"")+l.slice(5).trim():l===""&&n&&(this._handleSSEEvent(i||"message",n),i="",n="")}n&&this._handleSSEEvent(i||"message",n)}}finally{t.releaseLock()}}_handleSSEEvent(e,t){try{const s=JSON.parse(t);switch(e){case"status":this._isStreaming=!0,this.requestUpdate();break;case"token":s.content&&this._updateStreamingMessage(s.content);break;case"error":this._error=s.content||s.error?.message||r("errors.sendFailed"),this._isStreaming=!1,this._isSending=!1,this._streamingMessage=null,this.requestUpdate();break;case"result":this._finalizeMessage();break;default:s.content&&this._updateStreamingMessage(s.content);break}}catch{}}_updateStreamingMessage(e){if(this._streamingMessage){const t=this._streamingMessage.content.find(s=>s.type==="text");t?t.text=(t.text||"")+e:this._streamingMessage.content.push({type:"text",text:e})}else this._streamingMessage={role:"assistant",content:[{type:"text",text:e}],timestamp:Date.now()};this._isStreaming=!0,this._streamingContent=e,this.requestUpdate(),this._isAtBottom&&this._scrollToBottom()}_finalizeMessage(){this._streamingMessage&&(this._messages=[...this._messages,this._streamingMessage],this._streamingMessage=null),this._isStreaming=!1,this._streamingContent="",this._isSending=!1,this._isAtBottom&&this._scrollToBottom(),this.requestUpdate()}async request(e,t,s){if(!this.config)throw new Error("Not configured");const i=te(t),n=await fetch(i,{method:e,headers:pe(this.config.token),body:s?JSON.stringify(s):void 0});if(!n.ok){const a=await n.json().catch(()=>({error:{message:`HTTP ${n.status}`}}));throw new Error(a.error?.message||`HTTP ${n.status}`)}return n.json()}abort(){this._agentAbort?.abort(),this._agentAbort=void 0,this._isStreaming=!1,this._isSending=!1,this._streamingContent="",this._streamingMessage=null,this.requestUpdate()}get connectionState(){return this._connectionState}get messages(){return this._messages}clearMessages(){this._messages=[],this.requestUpdate()}render(){return o`
545
- ${this._renderStatus()}
546
- ${this._renderHeader()}
547
-
548
- <div class="chat-messages">
549
- <div class="chat-messages-inner">
550
- ${this._renderMessages()}
551
- </div>
552
- </div>
553
-
554
- <!-- Scroll to bottom button - placed outside overflow container -->
555
- ${this._isAtBottom?"":o`
556
- <button
557
- class="scroll-to-bottom-btn"
558
- style="position: fixed; bottom: 100px; right: 24px; width: 48px; height: 48px; border-radius: 50%; background: #3b82f6; color: white; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 100;"
559
- @click=${this._scrollToBottom}
560
- title="Scroll to bottom"
561
- >
562
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
563
- </button>
564
- `}
565
-
566
- <div class="chat-input-container">
567
- <div class="chat-input-inner">
568
- ${this._renderInput()}
569
- </div>
570
- </div>
571
- `}_renderHeader(){return o`
572
- <div class="chat-header">
573
- <div class="chat-header-title">
574
- <span class="font-semibold">${r("chat.title")||"XopcBot"}</span>
575
- ${this._currentSessionKey?o`
576
- <span class="text-xs text-muted ml-2">${this._sessions.find(e=>e.key===this._currentSessionKey)?.name||this._currentSessionKey}</span>
577
- `:""}
578
- </div>
579
- <button class="new-session-btn" @click=${()=>this._createNewSession()}>
580
- ${this._renderIcon("plus")}
581
- <span>${r("chat.newSession")||"New Chat"}</span>
582
- </button>
583
- </div>
584
- `}_renderStatus(){return this._connectionState==="error"&&this._error?o`
585
- <div class="status-bar error">
586
- ${this._renderIcon("alertCircle")}
587
- <span>${this._error}</span>
588
- <button class="underline ml-auto" @click=${()=>this.reconnect()}>${r("chat.retry")}</button>
589
- </div>
590
- `:this._connectionState==="reconnecting"?o`
591
- <div class="status-bar warning">
592
- <div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
593
- <span>${r("chat.reconnecting")}</span>
594
- </div>
595
- `:this._connectionState==="connecting"?o`
596
- <div class="status-bar warning">
597
- <div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
598
- <span>${r("chat.connecting")}</span>
599
- </div>
600
- `:null}_renderIcon(e){return{alertCircle:o`
601
- <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
602
- <circle cx="12" cy="12" r="10"/>
603
- <line x1="12" y1="8" x2="12" y2="12"/>
604
- <line x1="12" y1="16" x2="12.01" y2="16"/>
605
- </svg>
606
- `,chevronDown:o`
607
- <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
608
- <polyline points="6 9 12 15 18 9"/>
609
- </svg>
610
- `,plus:o`
611
- <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
612
- <line x1="12" y1="5" x2="12" y2="19"/>
613
- <line x1="5" y1="12" x2="19" y2="12"/>
614
- </svg>
615
- `}[e]||""}_renderScrollToBottomButton(){return o`
616
- <button
617
- class="scroll-to-bottom-btn"
618
- style="background: red !important; width: 60px; height: 60px; font-size: 24px;"
619
- @click=${this._scrollToBottom}
620
- title="Scroll to bottom"
621
- >
622
- 👇
623
- </button>
624
- `}_renderMessages(){return!this._messages.length&&!this._isStreaming?o`
625
- <div class="empty-state" style="padding-top: 30vh;">
626
- <div class="icon">🤖</div>
627
- <div class="title">${r("chat.welcomeTitle")}</div>
628
- <div class="description">${r("chat.welcomeDescription")}</div>
629
- </div>
630
- `:o`
631
- <div class="flex flex-col gap-4">
632
- ${this._messages.map(e=>this._renderMessage(e))}
633
- ${this._isStreaming&&this._streamingMessage?this._renderStreamingMessage():""}
634
- </div>
635
- `}_renderMessage(e){const t=e.role==="user";return!e.content?.some(i=>i.text)&&!e.attachments?.length?null:o`
636
- <div class="message-item ${t?"flex-row-reverse":""}">
637
- <div class="avatar ${t?"user":"assistant"}">
638
- ${t?r("chat.you").charAt(0):"X"}
639
- </div>
640
-
641
- <div class="flex flex-col gap-1 max-w-[calc(100%-3rem)]">
642
- <div class="flex items-center gap-2 text-xs text-muted ${t?"flex-row-reverse":""}">
643
- <span class="font-medium">${r(t?"chat.you":"chat.assistant")}</span>
644
- <span>·</span>
645
- <span>${this._formatTime(e.timestamp)}</span>
646
- </div>
647
-
648
- <div class="message-bubble ${t?"user":"assistant"}">
649
- ${this._renderMessageContent(e.content)}
650
- ${e.attachments?.length?this._renderAttachments(e.attachments):""}
651
- </div>
652
- </div>
653
- </div>
654
- `}_renderStreamingMessage(){const e=this._streamingMessage?.content||[];return o`
655
- <div class="message-item">
656
- <div class="avatar assistant">X</div>
657
- <div class="flex flex-col gap-1 max-w-[calc(100%-3rem)]">
658
- <div class="flex items-center gap-2 text-xs text-muted">
659
- <span class="font-medium">${r("chat.assistant")}</span>
660
- <span>·</span>
661
- <span class="text-primary animate-pulse">${r("chat.thinking")}</span>
662
- </div>
663
- <div class="message-bubble assistant">
664
- <div class="markdown-content">
665
- ${e.map(t=>t.type==="text"&&t.text?o`<p class="whitespace-pre-wrap">${t.text}<span class="streaming-cursor"></span></p>`:"")}
666
- ${e.length?"":o`<span class="streaming-cursor"></span>`}
667
- </div>
668
- </div>
669
- </div>
670
- </div>
671
- `}_renderMessageContent(e){return!e||e.length===0?null:o`
672
- <div class="markdown-content">
673
- ${e.map(t=>t.type==="text"&&t.text?o`<p class="whitespace-pre-wrap">${t.text}</p>`:"")}
674
- </div>
675
- `}_renderAttachments(e){const t=e.filter(i=>i.type==="image"||i.mimeType?.startsWith("image/")),s=e.filter(i=>i.type!=="image"&&!i.mimeType?.startsWith("image/"));return o`
676
- <div class="flex flex-col gap-2 mt-2">
677
- ${t.length>0?this._renderImageGallery(t):""}
678
- ${s.length>0?this._renderDocumentList(s):""}
679
- </div>
680
- `}_renderImageGallery(e){const t=e.length;let s="single";return t===2?s="double":t===3?s="triple":t>=4&&(s="quad"),o`
681
- <div class="image-gallery ${s}">
682
- ${e.map(i=>o`<img src="${i.data}" alt="${i.name||"Image"}" />`)}
683
- </div>
684
- `}_renderDocumentList(e){return o`
685
- <div class="flex flex-col gap-2">
686
- ${e.map(t=>this._renderDocumentPreview(t))}
687
- </div>
688
- `}_renderDocumentPreview(e){const t=e.name||"Document",s=e.size?this._formatFileSize(e.size):"";return o`
689
- <div class="document-preview">
690
- <div class="icon">${this._getDocumentIcon(e.mimeType||"")}</div>
691
- <div class="info">
692
- <div class="name">${t}</div>
693
- <div class="meta">${s||e.mimeType||"File"}</div>
694
- </div>
695
- </div>
696
- `}_getDocumentIcon(e){const t=e.includes("pdf")?"#ef4444":e.includes("word")||e.includes("document")?"#2563eb":e.includes("sheet")||e.includes("excel")?"#16a34a":"currentColor";return o`
697
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="${t}" stroke-width="2">
698
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
699
- <polyline points="14,2 14,8 20,8"/>
700
- </svg>
701
- `}_renderInput(){return o`
702
- <message-editor
703
- .isStreaming=${this._isStreaming}
704
- .showAttachmentButton=${this.enableAttachments}
705
- .showModelSelector=${this.enableModelSelector}
706
- .onSend=${(e,t)=>this._handleSend(e,t)}
707
- .onAbort=${()=>this.abort()}
708
- ></message-editor>
709
- `}_formatTime(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}};x([u({attribute:!1})],w.prototype,"config",2);x([u({attribute:!1})],w.prototype,"route",2);x([u({type:Boolean})],w.prototype,"enableAttachments",2);x([u({type:Boolean})],w.prototype,"enableModelSelector",2);x([oe("message-editor")],w.prototype,"_messageEditor",2);x([oe(".chat-messages")],w.prototype,"_chatMessages",2);x([c()],w.prototype,"_connectionState",2);x([c()],w.prototype,"_error",2);x([c()],w.prototype,"_messages",2);x([c()],w.prototype,"_isStreaming",2);x([c()],w.prototype,"_streamingContent",2);x([c()],w.prototype,"_streamingMessage",2);x([c()],w.prototype,"_reconnectCount",2);x([c()],w.prototype,"_isAtBottom",2);x([c()],w.prototype,"_currentSessionKey",2);x([c()],w.prototype,"_sessions",2);x([c()],w.prototype,"_hasMoreMessages",2);x([c()],w.prototype,"_isLoadingMore",2);w=x([k("xopcbot-gateway-chat")],w);var Vs=Object.defineProperty,Qs=Object.getOwnPropertyDescriptor,ze=(e,t,s,i)=>{for(var n=i>1?void 0:i?Qs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Vs(t,s,n),n};let Ce=class extends y{constructor(){super(...arguments),this.selected=!1}createRenderRoot(){return this}_emit(e){this.dispatchEvent(new CustomEvent("session-action",{detail:{action:e,key:this.session.key},bubbles:!0,composed:!0}))}_formatDate(e){const t=new Date(e),i=Math.floor((new Date().getTime()-t.getTime())/(1e3*60*60*24));return i===0?t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):i===1?"Yesterday":i<7?t.toLocaleDateString([],{weekday:"short"}):t.toLocaleDateString([],{month:"short",day:"numeric"})}_getChannelIcon(e){return{telegram:"send",whatsapp:"phone",gateway:"globe",cli:"terminal"}[e]||"messageSquare"}_getStatusBadge(){switch(this.session.status){case"archived":return"bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400";case"pinned":return"bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400";default:return"bg-green-100 text-green-600 dark:bg-green-900/30 dark:text-green-400"}}render(){const e=this.session.name||this.session.key,t=this.session.status==="archived",s=this.session.status==="pinned";return o`
710
- <div
711
- class="session-card ${this.selected?"session-card--selected":""} ${t?"session-card--archived":""}"
712
- @click=${()=>this._emit("click")}
713
- >
714
- <div class="session-card__header">
715
- <div class="session-card__channel">
716
- <span class="channel-icon">${d(this._getChannelIcon(this.session.sourceChannel))}</span>
717
- <span class="channel-name">${this.session.sourceChannel}</span>
718
- </div>
719
- <div class="session-card__meta">
720
- ${s?o`<span class="pin-badge" title="Pinned">${d("pin")}</span>`:""}
721
- <span class="date">${this._formatDate(this.session.updatedAt)}</span>
722
- </div>
723
- </div>
724
-
725
- <div class="session-card__title">
726
- ${e}
727
- </div>
728
-
729
- <div class="session-card__stats">
730
- <span class="stat">
731
- ${d("messageSquare")}
732
- ${this.session.messageCount}
733
- </span>
734
- <span class="stat">
735
- ${d("zap")}
736
- ${this._formatTokens(this.session.estimatedTokens)}
737
- </span>
738
- </div>
739
-
740
- ${this.session.tags.length>0?o`
741
- <div class="session-card__tags">
742
- ${this.session.tags.slice(0,3).map(i=>o`
743
- <span class="tag">${i}</span>
744
- `)}
745
- ${this.session.tags.length>3?o`
746
- <span class="tag tag--more">+${this.session.tags.length-3}</span>
747
- `:""}
748
- </div>
749
- `:""}
750
-
751
- <div class="session-card__actions" @click=${i=>i.stopPropagation()}>
752
- ${t?o`
753
- <button
754
- class="btn-icon btn-icon--success"
755
- title="Unarchive"
756
- @click=${()=>this._emit("unarchive")}
757
- >${d("archiveRestore")}</button>
758
- `:o`
759
- <button
760
- class="btn-icon"
761
- title="Archive"
762
- @click=${()=>this._emit("archive")}
763
- >${d("archive")}</button>
764
- `}
765
-
766
- ${s?o`
767
- <button
768
- class="btn-icon btn-icon--primary"
769
- title="Unpin"
770
- @click=${()=>this._emit("unpin")}
771
- >${d("pinOff")}</button>
772
- `:o`
773
- <button
774
- class="btn-icon"
775
- title="Pin"
776
- @click=${()=>this._emit("pin")}
777
- >${d("pin")}</button>
778
- `}
779
-
780
- <button
781
- class="btn-icon"
782
- title="Export"
783
- @click=${()=>this._emit("export")}
784
- >${d("download")}</button>
785
-
786
- <button
787
- class="btn-icon btn-icon--danger"
788
- title="Delete"
789
- @click=${()=>this._emit("delete")}
790
- >${d("trash")}</button>
791
- </div>
792
- </div>
793
- `}_formatTokens(e){return e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()}};ze([u({attribute:!1})],Ce.prototype,"session",2);ze([u({type:Boolean})],Ce.prototype,"selected",2);Ce=ze([k("session-card")],Ce);var Xs=Object.defineProperty,Ys=Object.getOwnPropertyDescriptor,re=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ys(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Xs(t,s,n),n};let Q=class extends y{constructor(){super(...arguments),this.sessions=[],this.loading=!1,this.hasMore=!1,this.selectedKey=null,this._viewMode="grid"}createRenderRoot(){return this}_emit(e,t){this.dispatchEvent(new CustomEvent("list-action",{detail:{action:e,key:t},bubbles:!0,composed:!0}))}_handleCardAction(e){const{action:t,key:s}=e.detail;t==="click"?this._emit("select",s):this._emit(t,s)}_loadMore(){this.dispatchEvent(new CustomEvent("load-more",{bubbles:!0,composed:!0}))}render(){return this.loading&&this.sessions.length===0?this._renderLoading():this.sessions.length===0?this._renderEmpty():o`
794
- <div class="session-list">
795
- ${this._renderToolbar()}
796
-
797
- <div class="session-list__content session-list__content--${this._viewMode}">
798
- ${this.sessions.map(e=>o`
799
- <session-card
800
- .session=${e}
801
- .selected=${e.key===this.selectedKey}
802
- @session-action=${this._handleCardAction}
803
- ></session-card>
804
- `)}
805
- </div>
806
-
807
- ${this.hasMore?o`
808
- <div class="session-list__load-more">
809
- <button class="btn btn--secondary" @click=${this._loadMore}>
810
- ${d("chevronDown")}
811
- Load More
812
- </button>
813
- </div>
814
- `:""}
815
-
816
- ${this.loading?o`
817
- <div class="session-list__loading-overlay">
818
- <div class="spinner"></div>
819
- </div>
820
- `:""}
821
- </div>
822
- `}_renderToolbar(){return o`
823
- <div class="session-list__toolbar">
824
- <div class="session-list__count">
825
- ${this.sessions.length} sessions
826
- </div>
827
-
828
- <div class="session-list__view-toggle">
829
- <button
830
- class="btn-icon ${this._viewMode==="grid"?"btn-icon--active":""}"
831
- title="Grid view"
832
- @click=${()=>this._viewMode="grid"}
833
- >${d("grid")}</button>
834
- <button
835
- class="btn-icon ${this._viewMode==="list"?"btn-icon--active":""}"
836
- title="List view"
837
- @click=${()=>this._viewMode="list"}
838
- >${d("list")}</button>
839
- </div>
840
- </div>
841
- `}_renderLoading(){return o`
842
- <div class="session-list session-list--loading">
843
- <div class="session-list__skeleton">
844
- ${Array.from({length:6}).map(()=>o`
845
- <div class="skeleton-card">
846
- <div class="skeleton skeleton--header"></div>
847
- <div class="skeleton skeleton--title"></div>
848
- <div class="skeleton skeleton--stats"></div>
849
- </div>
850
- `)}
851
- </div>
852
- </div>
853
- `}_renderEmpty(){return o`
854
- <div class="session-list session-list--empty">
855
- <div class="empty-state">
856
- <div class="empty-state__icon">${d("folderOpen")}</div>
857
- <div class="empty-state__title">No sessions found</div>
858
- <div class="empty-state__description">
859
- Start a conversation to create your first session.
860
- </div>
861
- </div>
862
- </div>
863
- `}};re([u({attribute:!1})],Q.prototype,"sessions",2);re([u({type:Boolean})],Q.prototype,"loading",2);re([u({type:Boolean})],Q.prototype,"hasMore",2);re([u({type:String})],Q.prototype,"selectedKey",2);re([c()],Q.prototype,"_viewMode",2);Q=re([k("session-list")],Q);var Zs=Object.defineProperty,ei=Object.getOwnPropertyDescriptor,Y=(e,t,s,i)=>{for(var n=i>1?void 0:i?ei(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Zs(t,s,n),n};let j=class extends y{constructor(){super(...arguments),this.session=null,this.open=!1,this.loading=!1,this._searchQuery="",this._searchResults=[],this._currentResultIndex=-1}createRenderRoot(){return this}_emit(e){this.dispatchEvent(new CustomEvent("detail-action",{detail:{action:e},bubbles:!0,composed:!0}))}_handleClose(){this._emit("close")}_handleBackdropClick(e){e.target===e.currentTarget&&this._handleClose()}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._performSearch()}_performSearch(){if(!this.session||!this._searchQuery.trim()){this._searchResults=[],this._currentResultIndex=-1;return}const e=this._searchQuery.toLowerCase(),t=[];this.session.messages.forEach((s,i)=>{s.content.toLowerCase().includes(e)&&t.push(i)}),this._searchResults=t,this._currentResultIndex=t.length>0?0:-1}_navigateSearch(e){if(this._searchResults.length===0)return;e==="next"?this._currentResultIndex=(this._currentResultIndex+1)%this._searchResults.length:this._currentResultIndex=(this._currentResultIndex-1+this._searchResults.length)%this._searchResults.length;const t=this._searchResults[this._currentResultIndex],s=this.querySelector(`[data-message-index="${t}"]`);s&&s.scrollIntoView({behavior:"smooth",block:"center"})}_highlightText(e){if(!this._searchQuery.trim())return e;const t=this._searchQuery;return e.split(new RegExp(`(${t})`,"gi")).map((i,n)=>i.toLowerCase()===t.toLowerCase()?o`<mark class="search-highlight">${i}</mark>`:i)}_formatDate(e){return new Date(e).toLocaleString()}render(){return this.open?o`
864
- <div class="drawer-backdrop" @click=${this._handleBackdropClick}>
865
- <div class="drawer drawer--${this.open?"open":"closed"}">
866
- ${this._renderHeader()}
867
- ${this._renderSearch()}
868
- ${this._renderContent()}
869
- ${this._renderActions()}
870
- </div>
871
- </div>
872
- `:""}_renderHeader(){if(!this.session)return"";const e=this.session.status==="archived",t=this.session.status==="pinned";return o`
873
- <div class="drawer-header">
874
- <div class="drawer-header__info">
875
- <div class="drawer-header__title">
876
- ${this.session.name||this.session.key}
877
- ${t?o`<span class="pin-badge">${d("pin")}</span>`:""}
878
- ${e?o`<span class="archive-badge">Archived</span>`:""}
879
- </div>
880
- <div class="drawer-header__meta">
881
- <span>${this.session.sourceChannel}</span>
882
- <span>•</span>
883
- <span>${this.session.messageCount} messages</span>
884
- <span>•</span>
885
- <span>${this._formatDate(this.session.updatedAt)}</span>
886
- </div>
887
- </div>
888
- <button class="btn-icon" @click=${this._handleClose} title="Close">
889
- ${d("x")}
890
- </button>
891
- </div>
892
- `}_renderSearch(){return this.session?o`
893
- <div class="drawer-search">
894
- <div class="search-input-wrapper">
895
- ${d("search")}
896
- <input
897
- type="text"
898
- placeholder="Search in session..."
899
- .value=${this._searchQuery}
900
- @input=${this._handleSearch}
901
- />
902
- ${this._searchQuery?o`
903
- <button class="btn-icon btn-icon--sm" @click=${()=>{this._searchQuery="",this._performSearch()}}>
904
- ${d("x")}
905
- </button>
906
- `:""}
907
- </div>
908
-
909
- ${this._searchResults.length>0?o`
910
- <div class="search-nav">
911
- <span class="search-count">${this._currentResultIndex+1} / ${this._searchResults.length}</span>
912
- <button class="btn-icon btn-icon--sm" @click=${()=>this._navigateSearch("prev")} title="Previous">
913
- ${d("chevronUp")}
914
- </button>
915
- <button class="btn-icon btn-icon--sm" @click=${()=>this._navigateSearch("next")} title="Next">
916
- ${d("chevronDown")}
917
- </button>
918
- </div>
919
- `:""}
920
- </div>
921
- `:""}_renderContent(){return this.loading?o`
922
- <div class="drawer-content drawer-content--loading">
923
- <div class="spinner"></div>
924
- <span>Loading...</span>
925
- </div>
926
- `:this.session?o`
927
- <div class="drawer-content">
928
- ${this.session.messages.map((e,t)=>{const s=this._searchResults.includes(t),i=this._searchResults[this._currentResultIndex]===t;return o`
929
- <div
930
- class="message ${e.role} ${s?"message--highlight":""} ${i?"message--current":""}"
931
- data-message-index="${t}"
932
- >
933
- <div class="message__header">
934
- <span class="message__role">${e.role}</span>
935
- ${e.timestamp?o`<span class="message__time">${this._formatDate(e.timestamp)}</span>`:""}
936
- </div>
937
- <div class="message__content">${this._highlightText(e.content)}</div>
938
- </div>
939
- `})}
940
- </div>
941
- `:o`
942
- <div class="drawer-content drawer-content--empty">
943
- <span>No session selected</span>
944
- </div>
945
- `}_renderActions(){if(!this.session)return"";const e=this.session.status==="archived",t=this.session.status==="pinned";return o`
946
- <div class="drawer-actions">
947
- ${e?o`
948
- <button class="btn btn--secondary" @click=${()=>this._emit("unarchive")}>
949
- ${d("archiveRestore")} Unarchive
950
- </button>
951
- `:o`
952
- <button class="btn btn--secondary" @click=${()=>this._emit("archive")}>
953
- ${d("archive")} Archive
954
- </button>
955
- `}
956
-
957
- ${t?o`
958
- <button class="btn btn--secondary" @click=${()=>this._emit("unpin")}>
959
- ${d("pinOff")} Unpin
960
- </button>
961
- `:o`
962
- <button class="btn btn--secondary" @click=${()=>this._emit("pin")}>
963
- ${d("pin")} Pin
964
- </button>
965
- `}
966
-
967
- <button class="btn btn--secondary" @click=${()=>this._emit("export")}>
968
- ${d("download")} Export
969
- </button>
970
-
971
- <button class="btn btn--danger" @click=${()=>this._emit("delete")}>
972
- ${d("trash")} Delete
973
- </button>
974
- </div>
975
- `}};Y([u({attribute:!1})],j.prototype,"session",2);Y([u({type:Boolean})],j.prototype,"open",2);Y([u({type:Boolean})],j.prototype,"loading",2);Y([c()],j.prototype,"_searchQuery",2);Y([c()],j.prototype,"_searchResults",2);Y([c()],j.prototype,"_currentResultIndex",2);j=Y([k("session-detail-drawer")],j);var ti=Object.defineProperty,si=Object.getOwnPropertyDescriptor,Z=(e,t,s,i)=>{for(var n=i>1?void 0:i?si(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ti(t,s,n),n};let U=class extends y{constructor(){super(...arguments),this.open=!1,this.title="Confirm",this.message="Are you sure?",this.confirmText="Confirm",this.cancelText="Cancel",this.type="warning"}createRenderRoot(){return this}_emit(e){this.dispatchEvent(new CustomEvent("confirm",{detail:{confirmed:e},bubbles:!0,composed:!0})),this.open=!1}_handleBackdropClick(e){e.target===e.currentTarget&&this._emit(!1)}_getIcon(){switch(this.type){case"danger":return"trash";case"warning":return"alertTriangle";case"info":return"info";default:return"helpCircle"}}_getIconColor(){switch(this.type){case"danger":return"text-red-500";case"warning":return"text-amber-500";case"info":return"text-blue-500";default:return"text-gray-500"}}render(){return this.open?o`
976
- <div class="modal-backdrop" @click=${this._handleBackdropClick}>
977
- <div class="modal modal--${this.type}">
978
- <div class="modal__icon ${this._getIconColor()}">
979
- ${d(this._getIcon())}
980
- </div>
981
-
982
- <div class="modal__content">
983
- <h3 class="modal__title">${this.title}</h3>
984
- <p class="modal__message">${this.message}</p>
985
- </div>
986
-
987
- <div class="modal__actions">
988
- <button class="btn btn--secondary" @click=${()=>this._emit(!1)}>
989
- ${this.cancelText}
990
- </button>
991
- <button class="btn btn--${this.type==="danger"?"danger":"primary"}" @click=${()=>this._emit(!0)}>
992
- ${this.confirmText}
993
- </button>
994
- </div>
995
- </div>
996
- </div>
997
- `:""}};Z([u({type:Boolean})],U.prototype,"open",2);Z([u({type:String})],U.prototype,"title",2);Z([u({type:String})],U.prototype,"message",2);Z([u({type:String})],U.prototype,"confirmText",2);Z([u({type:String})],U.prototype,"cancelText",2);Z([u({type:String})],U.prototype,"type",2);U=Z([k("confirm-dialog")],U);class ii{constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.token=s}async request(t,s,i){const n={"Content-Type":"application/json"};this.token&&(n.Authorization=`Bearer ${this.token}`);const a=await fetch(`${this.baseUrl}${s}`,{method:t,headers:n,body:i?JSON.stringify(i):void 0});if(!a.ok){const l=await a.json().catch(()=>({error:"Request failed"}));throw new Error(l.error||`HTTP ${a.status}`)}return a.json()}async listSessions(t){const s=new URLSearchParams;t?.status&&s.set("status",t.status),t?.search&&s.set("search",t.search),t?.limit&&s.set("limit",String(t.limit)),t?.offset&&s.set("offset",String(t.offset));const i=s.toString(),n=`/api/sessions${i?`?${i}`:""}`;return await this.request("GET",n)}async getSession(t){try{return(await this.request("GET",`/api/sessions/${t}`)).session||null}catch(s){if(s instanceof Error&&s.message.includes("404"))return null;throw s}}async deleteSession(t){return await this.request("DELETE",`/api/sessions/${t}`)}async archiveSession(t){return await this.request("POST",`/api/sessions/${t}/archive`)}async unarchiveSession(t){return await this.request("POST",`/api/sessions/${t}/unarchive`)}async pinSession(t){return await this.request("POST",`/api/sessions/${t}/pin`)}async unpinSession(t){return await this.request("POST",`/api/sessions/${t}/unpin`)}async renameSession(t,s){return await this.request("POST",`/api/sessions/${t}/rename`,{name:s})}async exportSession(t,s="json"){return(await this.request("GET",`/api/sessions/${t}/export?format=${s}`)).content}async getStats(){return await this.request("GET","/api/sessions/stats")}}var ni=Object.defineProperty,oi=Object.getOwnPropertyDescriptor,A=(e,t,s,i)=>{for(var n=i>1?void 0:i?oi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ni(t,s,n),n};let b=class extends y{constructor(){super(...arguments),this._sessions=[],this._loading=!1,this._hasMore=!1,this._stats=null,this._searchQuery="",this._statusFilter="all",this._offset=0,this._error=null,this._detailOpen=!1,this._detailSession=null,this._detailLoading=!1,this._confirmOpen=!1,this._confirmTitle="",this._confirmMessage="",this._confirmKey=null,this._confirmAction=null,this._limit=20,this._initialized=!1,this._debouncedSearch=this._debounce(()=>{this._loadSessions(!0)},300)}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){if(this._initialized)return;const e=window.location.origin;this._api=new ii(e,this.config?.token),this._initialized=!0,this._loadSessions(),this._loadStats()}disconnectedCallback(){super.disconnectedCallback()}async _loadSessions(e=!1){if(!this._loading){this._loading=!0,this._error=null,e&&(this._offset=0,this._sessions=[]);try{const t={limit:this._limit,offset:this._offset,sortBy:"updatedAt",sortOrder:"desc",...this._statusFilter!=="all"&&{status:this._statusFilter},...this._searchQuery&&{search:this._searchQuery}},s=await this._api.listSessions(t);e?this._sessions=s.items:this._sessions=[...this._sessions,...s.items],this._hasMore=s.hasMore,this._offset=s.offset+s.items.length}catch(t){this._error=t instanceof Error?t.message:"Failed to load sessions",console.error("[SessionManager] Load error:",t)}finally{this._loading=!1}}}async _loadStats(){try{this._stats=await this._api.getStats()}catch(e){console.error("[SessionManager] Stats error:",e)}}async _openDetail(e){this._detailOpen=!0,this._detailLoading=!0;try{const t=await this._api.getSession(e);this._detailSession=t}catch(t){console.error("[SessionManager] Load detail error:",t),this._detailOpen=!1}finally{this._detailLoading=!1}}_closeDetail(){this._detailOpen=!1,this._detailSession=null}_handleDetailAction(e){const{action:t}=e.detail,s=this._detailSession?.key;if(s)switch(t){case"close":this._closeDetail();break;case"delete":this._showConfirm(s);break;case"archive":this._archiveSession(s);break;case"unarchive":this._unarchiveSession(s);break;case"pin":this._pinSession(s);break;case"unpin":this._unpinSession(s);break;case"export":this._exportSession(s);break}}_showConfirm(e){this._confirmKey=e,this._confirmAction="delete",this._confirmTitle="Delete Session",this._confirmMessage=`Are you sure you want to delete session "${e}"?
998
-
999
- This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.detail.confirmed||!this._confirmKey){this._confirmOpen=!1,this._confirmKey=null;return}this._deleteSession(this._confirmKey),this._confirmOpen=!1,this._confirmKey=null}async _deleteSession(e){try{await this._api.deleteSession(e),this._sessions=this._sessions.filter(t=>t.key!==e),this._detailSession?.key===e&&this._closeDetail(),await this._loadStats()}catch(t){alert("Failed to delete session: "+(t instanceof Error?t.message:String(t)))}}async _archiveSession(e){try{await this._api.archiveSession(e),this._updateSessionStatus(e,"archived"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"archived"}),await this._loadStats()}catch(t){console.error("[SessionManager] Archive error:",t)}}async _unarchiveSession(e){try{await this._api.unarchiveSession(e),this._updateSessionStatus(e,"active"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"active"}),await this._loadStats()}catch(t){console.error("[SessionManager] Unarchive error:",t)}}async _pinSession(e){try{await this._api.pinSession(e),this._updateSessionStatus(e,"pinned"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"pinned"}),await this._loadStats()}catch(t){console.error("[SessionManager] Pin error:",t)}}async _unpinSession(e){try{await this._api.unpinSession(e),this._updateSessionStatus(e,"active"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"active"}),await this._loadStats()}catch(t){console.error("[SessionManager] Unpin error:",t)}}async _exportSession(e){try{const t=await this._api.exportSession(e,"json"),s=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(s),n=document.createElement("a");n.href=i,n.download=`session-${e.replace(/[^a-z0-9]/gi,"_")}.json`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(i)}catch(t){alert("Failed to export session: "+(t instanceof Error?t.message:String(t)))}}_updateSessionStatus(e,t){this._sessions=this._sessions.map(s=>s.key===e?{...s,status:t}:s)}_handleListAction(e){const{action:t,key:s}=e.detail;switch(t){case"select":this._openDetail(s);break;case"delete":this._showConfirm(s);break;case"archive":this._archiveSession(s);break;case"unarchive":this._unarchiveSession(s);break;case"pin":this._pinSession(s);break;case"unpin":this._unpinSession(s);break;case"export":this._exportSession(s);break}}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._debouncedSearch()}_debounce(e,t){let s;return()=>{clearTimeout(s),s=setTimeout(e,t)}}_handleStatusFilter(e){this._statusFilter=e,this._loadSessions(!0)}_handleLoadMore(){this._loadSessions()}render(){return o`
1000
- <div class="session-manager">
1001
- ${this._renderHeader()}
1002
- ${this._renderFilters()}
1003
- ${this._renderStats()}
1004
- ${this._error?o`<div class="error-banner">${this._error}</div>`:""}
1005
-
1006
- <session-list
1007
- .sessions=${this._sessions}
1008
- .loading=${this._loading}
1009
- .hasMore=${this._hasMore}
1010
- @list-action=${this._handleListAction}
1011
- @load-more=${this._handleLoadMore}
1012
- ></session-list>
1013
- </div>
1014
-
1015
- <session-detail-drawer
1016
- .session=${this._detailSession}
1017
- .open=${this._detailOpen}
1018
- .loading=${this._detailLoading}
1019
- @detail-action=${this._handleDetailAction}
1020
- ></session-detail-drawer>
1021
-
1022
- <confirm-dialog
1023
- .open=${this._confirmOpen}
1024
- .title=${this._confirmTitle}
1025
- .message=${this._confirmMessage}
1026
- .confirmText="Delete"
1027
- .cancelText="Cancel"
1028
- .type="danger"
1029
- @confirm=${this._handleConfirm}
1030
- ></confirm-dialog>
1031
- `}_renderHeader(){return o`
1032
- <div class="session-manager__header">
1033
- <h1 class="page-title">${d("folderOpen")} ${r("sessions.title")}</h1>
1034
- <div class="search-box">
1035
- ${d("search")}
1036
- <input
1037
- type="text"
1038
- placeholder="${r("sessions.searchPlaceholder")}"
1039
- .value=${this._searchQuery}
1040
- @input=${this._handleSearch}
1041
- />
1042
- </div>
1043
- </div>
1044
- `}_renderFilters(){return o`
1045
- <div class="session-manager__filters">
1046
- ${[{key:"all",label:"All",icon:"layers"},{key:"active",label:"Active",icon:"circle"},{key:"pinned",label:"Pinned",icon:"pin"},{key:"archived",label:"Archived",icon:"archive"}].map(t=>o`
1047
- <button
1048
- class="filter-btn ${this._statusFilter===t.key?"filter-btn--active":""}"
1049
- @click=${()=>this._handleStatusFilter(t.key)}
1050
- >
1051
- ${d(t.icon)}
1052
- ${t.label}
1053
- </button>
1054
- `)}
1055
- </div>
1056
- `}_renderStats(){return this._stats?o`
1057
- <div class="session-manager__stats">
1058
- <div class="stat-card">
1059
- <div class="stat-value">${this._stats.totalSessions}</div>
1060
- <div class="stat-label">${r("sessions.totalSessions")}</div>
1061
- </div>
1062
- <div class="stat-card">
1063
- <div class="stat-value">${this._stats.activeSessions}</div>
1064
- <div class="stat-label">${r("sessions.activeSessions")}</div>
1065
- </div>
1066
- <div class="stat-card">
1067
- <div class="stat-value">${this._stats.pinnedSessions}</div>
1068
- <div class="stat-label">${r("sessions.pinnedSessions")}</div>
1069
- </div>
1070
- <div class="stat-card">
1071
- <div class="stat-value">${this._stats.archivedSessions}</div>
1072
- <div class="stat-label">${r("sessions.archivedSessions")}</div>
1073
- </div>
1074
- </div>
1075
- `:""}};A([u({attribute:!1})],b.prototype,"config",2);A([c()],b.prototype,"_sessions",2);A([c()],b.prototype,"_loading",2);A([c()],b.prototype,"_hasMore",2);A([c()],b.prototype,"_stats",2);A([c()],b.prototype,"_searchQuery",2);A([c()],b.prototype,"_statusFilter",2);A([c()],b.prototype,"_offset",2);A([c()],b.prototype,"_error",2);A([c()],b.prototype,"_detailOpen",2);A([c()],b.prototype,"_detailSession",2);A([c()],b.prototype,"_detailLoading",2);A([c()],b.prototype,"_confirmOpen",2);A([c()],b.prototype,"_confirmTitle",2);A([c()],b.prototype,"_confirmMessage",2);A([c()],b.prototype,"_confirmKey",2);A([c()],b.prototype,"_confirmAction",2);b=A([k("session-manager")],b);class ai{constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.token=s}async request(t,s,i){const n={"Content-Type":"application/json"};this.token&&(n.Authorization=`Bearer ${this.token}`);const a=await fetch(`${this.baseUrl}${s}`,{method:t,headers:n,body:i?JSON.stringify(i):void 0});if(!a.ok){const l=await a.json().catch(()=>({error:"Request failed"}));throw new Error(l.error||`HTTP ${a.status}`)}return a.json()}async listJobs(){return(await this.request("GET","/api/cron")).jobs||[]}async getJob(t){try{return(await this.request("GET",`/api/cron/${t}`)).job||null}catch(s){if(s instanceof Error&&s.message.includes("404"))return null;throw s}}async addJob(t,s,i){return await this.request("POST","/api/cron",{schedule:t,message:s,...i})}async updateJob(t,s){return(await this.request("PATCH",`/api/cron/${t}`,s)).updated}async removeJob(t){return(await this.request("DELETE",`/api/cron/${t}`)).removed}async toggleJob(t,s){return(await this.request("POST",`/api/cron/${t}/toggle`,{enabled:s})).toggled}async runJob(t){await this.request("POST",`/api/cron/${t}/run`)}async getHistory(t,s=10){return(await this.request("GET",`/api/cron/${t}/history?limit=${s}`)).history||[]}async getMetrics(){return await this.request("GET","/api/cron/metrics")}async getChannels(){return(await this.request("GET","/api/channels/status")).payload?.channels||[]}async getModels(){return(await this.request("GET","/api/models")).payload?.models||[]}async getConfig(){return{model:((await this.request("GET","/api/config")).config||{}).agents?.defaults?.model||""}}async getSessionChatIds(t){const s=t?`?channel=${encodeURIComponent(t)}`:"";return(await this.request("GET",`/api/sessions/chat-ids${s}`)).payload?.chatIds||[]}disconnect(){}}var ri=Object.defineProperty,li=Object.getOwnPropertyDescriptor,v=(e,t,s,i)=>{for(var n=i>1?void 0:i?li(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ri(t,s,n),n};let m=class extends y{constructor(){super(...arguments),this._jobs=[],this._metrics=null,this._channels=[],this._availableModels=[],this._defaultModel="",this._sessionChatIds=[],this._loading=!1,this._error=null,this._formOpen=!1,this._formMode="add",this._formJobId=null,this._formName="",this._formSchedule="*/5 * * * *",this._formChannel="telegram",this._formChatId="",this._formMessage="",this._formSessionTarget="main",this._formModel="",this._formSubmitting=!1,this._detailOpen=!1,this._detailJob=null,this._detailHistory=[],this._detailLoading=!1,this._confirmOpen=!1,this._confirmTitle="",this._confirmMessage="",this._confirmJobId=null,this._confirmAction=null,this._initialized=!1}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){if(this._initialized)return;const e=window.location.origin;this._api=new ai(e,this.config?.token),this._initialized=!0,this._loadJobs(),this._loadMetrics(),this._loadChannels(),this._loadModels(),this._loadSessionChatIds()}disconnectedCallback(){super.disconnectedCallback(),this._api?.disconnect()}async _loadJobs(){if(!this._loading){this._loading=!0,this._error=null;try{this._jobs=await this._api.listJobs()}catch(e){this._error=e instanceof Error&&e.message||r("cron.failedToLoadJobs"),console.error("[CronManager] Load error:",e)}finally{this._loading=!1}}}async _loadMetrics(){try{this._metrics=await this._api.getMetrics()}catch(e){console.error("[CronManager] Metrics error:",e)}}async _loadChannels(){try{this._channels=await this._api.getChannels()}catch(e){console.error("[CronManager] Channels error:",e)}}async _loadModels(){try{this._availableModels=await this._api.getModels();const e=await this._api.getConfig();this._defaultModel=e.model||"",this._formModel=this._defaultModel,console.log("[CronManager] Loaded models:",this._availableModels.length,"default:",this._defaultModel)}catch(e){console.error("[CronManager] Models error:",e)}}async _loadSessionChatIds(){try{const e=await this._api.getSessionChatIds(this._formChannel);this._sessionChatIds=e,console.log("[CronManager] Loaded session chatIds for channel",this._formChannel,":",e.length,e)}catch(e){console.error("[CronManager] Session chatIds error:",e),this._sessionChatIds=[]}}_openForm(e){if(this._formOpen=!0,this._formMode=e?"edit":"add",this._formJobId=e?.id||null,e||this._loadSessionChatIds(),e)if(this._formName=e.name||"",this._formSchedule=e.schedule,this._formMessage=e.message,this._formSessionTarget=e.sessionTarget||"main",this._formModel=e.model||"",e.delivery)this._formChannel=e.delivery.channel||"telegram",this._formChatId=e.delivery.to||"";else{const t=e.message.split(":"),s=["telegram","whatsapp","cli","gateway"];t.length>=3&&s.includes(t[0])?(this._formChannel=t[0],this._formChatId=t[1],this._formMessage=t.slice(2).join(":")):(this._formChannel="telegram",this._formChatId="")}else this._formName="",this._formSchedule="*/5 * * * *",this._formChannel="telegram",this._formChatId="",this._formMessage="",this._formSessionTarget="main",this._formModel=this._defaultModel||(this._availableModels.length>0?this._availableModels[0].id:"")}_closeForm(){this._formOpen=!1,this._formMode="add",this._formJobId=null,this._formName="",this._formSchedule="*/5 * * * *",this._formChannel="telegram",this._formChatId="",this._formMessage="",this._formSessionTarget="main",this._formModel=""}async _submitForm(){if(!this._formSchedule||!this._formMessage){this._error=r("cron.scheduleRequired");return}if(!this._formChatId){this._error=r("cron.chatIdRequired");return}this._formSubmitting=!0,this._error=null;try{const e=this._formMessage,t={mode:"direct",channel:this._formChannel,to:this._formChatId},s=this._formSessionTarget==="isolated"?{kind:"agentTurn",message:e,model:this._formModel}:{kind:"systemEvent",text:e},i={name:this._formName||void 0,schedule:this._formSchedule,message:e,sessionTarget:this._formSessionTarget,model:this._formSessionTarget==="isolated"?this._formModel:void 0,delivery:t};this._formMode==="edit"&&this._formJobId?await this._api.updateJob(this._formJobId,i):await this._api.addJob(this._formSchedule,e,i),this._closeForm(),await this._loadJobs(),await this._loadMetrics()}catch(e){this._error=e instanceof Error?e.message||r("cron.failedToJob",{mode:this._formMode}):r("cron.failedToJob",{mode:this._formMode})}finally{this._formSubmitting=!1}}async _openDetail(e){this._detailOpen=!0,this._detailJob=e,this._detailLoading=!0;try{const t=await this._api.getJob(e.id);t&&(this._detailJob=t,this._detailHistory=await this._api.getHistory(e.id,20))}catch(t){console.error("[CronManager] Load detail error:",t)}finally{this._detailLoading=!1}}_closeDetail(){this._detailOpen=!1,this._detailJob=null,this._detailHistory=[]}async _toggleJob(e,t){try{await this._api.toggleJob(e.id,t),await this._loadJobs(),await this._loadMetrics()}catch(s){this._error=s instanceof Error&&s.message||r("cron.failedToToggleJob")}}_showRunConfirm(e){this._confirmOpen=!0,this._confirmTitle=r("cron.runNow"),this._confirmMessage=r("cron.confirmRun"),this._confirmJobId=e.id,this._confirmAction="run"}_showDeleteConfirm(e){this._confirmOpen=!0,this._confirmTitle=r("cron.delete"),this._confirmMessage=r("cron.confirmDelete"),this._confirmJobId=e.id,this._confirmAction="delete"}_closeConfirm(){this._confirmOpen=!1,this._confirmTitle="",this._confirmMessage="",this._confirmJobId=null,this._confirmAction=null}_handleConfirm(e){e.detail.confirmed?this._executeConfirmAction():this._closeConfirm()}async _executeConfirmAction(){if(!this._confirmJobId||!this._confirmAction)return;const e=this._confirmJobId,t=this._confirmAction;this._closeConfirm();try{t==="run"?(await this._api.runJob(e),await this._loadJobs(),await this._loadMetrics()):t==="delete"&&(await this._api.removeJob(e),await this._loadJobs(),await this._loadMetrics())}catch(s){this._error=s instanceof Error&&s.message||r("cron.actionFailed")}}render(){return o`
1076
- <div class="cron-manager">
1077
- ${this._error?o`<div class="error-banner">${this._error}</div>`:""}
1078
-
1079
- <!-- Header -->
1080
- <div class="cron-manager__header">
1081
- <h1 class="page-title">${d("clock")} ${r("cron.title")}</h1>
1082
- <div class="cron-manager__actions">
1083
- <button class="btn btn-secondary" @click=${this._loadJobs} ?disabled=${this._loading}>
1084
- ${d("refresh")} ${r("logs.refresh")}
1085
- </button>
1086
- <button class="btn btn-primary" @click=${()=>this._openForm()}>
1087
- ${d("plus")} ${r("cron.addJob")}
1088
- </button>
1089
- </div>
1090
- </div>
1091
-
1092
- <!-- Stats -->
1093
- ${this._metrics?o`
1094
- <div class="cron-manager__stats">
1095
- <div class="stat-card" style="text-align: center;">
1096
- <div class="stat-value">${this._metrics.totalJobs}</div>
1097
- <div class="stat-label">${r("sessions.totalSessions")}</div>
1098
- </div>
1099
- <div class="stat-card" style="text-align: center;">
1100
- <div class="stat-value">${this._metrics.enabledJobs}</div>
1101
- <div class="stat-label">${r("cron.enabled")}</div>
1102
- </div>
1103
- <div class="stat-card" style="text-align: center;">
1104
- <div class="stat-value">${this._metrics.runningJobs}</div>
1105
- <div class="stat-label">${r("cron.running")}</div>
1106
- </div>
1107
- <div class="stat-card" style="text-align: center;">
1108
- <div class="stat-value" style="font-size: 0.875rem;">
1109
- ${this._metrics.nextScheduledJob?this._formatNextRun(this._metrics.nextScheduledJob.runAt):"N/A"}
1110
- </div>
1111
- <div class="stat-label">${r("cron.nextRun")}</div>
1112
- </div>
1113
- </div>
1114
- `:_}
1115
-
1116
- <!-- Job List -->
1117
- <div class="session-list">
1118
- ${this._loading&&this._jobs.length===0?o`
1119
- <div class="session-list__loading-overlay">
1120
- <div class="spinner"></div>
1121
- </div>
1122
- `:this._jobs.length===0?o`
1123
- <div class="session-list session-list--empty">
1124
- <div class="empty-state">
1125
- <div class="empty-state__icon">${d("clock")}</div>
1126
- <div class="empty-state__title">No cron jobs yet</div>
1127
- <button class="btn btn-primary" @click=${this._openForm}>Create your first job</button>
1128
- </div>
1129
- </div>
1130
- `:o`
1131
- <div class="session-list__toolbar">
1132
- <div class="session-list__count">${this._jobs.length} job${this._jobs.length!==1?"s":""}</div>
1133
- </div>
1134
- <div class="session-list__content">
1135
- <table class="data-table">
1136
- <thead>
1137
- <tr>
1138
- <th>${r("cron.name")}</th>
1139
- <th>${r("cron.scheduleLabel")}</th>
1140
- <th>${r("cron.nextRun")}</th>
1141
- <th>${r("cron.status")}</th>
1142
- <th>${r("cron.actions")}</th>
1143
- </tr>
1144
- </thead>
1145
- <tbody>
1146
- ${this._jobs.map(e=>o`
1147
- <tr>
1148
- <td style="vertical-align: middle; text-align: center;">
1149
- <button class="btn btn-link" @click=${()=>this._openDetail(e)}>
1150
- ${e.name||e.id}
1151
- </button>
1152
- </td>
1153
- <td style="vertical-align: middle; text-align: center;"><code>${e.schedule}</code></td>
1154
- <td style="vertical-align: middle; text-align: center;">${e.next_run?this._formatNextRun(e.next_run):"-"}</td>
1155
- <td style="vertical-align: middle; text-align: center;">
1156
- <label class="toggle">
1157
- <input
1158
- type="checkbox"
1159
- ?checked=${e.enabled}
1160
- @change=${t=>this._toggleJob(e,t.target.checked)}
1161
- />
1162
- <span class="toggle__slider"></span>
1163
- </label>
1164
- </td>
1165
- <td style="vertical-align: middle; text-align: center;">
1166
- <div class="action-buttons">
1167
- <button class="btn btn-icon btn-secondary" title="Edit" @click=${()=>this._openForm(e)}>
1168
- ${d("edit")}
1169
- </button>
1170
- <button class="btn btn-icon btn-secondary" title="${r("cron.runNow")}" @click=${()=>this._showRunConfirm(e)}>
1171
- ${d("play")}
1172
- </button>
1173
- <button class="btn btn-icon btn-danger" title="${r("cron.delete")}" @click=${()=>this._showDeleteConfirm(e)}>
1174
- ${d("trash")}
1175
- </button>
1176
- </div>
1177
- </td>
1178
- </tr>
1179
- `)}
1180
- </tbody>
1181
- </table>
1182
- </div>
1183
- `}
1184
- </div>
1185
- </div>
1186
-
1187
- <!-- Add/Edit Job Form Modal -->
1188
- ${this._formOpen?o`
1189
- <div class="modal-backdrop" @click=${this._closeForm}>
1190
- <div class="modal modal--form" @click=${e=>e.stopPropagation()}>
1191
- <div class="modal__header">
1192
- <h2 class="modal__title">${this._formMode==="edit"?r("cron.editJob"):r("cron.addJob")}</h2>
1193
- <button class="btn-icon" @click=${this._closeForm}>${d("x")}</button>
1194
- </div>
1195
- <div class="modal__content">
1196
- <div class="form-field">
1197
- <label class="form-field__label">${r("cron.name")}</label>
1198
- <input
1199
- type="text"
1200
- class="form-field__input"
1201
- .value=${this._formName??""}
1202
- @input=${e=>this._formName=e.target.value}
1203
- placeholder="${r("cron.namePlaceholder")??"My scheduled task"}"
1204
- />
1205
- </div>
1206
- <div class="form-field">
1207
- <label class="form-field__label">${r("cron.schedule")}</label>
1208
- <div style="display: flex; gap: 0.5rem; align-items: center;">
1209
- <input
1210
- type="text"
1211
- class="form-field__input"
1212
- style="flex: 2; min-width: 0;"
1213
- .value=${this._formSchedule??"*/5 * * * *"}
1214
- @input=${e=>this._formSchedule=e.target.value}
1215
- placeholder="*/5 * * * *"
1216
- />
1217
- <select
1218
- class="form-field__select"
1219
- style="flex: 1; min-width: 0;"
1220
- .value=${this._formSchedule??"*/5 * * * *"}
1221
- @change=${e=>{const t=e.target.value;t&&(this._formSchedule=t)}}
1222
- >
1223
- <option value="">${r("cron.schedulePresets.custom")}</option>
1224
- <option value="*/1 * * * *">${r("cron.schedulePresets.everyMinute")}</option>
1225
- <option value="*/5 * * * *">${r("cron.schedulePresets.every5Minutes")}</option>
1226
- <option value="*/10 * * * *">${r("cron.schedulePresets.every10Minutes")}</option>
1227
- <option value="*/15 * * * *">${r("cron.schedulePresets.every15Minutes")}</option>
1228
- <option value="*/30 * * * *">${r("cron.schedulePresets.every30Minutes")}</option>
1229
- <option value="0 * * * *">${r("cron.schedulePresets.everyHour")}</option>
1230
- <option value="0 */2 * * *">${r("cron.schedulePresets.every2Hours")}</option>
1231
- <option value="0 */4 * * *">${r("cron.schedulePresets.every4Hours")}</option>
1232
- <option value="0 */6 * * *">${r("cron.schedulePresets.every6Hours")}</option>
1233
- <option value="0 */12 * * *">${r("cron.schedulePresets.every12Hours")}</option>
1234
- <option value="0 0 * * *">${r("cron.schedulePresets.everyDayMidnight")}</option>
1235
- <option value="0 9 * * *">${r("cron.schedulePresets.everyDay9AM")}</option>
1236
- <option value="0 21 * * *">${r("cron.schedulePresets.everyDay9PM")}</option>
1237
- </select>
1238
- </div>
1239
- <p class="form-field__hint">
1240
- ${r("cron.scheduleHintPreset")}
1241
- </p>
1242
- </div>
1243
- <div class="form-field">
1244
- <label class="form-field__label">${r("cron.mode")}</label>
1245
- <select
1246
- class="form-field__select"
1247
- .value=${this._formSessionTarget??"main"}
1248
- @change=${e=>this._formSessionTarget=e.target.value}
1249
- >
1250
- <option value="main">${r("cron.modeDirectOption")||"Direct (send message directly)"}</option>
1251
- <option value="isolated">${r("cron.modeAgentOption")||"AI Agent (process with AI then send)"}</option>
1252
- </select>
1253
- <p class="form-field__hint">
1254
- ${this._formSessionTarget==="main"?r("cron.modeDirect"):r("cron.modeAgent")}
1255
- </p>
1256
- </div>
1257
- ${this._formSessionTarget==="isolated"?o`
1258
- <div class="form-field">
1259
- <label class="form-field__label">${r("cron.model")}</label>
1260
- <select
1261
- class="form-field__select"
1262
- .value=${this._formModel??""}
1263
- @change=${e=>this._formModel=e.target.value}
1264
- >
1265
- ${this._availableModels.length>0?this._availableModels.map(e=>o`
1266
- <option value=${e.id}>${e.name} (${e.provider})</option>
1267
- `):o`
1268
- <option value="">${r("cron.noConfiguredModels")}</option>
1269
- `}
1270
- </select>
1271
- </div>
1272
- `:_}
1273
- <div class="form-field">
1274
- <label class="form-field__label">Channel</label>
1275
- <select
1276
- class="form-field__select"
1277
- .value=${this._formChannel??"telegram"}
1278
- @change=${e=>{this._formChannel=e.target.value,this._loadSessionChatIds(),this._formChatId=""}}
1279
- >
1280
- ${this._channels.map(e=>o`
1281
- <option value=${e.name} ?disabled=${!e.enabled}>
1282
- ${e.name} ${e.enabled?"":"(disabled)"}
1283
- </option>
1284
- `)}
1285
- </select>
1286
- </div>
1287
- <div class="form-field">
1288
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
1289
- <label class="form-field__label" style="margin: 0;">Chat ID *</label>
1290
- <button
1291
- type="button"
1292
- class="btn btn-secondary btn-sm"
1293
- @click=${()=>this._loadSessionChatIds()}
1294
- title="Refresh chat list"
1295
- style="padding: 0.25rem 0.5rem; font-size: 0.75rem;"
1296
- >
1297
- ${d("refresh")} Refresh
1298
- </button>
1299
- </div>
1300
- <div style="display: flex; gap: 0.5rem; align-items: center;">
1301
- <input
1302
- type="text"
1303
- class="form-field__input"
1304
- style="flex: 2; min-width: 0;"
1305
- .value=${this._formChatId??""}
1306
- @input=${e=>this._formChatId=e.target.value}
1307
- placeholder="e.g., 123456789"
1308
- />
1309
- <select
1310
- class="form-field__select"
1311
- style="flex: 1; min-width: 0;"
1312
- .value=${this._formChatId??""}
1313
- @change=${e=>{const t=e.target.value;t&&(this._formChatId=t)}}
1314
- >
1315
- <option value="">-- Select --</option>
1316
- ${this._sessionChatIds.length>0?this._sessionChatIds.map(e=>o`
1317
- <option value=${e.chatId}>
1318
- ${e.channel}: ${e.chatId} (${this._formatLastActive(e.lastActive)})
1319
- </option>
1320
- `):o`
1321
- <option value="" disabled>No recent chats</option>
1322
- `}
1323
- </select>
1324
- </div>
1325
- <p class="form-field__hint">
1326
- ${this._sessionChatIds.length>0?r("cron.enterManuallyOrSelect"):r("cron.noRecentChats")}
1327
- </p>
1328
- </div>
1329
- <div class="form-field">
1330
- <label class="form-field__label">${r("cron.message")}</label>
1331
- <textarea
1332
- class="form-field__textarea"
1333
- .value=${this._formMessage??""}
1334
- @input=${e=>this._formMessage=e.target.value}
1335
- placeholder="${r("cron.messagePlaceholder")??"What should the assistant do?"}"
1336
- rows="4"
1337
- ></textarea>
1338
- </div>
1339
- </div>
1340
- <div class="modal__actions">
1341
- <button class="btn btn-secondary" @click=${this._closeForm}>${r("common.cancel")}</button>
1342
- <button
1343
- class="btn btn-primary"
1344
- @click=${this._submitForm}
1345
- ?disabled=${this._formSubmitting||!this._formSchedule||!this._formChatId||!this._formMessage}
1346
- >
1347
- ${this._formSubmitting?r("common.loading"):this._formMode==="edit"?r("cron.save"):r("cron.create")}
1348
- </button>
1349
- </div>
1350
- </div>
1351
- </div>
1352
- `:_}
1353
-
1354
- <!-- Detail Drawer -->
1355
- ${this._detailOpen?o`
1356
- <div class="drawer-backdrop" @click=${this._closeDetail}>
1357
- <div class="drawer drawer--open" @click=${e=>e.stopPropagation()}>
1358
- <div class="drawer-header">
1359
- <div class="drawer-header__info">
1360
- <div class="drawer-header__title">${this._detailJob?.name||this._detailJob?.id}</div>
1361
- </div>
1362
- <button class="btn-icon" @click=${this._closeDetail}>${d("x")}</button>
1363
- </div>
1364
- <div class="drawer-content ${this._detailLoading?"drawer-content--loading":""}">
1365
- ${this._detailLoading?o`
1366
- <div class="spinner"></div>
1367
- `:o`
1368
- <div class="session-detail">
1369
- <div class="session-detail__row">
1370
- <span class="session-detail__label">${r("cron.scheduleLabel")}</span>
1371
- <code>${this._detailJob?.schedule}</code>
1372
- </div>
1373
- <div class="session-detail__row">
1374
- <span class="session-detail__label">${r("cron.messageLabel")}</span>
1375
- <span>${this._detailJob?.message}</span>
1376
- </div>
1377
- <div class="session-detail__row">
1378
- <span class="session-detail__label">${r("cron.status")}</span>
1379
- <span>${this._detailJob?.enabled?r("cron.enabled"):r("cron.disabled")}</span>
1380
- </div>
1381
- <div class="session-detail__row">
1382
- <span class="session-detail__label">${r("cron.nextRun")}</span>
1383
- <span>${this._detailJob?.next_run?this._formatNextRun(this._detailJob.next_run):"N/A"}</span>
1384
- </div>
1385
- </div>
1386
- `}
1387
- </div>
1388
- </div>
1389
- </div>
1390
- `:_}
1391
-
1392
- <!-- Confirm Dialog -->
1393
- <confirm-dialog
1394
- .open=${this._confirmOpen}
1395
- .title=${this._confirmTitle}
1396
- .message=${this._confirmMessage}
1397
- .confirmText=${this._confirmAction==="delete"?r("cron.delete"):r("cron.runNow")}
1398
- .cancelText=${r("common.cancel")}
1399
- .type=${this._confirmAction==="delete"?"danger":"warning"}
1400
- @confirm=${this._handleConfirm}
1401
- ></confirm-dialog>
1402
- `}_formatNextRun(e){const t=typeof e=="string"?new Date(e):e,s=new Date,i=t.getTime()-s.getTime();if(i<0)return r("cron.timeLabels.overdue");if(i<6e4)return r("cron.timeLabels.lessThanMinute");if(i<36e5){const n=Math.floor(i/6e4);return r("cron.timeLabels.minutes",{count:n})}if(i<864e5){const n=Math.floor(i/36e5);return r("cron.timeLabels.hours",{count:n})}return t.toLocaleString()}_formatLastActive(e){const t=new Date(e),i=new Date().getTime()-t.getTime();if(i<0||i<6e4)return r("cron.lastActiveLabels.justNow");if(i<36e5){const n=Math.floor(i/6e4);return r("cron.lastActiveLabels.minutesAgo",{count:n})}if(i<864e5){const n=Math.floor(i/36e5);return r("cron.lastActiveLabels.hoursAgo",{count:n})}if(i<6048e5){const n=Math.floor(i/864e5);return r("cron.lastActiveLabels.daysAgo",{count:n})}return t.toLocaleDateString()}_formatTime(e){return new Date(e).toLocaleString()}};v([u({attribute:!1})],m.prototype,"config",2);v([c()],m.prototype,"_jobs",2);v([c()],m.prototype,"_metrics",2);v([c()],m.prototype,"_channels",2);v([c()],m.prototype,"_availableModels",2);v([c()],m.prototype,"_defaultModel",2);v([c()],m.prototype,"_sessionChatIds",2);v([c()],m.prototype,"_loading",2);v([c()],m.prototype,"_error",2);v([c()],m.prototype,"_formOpen",2);v([c()],m.prototype,"_formMode",2);v([c()],m.prototype,"_formJobId",2);v([c()],m.prototype,"_formName",2);v([c()],m.prototype,"_formSchedule",2);v([c()],m.prototype,"_formChannel",2);v([c()],m.prototype,"_formChatId",2);v([c()],m.prototype,"_formMessage",2);v([c()],m.prototype,"_formSessionTarget",2);v([c()],m.prototype,"_formModel",2);v([c()],m.prototype,"_formSubmitting",2);v([c()],m.prototype,"_detailOpen",2);v([c()],m.prototype,"_detailJob",2);v([c()],m.prototype,"_detailHistory",2);v([c()],m.prototype,"_detailLoading",2);v([c()],m.prototype,"_confirmOpen",2);v([c()],m.prototype,"_confirmTitle",2);v([c()],m.prototype,"_confirmMessage",2);v([c()],m.prototype,"_confirmJobId",2);v([c()],m.prototype,"_confirmAction",2);m=v([k("cron-manager")],m);const ci=["trace","debug","info","warn","error","fatal"],be={trace:"#9ca3af",debug:"#6b7280",info:"#3b82f6",warn:"#f59e0b",error:"#ef4444",fatal:"#dc2626"};class hi{constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.token=s}async request(t,s,i){const n={"Content-Type":"application/json"};this.token&&(n.Authorization=`Bearer ${this.token}`);const a=await fetch(`${this.baseUrl}${s}`,{method:t,headers:n,body:i?JSON.stringify(i):void 0});if(!a.ok){const l=await a.json().catch(()=>({error:"Request failed"}));throw new Error(l.error||`HTTP ${a.status}`)}return a.json()}async queryLogs(t){const s=new URLSearchParams;t?.level?.length&&s.set("level",t.level.join(",")),t?.from&&s.set("from",t.from),t?.to&&s.set("to",t.to),t?.q&&s.set("q",t.q),t?.module&&s.set("module",t.module),t?.limit&&s.set("limit",String(t.limit)),t?.offset&&s.set("offset",String(t.offset));const i=s.toString(),n=`/api/logs${i?`?${i}`:""}`;return await this.request("GET",n)}async getLogFiles(){return(await this.request("GET","/api/logs/files")).files||[]}async getLogStats(){return await this.request("GET","/api/logs/stats")}async getLogLevels(){return(await this.request("GET","/api/logs/levels")).levels||[]}async getLogModules(){return(await this.request("GET","/api/logs/modules")).modules||[]}async getLogDir(){return(await this.request("GET","/api/logs/dir")).dir}}var di=Object.defineProperty,pi=Object.getOwnPropertyDescriptor,C=(e,t,s,i)=>{for(var n=i>1?void 0:i?pi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&di(t,s,n),n};let $=class extends y{constructor(){super(...arguments),this._logs=[],this._loading=!1,this._hasMore=!1,this._files=[],this._modules=[],this._showFilesPanel=!1,this._selectedLevels=new Set,this._searchQuery="",this._selectedModule="",this._dateFrom="",this._dateTo="",this._offset=0,this._error=null,this._selectedLog=null,this._autoRefresh=!1,this._limit=50,this._initialized=!1,this._debouncedSearch=this._debounce(()=>{this._loadLogs(!0)},300)}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}disconnectedCallback(){super.disconnectedCallback(),this._stopAutoRefresh()}firstUpdated(){this._tryInitialize()}_tryInitialize(){if(this._initialized)return;const e=window.location.origin;this._api=new hi(e,this.config?.token),this._initialized=!0,this._loadLogs(),this._loadFiles(),this._loadModules()}async _loadLogs(e=!1){if(!this._loading){this._loading=!0,this._error=null,e&&(this._offset=0,this._logs=[]);try{const t={level:this._selectedLevels.size>0?Array.from(this._selectedLevels):void 0,from:this._dateFrom||void 0,to:this._dateTo||void 0,q:this._searchQuery||void 0,module:this._selectedModule||void 0,limit:this._limit,offset:this._offset},s=await this._api.queryLogs(t);e?this._logs=s.logs:this._logs=[...this._logs,...s.logs],console.log("[LogManager] Total logs in state:",this._logs.length),this._hasMore=s.logs.length===this._limit,this._offset=this._offset+s.logs.length}catch(t){this._error=t instanceof Error?t.message:"Failed to load logs",console.error("[LogManager] Load error:",t)}finally{this._loading=!1}}}async _loadFiles(){try{this._files=await this._api.getLogFiles()}catch(e){console.error("[LogManager] Files error:",e)}}async _loadModules(){try{this._modules=await this._api.getLogModules()}catch(e){console.error("[LogManager] Modules error:",e)}}_toggleLevel(e){this._selectedLevels.has(e)?this._selectedLevels.delete(e):this._selectedLevels.add(e),this._selectedLevels=new Set(this._selectedLevels),this._loadLogs(!0)}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._debouncedSearch()}_debounce(e,t){let s;return()=>{clearTimeout(s),s=setTimeout(e,t)}}_handleModuleChange(e){const t=e.target;this._selectedModule=t.value,this._loadLogs(!0)}_handleDateFromChange(e){const t=e.target;this._dateFrom=t.value,this._loadLogs(!0)}_handleDateToChange(e){const t=e.target;this._dateTo=t.value,this._loadLogs(!0)}_clearFilters(){this._selectedLevels.clear(),this._selectedLevels=new Set,this._searchQuery="",this._selectedModule="",this._dateFrom="",this._dateTo="",this._loadLogs(!0)}_selectLog(e){this._selectedLog=e}_closeDetail(){this._selectedLog=null}_toggleAutoRefresh(){this._autoRefresh=!this._autoRefresh,this._autoRefresh?this._startAutoRefresh():this._stopAutoRefresh()}_startAutoRefresh(){this._refreshInterval=window.setInterval(()=>{this._loadLogs(!0)},5e3)}_stopAutoRefresh(){this._refreshInterval&&(clearInterval(this._refreshInterval),this._refreshInterval=void 0)}_handleLoadMore(){this._loadLogs()}_formatTimestamp(e){try{return new Date(e).toLocaleString([],{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{return e}}_formatFileSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}render(){return o`
1403
- <div class="log-manager">
1404
- ${this._renderHeader()}
1405
- <div class="log-manager__main">
1406
- ${this._renderFilters()}
1407
- ${this._renderLogTable()}
1408
- ${this._renderFilesPanel()}
1409
- </div>
1410
- ${this._error?o`<div class="error-banner">${this._error}</div>`:""}
1411
- </div>
1412
-
1413
- ${this._selectedLog?this._renderDetailDrawer():""}
1414
- `}_renderHeader(){return o`
1415
- <div class="log-manager__header">
1416
- <div class="log-manager__title">
1417
- <span class="title-icon">${d("fileText")}</span>
1418
- <div class="title-text">
1419
- <h1>${r("logs.title")}</h1>
1420
- <span class="title-subtitle">System logs and diagnostics</span>
1421
- </div>
1422
- </div>
1423
- <div class="log-manager__actions">
1424
- <button
1425
- class="btn-icon"
1426
- @click=${this._toggleFilesPanel}
1427
- title="Toggle log files"
1428
- >
1429
- ${d("folder")}
1430
- ${this._files.length>0?o`<span class="badge">${this._files.length}</span>`:""}
1431
- </button>
1432
- <button
1433
- class="btn-icon ${this._autoRefresh?"btn-icon--active":""}"
1434
- @click=${this._toggleAutoRefresh}
1435
- title=${this._autoRefresh?r("logs.pause"):r("logs.autoRefresh")}
1436
- >
1437
- ${d(this._autoRefresh?"pause":"play")}
1438
- </button>
1439
- <button
1440
- class="btn-icon"
1441
- @click=${()=>this._loadLogs(!0)}
1442
- title=${r("logs.refresh")}
1443
- >
1444
- ${d("refreshCw")}
1445
- </button>
1446
- </div>
1447
- </div>
1448
- `}_renderFilters(){return o`
1449
- <div class="log-manager__filters">
1450
- <div class="log-manager__filters-row">
1451
- <div class="filter-group">
1452
- <label class="filter-label">${r("logs.level")}</label>
1453
- <div class="level-filters">
1454
- ${ci.map(e=>o`
1455
- <button
1456
- class="level-badge ${this._selectedLevels.has(e)?"level-badge--active":""}"
1457
- style="--level-color: ${be[e]}"
1458
- @click=${()=>this._toggleLevel(e)}
1459
- >
1460
- ${e}
1461
- </button>
1462
- `)}
1463
- </div>
1464
- </div>
1465
-
1466
- <div class="filter-group">
1467
- <label class="filter-label">${r("logs.search")}</label>
1468
- <div class="search-box">
1469
- ${d("search")}
1470
- <input
1471
- type="text"
1472
- placeholder="${r("logs.searchPlaceholder")}"
1473
- .value=${this._searchQuery}
1474
- @input=${this._handleSearch}
1475
- />
1476
- </div>
1477
- </div>
1478
- </div>
1479
-
1480
- <div class="filter-row">
1481
- <div class="filter-group">
1482
- <label class="filter-label">Module</label>
1483
- <select @change=${this._handleModuleChange}>
1484
- <option value="">All modules</option>
1485
- ${this._modules.map(e=>o`<option value="${e}">${e}</option>`)}
1486
- </select>
1487
- </div>
1488
-
1489
- <div class="filter-group">
1490
- <label class="filter-label">From</label>
1491
- <input
1492
- type="datetime-local"
1493
- .value=${this._dateFrom}
1494
- @input=${this._handleDateFromChange}
1495
- />
1496
- </div>
1497
-
1498
- <div class="filter-group">
1499
- <label class="filter-label">To</label>
1500
- <input
1501
- type="datetime-local"
1502
- .value=${this._dateTo}
1503
- @input=${this._handleDateToChange}
1504
- />
1505
- </div>
1506
-
1507
- <button class="btn btn-ghost" @click=${this._clearFilters}>
1508
- ${d("x")}
1509
- Clear
1510
- </button>
1511
- </div>
1512
- </div>
1513
- `}_renderLogTable(){return this._loading&&this._logs.length===0?this._renderLoading():this._logs.length===0?o`
1514
- <div class="log-manager__empty">
1515
- <div class="empty-state">
1516
- <div class="empty-state__icon">${d("fileText")}</div>
1517
- <div class="empty-state__title">${r("logs.noLogs")}</div>
1518
- <div class="empty-state__description">
1519
- ${r("logs.noLogsDescription")}
1520
- </div>
1521
- </div>
1522
- </div>
1523
- `:o`
1524
- <div class="log-table-container">
1525
- <table class="log-table">
1526
- <thead>
1527
- <tr>
1528
- <th>${r("logs.time")}</th>
1529
- <th>${r("logs.level")}</th>
1530
- <th>${r("logs.module")}</th>
1531
- <th>${r("logs.message")}</th>
1532
- </tr>
1533
- </thead>
1534
- <tbody>
1535
- ${this._logs.length===0?o`
1536
- <tr>
1537
- <td colspan="4" style="padding: 2rem; text-align: center; color: var(--text-muted);">
1538
- No logs to display
1539
- </td>
1540
- </tr>
1541
- `:this._logs.map(e=>o`
1542
- <tr class="log-row log-row--${e.level||"info"}" @click=${()=>this._selectLog(e)}>
1543
- <td class="log-cell log-cell--time">${this._formatTimestamp(e.timestamp)}</td>
1544
- <td class="log-cell log-cell--level">
1545
- <span
1546
- class="level-badge level-badge--small"
1547
- style="--level-color: ${be[e.level]||be.info}"
1548
- >
1549
- ${e.level||"info"}
1550
- </span>
1551
- </td>
1552
- <td class="log-cell log-cell--module">${e.module||e.prefix||e.service||"-"}</td>
1553
- <td class="log-cell log-cell--message">${e.message||JSON.stringify(e)}</td>
1554
- </tr>
1555
- `)}
1556
- </tbody>
1557
- </table>
1558
-
1559
- ${this._hasMore?o`
1560
- <div class="log-table__load-more">
1561
- <button class="btn btn-secondary" @click=${this._handleLoadMore} ?disabled=${this._loading}>
1562
- ${this._loading?o`<span class="spinner"></span>`:d("chevronDown")}
1563
- Load More
1564
- </button>
1565
- </div>
1566
- `:""}
1567
- </div>
1568
- `}_toggleFilesPanel(){this._showFilesPanel=!this._showFilesPanel}_renderFilesPanel(){return o`
1569
- ${this._showFilesPanel?o`
1570
- <div class="drawer-overlay" @click=${this._toggleFilesPanel}></div>
1571
- `:""}
1572
- <div class="files-panel ${this._showFilesPanel?"files-panel--open":""}">
1573
- <div class="files-panel__header">
1574
- <span class="files-panel__title">
1575
- ${d("folder")}
1576
- Log Files
1577
- </span>
1578
- <button class="btn btn-icon" @click=${this._toggleFilesPanel}>
1579
- ${d("x")}
1580
- </button>
1581
- </div>
1582
- <div class="files-panel__content">
1583
- ${this._files.length===0?o`
1584
- <div class="files-panel__empty">No log files found</div>
1585
- `:o`
1586
- <div class="file-list">
1587
- ${this._files.map(e=>o`
1588
- <div class="file-item">
1589
- <span class="file-name">${d("file")}${e.name}</span>
1590
- <span class="file-meta">
1591
- <span class="file-size">${this._formatFileSize(e.size)}</span>
1592
- <span class="file-time">${this._formatTimestamp(e.modified)}</span>
1593
- </span>
1594
- </div>
1595
- `)}
1596
- </div>
1597
- `}
1598
- </div>
1599
- </div>
1600
- `}_renderDetailDrawer(){if(!this._selectedLog)return"";const e=this._selectedLog;return o`
1601
- <div class="drawer-overlay" @click=${this._closeDetail}></div>
1602
- <div class="drawer drawer--right">
1603
- <div class="drawer-header">
1604
- <h3 class="drawer-header__title">${r("logs.details")}</h3>
1605
- <button class="btn btn-icon" @click=${this._closeDetail}>${d("x")}</button>
1606
- </div>
1607
- <div class="drawer__content">
1608
- <div class="log-detail">
1609
- <div class="log-detail__field">
1610
- <label>${r("logs.time")}</label>
1611
- <code>${e.timestamp}</code>
1612
- </div>
1613
- <div class="log-detail__field">
1614
- <label>${r("logs.level")}</label>
1615
- <span
1616
- class="level-badge"
1617
- style="--level-color: ${be[e.level]}"
1618
- >
1619
- ${e.level}
1620
- </span>
1621
- </div>
1622
- <div class="log-detail__field">
1623
- <label>${r("logs.module")}</label>
1624
- <code>${e.module}</code>
1625
- </div>
1626
- <div class="log-detail__field">
1627
- <label>${r("logs.message")}</label>
1628
- <pre class="log-detail__message">${e.message}</pre>
1629
- </div>
1630
- ${e.meta?o`
1631
- <div class="log-detail__field">
1632
- <label>Metadata</label>
1633
- <pre class="log-detail__meta">${JSON.stringify(e.meta,null,2)}</pre>
1634
- </div>
1635
- `:""}
1636
- </div>
1637
- </div>
1638
- </div>
1639
- `}_renderLoading(){return o`
1640
- <div class="log-manager__loading">
1641
- <div class="skeleton-table">
1642
- ${Array.from({length:10}).map(()=>o`
1643
- <div class="skeleton-row">
1644
- <div class="skeleton skeleton--time"></div>
1645
- <div class="skeleton skeleton--level"></div>
1646
- <div class="skeleton skeleton--module"></div>
1647
- <div class="skeleton skeleton--message"></div>
1648
- </div>
1649
- `)}
1650
- </div>
1651
- </div>
1652
- `}};C([u({attribute:!1})],$.prototype,"config",2);C([c()],$.prototype,"_logs",2);C([c()],$.prototype,"_loading",2);C([c()],$.prototype,"_hasMore",2);C([c()],$.prototype,"_files",2);C([c()],$.prototype,"_modules",2);C([c()],$.prototype,"_showFilesPanel",2);C([c()],$.prototype,"_selectedLevels",2);C([c()],$.prototype,"_searchQuery",2);C([c()],$.prototype,"_selectedModule",2);C([c()],$.prototype,"_dateFrom",2);C([c()],$.prototype,"_dateTo",2);C([c()],$.prototype,"_offset",2);C([c()],$.prototype,"_error",2);C([c()],$.prototype,"_selectedLog",2);C([c()],$.prototype,"_autoRefresh",2);C([c()],$.prototype,"_refreshInterval",2);$=C([k("log-manager")],$);var ui=Object.defineProperty,gi=Object.getOwnPropertyDescriptor,P=(e,t,s,i)=>{for(var n=i>1?void 0:i?gi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ui(t,s,n),n};let E=class extends y{constructor(){super(...arguments),this._activeSection="agent",this._loading=!1,this._saving=!1,this._refreshingToken=!1,this._serverToken=null,this._showToken=!1,this._dirtyFields=new Set,this._errors=new Map,this._saveSuccess=!1,this._models=[],this._values={model:"anthropic/claude-sonnet-4-5",maxTokens:8192,temperature:.7,maxToolIterations:20,telegramEnabled:!1,telegramToken:"",telegramApiRoot:"",telegramDebug:!1,telegramAllowFrom:"",whatsappEnabled:!1,whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"",gatewayToken:"",heartbeatEnabled:!0,heartbeatIntervalMs:6e4,openaiApiKey:"",anthropicApiKey:"",googleApiKey:"",qwenApiKey:"",kimiApiKey:"",minimaxApiKey:"",deepseekApiKey:"",grokApiKey:"",openrouterApiKey:"",workspace:"",theme:"system"},this._initialized=!1}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){this._initialized||(this._initialized=!0,this._loadSettings())}get _sections(){const e=this._models.map(t=>({value:t.id,label:`${t.provider}/${t.name}`}));return[{id:"agent",title:r("settings.sections.agent"),icon:"bot",fields:[{key:"model",label:r("settings.fields.model"),type:"select",description:r("settings.descriptionsFields.model"),options:e},{key:"workspace",label:r("settings.fields.workspace"),type:"text",description:r("settings.descriptionsFields.workspace"),placeholder:r("settings.placeholders.workspace")},{key:"maxTokens",label:r("settings.fields.maxTokens"),type:"number",description:r("settings.descriptionsFields.maxTokens"),validation:{min:256,max:128e3}},{key:"temperature",label:r("settings.fields.temperature"),type:"number",description:r("settings.descriptionsFields.temperature"),validation:{min:0,max:2}},{key:"maxToolIterations",label:r("settings.fields.maxToolIterations"),type:"number",description:r("settings.descriptionsFields.maxToolIterations"),validation:{min:1,max:100}}]},{id:"providers",title:r("settings.sections.providers"),icon:"cloud",fields:[{key:"openaiApiKey",label:r("settings.fields.openaiApiKey"),type:"password",description:r("settings.descriptionsFields.openaiApiKey"),placeholder:r("settings.placeholders.openaiApiKey")},{key:"anthropicApiKey",label:r("settings.fields.anthropicApiKey"),type:"password",description:r("settings.descriptionsFields.anthropicApiKey"),placeholder:r("settings.placeholders.anthropicApiKey")},{key:"googleApiKey",label:r("settings.fields.googleApiKey"),type:"password",description:r("settings.descriptionsFields.googleApiKey"),placeholder:r("settings.placeholders.googleApiKey")},{key:"qwenApiKey",label:r("settings.fields.qwenApiKey"),type:"password",description:r("settings.descriptionsFields.qwenApiKey"),placeholder:r("settings.placeholders.qwenApiKey")},{key:"kimiApiKey",label:r("settings.fields.kimiApiKey"),type:"password",description:r("settings.descriptionsFields.kimiApiKey"),placeholder:r("settings.placeholders.kimiApiKey")},{key:"minimaxApiKey",label:r("settings.fields.minimaxApiKey"),type:"password",description:r("settings.descriptionsFields.minimaxApiKey"),placeholder:r("settings.placeholders.minimaxApiKey")},{key:"deepseekApiKey",label:r("settings.fields.deepseekApiKey"),type:"password",description:r("settings.descriptionsFields.deepseekApiKey"),placeholder:r("settings.placeholders.deepseekApiKey")},{key:"openrouterApiKey",label:r("settings.fields.openrouterApiKey"),type:"password",description:r("settings.descriptionsFields.openrouterApiKey"),placeholder:r("settings.placeholders.openrouterApiKey")}]},{id:"channels",title:r("settings.sections.channels"),icon:"plug",fields:[{key:"telegramEnabled",label:r("settings.fields.telegramEnabled"),type:"boolean",description:r("settings.descriptionsFields.telegramEnabled")},...this._values.telegramEnabled?[{key:"telegramToken",label:r("settings.fields.telegramToken"),type:"password",description:r("settings.descriptionsFields.telegramToken"),placeholder:r("settings.placeholders.telegramToken")},{key:"telegramApiRoot",label:r("settings.fields.telegramApiRoot"),type:"text",description:r("settings.descriptionsFields.telegramApiRoot"),placeholder:r("settings.placeholders.telegramApiRoot")},{key:"telegramAllowFrom",label:r("settings.fields.telegramAllowFrom"),type:"text",description:r("settings.descriptionsFields.telegramAllowFrom"),placeholder:r("settings.placeholders.telegramAllowFrom")},{key:"telegramDebug",label:r("settings.fields.telegramDebug"),type:"boolean",description:r("settings.descriptionsFields.telegramDebug")}]:[],{key:"whatsappEnabled",label:r("settings.fields.whatsappEnabled"),type:"boolean",description:r("settings.descriptionsFields.whatsappEnabled")},...this._values.whatsappEnabled?[{key:"whatsappBridgeUrl",label:r("settings.fields.whatsappBridgeUrl"),type:"text",description:r("settings.descriptionsFields.whatsappBridgeUrl"),placeholder:r("settings.placeholders.whatsappBridgeUrl")},{key:"whatsappAllowFrom",label:r("settings.fields.whatsappAllowFrom"),type:"text",description:r("settings.descriptionsFields.whatsappAllowFrom"),placeholder:r("settings.placeholders.whatsappAllowFrom")}]:[]]},{id:"gateway",title:r("settings.sections.gateway"),icon:"globe",fields:[{key:"gatewayToken",label:r("settings.fields.gatewayToken"),type:"password",description:r("settings.descriptionsFields.gatewayToken"),placeholder:r("settings.placeholders.gatewayToken")},{key:"heartbeatEnabled",label:r("settings.fields.heartbeatEnabled"),type:"boolean",description:r("settings.descriptionsFields.heartbeatEnabled")},{key:"heartbeatIntervalMs",label:r("settings.fields.heartbeatIntervalMs"),type:"number",description:r("settings.descriptionsFields.heartbeatIntervalMs"),validation:{min:1e3,max:6e5}}]}]}async _loadSettings(){this._loading=!0;const e=window.location.origin,t=this.config?.token;try{await this._loadModels();const s=this._loadUiSettings();this._values.gatewayToken=s.token||"",await this._loadServerToken();const i=await fetch(`${e}/api/config`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(i.ok){const a=(await i.json()).payload?.config;if(a){let l=a.agents?.defaults?.model;l&&typeof l=="object"&&(l=l.primary||""),this._values={...this._values,model:l||"anthropic/claude-sonnet-4-5",workspace:a.agents?.defaults?.workspace||"",maxTokens:a.agents?.defaults?.maxTokens||8192,temperature:a.agents?.defaults?.temperature??.7,maxToolIterations:a.agents?.defaults?.maxToolIterations||20,openaiApiKey:a.providers?.openai?.apiKey||"",anthropicApiKey:a.providers?.anthropic?.apiKey||"",googleApiKey:a.providers?.google?.apiKey||"",qwenApiKey:a.providers?.qwen?.apiKey||"",kimiApiKey:a.providers?.kimi?.apiKey||"",minimaxApiKey:a.providers?.minimax?.apiKey||"",deepseekApiKey:a.providers?.deepseek?.apiKey||"",openrouterApiKey:a.providers?.openrouter?.apiKey||"",telegramEnabled:a.channels?.telegram?.enabled||!1,telegramToken:a.channels?.telegram?.token||"",telegramApiRoot:a.channels?.telegram?.apiRoot||"",telegramDebug:a.channels?.telegram?.debug||!1,telegramAllowFrom:(a.channels?.telegram?.allowFrom||[]).join(", "),whatsappEnabled:a.channels?.whatsapp?.enabled||!1,whatsappBridgeUrl:a.channels?.whatsapp?.bridgeUrl||"ws://localhost:3001",whatsappAllowFrom:(a.channels?.whatsapp?.allowFrom||[]).join(", "),heartbeatEnabled:a.gateway?.heartbeat?.enabled??!0,heartbeatIntervalMs:a.gateway?.heartbeat?.intervalMs||6e4}}}}catch(s){console.error("Failed to load settings:",s)}finally{this._loading=!1}}_loadUiSettings(){try{return{token:localStorage.getItem("xopcbot.token")||""}}catch{return{token:""}}}_saveUiSettings(e){try{localStorage.setItem("xopcbot.token",e)}catch(t){console.error("Failed to save UI settings:",t)}}async _loadServerToken(){try{const e=window.location.origin,t=this.config?.token,s=await fetch(`${e}/api/auth/token`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.ok&&i.payload?.token&&(this._serverToken=i.payload.token)}}catch(e){console.error("Failed to load server token:",e)}}async _refreshServerToken(){this._refreshingToken=!0;try{const e=window.location.origin,t=this.config?.token,s=await fetch(`${e}/api/auth/token/refresh`,{method:"POST",headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.ok&&i.payload?.token&&(this._serverToken=i.payload.token,this._values.gatewayToken=i.payload.token,this._saveUiSettings(i.payload.token),this.requestUpdate(),alert("Token refreshed successfully! Please copy the new token and update any other clients."))}else{const i=await s.json();throw new Error(i.error||"Failed to refresh token")}}catch(e){console.error("Failed to refresh token:",e),alert(e instanceof Error?e.message:"Failed to refresh token")}finally{this._refreshingToken=!1,this.requestUpdate()}}async _loadModels(){try{const e=window.location.origin,t=this.config?.token,s=await fetch(`${e}/api/models`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.payload?.models&&(this._models=i.payload.models)}}catch(e){console.error("Failed to load models:",e)}}async _saveSettings(){if(this._errors.size>0)return;this._saving=!0,this._saveSuccess=!1;const e=window.location.origin,t=this.config?.token,s={};(this._dirtyFields.has("model")||this._dirtyFields.has("maxTokens")||this._dirtyFields.has("temperature")||this._dirtyFields.has("maxToolIterations")||this._dirtyFields.has("workspace"))&&(s.agents={defaults:{}},this._dirtyFields.has("model")&&(s.agents.defaults.model=this._values.model),this._dirtyFields.has("workspace")&&(s.agents.defaults.workspace=this._values.workspace),this._dirtyFields.has("maxTokens")&&(s.agents.defaults.maxTokens=Number(this._values.maxTokens)),this._dirtyFields.has("temperature")&&(s.agents.defaults.temperature=Number(this._values.temperature)),this._dirtyFields.has("maxToolIterations")&&(s.agents.defaults.maxToolIterations=Number(this._values.maxToolIterations))),["openaiApiKey","anthropicApiKey","googleApiKey","qwenApiKey","kimiApiKey","minimaxApiKey","deepseekApiKey","openrouterApiKey"].filter(a=>this._dirtyFields.has(a)).length>0&&(s.providers={},this._dirtyFields.has("openaiApiKey")&&(s.providers.openai={apiKey:this._values.openaiApiKey}),this._dirtyFields.has("anthropicApiKey")&&(s.providers.anthropic={apiKey:this._values.anthropicApiKey}),this._dirtyFields.has("googleApiKey")&&(s.providers.google={apiKey:this._values.googleApiKey}),this._dirtyFields.has("qwenApiKey")&&(s.providers.qwen={apiKey:this._values.qwenApiKey}),this._dirtyFields.has("kimiApiKey")&&(s.providers.kimi={apiKey:this._values.kimiApiKey}),this._dirtyFields.has("minimaxApiKey")&&(s.providers.minimax={apiKey:this._values.minimaxApiKey}),this._dirtyFields.has("deepseekApiKey")&&(s.providers.deepseek={apiKey:this._values.deepseekApiKey}),this._dirtyFields.has("openrouterApiKey")&&(s.providers.openrouter={apiKey:this._values.openrouterApiKey})),(this._dirtyFields.has("telegramEnabled")||this._dirtyFields.has("whatsappEnabled")||this._dirtyFields.has("telegramToken")||this._dirtyFields.has("telegramApiRoot")||this._dirtyFields.has("telegramDebug")||this._dirtyFields.has("telegramAllowFrom")||this._dirtyFields.has("whatsappBridgeUrl")||this._dirtyFields.has("whatsappAllowFrom"))&&(s.channels={},(this._dirtyFields.has("telegramEnabled")||this._dirtyFields.has("telegramToken")||this._dirtyFields.has("telegramApiRoot")||this._dirtyFields.has("telegramDebug")||this._dirtyFields.has("telegramAllowFrom"))&&(s.channels={...s.channels,telegram:{}},this._dirtyFields.has("telegramEnabled")&&(s.channels.telegram.enabled=!!this._values.telegramEnabled),this._dirtyFields.has("telegramToken")&&(s.channels.telegram.token=this._values.telegramToken),this._dirtyFields.has("telegramApiRoot")&&(s.channels.telegram.apiRoot=this._values.telegramApiRoot||void 0),this._dirtyFields.has("telegramDebug")&&(s.channels.telegram.debug=!!this._values.telegramDebug),this._dirtyFields.has("telegramAllowFrom")&&(s.channels.telegram.allowFrom=this._values.telegramAllowFrom?this._values.telegramAllowFrom.split(",").map(a=>a.trim()).filter(a=>a):[])),(this._dirtyFields.has("whatsappEnabled")||this._dirtyFields.has("whatsappBridgeUrl")||this._dirtyFields.has("whatsappAllowFrom"))&&(s.channels={...s.channels,whatsapp:{}},this._dirtyFields.has("whatsappEnabled")&&(s.channels.whatsapp.enabled=!!this._values.whatsappEnabled),this._dirtyFields.has("whatsappBridgeUrl")&&(s.channels.whatsapp.bridgeUrl=this._values.whatsappBridgeUrl),this._dirtyFields.has("whatsappAllowFrom")&&(s.channels.whatsapp.allowFrom=this._values.whatsappAllowFrom?this._values.whatsappAllowFrom.split(",").map(a=>a.trim()).filter(a=>a):[]))),(this._dirtyFields.has("heartbeatEnabled")||this._dirtyFields.has("heartbeatIntervalMs"))&&(s.gateway={heartbeat:{}},this._dirtyFields.has("heartbeatEnabled")&&(s.gateway.heartbeat.enabled=!!this._values.heartbeatEnabled),this._dirtyFields.has("heartbeatIntervalMs")&&(s.gateway.heartbeat.intervalMs=Number(this._values.heartbeatIntervalMs)));try{const a=await fetch(`${e}/api/config`,{method:"PATCH",headers:{"Content-Type":"application/json",...t?{Authorization:`Bearer ${t}`}:{}},body:JSON.stringify(s)});if(!a.ok){const l=await a.json();throw new Error(l.error||"Failed to save settings")}this._dirtyFields.clear(),this._dirtyFields.has("gatewayToken")&&this._saveUiSettings(this._values.gatewayToken||""),this._saveSuccess=!0,setTimeout(()=>{this._saveSuccess=!1},3e3)}catch(a){console.error("Failed to save settings:",a),alert(a instanceof Error?a.message:"Failed to save settings")}finally{this._saving=!1}}_handleInput(e,t){this._values={...this._values,[e]:t},this._dirtyFields.add(e),this.requestUpdate()}render(){return o`
1653
- <div class="settings-page">
1654
- <div class="settings-sidebar">
1655
- <div class="sidebar-header">
1656
- <h3>${r("settings.title")}</h3>
1657
- </div>
1658
- <nav class="sidebar-nav">
1659
- ${this._sections.map(e=>o`
1660
- <button
1661
- class="nav-item ${this._activeSection===e.id?"active":""}"
1662
- @click=${()=>this._activeSection=e.id}
1663
- >
1664
- ${d(e.icon)}
1665
- <span>${e.title}</span>
1666
- </button>
1667
- `)}
1668
- </nav>
1669
- </div>
1670
-
1671
- <div class="settings-main">
1672
- ${this._loading?o`
1673
- <div class="loading-state">
1674
- <div class="spinner"></div>
1675
- <p>${r("settings.loading")}</p>
1676
- </div>
1677
- `:this._renderSection()}
1678
- </div>
1679
-
1680
- <!-- Save button floating -->
1681
- ${this._dirtyFields.size>0?o`
1682
- <div class="floating-save">
1683
- <span class="dirty-count">${r("settings.unsaved",{count:this._dirtyFields.size})}</span>
1684
- <button
1685
- class="btn btn-primary"
1686
- ?disabled=${this._saving||this._errors.size>0}
1687
- @click=${this._saveSettings}
1688
- >
1689
- ${this._saving?o`
1690
- <span class="spinner-sm"></span>
1691
- ${r("settings.saving")}
1692
- `:o`
1693
- <span>${d("save")}</span>
1694
- ${r("settings.saveChanges")}
1695
- `}
1696
- </button>
1697
- </div>
1698
- `:""}
1699
- </div>
1700
- `}_renderSection(){const e=this._sections.find(s=>s.id===this._activeSection);if(!e)return o`<div>${r("settings.noSection")}</div>`;const t=`settings.descriptions.${e.id}`;return o`
1701
- <div class="section-content">
1702
- <div class="section-header">
1703
- <h2>${e.title}</h2>
1704
- <p class="section-desc">${r(t)}</p>
1705
- </div>
1706
-
1707
- ${e.id==="gateway"?this._renderGatewaySection():""}
1708
-
1709
- <div class="fields-grid">
1710
- ${e.fields.map(s=>this._renderField(s))}
1711
- </div>
1712
- </div>
1713
- `}_renderGatewaySection(){const e=this._serverToken?`${this._serverToken.slice(0,8)}...${this._serverToken.slice(-8)}`:"Not available";return o`
1714
- <div class="gateway-token-section" style="margin-bottom: 24px; padding: 16px; background: var(--muted); border-radius: 8px;">
1715
- <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;">
1716
- <h4 style="margin: 0; font-size: 14px; font-weight: 600;">Server Authentication Token</h4>
1717
- <button
1718
- class="btn btn-sm btn-secondary"
1719
- ?disabled=${this._refreshingToken}
1720
- @click=${this._refreshServerToken}
1721
- style="display: flex; align-items: center; gap: 6px;"
1722
- >
1723
- ${this._refreshingToken?o`
1724
- <span class="spinner-sm"></span>
1725
- Refreshing...
1726
- `:o`
1727
- ${d("refreshCw")}
1728
- Refresh Token
1729
- `}
1730
- </button>
1731
- </div>
1732
-
1733
- <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 8px;">
1734
- <code style="flex: 1; padding: 8px 12px; background: var(--background); border-radius: 4px; font-family: monospace; font-size: 13px; word-break: break-all;">
1735
- ${this._showToken?this._serverToken||"Not available":e}
1736
- </code>
1737
- <button
1738
- class="btn btn-icon"
1739
- @click=${()=>this._showToken=!this._showToken}
1740
- title=${this._showToken?"Hide token":"Show token"}
1741
- >
1742
- ${this._showToken?d("eyeOff"):d("eye")}
1743
- </button>
1744
- <button
1745
- class="btn btn-icon"
1746
- ?disabled=${!this._serverToken}
1747
- @click=${()=>{this._serverToken&&(navigator.clipboard.writeText(this._serverToken),alert("Token copied to clipboard!"))}}
1748
- title="Copy token"
1749
- >
1750
- ${d("copy")}
1751
- </button>
1752
- </div>
1753
-
1754
- <p style="margin: 0; font-size: 12px; color: var(--muted-foreground);">
1755
- This is the current server token. Click "Refresh Token" to generate a new one.
1756
- After refreshing, copy the new token and update your client configuration.
1757
- </p>
1758
- </div>
1759
- `}_renderField(e){const t=this._values[e.key],s=this._errors.get(e.key);return o`
1760
- <div class="field-group ${s?"has-error":""}">
1761
- <div class="field-header">
1762
- <label class="field-label">${e.label}</label>
1763
- ${e.validation?.required?o`<span class="required-mark">*</span>`:""}
1764
- </div>
1765
-
1766
- ${e.description?o`<p class="field-desc">${e.description}</p>`:""}
1767
-
1768
- ${e.type==="boolean"?this._renderBooleanField(e,t):""}
1769
- ${e.type==="select"?this._renderSelectField(e,t):""}
1770
- ${["text","password","number"].includes(e.type)?this._renderInputField(e,t):""}
1771
-
1772
- ${s?o`
1773
- <div class="field-error">
1774
- <span>${s}</span>
1775
- </div>
1776
- `:""}
1777
- </div>
1778
- `}_renderInputField(e,t){return o`
1779
- <input
1780
- type=${e.type==="number"?"number":"text"}
1781
- class="text-input"
1782
- .value=${String(t??"")}
1783
- placeholder=${e.placeholder||""}
1784
- minlength=${e.validation?.min}
1785
- maxlength=${e.validation?.max}
1786
- min=${e.validation?.min}
1787
- max=${e.validation?.max}
1788
- @input=${s=>this._handleInput(e.key,s.target.value)}
1789
- />
1790
- `}_renderSelectField(e,t){return o`
1791
- <select
1792
- class="select-input"
1793
- .value=${String(t??"")}
1794
- @change=${s=>this._handleInput(e.key,s.target.value)}
1795
- >
1796
- ${e.options?.map(s=>o`
1797
- <option value=${s.value} ?selected=${t===s.value}>${s.label}</option>
1798
- `)}
1799
- </select>
1800
- `}_renderBooleanField(e,t){return o`
1801
- <label class="toggle-label">
1802
- <input
1803
- type="checkbox"
1804
- class="toggle-input"
1805
- .checked=${!!t}
1806
- @change=${s=>this._handleInput(e.key,s.target.checked)}
1807
- />
1808
- <span class="toggle-switch"></span>
1809
- <span class="toggle-text">${e.description||r("settings.enableFeature")}</span>
1810
- </label>
1811
- `}};P([u({attribute:!1})],E.prototype,"config",2);P([c()],E.prototype,"_activeSection",2);P([c()],E.prototype,"_loading",2);P([c()],E.prototype,"_saving",2);P([c()],E.prototype,"_refreshingToken",2);P([c()],E.prototype,"_serverToken",2);P([c()],E.prototype,"_showToken",2);P([c()],E.prototype,"_dirtyFields",2);P([c()],E.prototype,"_errors",2);P([c()],E.prototype,"_saveSuccess",2);P([c()],E.prototype,"_models",2);P([c()],E.prototype,"_values",2);E=P([k("settings-page")],E);var _i=Object.defineProperty,mi=Object.getOwnPropertyDescriptor,le=(e,t,s,i)=>{for(var n=i>1?void 0:i?mi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&_i(t,s,n),n};let X=class extends y{constructor(){super(...arguments),this._token="",this._showToken=!1,this._loading=!1,this._error=""}createRenderRoot(){return this}_handleSave(){if(!this._token.trim()){this._error="Please enter a token";return}this.config?.onSave(this._token.trim())}_handleKeydown(e){e.key==="Enter"&&this._handleSave()}render(){return o`
1812
- <div class="token-dialog-overlay" @click=${this._handleOverlayClick}>
1813
- <div class="token-dialog" @click=${e=>e.stopPropagation()}>
1814
- <div class="token-dialog-header">
1815
- <h3>🔐 Authentication Required</h3>
1816
- <p>Please enter your gateway authentication token to continue.</p>
1817
- </div>
1818
-
1819
- <div class="token-dialog-body">
1820
- <div class="field-group">
1821
- <label class="field-label">Gateway URL</label>
1822
- <input
1823
- type="text"
1824
- class="text-input"
1825
- .value=${this.config?.serverUrl||""}
1826
- disabled
1827
- />
1828
- </div>
1829
-
1830
- <div class="field-group">
1831
- <label class="field-label">Token</label>
1832
- <div class="token-input-wrapper">
1833
- <input
1834
- type=${this._showToken?"text":"password"}
1835
- class="text-input"
1836
- .value=${this._token}
1837
- placeholder="Enter your gateway token (e.g., ea4c67bf...)"
1838
- @input=${e=>{this._token=e.target.value,this._error=""}}
1839
- @keydown=${this._handleKeydown}
1840
- />
1841
- <button
1842
- class="btn btn-icon toggle-visibility"
1843
- @click=${()=>this._showToken=!this._showToken}
1844
- title=${this._showToken?"Hide token":"Show token"}
1845
- >
1846
- ${this._showToken?d("eyeOff"):d("eye")}
1847
- </button>
1848
- </div>
1849
- ${this._error?o`<span class="field-error">${this._error}</span>`:""}
1850
- </div>
1851
-
1852
- <div class="token-hint">
1853
- <p>💡 <strong>How to get your token:</strong></p>
1854
- <ol>
1855
- <li>Run <code>xopcbot gateway token</code> in your terminal</li>
1856
- <li>Or run <code>xopcbot gateway token --generate</code> to create a new one</li>
1857
- <li>Copy the token and paste it here</li>
1858
- </ol>
1859
- </div>
1860
- </div>
1861
-
1862
- <div class="token-dialog-footer">
1863
- <button
1864
- class="btn btn-primary"
1865
- ?disabled=${this._loading}
1866
- @click=${this._handleSave}
1867
- >
1868
- ${this._loading?o`
1869
- <span class="spinner-sm"></span>
1870
- Connecting...
1871
- `:o`
1872
- ${d("check")}
1873
- Connect
1874
- `}
1875
- </button>
1876
- </div>
1877
- </div>
1878
- </div>
1879
- `}_handleOverlayClick(e){this.config?.onCancel&&this.config.onCancel()}};le([u({attribute:!1})],X.prototype,"config",2);le([c()],X.prototype,"_token",2);le([c()],X.prototype,"_showToken",2);le([c()],X.prototype,"_loading",2);le([c()],X.prototype,"_error",2);X=le([k("token-dialog")],X);function vi(){return[{label:r("nav.chat"),tabs:["chat"]},{label:r("nav.management"),tabs:["sessions","cron","logs"]},{label:r("nav.settings"),tabs:["settings"]}]}function fi(e){return r(`nav.${e}`)}const yi={chat:"messageSquare",sessions:"folderOpen",cron:"clock",logs:"fileText",settings:"settings"};function wi(e){const t=e.replace(/^#\/?chat\/?/,"");if(!t||t==="/")return{type:"recent"};const s=t.replace(/^\/?/,"");return s==="new"?{type:"new"}:s&&s.length>0?{type:"session",sessionKey:decodeURIComponent(s)}:{type:"recent"}}function ot(e){switch(e.type){case"recent":return"#/chat";case"new":return"#/chat/new";case"session":return`#/chat/${encodeURIComponent(e.sessionKey)}`}}function bi(e,t,s){const i=yi[e],n=fi(e);return o`
1880
- <button
1881
- class="nav-item ${t?"nav-item--active":""}"
1882
- @click=${s}
1883
- role="tab"
1884
- aria-selected=${t}
1885
- >
1886
- <span class="nav-item__icon">${d(i)}</span>
1887
- <span class="nav-item__text">${n}</span>
1888
- </button>
1889
- `}const yt="xopcbot.token",wt="xopcbot.theme",bt="xopcbot.language";function z(){try{return localStorage.getItem(yt)||""}catch{return""}}function at(e){try{localStorage.setItem(yt,e)}catch(t){console.error("Failed to save token:",t)}}function $i(){try{const e=localStorage.getItem(wt);return e==="light"||e==="dark"||e==="system"?e:"system"}catch{return"system"}}function ki(e){try{localStorage.setItem(wt,e)}catch(t){console.error("Failed to save theme:",t)}}function xi(){try{const e=localStorage.getItem(bt);return e==="en"||e==="zh"?e:"en"}catch{return"en"}}function Si(e){try{localStorage.setItem(bt,e)}catch(t){console.error("Failed to save language:",t)}}var Ai=Object.defineProperty,Ci=Object.getOwnPropertyDescriptor,O=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ci(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ai(t,s,n),n};let L=class extends y{constructor(){super(),this._gatewayConfig={url:window.location.origin,token:z()||void 0},this._activeTab="chat",this._navCollapsed=!1,this._navMobileOpen=!1,this._theme="system",this._language="en",this._chatRoute={type:"recent"},this._showTokenDialog=!1}get gatewayConfig(){return this._gatewayConfig}set gatewayConfig(e){this._gatewayConfig=e||{url:window.location.origin}}_initializeToken(){const t=new URLSearchParams(window.location.search).get("token");if(t){at(t);const i=window.location.pathname+window.location.hash;window.history.replaceState({},"",i)}const s=z();this._gatewayConfig={url:window.location.origin,token:s||void 0},this._showTokenDialog=!s}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._initializeToken(),this._loadTheme(),this._loadLanguage(),this._loadRouteFromHash(),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{this._theme==="system"&&this._applyTheme()}),window.addEventListener("languagechange",()=>{this.requestUpdate()}),window.addEventListener("hashchange",()=>{this._loadRouteFromHash()})}_loadRouteFromHash(){const e=location.hash.slice(1);if(e.startsWith("chat")){const i=wi(e);i&&(this._activeTab!=="chat"&&(this._activeTab="chat"),JSON.stringify(this._chatRoute)!==JSON.stringify(i)&&(this._chatRoute=i));return}const t=e;["sessions","cron","logs","settings"].includes(t)&&this._activeTab!==t&&(this._activeTab=t)}_switchTab(e){this._activeTab=e;let t;e==="chat"?t=ot(this._chatRoute):t=`#${e}`,location.hash!==t&&history.pushState(null,"",t),this._navMobileOpen=!1}_updateChatRoute(e){this._chatRoute=e;const t=ot(e);history.pushState(null,"",t)}_loadTheme(){this._theme=$i(),this._applyTheme()}_loadLanguage(){this._language=xi(),nt(this._language)}_applyTheme(){const e=document.documentElement;e.classList.remove("light","dark");let t=!1;this._theme==="dark"?t=!0:this._theme==="system"&&(t=window.matchMedia("(prefers-color-scheme: dark)").matches),t?e.classList.add("dark"):e.classList.add("light"),window.dispatchEvent(new CustomEvent("themechange",{detail:{theme:t?"dark":"light"}}))}_setTheme(e){this._theme=e,ki(e),this._applyTheme()}_setLanguage(e){this._language=e,nt(e),Si(e),this.requestUpdate()}_renderThemeToggle(){return o`
1890
- <div class="pill-toggle">
1891
- <button
1892
- class="pill-btn ${this._theme==="light"?"active":""}"
1893
- @click=${()=>this._setTheme("light")}
1894
- title="Light"
1895
- >
1896
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1897
- <circle cx="12" cy="12" r="5"></circle>
1898
- <line x1="12" y1="1" x2="12" y2="3"></line>
1899
- <line x1="12" y1="21" x2="12" y2="23"></line>
1900
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
1901
- <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
1902
- <line x1="1" y1="12" x2="3" y2="12"></line>
1903
- <line x1="21" y1="12" x2="23" y2="12"></line>
1904
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
1905
- <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
1906
- </svg>
1907
- </button>
1908
- <button
1909
- class="pill-btn ${this._theme==="dark"?"active":""}"
1910
- @click=${()=>this._setTheme("dark")}
1911
- title="Dark"
1912
- >
1913
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1914
- <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
1915
- </svg>
1916
- </button>
1917
- <button
1918
- class="pill-btn ${this._theme==="system"?"active":""}"
1919
- @click=${()=>this._setTheme("system")}
1920
- title="System"
1921
- >
1922
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1923
- <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
1924
- <line x1="8" y1="21" x2="16" y2="21"></line>
1925
- <line x1="12" y1="17" x2="12" y2="21"></line>
1926
- </svg>
1927
- </button>
1928
- </div>
1929
- `}_renderLanguageToggle(){return o`
1930
- <div class="pill-toggle">
1931
- <button
1932
- class="pill-btn ${this._language==="en"?"active":""}"
1933
- @click=${()=>this._setLanguage("en")}
1934
- title="English"
1935
- >
1936
- EN
1937
- </button>
1938
- <button
1939
- class="pill-btn ${this._language==="zh"?"active":""}"
1940
- @click=${()=>this._setLanguage("zh")}
1941
- title="中文"
1942
- >
1943
-
1944
- </button>
1945
- </div>
1946
- `}_toggleNav(){window.innerWidth<768?this._navMobileOpen=!this._navMobileOpen:this._navCollapsed=!this._navCollapsed}_closeNavMobile(){this._navMobileOpen=!1}_handleTokenSave(e){at(e),this._gatewayConfig={url:window.location.origin,token:e},this._showTokenDialog=!1,this.requestUpdate()}render(){return this._showTokenDialog?o`
1947
- <token-dialog
1948
- .config=${{serverUrl:window.location.origin,onSave:e=>this._handleTokenSave(e)}}
1949
- ></token-dialog>
1950
- `:o`
1951
- <div class="shell ${this._activeTab==="chat"?"shell--chat":""} ${this._navCollapsed?"shell--nav-collapsed":""}">
1952
- <!-- Topbar -->
1953
- <header class="topbar">
1954
- <div class="topbar-left">
1955
- <button
1956
- class="nav-collapse-toggle"
1957
- @click=${this._toggleNav}
1958
- title="${this._navCollapsed?"Expand sidebar":"Collapse sidebar"}"
1959
- aria-label="${this._navCollapsed?"Expand sidebar":"Collapse sidebar"}"
1960
- >
1961
- <span class="nav-collapse-toggle__icon">${d("menu")}</span>
1962
- </button>
1963
-
1964
- <div class="brand">
1965
- <div class="brand-logo">
1966
- <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1967
- <rect width="24" height="24" rx="6" fill="url(#logo-gradient)"/>
1968
- <path d="M8 12L11 15L16 9" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1969
- <defs>
1970
- <linearGradient id="logo-gradient" x1="0" y1="0" x2="24" y2="24" gradientUnits="userSpaceOnUse">
1971
- <stop stop-color="#3b82f6"/>
1972
- <stop offset="1" stop-color="#8b5cf6"/>
1973
- </linearGradient>
1974
- </defs>
1975
- </svg>
1976
- </div>
1977
- <div class="brand-text">
1978
- <div class="brand-title">XOPCBOT</div>
1979
- <div class="brand-sub">Gateway</div>
1980
- </div>
1981
- </div>
1982
- </div>
1983
-
1984
- <div class="topbar-status">
1985
- ${this._renderLanguageToggle()}
1986
- ${this._renderThemeToggle()}
1987
- </div>
1988
- </header>
1989
-
1990
- <!-- Mobile Overlay Backdrop -->
1991
- ${this._navMobileOpen?o`
1992
- <div class="nav-overlay" @click=${this._closeNavMobile}></div>
1993
- `:_}
1994
-
1995
- <div class="shell-main">
1996
- <!-- Sidebar Navigation -->
1997
- <aside class="nav ${this._navCollapsed?"nav--collapsed":""} ${this._navMobileOpen?"nav--mobile-open":""}">
1998
- ${vi().map(e=>(e.tabs.some(t=>t===this._activeTab),o`
1999
- <div class="nav-group">
2000
- <div class="nav-label nav-label--static">
2001
- <span class="nav-label__text">${e.label}</span>
2002
- </div>
2003
- <div class="nav-group__items">
2004
- ${e.tabs.map(t=>bi(t,this._activeTab===t,()=>{this._switchTab(t)}))}
2005
- </div>
2006
- </div>
2007
- `))}
2008
- </aside>
2009
-
2010
- <!-- Main Content -->
2011
- <main class="content ${this._activeTab==="chat"?"content--chat":""}">
2012
- ${this._activeTab==="chat"?this._renderChat():_}
2013
- ${this._activeTab==="sessions"?this._renderSessions():_}
2014
- ${this._activeTab==="cron"?this._renderCron():_}
2015
- ${this._activeTab==="logs"?this._renderLogs():_}
2016
- ${this._activeTab==="settings"?this._renderSettings():_}
2017
- </main>
2018
- </div>
2019
- </div>
2020
- `}_renderChat(){const e=z();return o`
2021
- <xopcbot-gateway-chat
2022
- .config=${{url:window.location.origin,token:e||void 0}}
2023
- .route=${this._chatRoute}
2024
- .enableAttachments=${!0}
2025
- .enableModelSelector=${!0}
2026
- .enableThinkingSelector=${!0}
2027
- @route-change=${t=>this._updateChatRoute(t.detail)}
2028
- ></xopcbot-gateway-chat>
2029
- `}_renderSessions(){const e=z()||this._gatewayConfig?.token;return o`
2030
- <session-manager
2031
- .config=${{token:e}}
2032
- ></session-manager>
2033
- `}_renderCron(){const e=z()||this._gatewayConfig?.token;return o`
2034
- <cron-manager
2035
- .config=${{token:e}}
2036
- ></cron-manager>
2037
- `}_renderLogs(){const e=z()||this._gatewayConfig?.token;return o`
2038
- <log-manager
2039
- .config=${{token:e}}
2040
- ></log-manager>
2041
- `}_renderSettings(){const e=z()||this._gatewayConfig?.token;return o`
2042
- <settings-page
2043
- .config=${{token:e}}
2044
- ></settings-page>
2045
- `}showChat(){this._activeTab="chat"}get chatElement(){return this._chatElement}};O([c()],L.prototype,"_gatewayConfig",2);O([c()],L.prototype,"_activeTab",2);O([c()],L.prototype,"_navCollapsed",2);O([c()],L.prototype,"_navMobileOpen",2);O([c()],L.prototype,"_theme",2);O([c()],L.prototype,"_language",2);O([c()],L.prototype,"_chatRoute",2);O([c()],L.prototype,"_showTokenDialog",2);O([oe("xopcbot-gateway-chat")],L.prototype,"_chatElement",2);L=O([k("xopcbot-app")],L);var Ti=Object.defineProperty,Mi=Object.getOwnPropertyDescriptor,R=(e,t,s,i)=>{for(var n=i>1?void 0:i?Mi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ti(t,s,n),n};let D=class extends y{constructor(){super(...arguments),this.sections=[],this.values={},this.loading=!1,this._activeSection="",this._dirtyFields=new Set,this._showPasswords=new Set,this._errors=new Map}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._updateActiveSection()}willUpdate(e){e.has("sections")&&this._updateActiveSection()}_updateActiveSection(){this.sections.length>0&&!this._activeSection&&(this._activeSection=this.sections[0].id)}_getIcon(e){return{user:o`<User class="w-5 h-5" />`,bot:o`<Bot class="w-5 h-5" />`,plug:o`<Plug class="w-5 h-5" />`,globe:o`<Globe class="w-5 h-5" />`,search:o`<Search class="w-5 h-5" />`,clock:o`<Clock class="w-5 h-5" />`,puzzle:o`<Puzzle class="w-5 h-5" />`,settings:o`<Settings class="w-5 h-5" />`}[e]||o`<Settings class="w-5 h-5" />`}render(){return o`
2046
- <div class="settings-overlay" @click=${e=>e.target===e.currentTarget&&this.onClose?.()}>
2047
- <div class="settings-dialog">
2048
- ${this.renderHeader()}
2049
- <div class="settings-content">
2050
- ${this.renderSidebar()}
2051
- ${this.renderMain()}
2052
- </div>
2053
- ${this.renderFooter()}
2054
- </div>
2055
- </div>
2056
- `}renderHeader(){return o`
2057
- <div class="settings-header">
2058
- <div class="settings-title">
2059
- <Settings class="w-5 h-5" />
2060
- <span>Settings</span>
2061
- </div>
2062
- <button class="close-btn" @click=${()=>this.onClose?.()}>
2063
- <X class="w-5 h-5" />
2064
- </button>
2065
- </div>
2066
- `}renderSidebar(){return o`
2067
- <nav class="settings-sidebar">
2068
- ${this.sections.map(e=>o`
2069
- <button
2070
- class="sidebar-item ${this._activeSection===e.id?"active":""}"
2071
- @click=${()=>this._activeSection=e.id}
2072
- >
2073
- ${this._getIcon(e.icon)}
2074
- <span>${e.title}</span>
2075
- <ChevronRight class="w-4 h-4 chevron" />
2076
- </button>
2077
- `)}
2078
- </nav>
2079
- `}renderMain(){const e=this.sections.find(s=>s.id===this._activeSection);if(!e)return o`<div class="settings-main">${r("settings.noSection")}</div>`;const t=`settings.descriptions.${e.id}`;return o`
2080
- <div class="settings-main">
2081
- <div class="section-header">
2082
- <h2>${e.title}</h2>
2083
- <p class="section-description">${r(t)}</p>
2084
- </div>
2085
-
2086
- <div class="fields-grid">
2087
- ${e.fields.map(s=>this.renderField(s,e.id))}
2088
- </div>
2089
- </div>
2090
- `}renderField(e,t){const s=`${t}.${e.key}`,i=this._getValue(e.key),n=this._dirtyFields.has(s),a=this._errors.get(s),l=this._showPasswords.has(s);return o`
2091
- <div class="field-group ${a?"has-error":""}">
2092
- <div class="field-header">
2093
- <label class="field-label">${e.label}</label>
2094
- ${e.validation?.required?o`<span class="required-mark">*</span>`:""}
2095
- </div>
2096
-
2097
- ${e.description?o`<p class="field-description">${e.description}</p>`:""}
2098
-
2099
- ${e.type==="boolean"?this.renderBooleanField(e,i,s):""}
2100
-
2101
- ${e.type==="select"?this.renderSelectField(e,i,s):""}
2102
-
2103
- ${e.type==="textarea"?this.renderTextareaField(e,i,s):""}
2104
-
2105
- ${["text","password","number"].includes(e.type)?this.renderInputField(e,i,s,l):""}
2106
-
2107
- ${a?o`
2108
- <div class="field-error">
2109
- <AlertCircle class="w-4 h-4" />
2110
- <span>${a}</span>
2111
- </div>
2112
- `:""}
2113
-
2114
- ${n&&!a?o`
2115
- <div class="field-dirty">${r("settings.unsavedChanges")}</div>
2116
- `:""}
2117
- </div>
2118
- `}renderInputField(e,t,s,i){const n=e.type==="password"?i?"text":"password":e.type;return o`
2119
- <div class="input-wrapper">
2120
- <input
2121
- type=${n}
2122
- class="text-input ${e.type==="password"?"has-toggle":""}"
2123
- .value=${String(t??"")}
2124
- placeholder=${e.placeholder||""}
2125
- minlength=${e.validation?.min}
2126
- maxlength=${e.validation?.max}
2127
- pattern=${e.validation?.pattern||""}
2128
- @input=${a=>this._handleInput(e,s,a.target.value)}
2129
- />
2130
- ${e.type==="password"?o`
2131
- <button
2132
- type="button"
2133
- class="password-toggle"
2134
- @click=${()=>this._togglePassword(s)}
2135
- >
2136
- ${i?o`<EyeOff class="w-4 h-4" />`:o`<Eye class="w-4 h-4" />`}
2137
- </button>
2138
- `:""}
2139
- </div>
2140
- `}renderTextareaField(e,t,s){return o`
2141
- <textarea
2142
- class="textarea-input"
2143
- .value=${String(t??"")}
2144
- placeholder=${e.placeholder||""}
2145
- rows="4"
2146
- @input=${i=>this._handleInput(e,s,i.target.value)}
2147
- ></textarea>
2148
- `}renderSelectField(e,t,s){return o`
2149
- <select
2150
- class="select-input"
2151
- .value=${String(t??"")}
2152
- @change=${i=>this._handleInput(e,s,i.target.value)}
2153
- >
2154
- ${e.options?.map(i=>o`
2155
- <option value=${i.value} ?selected=${t===i.value}>${i.label}</option>
2156
- `)}
2157
- </select>
2158
- `}renderBooleanField(e,t,s){return o`
2159
- <label class="toggle-label">
2160
- <input
2161
- type="checkbox"
2162
- class="toggle-input"
2163
- .checked=${!!t}
2164
- @change=${i=>this._handleInput(e,s,i.target.checked)}
2165
- />
2166
- <span class="toggle-switch"></span>
2167
- <span class="toggle-text">${e.description||r("settings.enableFeature")}</span>
2168
- </label>
2169
- `}renderFooter(){const e=this._dirtyFields.size>0;return o`
2170
- <div class="settings-footer">
2171
- <button class="btn btn-ghost" @click=${()=>this.onClose?.()}>
2172
- ${r("settings.cancel")}
2173
- </button>
2174
- <button
2175
- class="btn btn-primary"
2176
- ?disabled=${this.loading||!e}
2177
- @click=${()=>this._save()}
2178
- >
2179
- ${this.loading?o`
2180
- <Loader2 class="w-4 h-4 animate-spin" />
2181
- ${r("settings.saving")}
2182
- `:o`
2183
- <Save class="w-4 h-4" />
2184
- ${r("settings.saveChanges")}
2185
- `}
2186
- </button>
2187
- </div>
2188
- `}_getValue(e){return this.values[e]}_handleInput(e,t,s){e.validation?.required&&!s?this._errors.set(t,r("settings.required",{field:e.label})):e.validation?.pattern&&s?new RegExp(e.validation.pattern).test(s)?this._errors.delete(t):this._errors.set(t,r("settings.invalidFormat")):this._errors.delete(t),this._dirtyFields.add(t),this.requestUpdate()}_togglePassword(e){this._showPasswords.has(e)?this._showPasswords.delete(e):this._showPasswords.add(e),this.requestUpdate()}_save(){this._errors.size>0||this.onSave&&this.onSave(this.values)}};R([u({attribute:!1})],D.prototype,"sections",2);R([u({attribute:!1})],D.prototype,"values",2);R([u({type:Boolean})],D.prototype,"loading",2);R([u({attribute:!1})],D.prototype,"onSave",2);R([u({attribute:!1})],D.prototype,"onClose",2);R([c()],D.prototype,"_activeSection",2);R([c()],D.prototype,"_dirtyFields",2);R([c()],D.prototype,"_showPasswords",2);R([c()],D.prototype,"_errors",2);D=R([k("xopcbot-settings")],D);var Ei=Object.defineProperty,Pi=Object.getOwnPropertyDescriptor,ee=(e,t,s,i)=>{for(var n=i>1?void 0:i?Pi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ei(t,s,n),n};let H=class extends y{constructor(){super(...arguments),this.enableAttachments=!0,this.enableModelSelector=!0,this.enableThinkingSelector=!0,this._autoScroll=!0,this._lastScrollTop=0,this._handleScroll=()=>{if(!this._scrollContainer)return;const e=this._scrollContainer.scrollTop,t=this._scrollContainer.scrollHeight,s=this._scrollContainer.clientHeight,i=t-e-s;if(s<this._lastClientHeight){this._lastClientHeight=s;return}e!==0&&e<this._lastScrollTop&&i>50?this._autoScroll=!1:i<10&&(this._autoScroll=!0),this._lastScrollTop=e,this._lastClientHeight=s}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.style.display="flex",this.style.flexDirection="column",this.style.height="100%",this.style.minHeight="0",this.setupSessionSubscription()}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver?.disconnect(),this._scrollContainer?.removeEventListener("scroll",this._handleScroll),this._unsubscribeSession?.()}setupSessionSubscription(){this._unsubscribeSession&&this._unsubscribeSession(),this.agent&&(this._unsubscribeSession=this.agent.subscribe(async e=>{switch(e.type){case"message_start":case"message_end":case"turn_start":case"turn_end":case"agent_start":this.requestUpdate();break;case"agent_end":this._streamingContainer&&(this._streamingContainer.isStreaming=!1,this._streamingContainer.setMessage(null,!0)),this.requestUpdate();break;case"message_update":this._streamingContainer&&(this._streamingContainer.isStreaming=this.agent?.state.isStreaming||!1,this._streamingContainer.setMessage(e.message,!this._streamingContainer.isStreaming)),this.requestUpdate();break}}))}setInput(e,t){this._messageEditor&&(this._messageEditor.value=e,this._messageEditor.attachments=t||[])}setAutoScroll(e){this._autoScroll=e}async sendMessage(e,t){if(!(!e.trim()&&t?.length===0||this.agent?.state.isStreaming)){if(!this.agent)throw new Error("No agent set");if(!this.agent.state.model)throw new Error("No model set");this._messageEditor.value="",this._messageEditor.attachments=[],this._autoScroll=!0,t&&t.length>0?await this.agent.prompt({role:"user-with-attachments",content:e,attachments:t,timestamp:Date.now()}):await this.agent.prompt(e)}}renderMessages(){if(!this.agent)return o`<div class="p-4 text-center text-muted-foreground">${ie("No session available")}</div>`;const e=this.agent.state;return o`
2189
- <div class="flex flex-col gap-3">
2190
- <message-list
2191
- .messages=${this.agent.state.messages}
2192
- .tools=${e.tools}
2193
- .pendingToolCalls=${this.agent?this.agent.state.pendingToolCalls:new Set}
2194
- .isStreaming=${e.isStreaming}
2195
- ></message-list>
2196
-
2197
- <streaming-message-container
2198
- class="${e.isStreaming?"":"hidden"}"
2199
- .tools=${e.tools}
2200
- .isStreaming=${e.isStreaming}
2201
- .pendingToolCalls=${e.pendingToolCalls}
2202
- .isStreaming=${e.isStreaming}
2203
- ></streaming-message-container>
2204
- </div>
2205
- `}render(){if(!this.agent)return o`<div class="p-4 text-center text-muted-foreground">${ie("No agent set")}</div>`;const e=this.agent.state;return o`
2206
- <div class="flex flex-col h-full bg-background text-foreground">
2207
- <div class="flex-1 overflow-y-auto">
2208
- <div class="max-w-3xl mx-auto p-4 pb-0">${this.renderMessages()}</div>
2209
- </div>
2210
-
2211
- <div class="shrink-0">
2212
- <div class="max-w-3xl mx-auto px-2">
2213
- <message-editor
2214
- .isStreaming=${e.isStreaming}
2215
- .currentModel=${e.model}
2216
- .thinkingLevel=${e.thinkingLevel}
2217
- .showAttachmentButton=${this.enableAttachments}
2218
- .showModelSelector=${this.enableModelSelector}
2219
- .showThinkingSelector=${this.enableThinkingSelector}
2220
- .onSend=${(t,s)=>this.sendMessage(t,s)}
2221
- .onAbort=${()=>this.agent?.abort()}
2222
- ></message-editor>
2223
- </div>
2224
- </div>
2225
- </div>
2226
- `}};ee([u({attribute:!1})],H.prototype,"agent",2);ee([u({type:Boolean})],H.prototype,"enableAttachments",2);ee([u({type:Boolean})],H.prototype,"enableModelSelector",2);ee([u({type:Boolean})],H.prototype,"enableThinkingSelector",2);ee([oe("message-editor")],H.prototype,"_messageEditor",2);ee([oe("streaming-message-container")],H.prototype,"_streamingContainer",2);H=ee([k("xopcbot-chat")],H);
2227
- //# sourceMappingURL=main-DevbZW9K.js.map