koishi-plugin-chatluna-toolbox 0.0.11 → 0.0.12

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.
@@ -0,0 +1,20 @@
1
+ <!--
2
+ Toolbox 详情加载器
3
+ 根据当前插件名称决定是否显示共享导航组件
4
+ -->
5
+ <template>
6
+ <SharedNav v-if="isOwn" :sections="navSections" />
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import { ComputedRef, computed, inject } from "vue";
11
+ import { SharedNav } from "shared-nav";
12
+ import { NAV_SECTIONS, PLUGIN_CANDIDATE_NAMES } from "./constants";
13
+
14
+ const pluginName = inject<ComputedRef<string>>("plugin:name");
15
+ const navSections = NAV_SECTIONS;
16
+ const isOwn = computed(() => {
17
+ const name = pluginName?.value || "";
18
+ return PLUGIN_CANDIDATE_NAMES.includes(name);
19
+ });
20
+ </script>
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 前端常量定义
3
+ * 包含导航分组和插件候选名称
4
+ */
5
+
6
+ import type { SharedNavSection } from "shared-nav";
7
+
8
+ export const NAV_SECTIONS: SharedNavSection[] = [
9
+ { title: "基础设置", key: "basic" },
10
+ { title: "原生工具", key: "nativeTools" },
11
+ { title: "XML 工具", key: "xmlTools" },
12
+ { title: "其他变量", key: "variables" },
13
+ { title: "其他设置", key: "other" },
14
+ ];
15
+
16
+ export const PLUGIN_CANDIDATE_NAMES = [
17
+ "chatluna-toolbox",
18
+ "koishi-plugin-chatluna-toolbox",
19
+ ];
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 前端入口
3
+ * 注册 Koishi 控制台插件详情扩展
4
+ */
5
+
6
+ import { Context } from "@koishijs/client";
7
+ import ToolboxDetailsLoader from "./ToolboxDetailsLoader.vue";
8
+
9
+ export default (ctx: Context) => {
10
+ ctx.slot({
11
+ type: "plugin-details",
12
+ component: ToolboxDetailsLoader,
13
+ order: -999,
14
+ });
15
+ };
package/dist/index.js ADDED
@@ -0,0 +1,264 @@
1
+ import { openBlock as y, createElementBlock as _, createElementVNode as w, defineComponent as b, Fragment as E, renderList as N, normalizeClass as m, toDisplayString as z, reactive as I, computed as f, onUnmounted as L, ref as T, onMounted as B, normalizeStyle as A, unref as k, createVNode as x, withModifiers as D, inject as K, createBlock as X, createCommentVNode as O } from "vue";
2
+ const M = (s, o) => {
3
+ const r = s.__vccOpts || s;
4
+ for (const [c, t] of o)
5
+ r[c] = t;
6
+ return r;
7
+ }, V = {}, Y = {
8
+ viewBox: "0 0 1024 1024",
9
+ xmlns: "http://www.w3.org/2000/svg",
10
+ width: "20",
11
+ height: "20"
12
+ };
13
+ function q(s, o) {
14
+ return y(), _("svg", Y, [...o[0] || (o[0] = [
15
+ w("path", {
16
+ d: "M288 224c0-35.3 28.7-64 64-64s64 28.7 64 64-28.7 64-64 64-64-28.7-64-64zm320 0c0-35.3 28.7-64 64-64s64 28.7 64 64-28.7 64-64 64-64-28.7-64-64zM288 512c0-35.3 28.7-64 64-64s64 28.7 64 64-28.7 64-64 64-64-28.7-64-64zm320 0c0-35.3 28.7-64 64-64s64 28.7 64 64-28.7 64-64 64-64-28.7-64-64zM352 864c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64zm320 0c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z",
17
+ fill: "currentColor"
18
+ }, null, -1)
19
+ ])]);
20
+ }
21
+ const P = /* @__PURE__ */ M(V, [["render", q]]), W = {}, j = {
22
+ viewBox: "0 0 1024 1024",
23
+ xmlns: "http://www.w3.org/2000/svg",
24
+ width: "20",
25
+ height: "20"
26
+ };
27
+ function U(s, o) {
28
+ return y(), _("svg", j, [...o[0] || (o[0] = [
29
+ w("path", {
30
+ d: "M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.712a29.12 29.12 0 0 0 0-41.728 30.592 30.592 0 0 0-42.752 0z",
31
+ fill: "currentColor"
32
+ }, null, -1)
33
+ ])]);
34
+ }
35
+ const F = /* @__PURE__ */ M(W, [["render", U]]), G = ["onClick"], H = /* @__PURE__ */ b({
36
+ __name: "NavSection",
37
+ props: {
38
+ sections: {},
39
+ activeKey: {}
40
+ },
41
+ emits: ["select"],
42
+ setup(s) {
43
+ return (o, r) => (y(!0), _(E, null, N(s.sections, (c) => (y(), _("div", {
44
+ key: c.key,
45
+ class: m([o.$style.item, s.activeKey === c.key ? o.$style.active : ""]),
46
+ onClick: (t) => o.$emit("select", c)
47
+ }, z(c.title), 11, G))), 128));
48
+ }
49
+ }), J = "_item_1m2kp_1", Q = "_active_1m2kp_16", Z = {
50
+ item: J,
51
+ active: Q
52
+ }, tt = {
53
+ $style: Z
54
+ }, et = /* @__PURE__ */ M(H, [["__cssModules", tt]]);
55
+ function R(s) {
56
+ return s instanceof TouchEvent ? {
57
+ x: s.touches[0].clientX,
58
+ y: s.touches[0].clientY
59
+ } : {
60
+ x: s.clientX,
61
+ y: s.clientY
62
+ };
63
+ }
64
+ function ot(s = {}) {
65
+ const {
66
+ initialTop: o = 100,
67
+ initialRight: r = 20,
68
+ boundarySelector: c = ".plugin-view"
69
+ } = s, t = I({
70
+ isDragging: !1,
71
+ top: o,
72
+ right: r,
73
+ startTop: 0,
74
+ startRight: 0,
75
+ startX: 0,
76
+ startY: 0,
77
+ width: 0,
78
+ height: 0
79
+ }), g = f(() => ({
80
+ top: `${t.top}px`,
81
+ right: `${t.right}px`
82
+ })), i = (d) => {
83
+ var C;
84
+ if (!t.isDragging)
85
+ return;
86
+ const a = R(d), l = t.startTop + (a.y - t.startY), e = t.startRight - (a.x - t.startX), n = (C = document.querySelector(c)) == null ? void 0 : C.getBoundingClientRect();
87
+ let h = 0, v = window.innerHeight - t.height, S = 0, $ = window.innerWidth - t.width;
88
+ n && (h = n.top, v = n.bottom - t.height, S = window.innerWidth - n.right, $ = window.innerWidth - n.left - t.width), t.top = Math.max(h, Math.min(v, l)), t.right = Math.max(S, Math.min($, e));
89
+ }, p = (d, a) => {
90
+ const l = R(d), e = a == null ? void 0 : a.getBoundingClientRect();
91
+ e && (t.width = e.width, t.height = e.height), t.startTop = t.top, t.startRight = t.right, t.startX = l.x, t.startY = l.y, t.isDragging = !0;
92
+ }, u = () => {
93
+ t.isDragging = !1;
94
+ };
95
+ return window.addEventListener("mousemove", i), window.addEventListener("mouseup", u), window.addEventListener("touchmove", i), window.addEventListener("touchend", u), L(() => {
96
+ window.removeEventListener("mousemove", i), window.removeEventListener("mouseup", u), window.removeEventListener("touchmove", i), window.removeEventListener("touchend", u);
97
+ }), {
98
+ position: g,
99
+ startDrag: p
100
+ };
101
+ }
102
+ function nt(s) {
103
+ const {
104
+ titleToKeyMap: o,
105
+ headerSelector: r = ".k-schema-header",
106
+ rootMargin: c = "-20% 0px -60% 0px",
107
+ threshold: t = 0
108
+ } = s, g = T("");
109
+ let i = null;
110
+ const p = /* @__PURE__ */ new Map(), u = () => {
111
+ i == null || i.disconnect(), p.clear(), i = new IntersectionObserver(
112
+ (l) => {
113
+ for (const e of l) {
114
+ if (!e.isIntersecting)
115
+ continue;
116
+ const n = p.get(e.target);
117
+ n && (g.value = n);
118
+ }
119
+ },
120
+ {
121
+ root: null,
122
+ rootMargin: c,
123
+ threshold: t
124
+ }
125
+ ), document.querySelectorAll(r).forEach((l) => {
126
+ const e = l.textContent || "";
127
+ for (const [n, h] of Object.entries(o))
128
+ if (e.includes(n)) {
129
+ i == null || i.observe(l), p.set(l, h);
130
+ break;
131
+ }
132
+ });
133
+ }, d = () => {
134
+ setTimeout(u, 500);
135
+ };
136
+ return B(d), L(() => {
137
+ i == null || i.disconnect();
138
+ }), {
139
+ activeSection: g,
140
+ refresh: d
141
+ };
142
+ }
143
+ const st = /* @__PURE__ */ b({
144
+ __name: "SharedNav",
145
+ props: {
146
+ sections: {},
147
+ headerSelector: { default: ".k-schema-header" },
148
+ boundarySelector: { default: ".plugin-view" },
149
+ initialTop: { default: 100 },
150
+ initialRight: { default: 20 },
151
+ rootMargin: { default: "-20% 0px -60% 0px" },
152
+ threshold: { default: 0 }
153
+ },
154
+ setup(s) {
155
+ const o = s, r = T(!1), c = T(null), t = f(
156
+ () => o.sections.reduce(
157
+ (e, n) => (e[n.matchText ?? n.title] = n.key, e),
158
+ {}
159
+ )
160
+ ), g = f(
161
+ () => o.sections.reduce(
162
+ (e, n) => (e[n.key] = n.matchText ?? n.title, e),
163
+ {}
164
+ )
165
+ ), i = (e) => {
166
+ e.stopPropagation(), r.value = !r.value;
167
+ }, { position: p, startDrag: u } = ot({
168
+ initialTop: o.initialTop,
169
+ initialRight: o.initialRight,
170
+ boundarySelector: o.boundarySelector
171
+ }), d = (e) => {
172
+ u(e, c.value);
173
+ }, { activeSection: a } = nt({
174
+ titleToKeyMap: t.value,
175
+ headerSelector: o.headerSelector,
176
+ rootMargin: o.rootMargin,
177
+ threshold: o.threshold
178
+ }), l = (e) => {
179
+ a.value = e.key;
180
+ const n = document.querySelectorAll(o.headerSelector);
181
+ for (let h = 0; h < n.length; h += 1) {
182
+ const v = n[h];
183
+ if ((v.textContent || "").includes(g.value[e.key])) {
184
+ v.scrollIntoView({ behavior: "smooth", block: "start" });
185
+ return;
186
+ }
187
+ }
188
+ };
189
+ return (e, n) => (y(), _("div", {
190
+ ref_key: "containerRef",
191
+ ref: c,
192
+ class: m([e.$style.container, r.value ? e.$style.collapsed : ""]),
193
+ style: A(k(p))
194
+ }, [
195
+ w("div", {
196
+ class: m(e.$style.header),
197
+ onMousedown: d,
198
+ onTouchstart: d
199
+ }, [
200
+ x(P, {
201
+ class: m(e.$style.move)
202
+ }, null, 8, ["class"]),
203
+ w("div", {
204
+ class: m(e.$style.toggle),
205
+ onClick: i,
206
+ onMousedown: n[0] || (n[0] = D(() => {
207
+ }, ["stop"])),
208
+ onTouchstart: n[1] || (n[1] = D(() => {
209
+ }, ["stop"]))
210
+ }, [
211
+ x(F)
212
+ ], 34)
213
+ ], 34),
214
+ w("div", {
215
+ class: m(e.$style.body)
216
+ }, [
217
+ x(et, {
218
+ sections: s.sections,
219
+ "active-key": k(a),
220
+ onSelect: l
221
+ }, null, 8, ["sections", "active-key"])
222
+ ], 2)
223
+ ], 6));
224
+ }
225
+ }), it = "_container_pbgsl_2", ct = "_header_pbgsl_21", rt = "_move_pbgsl_36", lt = "_toggle_pbgsl_45", at = "_body_pbgsl_56", dt = "_collapsed_pbgsl_67", ut = {
226
+ container: it,
227
+ header: ct,
228
+ move: rt,
229
+ toggle: lt,
230
+ body: at,
231
+ collapsed: dt
232
+ }, ht = {
233
+ $style: ut
234
+ }, gt = /* @__PURE__ */ M(st, [["__cssModules", ht]]), pt = [
235
+ { title: "基础设置", key: "basic" },
236
+ { title: "原生工具", key: "nativeTools" },
237
+ { title: "XML 工具", key: "xmlTools" },
238
+ { title: "其他变量", key: "variables" },
239
+ { title: "其他设置", key: "other" }
240
+ ], mt = [
241
+ "chatluna-toolbox",
242
+ "koishi-plugin-chatluna-toolbox"
243
+ ], yt = /* @__PURE__ */ b({
244
+ __name: "ToolboxDetailsLoader",
245
+ setup(s) {
246
+ const o = K("plugin:name"), r = pt, c = f(() => {
247
+ const t = (o == null ? void 0 : o.value) || "";
248
+ return mt.includes(t);
249
+ });
250
+ return (t, g) => c.value ? (y(), X(k(gt), {
251
+ key: 0,
252
+ sections: k(r)
253
+ }, null, 8, ["sections"])) : O("", !0);
254
+ }
255
+ }), wt = (s) => {
256
+ s.slot({
257
+ type: "plugin-details",
258
+ component: yt,
259
+ order: -999
260
+ });
261
+ };
262
+ export {
263
+ wt as default
264
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ @charset "UTF-8";._item_1m2kp_1{padding:8px 16px;font-size:13px;color:var(--k-text-normal);cursor:pointer;transition:all .2s ease;white-space:nowrap;border-radius:9999px;margin:4px 0;background:transparent}._item_1m2kp_1:hover{background:#0000000f;color:var(--k-text-active)}._item_1m2kp_1._active_1m2kp_16{color:#fff;background:var(--k-color-primary);font-weight:500}._container_pbgsl_2{position:absolute;z-index:1000;width:140px;max-width:90vw;max-height:70vh;background:transparent;display:flex;flex-direction:column;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Arial,sans-serif;-webkit-user-select:none;user-select:none;overflow:visible}@media(max-width:768px){._container_pbgsl_2{width:120px;max-height:50vh}}._container_pbgsl_2 ._header_pbgsl_21{padding:6px 10px;display:flex;justify-content:space-between;align-items:center;cursor:move;background:#ffffffd9;border-radius:20px;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);margin-bottom:8px;box-shadow:0 2px 8px #00000014}._container_pbgsl_2 ._header_pbgsl_21:hover{background:#fffffff2}._container_pbgsl_2 ._header_pbgsl_21 ._move_pbgsl_36{color:var(--k-text-light);cursor:grab;transition:color .2s}._container_pbgsl_2 ._header_pbgsl_21 ._move_pbgsl_36:active{cursor:grabbing;color:var(--k-color-primary)}._container_pbgsl_2 ._header_pbgsl_21 ._toggle_pbgsl_45{cursor:pointer;color:var(--k-text-light);transition:transform .3s ease,color .2s;display:flex;align-items:center;padding:2px}._container_pbgsl_2 ._header_pbgsl_21 ._toggle_pbgsl_45:hover{color:var(--k-color-primary)}._container_pbgsl_2 ._body_pbgsl_56{overflow-y:auto;padding:4px 0;transition:max-height .3s ease,opacity .3s ease;opacity:1;scrollbar-width:none;-ms-overflow-style:none}._container_pbgsl_2 ._body_pbgsl_56::-webkit-scrollbar{display:none}._container_pbgsl_2._collapsed_pbgsl_67{max-height:40px!important}._container_pbgsl_2._collapsed_pbgsl_67 ._body_pbgsl_56{max-height:0;padding:0;opacity:0;overflow:hidden}._container_pbgsl_2._collapsed_pbgsl_67 ._toggle_pbgsl_45{transform:rotate(180deg)}
package/lib/index.js CHANGED
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
6
11
  var __export = (target, all) => {
7
12
  for (var name2 in all)
8
13
  __defProp(target, name2, { get: all[name2], enumerable: true });
@@ -15,8 +20,376 @@ var __copyProps = (to, from, except, desc) => {
15
20
  }
16
21
  return to;
17
22
  };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
18
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
32
 
33
+ // ../../packages/shared-chatluna-xmltools/lib/index.js
34
+ var require_lib = __commonJS({
35
+ "../../packages/shared-chatluna-xmltools/lib/index.js"(exports2, module2) {
36
+ "use strict";
37
+ var __defProp2 = Object.defineProperty;
38
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
39
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
40
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
41
+ var __export2 = (target, all) => {
42
+ for (var name2 in all)
43
+ __defProp2(target, name2, { get: all[name2], enumerable: true });
44
+ };
45
+ var __copyProps2 = (to, from, except, desc) => {
46
+ if (from && typeof from === "object" || typeof from === "function") {
47
+ for (let key of __getOwnPropNames2(from))
48
+ if (!__hasOwnProp2.call(to, key) && key !== except)
49
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
50
+ }
51
+ return to;
52
+ };
53
+ var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
54
+ var index_exports2 = {};
55
+ __export2(index_exports2, {
56
+ createCharacterTempRuntime: () => createCharacterTempRuntime2,
57
+ extractAssistantText: () => extractAssistantText,
58
+ extractTextContent: () => extractTextContent,
59
+ getMessageType: () => getMessageType,
60
+ isAssistantMessage: () => isAssistantMessage,
61
+ parseSelfClosingXmlTags: () => parseSelfClosingXmlTags2,
62
+ registerGetTempListener: () => registerGetTempListener,
63
+ subscribeAssistantResponses: () => subscribeAssistantResponses
64
+ });
65
+ module2.exports = __toCommonJS2(index_exports2);
66
+ function parseSelfClosingXmlTags2(text, tagName) {
67
+ const tags = Array.from(
68
+ text.matchAll(new RegExp(`<${tagName}\\b([^>]*)\\/>`, "gi"))
69
+ );
70
+ if (!tags.length) return [];
71
+ return tags.map((tag) => {
72
+ const attrText = String(tag[1] || "");
73
+ const attrs = {};
74
+ for (const pair of attrText.matchAll(/([a-zA-Z_][\w-]*)="([^"]*)"/g)) {
75
+ attrs[pair[1]] = pair[2];
76
+ }
77
+ return attrs;
78
+ });
79
+ }
80
+ function getMessageType(message) {
81
+ if (!message) return "";
82
+ if (typeof message._getType === "function") {
83
+ return String(message._getType() || "").trim().toLowerCase();
84
+ }
85
+ return String(message.type || message.role || "").trim().toLowerCase();
86
+ }
87
+ function isAssistantMessage(message) {
88
+ const type = getMessageType(message);
89
+ return type === "assistant" || type === "ai";
90
+ }
91
+ function extractTextContent(value) {
92
+ if (typeof value === "string") return value;
93
+ if (value == null) return "";
94
+ if (Array.isArray(value)) {
95
+ return value.map((item) => extractTextContent(item)).join("");
96
+ }
97
+ if (typeof value !== "object") return "";
98
+ const record = value;
99
+ if (typeof record.text === "string") return record.text;
100
+ if (record.content !== void 0 && record.content !== value) {
101
+ return extractTextContent(record.content);
102
+ }
103
+ if (Array.isArray(record.children)) {
104
+ return extractTextContent(record.children);
105
+ }
106
+ if (typeof record.attrs === "object" && record.attrs) {
107
+ const attrs = record.attrs;
108
+ if (typeof attrs.content === "string") return attrs.content;
109
+ if (typeof attrs.text === "string") return attrs.text;
110
+ }
111
+ return "";
112
+ }
113
+ function extractAssistantText(message) {
114
+ if (!isAssistantMessage(message)) return "";
115
+ return extractTextContent(message?.content ?? message?.text).trim();
116
+ }
117
+ var GET_TEMP_TAG_PREFIX = "chatlunaXmlToolsGetTempTag";
118
+ var GET_TEMP_ORIGINAL_PREFIX = "chatlunaXmlToolsGetTempOriginal";
119
+ var GET_TEMP_LISTENERS_PREFIX = "chatlunaXmlToolsGetTempListeners";
120
+ function resolveSymbolNamespace(namespace) {
121
+ return namespace?.trim() || "default";
122
+ }
123
+ function resolveGetTempTag(namespace) {
124
+ return /* @__PURE__ */ Symbol.for(`${GET_TEMP_TAG_PREFIX}:${resolveSymbolNamespace(namespace)}`);
125
+ }
126
+ function resolveGetTempOriginal(namespace) {
127
+ return /* @__PURE__ */ Symbol.for(
128
+ `${GET_TEMP_ORIGINAL_PREFIX}:${resolveSymbolNamespace(namespace)}`
129
+ );
130
+ }
131
+ function resolveGetTempListeners(namespace) {
132
+ return /* @__PURE__ */ Symbol.for(
133
+ `${GET_TEMP_LISTENERS_PREFIX}:${resolveSymbolNamespace(namespace)}`
134
+ );
135
+ }
136
+ function registerGetTempListener(service, listener, options = {}) {
137
+ const getTemp = service.getTemp;
138
+ if (typeof getTemp !== "function") return null;
139
+ const tagKey = resolveGetTempTag(options.symbolNamespace);
140
+ const originalKey = resolveGetTempOriginal(options.symbolNamespace);
141
+ const listenersKey = resolveGetTempListeners(options.symbolNamespace);
142
+ const serviceRecord = service;
143
+ let listeners = serviceRecord[listenersKey];
144
+ if (!listeners) {
145
+ listeners = /* @__PURE__ */ new Set();
146
+ serviceRecord[listenersKey] = listeners;
147
+ }
148
+ if (!serviceRecord[tagKey]) {
149
+ Object.defineProperty(serviceRecord, originalKey, {
150
+ value: getTemp,
151
+ configurable: true,
152
+ enumerable: false,
153
+ writable: true
154
+ });
155
+ service.getTemp = async (...args) => {
156
+ const originalGetTemp = serviceRecord[originalKey];
157
+ const temp = await originalGetTemp?.apply(service, args);
158
+ const activeListeners = serviceRecord[listenersKey];
159
+ const session = options.resolveSession ? options.resolveSession(args) : args[0] && typeof args[0] === "object" ? args[0] : null;
160
+ if (temp && activeListeners?.size) {
161
+ for (const handler of Array.from(activeListeners)) {
162
+ handler(temp, session);
163
+ }
164
+ }
165
+ return temp;
166
+ };
167
+ serviceRecord[tagKey] = true;
168
+ }
169
+ listeners.add(listener);
170
+ return () => {
171
+ const currentListeners = serviceRecord[listenersKey];
172
+ currentListeners?.delete(listener);
173
+ if (currentListeners?.size) return;
174
+ const originalGetTemp = serviceRecord[originalKey];
175
+ if (originalGetTemp && service.getTemp !== originalGetTemp) {
176
+ service.getTemp = originalGetTemp;
177
+ }
178
+ delete serviceRecord[originalKey];
179
+ delete serviceRecord[tagKey];
180
+ delete serviceRecord[listenersKey];
181
+ };
182
+ }
183
+ var PUSH_DISPATCHER_PREFIX = "chatlunaXmlToolsPushDispatcher";
184
+ function resolvePushDispatcherKey(namespace) {
185
+ const target = namespace?.trim() || "default";
186
+ return /* @__PURE__ */ Symbol.for(`${PUSH_DISPATCHER_PREFIX}:${target}`);
187
+ }
188
+ function getDispatcher(messages, key) {
189
+ return messages[key] ?? null;
190
+ }
191
+ function setDispatcher(messages, key, dispatcher) {
192
+ const record = messages;
193
+ if (!dispatcher) {
194
+ delete record[key];
195
+ return;
196
+ }
197
+ Object.defineProperty(record, key, {
198
+ value: dispatcher,
199
+ configurable: true,
200
+ enumerable: false,
201
+ writable: true
202
+ });
203
+ }
204
+ function restoreDispatcher(key, dispatcher) {
205
+ if (dispatcher.messages.push === dispatcher.patchedPush) {
206
+ dispatcher.messages.push = dispatcher.originalPush;
207
+ }
208
+ setDispatcher(dispatcher.messages, key, null);
209
+ }
210
+ function subscribeAssistantResponses(messages, options) {
211
+ const key = resolvePushDispatcherKey(options.symbolNamespace);
212
+ let dispatcher = getDispatcher(messages, key);
213
+ if (!dispatcher) {
214
+ const listeners = /* @__PURE__ */ new Set();
215
+ const processedMessages = /* @__PURE__ */ new WeakSet();
216
+ const originalPush = messages.push;
217
+ const patchedPush = function patchedPush2(...items) {
218
+ const result = originalPush.apply(this, items);
219
+ for (const item of items) {
220
+ if (!item || typeof item !== "object") continue;
221
+ if (processedMessages.has(item)) continue;
222
+ processedMessages.add(item);
223
+ const message = item;
224
+ const response = extractAssistantText(message);
225
+ if (!response) continue;
226
+ for (const listener2 of Array.from(listeners)) {
227
+ try {
228
+ listener2(message);
229
+ } catch (error) {
230
+ options.onListenerError?.(error);
231
+ }
232
+ }
233
+ }
234
+ return result;
235
+ };
236
+ dispatcher = {
237
+ messages,
238
+ originalPush,
239
+ patchedPush,
240
+ listeners,
241
+ processedMessages
242
+ };
243
+ messages.push = patchedPush;
244
+ setDispatcher(messages, key, dispatcher);
245
+ }
246
+ const listener = (message) => {
247
+ const response = extractAssistantText(message);
248
+ if (!response) return;
249
+ options.onResponse({
250
+ response,
251
+ message,
252
+ session: options.getSession?.() ?? null
253
+ });
254
+ };
255
+ dispatcher.listeners.add(listener);
256
+ return () => {
257
+ const current = getDispatcher(messages, key);
258
+ if (!current) return;
259
+ current.listeners.delete(listener);
260
+ if (current.listeners.size > 0) return;
261
+ restoreDispatcher(key, current);
262
+ };
263
+ }
264
+ function createCharacterTempRuntime2(options) {
265
+ const {
266
+ getCharacterService,
267
+ symbolNamespace,
268
+ onResponse,
269
+ getMessages = (temp) => temp?.completionMessages,
270
+ resolveSession,
271
+ onServiceMissing,
272
+ onServiceChanged,
273
+ onBound,
274
+ onStarted,
275
+ onResponseError,
276
+ onListenerError
277
+ } = options;
278
+ const messageSubscriptions = /* @__PURE__ */ new WeakMap();
279
+ const sessionByMessages = /* @__PURE__ */ new WeakMap();
280
+ const trackedMessages = /* @__PURE__ */ new Set();
281
+ let detachGetTempListener = null;
282
+ let activeService = null;
283
+ let active = false;
284
+ const cleanupMessageSubscriptions = () => {
285
+ for (const messages of Array.from(trackedMessages)) {
286
+ messageSubscriptions.get(messages)?.();
287
+ messageSubscriptions.delete(messages);
288
+ sessionByMessages.delete(messages);
289
+ trackedMessages.delete(messages);
290
+ }
291
+ };
292
+ const cleanupServiceBinding = () => {
293
+ detachGetTempListener?.();
294
+ detachGetTempListener = null;
295
+ activeService = null;
296
+ active = false;
297
+ };
298
+ const handleTemp = (temp, session) => {
299
+ const messages = getMessages(temp);
300
+ if (!Array.isArray(messages) || typeof messages.push !== "function") return;
301
+ sessionByMessages.set(messages, session);
302
+ if (messageSubscriptions.has(messages)) return;
303
+ const unsubscribe = subscribeAssistantResponses(messages, {
304
+ symbolNamespace,
305
+ getSession: () => sessionByMessages.get(messages) ?? null,
306
+ onListenerError,
307
+ onResponse: ({ response, message, session: boundSession }) => {
308
+ const text = response || extractAssistantText(message);
309
+ if (!text) return;
310
+ void Promise.resolve(
311
+ onResponse({
312
+ response: text,
313
+ message,
314
+ session: boundSession
315
+ })
316
+ ).catch((error) => {
317
+ onResponseError?.(error);
318
+ });
319
+ }
320
+ });
321
+ trackedMessages.add(messages);
322
+ messageSubscriptions.set(messages, () => {
323
+ unsubscribe();
324
+ trackedMessages.delete(messages);
325
+ sessionByMessages.delete(messages);
326
+ });
327
+ };
328
+ const bindCurrentService = () => {
329
+ const service = getCharacterService();
330
+ if (!service || typeof service.getTemp !== "function") {
331
+ cleanupServiceBinding();
332
+ cleanupMessageSubscriptions();
333
+ onServiceMissing?.();
334
+ return { bound: false, changed: false, missing: true };
335
+ }
336
+ if (detachGetTempListener && activeService === service) {
337
+ active = true;
338
+ onServiceChanged?.({
339
+ changed: false,
340
+ previousService: activeService,
341
+ nextService: service
342
+ });
343
+ return { bound: true, changed: false, missing: false };
344
+ }
345
+ const previousService = activeService;
346
+ cleanupServiceBinding();
347
+ cleanupMessageSubscriptions();
348
+ const detach = registerGetTempListener(service, handleTemp, {
349
+ symbolNamespace,
350
+ resolveSession
351
+ });
352
+ if (!detach) {
353
+ onServiceMissing?.();
354
+ return { bound: false, changed: false, missing: true };
355
+ }
356
+ detachGetTempListener = detach;
357
+ activeService = service;
358
+ active = true;
359
+ onServiceChanged?.({
360
+ changed: previousService !== service,
361
+ previousService,
362
+ nextService: service
363
+ });
364
+ onBound?.({ service });
365
+ return {
366
+ bound: true,
367
+ changed: previousService !== service,
368
+ missing: false
369
+ };
370
+ };
371
+ return {
372
+ start: () => {
373
+ const { bound, changed, missing } = bindCurrentService();
374
+ if (!bound) {
375
+ if (!missing) {
376
+ onServiceMissing?.();
377
+ }
378
+ return false;
379
+ }
380
+ onStarted?.({ changed });
381
+ return true;
382
+ },
383
+ stop: () => {
384
+ cleanupServiceBinding();
385
+ cleanupMessageSubscriptions();
386
+ },
387
+ isActive: () => active
388
+ };
389
+ }
390
+ }
391
+ });
392
+
20
393
  // src/index.ts
21
394
  var index_exports = {};
22
395
  __export(index_exports, {
@@ -50,7 +423,7 @@ __export(index_exports, {
50
423
  hasReplyToolsEnabled: () => hasReplyToolsEnabled,
51
424
  inject: () => inject,
52
425
  name: () => name,
53
- parseSelfClosingXmlTags: () => parseSelfClosingXmlTags,
426
+ parseSelfClosingXmlTags: () => import_shared_chatluna_xmltools.parseSelfClosingXmlTags,
54
427
  registerCharacterReplyTools: () => registerCharacterReplyTools,
55
428
  registerNativeTools: () => registerNativeTools,
56
429
  registerVariables: () => registerVariables,
@@ -82,7 +455,7 @@ var import_koishi2 = require("koishi");
82
455
  var DEFAULT_POKE_TOOL_DESCRIPTION = "\u5BF9\u6307\u5B9A\u7528\u6237\u6267\u884C\u6233\u4E00\u6233\u3002";
83
456
  var DEFAULT_SET_SELF_PROFILE_TOOL_DESCRIPTION = "\u4FEE\u6539\u81EA\u5DF1\u7684 QQ \u8D44\u6599\uFF0C\u53EF\u8BBE\u7F6E\u6635\u79F0\u3001\u7B7E\u540D\u548C\u6027\u522B\u3002";
84
457
  var DEFAULT_SET_GROUP_CARD_TOOL_DESCRIPTION = "\u4FEE\u6539\u7FA4\u6210\u5458\u7684\u7FA4\u6635\u79F0\u3002";
85
- var DEFAULT_SET_GROUP_BAN_TOOL_DESCRIPTION = "\u7981\u8A00\u6307\u5B9A\u7FA4\u6210\u5458\uFF0Cduration=0 \u8868\u793A\u89E3\u9664\u7981\u8A00\u3002";
458
+ var DEFAULT_SET_GROUP_BAN_TOOL_DESCRIPTION = "\u7528\u4E8E\u7BA1\u7406\u7FA4\u6210\u5458\u7981\u8A00\u72B6\u6001\uFF0C\u53EF\u8BBE\u7F6E\u7981\u8A00\u65F6\u957F\u6216\u89E3\u9664\u7981\u8A00\u3002";
86
459
  var DEFAULT_SET_MSG_EMOJI_TOOL_DESCRIPTION = "\u5BF9\u6307\u5B9A\u6D88\u606F\u6DFB\u52A0\u8868\u60C5\u56DE\u5E94\u3002";
87
460
  var DEFAULT_DELETE_MESSAGE_TOOL_DESCRIPTION = "\u6839\u636E\u6D88\u606F ID \u64A4\u56DE\u6307\u5B9A\u6D88\u606F\u3002";
88
461
 
@@ -210,7 +583,7 @@ var XmlToolsSchema = import_koishi3.Schema.object({
210
583
  enableBanXmlTool: import_koishi3.Schema.boolean().default(false).description(
211
584
  "\u542F\u7528 XML \u5F62\u5F0F\u7684\u7FA4\u6210\u5458\u7981\u8A00\u8C03\u7528\uFF08\u4E0E \u539F\u751F\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF09"
212
585
  ),
213
- referencePrompt: import_koishi3.Schema.string().role("textarea").default(DEFAULT_XML_REFERENCE_PROMPT).description("\u6A21\u578B\u56DE\u590D XML \u53C2\u8003\u63D0\u793A\u8BCD\uFF0C\u81EA\u884C\u5199\u5165\u63D0\u793A\u8BCD\u4E2D\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6CE8\u5165")
586
+ referencePrompt: import_koishi3.Schema.string().role("textarea").default(DEFAULT_XML_REFERENCE_PROMPT).description("\u6A21\u578B\u56DE\u590D XML \u53C2\u8003\u63D0\u793A\u8BCD\uFF0C\u81EA\u884C\u5199\u5165\u63D0\u793A\u8BCD\u4E2D\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6CE8\u5165\uFF1B\u82E5\u5F00\u542F\u201C\u5C06 XML \u5DE5\u5177\u6539\u4E3A\u6CE8\u5165\u5B9E\u9A8C\u6027\u5DE5\u5177\u8C03\u7528\u56DE\u590D\u201D\uFF0C\u5219\u65E0\u9700\u589E\u52A0\u989D\u5916\u63D0\u793A\u8BCD")
214
587
  }).description("XML \u5DE5\u5177");
215
588
 
216
589
  // src/schema/variables.ts
@@ -326,6 +699,9 @@ var ConfigSchema = import_koishi5.Schema.intersect([
326
699
  OtherSettingsSchema
327
700
  ]);
328
701
 
702
+ // src/plugin.ts
703
+ var path = __toESM(require("path"));
704
+
329
705
  // src/helpers/logger.ts
330
706
  function createLogger(ctx, config) {
331
707
  const logger = ctx.logger("chatluna-toolbox");
@@ -725,6 +1101,20 @@ function createSetProfileTool(deps) {
725
1101
  }
726
1102
 
727
1103
  // src/features/native-tools/register.ts
1104
+ var NATIVE_TOOL_DEFAULT_AVAILABILITY = {
1105
+ enabled: true,
1106
+ main: true,
1107
+ chatluna: true,
1108
+ characterScope: "all"
1109
+ };
1110
+ function createNativeToolMeta(group, tags) {
1111
+ return {
1112
+ source: "extension",
1113
+ group,
1114
+ tags,
1115
+ defaultAvailability: NATIVE_TOOL_DEFAULT_AVAILABILITY
1116
+ };
1117
+ }
728
1118
  function resolveToolName(value, fallback) {
729
1119
  const trimmedValue = value.trim();
730
1120
  return trimmedValue || fallback;
@@ -754,7 +1144,9 @@ function registerNativeTools(deps) {
754
1144
  plugin.registerTool(toolName, {
755
1145
  selector: () => true,
756
1146
  authorization: (session) => session?.platform === "onebot",
757
- createTool: () => createPokeTool({ ctx, toolName, description, log, protocol })
1147
+ description,
1148
+ createTool: () => createPokeTool({ ctx, toolName, description, log, protocol }),
1149
+ meta: createNativeToolMeta("onebot", ["poke"])
758
1150
  });
759
1151
  log?.("info", `\u6233\u4E00\u6233\u5DE5\u5177\u5DF2\u6CE8\u518C: ${toolName}`);
760
1152
  }
@@ -770,7 +1162,9 @@ function registerNativeTools(deps) {
770
1162
  plugin.registerTool(toolName, {
771
1163
  selector: () => true,
772
1164
  authorization: (session) => session?.platform === "onebot",
773
- createTool: () => createSetProfileTool({ ctx, toolName, description, log, protocol })
1165
+ description,
1166
+ createTool: () => createSetProfileTool({ ctx, toolName, description, log, protocol }),
1167
+ meta: createNativeToolMeta("onebot", [])
774
1168
  });
775
1169
  log?.("info", `\u8BBE\u7F6E\u8D44\u6599\u5DE5\u5177\u5DF2\u6CE8\u518C: ${toolName}`);
776
1170
  }
@@ -786,7 +1180,9 @@ function registerNativeTools(deps) {
786
1180
  plugin.registerTool(toolName, {
787
1181
  selector: () => true,
788
1182
  authorization: (session) => session?.platform === "onebot",
789
- createTool: () => createSetGroupCardTool({ ctx, toolName, description, log })
1183
+ description,
1184
+ createTool: () => createSetGroupCardTool({ ctx, toolName, description, log }),
1185
+ meta: createNativeToolMeta("onebot", ["group"])
790
1186
  });
791
1187
  log?.("info", `\u7FA4\u6635\u79F0\u5DE5\u5177\u5DF2\u6CE8\u518C: ${toolName}`);
792
1188
  }
@@ -802,7 +1198,9 @@ function registerNativeTools(deps) {
802
1198
  plugin.registerTool(toolName, {
803
1199
  selector: () => true,
804
1200
  authorization: (session) => session?.platform === "onebot",
805
- createTool: () => createSetGroupBanTool({ toolName, description, log, protocol })
1201
+ description,
1202
+ createTool: () => createSetGroupBanTool({ toolName, description, log, protocol }),
1203
+ meta: createNativeToolMeta("onebot", ["group"])
806
1204
  });
807
1205
  log?.("info", `\u7FA4\u6210\u5458\u7981\u8A00\u5DE5\u5177\u5DF2\u6CE8\u518C: ${toolName}`);
808
1206
  }
@@ -818,7 +1216,9 @@ function registerNativeTools(deps) {
818
1216
  plugin.registerTool(toolName, {
819
1217
  selector: () => true,
820
1218
  authorization: (session) => session?.platform === "onebot",
821
- createTool: () => createSetMsgEmojiTool({ toolName, description, log, protocol })
1219
+ description,
1220
+ createTool: () => createSetMsgEmojiTool({ toolName, description, log, protocol }),
1221
+ meta: createNativeToolMeta("onebot", ["message"])
822
1222
  });
823
1223
  log?.("info", `\u6D88\u606F\u8868\u60C5\u5DE5\u5177\u5DF2\u6CE8\u518C: ${toolName}`);
824
1224
  }
@@ -834,7 +1234,9 @@ function registerNativeTools(deps) {
834
1234
  plugin.registerTool(toolName, {
835
1235
  selector: () => true,
836
1236
  authorization: (session) => session?.platform === "onebot",
837
- createTool: () => createDeleteMessageTool({ toolName, description, log })
1237
+ description,
1238
+ createTool: () => createDeleteMessageTool({ toolName, description, log }),
1239
+ meta: createNativeToolMeta("onebot", ["message"])
838
1240
  });
839
1241
  log?.("info", `\u5220\u9664\u6D88\u606F\u5DE5\u5177\u5DF2\u6CE8\u518C: ${toolName}`);
840
1242
  }
@@ -1088,20 +1490,7 @@ function registerCharacterReplyTools(deps) {
1088
1490
  }
1089
1491
 
1090
1492
  // src/features/xml-tools/parser.ts
1091
- function parseSelfClosingXmlTags(text, tagName) {
1092
- const tags = Array.from(
1093
- text.matchAll(new RegExp(`<${tagName}\\b([^>]*)\\/>`, "gi"))
1094
- );
1095
- if (!tags.length) return [];
1096
- return tags.map((tag) => {
1097
- const attrText = String(tag[1] || "");
1098
- const attrs = {};
1099
- for (const pair of attrText.matchAll(/([a-zA-Z_][\w-]*)="([^"]*)"/g)) {
1100
- attrs[pair[1]] = pair[2];
1101
- }
1102
- return attrs;
1103
- });
1104
- }
1493
+ var import_shared_chatluna_xmltools = __toESM(require_lib());
1105
1494
 
1106
1495
  // src/features/xml-tools/processor.ts
1107
1496
  function createXmlProcessor(deps) {
@@ -1120,10 +1509,10 @@ function createXmlProcessor(deps) {
1120
1509
  }) => {
1121
1510
  const content = String(response || "").trim();
1122
1511
  if (!content) return false;
1123
- const pokeTags = parseSelfClosingXmlTags(content, "poke");
1124
- const emojiTags = parseSelfClosingXmlTags(content, "emoji");
1125
- const deleteTags = parseSelfClosingXmlTags(content, "delete");
1126
- const banTags = parseSelfClosingXmlTags(content, "ban");
1512
+ const pokeTags = (0, import_shared_chatluna_xmltools.parseSelfClosingXmlTags)(content, "poke");
1513
+ const emojiTags = (0, import_shared_chatluna_xmltools.parseSelfClosingXmlTags)(content, "emoji");
1514
+ const deleteTags = (0, import_shared_chatluna_xmltools.parseSelfClosingXmlTags)(content, "delete");
1515
+ const banTags = (0, import_shared_chatluna_xmltools.parseSelfClosingXmlTags)(content, "ban");
1127
1516
  let handled = false;
1128
1517
  if (config.enablePokeXmlTool && pokeTags.length > 0) {
1129
1518
  if (!session) {
@@ -1208,208 +1597,23 @@ function createXmlProcessor(deps) {
1208
1597
  }
1209
1598
 
1210
1599
  // src/features/xml-tools/temp-runtime.ts
1211
- var GET_TEMP_TAG = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlGetTempRuntime");
1212
- var GET_TEMP_ORIGINAL = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlOriginalGetTemp");
1213
- var GET_TEMP_LISTENERS = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlGetTempListeners");
1214
- var PUSH_DISPATCHER = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlPushDispatcher");
1215
- function getMessageType(message) {
1216
- if (!message) return "";
1217
- if (typeof message._getType === "function") {
1218
- return String(message._getType() || "").trim().toLowerCase();
1219
- }
1220
- return String(message.type || message.role || "").trim().toLowerCase();
1221
- }
1222
- function isAssistantMessage(message) {
1223
- const type = getMessageType(message);
1224
- return type === "ai" || type === "assistant";
1225
- }
1226
- function extractText(value) {
1227
- if (typeof value === "string") return value;
1228
- if (value == null) return "";
1229
- if (Array.isArray(value)) {
1230
- return value.map((item) => extractText(item)).join("");
1231
- }
1232
- if (typeof value !== "object") return "";
1233
- const record = value;
1234
- if (typeof record.text === "string") return record.text;
1235
- if (record.content !== void 0 && record.content !== value) {
1236
- return extractText(record.content);
1237
- }
1238
- if (Array.isArray(record.children)) return extractText(record.children);
1239
- if (typeof record.attrs === "object" && record.attrs) {
1240
- const attrs = record.attrs;
1241
- if (typeof attrs.content === "string") return attrs.content;
1242
- if (typeof attrs.text === "string") return attrs.text;
1243
- }
1244
- return "";
1245
- }
1246
- function getResponseText(message) {
1247
- if (!isAssistantMessage(message)) return "";
1248
- return extractText(message?.content ?? message?.text).trim();
1249
- }
1250
- function getDispatcher(messages) {
1251
- return messages[PUSH_DISPATCHER] ?? null;
1252
- }
1253
- function setDispatcher(messages, dispatcher) {
1254
- const record = messages;
1255
- if (!dispatcher) {
1256
- delete record[PUSH_DISPATCHER];
1257
- return;
1258
- }
1259
- Object.defineProperty(record, PUSH_DISPATCHER, {
1260
- value: dispatcher,
1261
- configurable: true,
1262
- enumerable: false,
1263
- writable: true
1264
- });
1265
- }
1266
- function attachDispatcher(messages, log) {
1267
- const existing = getDispatcher(messages);
1268
- if (existing) return existing;
1269
- const listeners = /* @__PURE__ */ new Set();
1270
- const processedMessages = /* @__PURE__ */ new WeakSet();
1271
- const originalPush = messages.push;
1272
- const patchedPush = function patchedPush2(...items) {
1273
- const result = originalPush.apply(this, items);
1274
- for (const item of items) {
1275
- if (!item || typeof item !== "object") continue;
1276
- const message = item;
1277
- if (!isAssistantMessage(message)) continue;
1278
- if (processedMessages.has(item)) continue;
1279
- const response = getResponseText(message);
1280
- if (!response) continue;
1281
- processedMessages.add(item);
1282
- for (const listener of Array.from(listeners)) {
1283
- try {
1284
- listener(message);
1285
- } catch (error) {
1286
- log?.("warn", "\u5904\u7406 XML completionMessages \u76D1\u542C\u5668\u5931\u8D25", error);
1287
- }
1288
- }
1289
- }
1290
- return result;
1291
- };
1292
- const dispatcher = {
1293
- messages,
1294
- originalPush,
1295
- patchedPush,
1296
- listeners,
1297
- processedMessages
1298
- };
1299
- messages.push = patchedPush;
1300
- setDispatcher(messages, dispatcher);
1301
- return dispatcher;
1302
- }
1303
- function restoreDispatcher(dispatcher) {
1304
- if (dispatcher.messages.push === dispatcher.patchedPush) {
1305
- dispatcher.messages.push = dispatcher.originalPush;
1306
- }
1307
- setDispatcher(dispatcher.messages, null);
1308
- }
1309
- function registerGetTempListener(service, listener) {
1310
- const getTemp = service.getTemp;
1311
- if (typeof getTemp !== "function") return null;
1312
- const serviceRecord = service;
1313
- let listeners = serviceRecord[GET_TEMP_LISTENERS];
1314
- if (!listeners) {
1315
- listeners = /* @__PURE__ */ new Set();
1316
- serviceRecord[GET_TEMP_LISTENERS] = listeners;
1317
- }
1318
- if (!serviceRecord[GET_TEMP_TAG]) {
1319
- Object.defineProperty(serviceRecord, GET_TEMP_ORIGINAL, {
1320
- value: getTemp,
1321
- configurable: true,
1322
- enumerable: false,
1323
- writable: true
1324
- });
1325
- service.getTemp = async (...args) => {
1326
- const originalGetTemp = serviceRecord[GET_TEMP_ORIGINAL];
1327
- const temp = await originalGetTemp?.apply(
1328
- service,
1329
- args
1330
- );
1331
- const activeListeners = serviceRecord[GET_TEMP_LISTENERS];
1332
- const session = args[0] && typeof args[0] === "object" ? args[0] : null;
1333
- if (temp && activeListeners?.size) {
1334
- for (const handler of Array.from(activeListeners)) {
1335
- handler(temp, session);
1336
- }
1337
- }
1338
- return temp;
1339
- };
1340
- serviceRecord[GET_TEMP_TAG] = true;
1341
- }
1342
- listeners.add(listener);
1343
- return () => {
1344
- const currentListeners = serviceRecord[GET_TEMP_LISTENERS];
1345
- currentListeners?.delete(listener);
1346
- if (currentListeners?.size) return;
1347
- const originalGetTemp = serviceRecord[GET_TEMP_ORIGINAL];
1348
- if (originalGetTemp) service.getTemp = originalGetTemp;
1349
- delete serviceRecord[GET_TEMP_ORIGINAL];
1350
- delete serviceRecord[GET_TEMP_TAG];
1351
- delete serviceRecord[GET_TEMP_LISTENERS];
1352
- };
1353
- }
1600
+ var import_shared_chatluna_xmltools2 = __toESM(require_lib());
1354
1601
  function createCharacterTempXmlRuntime(params) {
1355
1602
  const { getCharacterService, processModelResponse, log } = params;
1356
- let attachedDispatchers = [];
1357
- let stopListening = null;
1358
- const compactAttachedDispatchers = () => {
1359
- attachedDispatchers = attachedDispatchers.filter(
1360
- (entry) => Boolean(entry.ref.deref())
1361
- );
1362
- };
1363
- const hasAttachedListener = (dispatcher) => {
1364
- compactAttachedDispatchers();
1365
- return attachedDispatchers.some(
1366
- (entry) => entry.ref.deref() === dispatcher
1367
- );
1368
- };
1369
- const detachDispatcherListener = (entry) => {
1370
- const dispatcher = entry.ref.deref();
1371
- if (!dispatcher) return;
1372
- dispatcher.listeners.delete(entry.listener);
1373
- if (dispatcher.listeners.size === 0) restoreDispatcher(dispatcher);
1374
- };
1375
- const handleTemp = (temp, session) => {
1376
- const messages = temp.completionMessages;
1377
- if (!Array.isArray(messages) || typeof messages.push !== "function") return;
1378
- const dispatcher = attachDispatcher(messages, log);
1379
- if (hasAttachedListener(dispatcher)) return;
1380
- const listener = (message) => {
1381
- const response = getResponseText(message);
1382
- if (!response) return;
1383
- void processModelResponse({ response, session }).catch((error) => {
1384
- log?.("warn", "\u5904\u7406 XML \u6A21\u578B\u54CD\u5E94\u5931\u8D25", error);
1385
- });
1386
- };
1387
- dispatcher.listeners.add(listener);
1388
- attachedDispatchers.push({ ref: new WeakRef(dispatcher), listener });
1389
- };
1390
- return {
1391
- start: () => {
1392
- if (stopListening) return true;
1393
- const service = getCharacterService();
1394
- if (!service) return false;
1395
- const detach = registerGetTempListener(service, handleTemp);
1396
- if (!detach) return false;
1397
- stopListening = () => {
1398
- compactAttachedDispatchers();
1399
- for (const entry of attachedDispatchers) {
1400
- detachDispatcherListener(entry);
1401
- }
1402
- attachedDispatchers = [];
1403
- detach();
1404
- stopListening = null;
1405
- };
1406
- return true;
1603
+ return (0, import_shared_chatluna_xmltools2.createCharacterTempRuntime)({
1604
+ getCharacterService,
1605
+ symbolNamespace: "chatluna-toolbox",
1606
+ resolveSession: (args) => args[0] && typeof args[0] === "object" ? args[0] : null,
1607
+ onListenerError: (error) => {
1608
+ log?.("warn", "\u5904\u7406 XML completionMessages \u76D1\u542C\u5668\u5931\u8D25", error);
1407
1609
  },
1408
- stop: () => {
1409
- stopListening?.();
1610
+ onResponseError: (error) => {
1611
+ log?.("warn", "\u5904\u7406 XML \u6A21\u578B\u54CD\u5E94\u5931\u8D25", error);
1410
1612
  },
1411
- isActive: () => Boolean(stopListening)
1412
- };
1613
+ onResponse: async ({ response, session }) => {
1614
+ await processModelResponse({ response, session });
1615
+ }
1616
+ });
1413
1617
  }
1414
1618
 
1415
1619
  // src/features/xml-tools/register.ts
@@ -2139,6 +2343,13 @@ function registerVariables(deps) {
2139
2343
 
2140
2344
  // src/plugin.ts
2141
2345
  function apply(ctx, config) {
2346
+ ctx.inject(["console"], (innerCtx) => {
2347
+ const consoleService = innerCtx.console;
2348
+ consoleService?.addEntry?.({
2349
+ dev: path.resolve(__dirname, "../client/index.ts"),
2350
+ prod: path.resolve(__dirname, "../dist")
2351
+ });
2352
+ });
2142
2353
  const chatlunaService = ctx.chatluna;
2143
2354
  const plugin = {
2144
2355
  registerTool: (name2, tool) => {
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "koishi-plugin-chatluna-toolbox",
3
3
  "description": "为 ChatLuna 提供更多原生工具、XML 工具与变量,仅支持 onebot 平台。",
4
- "version": "0.0.11",
4
+ "version": "0.0.12",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "files": [
8
- "lib"
8
+ "lib",
9
+ "dist",
10
+ "client"
9
11
  ],
10
12
  "license": "MIT",
11
13
  "homepage": "https://github.com/Sor85/koishi-plugins",
@@ -22,11 +24,15 @@
22
24
  "peerDependencies": {
23
25
  "koishi": "^4.18.7",
24
26
  "koishi-plugin-chatluna": "*",
25
- "koishi-plugin-chatluna-character": "*"
27
+ "koishi-plugin-chatluna-character": "*",
28
+ "@koishijs/plugin-console": "^5.30.0"
26
29
  },
27
30
  "peerDependenciesMeta": {
28
31
  "koishi-plugin-chatluna-character": {
29
32
  "optional": true
33
+ },
34
+ "@koishijs/plugin-console": {
35
+ "optional": true
30
36
  }
31
37
  },
32
38
  "dependencies": {
@@ -34,13 +40,19 @@
34
40
  "zod": "^3.25.76"
35
41
  },
36
42
  "devDependencies": {
43
+ "@koishijs/client": "^5.30.0",
37
44
  "@types/node": "^22.10.1",
45
+ "@vitejs/plugin-vue": "^6.0.2",
46
+ "sass": "^1.77.0",
38
47
  "tsup": "^8.0.0",
39
48
  "typescript": "^5.7.2",
40
- "vitest": "^3.2.4"
49
+ "vite": "^6.0.0",
50
+ "vitest": "^3.2.4",
51
+ "shared-chatluna-xmltools": "0.0.1",
52
+ "shared-nav": "0.0.1"
41
53
  },
42
54
  "scripts": {
43
- "build": "tsup",
55
+ "build": "tsup && vite build",
44
56
  "watch": "tsup --watch",
45
57
  "typecheck": "NODE_OPTIONS=--max-old-space-size=8192 tsc --noEmit",
46
58
  "test": "vitest run"