xiaozuoassistant 0.2.7 → 0.2.8

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 (54) hide show
  1. package/dist/client/assets/browser-ponyfill-C7q-vgM7.js +2 -0
  2. package/dist/client/assets/index-DkOojrRj.js +201 -0
  3. package/dist/client/assets/index-u0lXmgyZ.css +1 -0
  4. package/dist/client/favicon.svg +4 -0
  5. package/dist/client/index.html +14 -0
  6. package/dist/client/locales/en/translation.json +110 -0
  7. package/dist/client/locales/zh/translation.json +112 -0
  8. package/dist/server/agents/office.js +23 -0
  9. package/dist/server/app.js +50 -0
  10. package/dist/server/channels/base-channel.js +23 -0
  11. package/dist/server/channels/create-channels.js +18 -0
  12. package/dist/server/channels/dingtalk.js +83 -0
  13. package/dist/server/channels/feishu.js +108 -0
  14. package/dist/server/channels/telegram.js +53 -0
  15. package/dist/server/channels/terminal.js +49 -0
  16. package/dist/server/channels/web.js +66 -0
  17. package/dist/server/channels/wechat.js +107 -0
  18. package/dist/server/config/loader.js +96 -0
  19. package/dist/server/config/paths.js +24 -0
  20. package/dist/server/config/prompts.js +12 -0
  21. package/dist/server/core/agents/manager.js +27 -0
  22. package/dist/server/core/agents/runtime.js +92 -0
  23. package/dist/server/core/brain.js +255 -0
  24. package/dist/server/core/event-bus.js +24 -0
  25. package/dist/server/core/logger.js +71 -0
  26. package/dist/server/core/memories/manager.js +238 -0
  27. package/dist/server/core/memories/short-term.js +512 -0
  28. package/dist/server/core/memories/structured.js +357 -0
  29. package/dist/server/core/memories/vector.js +137 -0
  30. package/dist/server/core/memory.js +2 -0
  31. package/dist/server/core/plugin-manager.js +128 -0
  32. package/dist/server/core/plugin.js +1 -0
  33. package/dist/server/core/scheduler.js +85 -0
  34. package/dist/server/core/task-queue.js +104 -0
  35. package/dist/server/core/types.js +1 -0
  36. package/dist/server/index.js +862 -0
  37. package/dist/server/llm/openai.js +23 -0
  38. package/dist/server/plugins/core-skills/src/create-agent.js +58 -0
  39. package/dist/server/plugins/core-skills/src/delegate.js +39 -0
  40. package/dist/server/plugins/core-skills/src/file-system.js +142 -0
  41. package/dist/server/plugins/core-skills/src/index.js +26 -0
  42. package/dist/server/plugins/core-skills/src/list-agents.js +24 -0
  43. package/dist/server/plugins/core-skills/src/search.js +31 -0
  44. package/dist/server/plugins/core-skills/src/system-time.js +27 -0
  45. package/dist/server/plugins/office-skills/src/index.js +19 -0
  46. package/dist/server/plugins/office-skills/src/office-excel.js +84 -0
  47. package/dist/server/plugins/office-skills/src/office-ppt.js +58 -0
  48. package/dist/server/plugins/office-skills/src/office-word.js +90 -0
  49. package/dist/server/routes/auth.js +28 -0
  50. package/dist/server/server/create-http.js +22 -0
  51. package/dist/server/server.js +29 -0
  52. package/dist/server/skills/base-skill.js +20 -0
  53. package/dist/server/skills/registry.js +52 -0
  54. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.top-0{top:0}.z-10{z-index:10}.z-50{z-index:50}.z-\[60\]{z-index:60}.-m-6{margin:-1.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.h-16{height:4rem}.h-2{height:.5rem}.h-4{height:1rem}.h-8{height:2rem}.h-\[60vh\]{height:60vh}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[200px\]{max-height:200px}.max-h-\[70vh\]{max-height:70vh}.max-h-\[90vh\]{max-height:90vh}.min-h-\[100px\]{min-height:100px}.min-h-\[300px\]{min-height:300px}.min-h-\[50px\]{min-height:50px}.w-16{width:4rem}.w-4{width:1rem}.w-8{width:2rem}.w-\[260px\]{width:260px}.w-full{width:100%}.w-screen{width:100vw}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-\[46vw\]{max-width:46vw}.max-w-\[85\%\]{max-width:85%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-bl-none{border-bottom-left-radius:0}.rounded-br-none{border-bottom-right-radius:0}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-none{border-style:none}.border-black\/10{border-color:#0000001a}.border-blue-100{--tw-border-opacity: 1;border-color:rgb(219 234 254 / var(--tw-border-opacity, 1))}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-blue-600{--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity, 1))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity: 1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/20{background-color:#0003}.bg-black\/40{background-color:#0006}.bg-black\/50{background-color:#00000080}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-teal-600{--tw-bg-opacity: 1;background-color:rgb(13 148 136 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/80{background-color:#fffc}.bg-yellow-100{--tw-bg-opacity: 1;background-color:rgb(254 249 195 / var(--tw-bg-opacity, 1))}.bg-opacity-50{--tw-bg-opacity: .5}.fill-current{fill:currentColor}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[15px\]{font-size:15px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-orange-500{--tw-text-opacity: 1;color:rgb(249 115 22 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-800{--tw-text-opacity: 1;color:rgb(133 77 14 / var(--tw-text-opacity, 1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.accent-blue-600{accent-color:#2563eb}.opacity-0{opacity:0}.opacity-50{opacity:.5}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}:root{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;line-height:1.5;font-weight:400;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.custom-scrollbar::-webkit-scrollbar{width:5px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:#9b9b9b33;border-radius:10px}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#9b9b9b66}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.selection\:bg-blue-100 *::-moz-selection{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.selection\:bg-blue-100 *::selection{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.selection\:text-blue-900 *::-moz-selection{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.selection\:text-blue-900 *::selection{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.selection\:bg-blue-100::-moz-selection{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.selection\:bg-blue-100::selection{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.selection\:text-blue-900::-moz-selection{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.selection\:text-blue-900::selection{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.focus-within\:border-blue-400:focus-within{--tw-border-opacity: 1;border-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.focus-within\:ring-2:focus-within{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-within\:ring-blue-100:focus-within{--tw-ring-opacity: 1;--tw-ring-color: rgb(219 234 254 / var(--tw-ring-opacity, 1))}.hover\:border-blue-300:hover{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1))}.hover\:bg-blue-100:hover{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-50:hover{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-800:hover{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-800\/50:hover{background-color:#1f293780}.hover\:bg-green-100:hover{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.hover\:bg-red-100:hover{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.hover\:bg-red-50:hover{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.hover\:text-blue-300:hover{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.hover\:text-blue-700:hover{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.hover\:text-red-400:hover{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:text-red-700:hover{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:shadow-sm:hover{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-0:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-70:disabled{opacity:.7}.group:hover .group-hover\:rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.group:hover .group-hover\:text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:opacity-100{opacity:1}
@@ -0,0 +1,4 @@
1
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="32" height="32" fill="#0A0B0D"/>
3
+ <path d="M26.6677 23.7149H8.38057V20.6496H5.33301V8.38159H26.6677V23.7149ZM8.38057 20.6496H23.6201V11.4482H8.38057V20.6496ZM16.0011 16.0021L13.8461 18.1705L11.6913 16.0021L13.8461 13.8337L16.0011 16.0021ZM22.0963 16.0008L19.9414 18.1691L17.7865 16.0008L19.9414 13.8324L22.0963 16.0008Z" fill="#32F08C"/>
4
+ </svg>
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🍇</text></svg>" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>xiaozuoAssistant</title>
8
+ <script type="module" crossorigin src="/assets/index-DkOojrRj.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-u0lXmgyZ.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
@@ -0,0 +1,110 @@
1
+ {
2
+ "welcome": {
3
+ "title": "Welcome to xiaozuoAssistant",
4
+ "subtitle": "Your personal AI assistant. Select a conversation from the sidebar or start a new one to begin."
5
+ },
6
+ "chat": {
7
+ "title": "Chat",
8
+ "empty": "Start a conversation...",
9
+ "you": "You",
10
+ "assistant": "xiaozuoAssistant",
11
+ "thinking": "Thinking...",
12
+ "inputPlaceholder": "Message xiaozuoAssistant...",
13
+ "disclaimer": "xiaozuoAssistant can make mistakes. Consider checking important information."
14
+ },
15
+ "sessionList": {
16
+ "title": "xiaozuoAssistant",
17
+ "newChat": "New chat",
18
+ "recent": "Recent",
19
+ "settings": "Settings",
20
+ "editSession": "Edit session",
21
+ "deleteConfirm": "Are you sure you want to delete this session?"
22
+ },
23
+ "sessionMeta": {
24
+ "title": "Session Settings",
25
+ "aliasLabel": "Alias (optional)",
26
+ "aliasPlaceholder": "e.g., Project A / Requirements",
27
+ "aliasHint": "Alias is shown in the list and header. Empty falls back to session ID.",
28
+ "workspaceLabel": "Workspace",
29
+ "workspaceHint": "File tools default to this workspace and are restricted to it.",
30
+ "contextLabel": "Context (optional)",
31
+ "contextPlaceholder": "E.g. project background, terminology, current conclusions, long-lived context...",
32
+ "contextHint": "This is persisted and can be used as session context in complex tasks.",
33
+ "selectWorkspace": "Select workspace",
34
+ "selectCurrentFolder": "Select current folder",
35
+ "persistNow": "Persist now",
36
+ "persisting": "Persisting...",
37
+ "persistSuccess": "Persisted",
38
+ "delete": "Delete session",
39
+ "deleting": "Deleting...",
40
+ "deleteConfirm": "Are you sure you want to delete this session?"
41
+ },
42
+ "settings": {
43
+ "title": "Settings",
44
+ "tabs": {
45
+ "general": "General",
46
+ "identity": "Identity",
47
+ "scheduler": "Memory & Scheduler"
48
+ },
49
+ "general": {
50
+ "provider": "Provider",
51
+ "apiKey": "API Key",
52
+ "baseURL": "Base URL",
53
+ "modelName": "Model Name",
54
+ "temperature": "Temperature"
55
+ },
56
+ "identity": {
57
+ "title": "User identity",
58
+ "userId": "UserId",
59
+ "userIdHint": "Used to load identity profile and memories for this userId.",
60
+ "name": "Name",
61
+ "role": "Role",
62
+ "company": "Company",
63
+ "email": "Email",
64
+ "promptTitle": "Base prompt",
65
+ "promptPlaceholder": "E.g. how the assistant should work, output format, constraints...",
66
+ "promptHint": "System prompt is composed from user identity + base prompt and is loaded before new sessions."
67
+ },
68
+ "prompt": {
69
+ "description": "Define how xiaozuoAssistant behaves and responds.",
70
+ "placeholder": "You are a helpful AI assistant..."
71
+ },
72
+ "scheduler": {
73
+ "memoryMaintenance": "Memory Maintenance",
74
+ "description": "Configure when the system should compress old memories and delete expired sessions.",
75
+ "sessionRetentionDays": "Session retention",
76
+ "sessionRetentionHint": "Sessions inactive for longer than this will be deleted during maintenance.",
77
+ "days": "days",
78
+ "cronSchedule": "Cron Schedule",
79
+ "cronHint": "Format: Minute Hour Day Month DayOfWeek (e.g., \"0 0 * * *\" for daily at midnight)",
80
+ "manualTrigger": "Manual Trigger",
81
+ "manualDescription": "Force run the maintenance task immediately.",
82
+ "runNow": "Run Maintenance Now",
83
+ "daily": "Daily",
84
+ "weekly": "Weekly",
85
+ "custom": "Custom (Cron)"
86
+ },
87
+ "buttons": {
88
+ "close": "Close",
89
+ "save": "Save Changes",
90
+ "saving": "Saving...",
91
+ "cancel": "Cancel"
92
+ },
93
+ "messages": {
94
+ "savedSuccess": "Configuration saved successfully!",
95
+ "saveFailed": "Failed to save configuration",
96
+ "networkError": "Network error occurred",
97
+ "maintenanceSuccess": "Maintenance triggered successfully!"
98
+ },
99
+ "language": "Language"
100
+ },
101
+ "weekdays": {
102
+ "sunday": "Sunday",
103
+ "monday": "Monday",
104
+ "tuesday": "Tuesday",
105
+ "wednesday": "Wednesday",
106
+ "thursday": "Thursday",
107
+ "friday": "Friday",
108
+ "saturday": "Saturday"
109
+ }
110
+ }
@@ -0,0 +1,112 @@
1
+ {
2
+ "welcome": {
3
+ "title": "欢迎使用 xiaozuoAssistant",
4
+ "subtitle": "您的个人 AI 助手。请从侧边栏选择一个会话或开始一个新的会话。"
5
+ },
6
+ "chat": {
7
+ "title": "聊天",
8
+ "empty": "开始一个新的对话...",
9
+ "you": "你",
10
+ "assistant": "xiaozuoAssistant",
11
+ "thinking": "思考中...",
12
+ "inputPlaceholder": "给 xiaozuoAssistant 发送消息 (Cmd/Ctrl + Enter 发送)...",
13
+ "disclaimer": "xiaozuoAssistant 可能会犯错。请核对重要信息。",
14
+ "resetSession": "重置会话",
15
+ "confirmReset": "确定要重置当前会话记忆吗?这将清空所有消息历史。"
16
+ },
17
+ "sessionList": {
18
+ "title": "xiaozuoAssistant",
19
+ "newChat": "新对话",
20
+ "recent": "最近",
21
+ "settings": "设置",
22
+ "editSession": "编辑会话",
23
+ "deleteConfirm": "确定要删除这个会话吗?"
24
+ },
25
+ "sessionMeta": {
26
+ "title": "会话设置",
27
+ "aliasLabel": "会话别名(可选)",
28
+ "aliasPlaceholder": "例如:项目A / 需求讨论",
29
+ "aliasHint": "列表与聊天头部将优先展示别名。留空将回退显示会话 ID。",
30
+ "workspaceLabel": "Workspace(工作目录)",
31
+ "workspaceHint": "文件相关工具默认以该目录为工作区,并限制访问范围。",
32
+ "contextLabel": "上下文数据(可选)",
33
+ "contextPlaceholder": "例如:项目背景、术语约定、当前阶段结论、需要长期保持的上下文...",
34
+ "contextHint": "该内容会持久化保存,并在复杂任务中作为会话上下文使用。",
35
+ "selectWorkspace": "选择工作目录",
36
+ "selectCurrentFolder": "选择当前目录",
37
+ "persistNow": "立即持久化",
38
+ "persisting": "持久化中...",
39
+ "persistSuccess": "已持久化",
40
+ "delete": "删除会话",
41
+ "deleting": "删除中...",
42
+ "deleteConfirm": "确定要删除这个会话吗?"
43
+ },
44
+ "settings": {
45
+ "title": "设置",
46
+ "tabs": {
47
+ "general": "常规",
48
+ "identity": "用户身份管理",
49
+ "scheduler": "定时任务"
50
+ },
51
+ "general": {
52
+ "provider": "模型提供商",
53
+ "apiKey": "API Key",
54
+ "baseURL": "Base URL",
55
+ "modelName": "模型名称",
56
+ "temperature": "温度 (Temperature)"
57
+ },
58
+ "identity": {
59
+ "title": "用户身份",
60
+ "userId": "UserId",
61
+ "userIdHint": "用于加载该 UserId 对应的身份资料与记忆。",
62
+ "name": "姓名",
63
+ "role": "岗位",
64
+ "company": "公司",
65
+ "email": "邮箱",
66
+ "promptTitle": "基本提示信息",
67
+ "promptPlaceholder": "例如:你希望助手的工作方式、输出格式、约束规则...",
68
+ "promptHint": "系统提示词将由“用户身份 + 基本提示信息”自动组成,并在新会话中预先加载。"
69
+ },
70
+ "prompt": {
71
+ "description": "定义 xiaozuoAssistant 的行为和响应方式。",
72
+ "placeholder": "你是一个有用的 AI 助手..."
73
+ },
74
+ "scheduler": {
75
+ "memoryMaintenance": "记忆维护",
76
+ "description": "配置系统何时压缩旧记忆并删除过期会话。",
77
+ "sessionRetentionDays": "会话保留天数",
78
+ "sessionRetentionHint": "超过该天数未活跃的会话会在维护任务中被自动删除。",
79
+ "days": "天",
80
+ "cronSchedule": "Cron 表达式",
81
+ "cronHint": "格式: 分 时 日 月 周 (例如 \"0 0 * * *\" 表示每天午夜)",
82
+ "manualTrigger": "手动触发",
83
+ "manualDescription": "立即强制运行维护任务。",
84
+ "runNow": "立即运行维护",
85
+ "daily": "每天",
86
+ "weekly": "每周",
87
+ "custom": "自定义 (Cron)"
88
+ },
89
+ "buttons": {
90
+ "close": "关闭",
91
+ "save": "保存更改",
92
+ "saving": "保存中...",
93
+ "cancel": "取消"
94
+ },
95
+ "messages": {
96
+ "savedSuccess": "配置保存成功!",
97
+ "saveFailed": "保存配置失败",
98
+ "networkError": "发生网络错误",
99
+ "maintenanceSuccess": "维护任务触发成功!"
100
+ },
101
+ "language": "语言"
102
+ },
103
+ "weekdays": {
104
+ "sunday": "星期日",
105
+ "monday": "星期一",
106
+ "tuesday": "星期二",
107
+ "wednesday": "星期三",
108
+ "thursday": "星期四",
109
+ "friday": "星期五",
110
+ "saturday": "星期六"
111
+ }
112
+ }
@@ -0,0 +1,23 @@
1
+ import { AgentRuntime } from '../core/agents/runtime.js';
2
+ import { ReadWordSkill, CreateWordSkill } from '../plugins/office-skills/src/office-word.js';
3
+ import { ReadExcelSkill, CreateExcelSkill } from '../plugins/office-skills/src/office-excel.js';
4
+ import { CreatePptxSkill } from '../plugins/office-skills/src/office-ppt.js';
5
+ export const createOfficeAgent = () => {
6
+ return new AgentRuntime({
7
+ name: 'office_agent',
8
+ description: 'A specialist in handling Microsoft Office documents (Word, Excel, PowerPoint). Capable of reading, creating, and modifying files.',
9
+ systemPrompt: `你是一个办公文档专家 Agent。
10
+ 你的目标是帮助用户处理 Word、Excel 和 PowerPoint 任务。
11
+ 你可以使用工具来读取、创建和修改这些文件。
12
+ 在进行操作之前,请始终确认文件路径。
13
+ 如果创建文件的内容结构不明确,请先向用户确认。
14
+ 请始终用中文回复用户。`,
15
+ skills: [
16
+ new ReadWordSkill(),
17
+ new CreateWordSkill(),
18
+ new ReadExcelSkill(),
19
+ new CreateExcelSkill(),
20
+ new CreatePptxSkill()
21
+ ]
22
+ });
23
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * This is a API server
3
+ */
4
+ import express from 'express';
5
+ import cors from 'cors';
6
+ import path from 'path';
7
+ import dotenv from 'dotenv';
8
+ import { fileURLToPath } from 'url';
9
+ import authRoutes from './routes/auth.js';
10
+ // for esm mode
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ // load env
14
+ dotenv.config();
15
+ const app = express();
16
+ app.use(cors());
17
+ app.use(express.json({ limit: '10mb' }));
18
+ app.use(express.urlencoded({ extended: true, limit: '10mb' }));
19
+ /**
20
+ * API Routes
21
+ */
22
+ app.use('/api/auth', authRoutes);
23
+ /**
24
+ * health
25
+ */
26
+ app.use('/api/health', (req, res, next) => {
27
+ res.status(200).json({
28
+ success: true,
29
+ message: 'ok',
30
+ });
31
+ });
32
+ /**
33
+ * error handler middleware
34
+ */
35
+ app.use((error, req, res, next) => {
36
+ res.status(500).json({
37
+ success: false,
38
+ error: 'Server internal error',
39
+ });
40
+ });
41
+ /**
42
+ * 404 handler
43
+ */
44
+ app.use((req, res) => {
45
+ res.status(404).json({
46
+ success: false,
47
+ error: 'API not found',
48
+ });
49
+ });
50
+ export default app;
@@ -0,0 +1,23 @@
1
+ export class BaseChannel {
2
+ constructor() {
3
+ this.messageHandler = null;
4
+ }
5
+ sendEvent(sessionId, event, payload) {
6
+ // 过滤掉内部状态事件,避免发送无效消息到外部渠道(如飞书、微信等)
7
+ if (['run_ack', 'run_status'].includes(event)) {
8
+ return;
9
+ }
10
+ const text = event === 'message'
11
+ ? String(payload?.content ?? '')
12
+ : `[${event}] ${typeof payload === 'string' ? payload : JSON.stringify(payload)}`;
13
+ void this.send(sessionId, text);
14
+ }
15
+ onMessage(handler) {
16
+ this.messageHandler = handler;
17
+ }
18
+ emitMessage(sessionId, message) {
19
+ if (this.messageHandler) {
20
+ this.messageHandler(sessionId, message);
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,18 @@
1
+ import { TerminalChannel } from './terminal.js';
2
+ import { WebChannel } from './web.js';
3
+ import { TelegramChannel } from './telegram.js';
4
+ import { FeishuChannel } from './feishu.js';
5
+ import { DingTalkChannel } from './dingtalk.js';
6
+ import { WechatChannel } from './wechat.js';
7
+ export function createChannels({ app, io, config, pluginManager }) {
8
+ const channels = [
9
+ new TerminalChannel(),
10
+ new WebChannel(io),
11
+ ...(config.channels?.telegram?.token ? [new TelegramChannel()] : []),
12
+ ...(config.channels?.feishu ? [new FeishuChannel()] : []),
13
+ ...(config.channels?.dingtalk?.clientId ? [new DingTalkChannel(app)] : []),
14
+ ...(config.channels?.wechat?.enabled ? [new WechatChannel()] : []),
15
+ ...pluginManager.getChannels()
16
+ ];
17
+ return channels;
18
+ }
@@ -0,0 +1,83 @@
1
+ import { BaseChannel } from './base-channel.js';
2
+ import { config } from '../config/loader.js';
3
+ import axios from 'axios';
4
+ export class DingTalkChannel extends BaseChannel {
5
+ constructor(app) {
6
+ super();
7
+ this.app = app;
8
+ this.name = 'dingtalk';
9
+ this.accessToken = '';
10
+ this.tokenExpire = 0;
11
+ this.clientId = config.channels?.dingtalk?.clientId;
12
+ this.clientSecret = config.channels?.dingtalk?.clientSecret;
13
+ }
14
+ async start() {
15
+ if (!this.clientId || !this.clientSecret) {
16
+ console.log('DingTalk credentials not configured, skipping DingTalk channel.');
17
+ return;
18
+ }
19
+ // Register webhook route
20
+ this.app.post('/api/channels/dingtalk/event', async (req, res) => {
21
+ // DingTalk sends messages here
22
+ // Note: Actual implementation depends on DingTalk's specific event format (Stream mode vs HTTP)
23
+ // For simplicity, we assume standard HTTP callback for enterprise internal apps
24
+ const { msgtype, text, conversationId, senderId } = req.body;
25
+ if (msgtype === 'text' && text?.content) {
26
+ const sessionId = `dingtalk:${conversationId || senderId}`;
27
+ // Remove @Bot prefix if present
28
+ const content = text.content.trim();
29
+ this.emitMessage(sessionId, content);
30
+ }
31
+ res.json({ msg: 'success' });
32
+ });
33
+ console.log('DingTalk Channel Started (Webhook at /api/channels/dingtalk/event)');
34
+ }
35
+ async stop() {
36
+ }
37
+ async getAccessToken() {
38
+ if (this.accessToken && Date.now() < this.tokenExpire) {
39
+ return this.accessToken;
40
+ }
41
+ try {
42
+ const res = await axios.post('https://api.dingtalk.com/v1.0/oauth2/accessToken', {
43
+ appKey: this.clientId,
44
+ appSecret: this.clientSecret
45
+ });
46
+ if (res.data.accessToken) {
47
+ this.accessToken = res.data.accessToken;
48
+ this.tokenExpire = Date.now() + (res.data.expireIn - 60) * 1000;
49
+ return this.accessToken;
50
+ }
51
+ return '';
52
+ }
53
+ catch (error) {
54
+ console.error('Error getting DingTalk token:', error);
55
+ return '';
56
+ }
57
+ }
58
+ async send(sessionId, message) {
59
+ if (!sessionId.startsWith('dingtalk:'))
60
+ return;
61
+ // For DingTalk, sending back usually requires knowing the conversation ID or using the Robot Webhook if it's a group
62
+ // This is a simplified implementation for Enterprise Internal Robot
63
+ const chatId = sessionId.split(':')[1];
64
+ const token = await this.getAccessToken();
65
+ if (!token)
66
+ return;
67
+ try {
68
+ await axios.post('https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend', {
69
+ robotCode: config.channels?.dingtalk?.robotCode,
70
+ userIds: [chatId], // Assuming sessionId is userId for direct messages
71
+ msgKey: 'sampleText',
72
+ msgParam: JSON.stringify({ content: message })
73
+ }, {
74
+ headers: {
75
+ 'x-acs-dingtalk-access-token': token
76
+ }
77
+ });
78
+ }
79
+ catch (error) {
80
+ console.error('Failed to send DingTalk message:', error);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,108 @@
1
+ import { BaseChannel } from './base-channel.js';
2
+ import { config } from '../config/loader.js';
3
+ import * as lark from '@larksuiteoapi/node-sdk';
4
+ export class FeishuChannel extends BaseChannel {
5
+ constructor() {
6
+ super();
7
+ this.name = 'feishu';
8
+ this.bots = [];
9
+ }
10
+ async start() {
11
+ // 每次 start 时重新读取最新配置,避免使用旧缓存
12
+ const feishuConfig = config.channels?.feishu;
13
+ // 清空现有机器人
14
+ this.bots = [];
15
+ // 检查配置是否为数组
16
+ if (!Array.isArray(feishuConfig) || feishuConfig.length === 0) {
17
+ console.log('Feishu bots not configured, skipping Feishu channel.');
18
+ return;
19
+ }
20
+ // 为每个机器人初始化客户端
21
+ for (const botConfig of feishuConfig) {
22
+ const { name, appId, appSecret } = botConfig;
23
+ if (!name || !appId || !appSecret) {
24
+ console.warn(`Feishu bot ${name || 'unknown'} missing required config, skipping.`);
25
+ continue;
26
+ }
27
+ try {
28
+ // Initialize Lark Client for API calls
29
+ const client = new lark.Client({
30
+ appId,
31
+ appSecret,
32
+ appType: lark.AppType.SelfBuild,
33
+ domain: lark.Domain.Feishu,
34
+ });
35
+ // Initialize WebSocket Client for receiving events
36
+ const wsClient = new lark.WSClient({
37
+ appId,
38
+ appSecret,
39
+ });
40
+ // Start WebSocket client
41
+ await wsClient.start({
42
+ eventDispatcher: new lark.EventDispatcher({}).register({
43
+ 'im.message.receive_v1': async (data) => {
44
+ const event = data.message;
45
+ if (!event || !data.sender)
46
+ return;
47
+ // Ignore bot messages
48
+ if (data.sender.sender_type !== 'user')
49
+ return;
50
+ try {
51
+ const content = JSON.parse(event.content).text;
52
+ // Use chat_id for group chats, open_id/user_id for p2p?
53
+ // Actually message.chat_id is universal for where the message comes from.
54
+ const sessionId = `feishu:${name}:${event.chat_id}`;
55
+ this.emitMessage(sessionId, content);
56
+ }
57
+ catch (e) {
58
+ console.error(`[Feishu-${name}] Failed to parse message content:`, e);
59
+ }
60
+ }
61
+ })
62
+ });
63
+ this.bots.push({ name, client, wsClient });
64
+ console.log(`Feishu Bot ${name} Started (WebSocket Mode)`);
65
+ }
66
+ catch (error) {
67
+ console.error(`[Feishu-${name}] Failed to start WebSocket client:`, error);
68
+ }
69
+ }
70
+ }
71
+ async stop() {
72
+ // There is no explicit stop method for WSClient in the current SDK version exposed clearly,
73
+ // but typically it persists until process exit.
74
+ // If needed, we can just clear the bots array.
75
+ this.bots = [];
76
+ }
77
+ async send(sessionId, message) {
78
+ if (!sessionId.startsWith('feishu:'))
79
+ return;
80
+ // Parse sessionId: feishu:<botName>:<chatId>
81
+ const parts = sessionId.split(':');
82
+ if (parts.length < 3)
83
+ return;
84
+ const botName = parts[1];
85
+ const chatId = parts[2];
86
+ // Find the bot client
87
+ const bot = this.bots.find(b => b.name === botName);
88
+ if (!bot) {
89
+ console.error(`Feishu bot ${botName} not found`);
90
+ return;
91
+ }
92
+ try {
93
+ await bot.client.im.message.create({
94
+ params: {
95
+ receive_id_type: 'chat_id',
96
+ },
97
+ data: {
98
+ receive_id: chatId,
99
+ msg_type: 'text',
100
+ content: JSON.stringify({ text: message }),
101
+ },
102
+ });
103
+ }
104
+ catch (error) {
105
+ console.error(`[Feishu-${botName}] Failed to send message to ${chatId}:`, error);
106
+ }
107
+ }
108
+ }