@jsbot-tellus/core 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +16 -4
  2. package/dist/core/dispatch/command.d.ts +5 -2
  3. package/dist/core/dispatch/command.d.ts.map +1 -1
  4. package/dist/core/dispatch/command.js +33 -7
  5. package/dist/core/dispatch/command.js.map +1 -1
  6. package/dist/core/dispatch/handler.d.ts +5 -3
  7. package/dist/core/dispatch/handler.d.ts.map +1 -1
  8. package/dist/core/dispatch/handler.js +6 -1
  9. package/dist/core/dispatch/handler.js.map +1 -1
  10. package/dist/core/dispatch/router.d.ts +4 -2
  11. package/dist/core/dispatch/router.d.ts.map +1 -1
  12. package/dist/core/dispatch/router.js +9 -5
  13. package/dist/core/dispatch/router.js.map +1 -1
  14. package/dist/core/index.d.ts +1 -1
  15. package/dist/core/index.d.ts.map +1 -1
  16. package/dist/core/kernel.d.ts +1 -1
  17. package/dist/core/kernel.d.ts.map +1 -1
  18. package/dist/core/kernel.js +4 -1
  19. package/dist/core/kernel.js.map +1 -1
  20. package/dist/core/plugin/context.d.ts.map +1 -1
  21. package/dist/core/plugin/context.js +12 -0
  22. package/dist/core/plugin/context.js.map +1 -1
  23. package/dist/core/plugin/loader.d.ts +1 -1
  24. package/dist/core/plugin/loader.d.ts.map +1 -1
  25. package/dist/core/plugin/loader.js +31 -46
  26. package/dist/core/plugin/loader.js.map +1 -1
  27. package/dist/core/plugin/types.d.ts +9 -1
  28. package/dist/core/plugin/types.d.ts.map +1 -1
  29. package/dist/core/plugin/types.js.map +1 -1
  30. package/dist/webui/assets/ActionsView-B3Q3rh2X.js +1 -0
  31. package/dist/webui/assets/ConfigView-Baeqfi8s.js +1 -0
  32. package/dist/webui/assets/DashboardView-DLKD8DqF.js +1 -0
  33. package/dist/webui/assets/EventsView-CGUPPvRI.js +1 -0
  34. package/dist/webui/assets/KvView-CeovApuA.js +1 -0
  35. package/dist/webui/assets/LoginView-C2cfmXmS.js +1 -0
  36. package/dist/webui/assets/LogsView-K7nWoSFe.js +1 -0
  37. package/dist/webui/assets/MainLayout-bySbvMWB.js +1 -0
  38. package/dist/webui/assets/{MainLayout-glfVNbMz.css → MainLayout-qhsp--2k.css} +1 -1
  39. package/dist/webui/assets/PluginsView-DQZu8in1.js +1 -0
  40. package/dist/webui/assets/SessionsView-C0vTCqqE.js +1 -0
  41. package/dist/webui/assets/api-Bm2KUKXH.js +3 -0
  42. package/dist/webui/assets/index-CFz4VL67.js +50 -0
  43. package/dist/webui/assets/{index-CePlRZX6.css → index-Cs8jafCm.css} +1 -1
  44. package/dist/webui/index.html +3 -3
  45. package/docs/architecture.md +3 -3
  46. package/docs/configuration.md +3 -3
  47. package/docs/docker.md +166 -0
  48. package/docs/feature-parity.md +2 -2
  49. package/docs/migration.md +1 -1
  50. package/docs/plugin-api.md +20 -5
  51. package/docs/plugin-development.md +30 -27
  52. package/docs/release.md +50 -8
  53. package/package.json +3 -3
  54. package/src/core/dispatch/command.ts +53 -1
  55. package/src/core/dispatch/handler.ts +19 -1
  56. package/src/core/dispatch/router.ts +20 -3
  57. package/src/core/index.ts +4 -0
  58. package/src/core/kernel.ts +8 -1
  59. package/src/core/plugin/context.ts +21 -0
  60. package/src/core/plugin/loader.ts +41 -66
  61. package/src/core/plugin/types.ts +20 -0
  62. package/dist/webui/assets/ActionsView-BDuXBWG1.js +0 -1
  63. package/dist/webui/assets/ConfigView-B3Gv2uRG.js +0 -1
  64. package/dist/webui/assets/DashboardView-n9LGPmQL.js +0 -1
  65. package/dist/webui/assets/EventsView-DhO8twWb.js +0 -1
  66. package/dist/webui/assets/KvView-BCz_dOVC.js +0 -1
  67. package/dist/webui/assets/LoginView-Br3_AC5z.js +0 -1
  68. package/dist/webui/assets/LogsView-Ba_12frI.js +0 -1
  69. package/dist/webui/assets/MainLayout-D2LTc57u.js +0 -1
  70. package/dist/webui/assets/PluginsView-vQKBSCU8.js +0 -1
  71. package/dist/webui/assets/SessionsView-DSl37qpo.js +0 -1
  72. package/dist/webui/assets/api-CNzxhTWe.js +0 -3
  73. package/dist/webui/assets/index-CUvpnClx.js +0 -50
@@ -11,17 +11,42 @@ import type {
11
11
  CommandInfo,
12
12
  CommandMatch,
13
13
  CommandOptions,
14
+ MessageType,
15
+ MessageTypeFilter,
14
16
  } from '../plugin/types.js'
15
17
  import type { Permission } from '../security/permission.js'
16
18
 
17
19
  type AnyCommandHandler = CommandHandler<OneBotMessageEvent, any[]>
18
20
 
21
+ const DEFAULT_MESSAGE_TYPES: MessageType[] = ['group', 'private']
22
+
23
+ export function normalizeMessageTypes(
24
+ value: MessageTypeFilter | undefined
25
+ ): MessageType[] {
26
+ if (value === undefined) return [...DEFAULT_MESSAGE_TYPES]
27
+
28
+ const values = typeof value === 'string' ? [value] : value
29
+ const result: MessageType[] = []
30
+
31
+ for (const item of values) {
32
+ if (
33
+ (item === 'group' || item === 'private') &&
34
+ !result.includes(item)
35
+ ) {
36
+ result.push(item)
37
+ }
38
+ }
39
+
40
+ return result.length > 0 ? result : [...DEFAULT_MESSAGE_TYPES]
41
+ }
42
+
19
43
  export interface CommandRegistration {
20
44
  pluginId: string
21
45
  name: string
22
46
  aliases: string[]
23
47
  prefixes: string[]
24
48
  permission: Permission
49
+ messageTypes: MessageType[]
25
50
  description?: string | undefined
26
51
  params?: string | undefined
27
52
  paramsParser?: CompiledCommandParams | undefined
@@ -35,6 +60,7 @@ export interface CommandGroupRegistration {
35
60
  aliases: string[]
36
61
  prefixes: string[]
37
62
  permission: Permission
63
+ messageTypes: MessageType[]
38
64
  description?: string | undefined
39
65
  params?: string | undefined
40
66
  handler?: AnyCommandHandler | undefined
@@ -188,6 +214,7 @@ export class CommandRegistry {
188
214
  bases,
189
215
  prefixes,
190
216
  registration.permission,
217
+ registration.messageTypes,
191
218
  children
192
219
  )
193
220
 
@@ -199,6 +226,7 @@ export class CommandRegistry {
199
226
  bases,
200
227
  prefixes,
201
228
  registration.permission,
229
+ registration.messageTypes,
202
230
  registration.description,
203
231
  registration.params,
204
232
  registration.handler,
@@ -253,6 +281,7 @@ export class CommandRegistry {
253
281
  name: registration.name,
254
282
  aliases: [...registration.aliases],
255
283
  permission: registration.permission,
284
+ messageTypes: [...registration.messageTypes],
256
285
  ...(registration.description !== undefined
257
286
  ? { description: registration.description }
258
287
  : {}),
@@ -263,7 +292,10 @@ export class CommandRegistry {
263
292
  }))
264
293
  }
265
294
 
266
- match(rawMessage: string): RegisteredCommand | null {
295
+ match(
296
+ rawMessage: string,
297
+ messageType?: MessageType
298
+ ): RegisteredCommand | null {
267
299
  const raw = stripLeadingReply(rawMessage.trim()).trim()
268
300
 
269
301
  if (!raw) return null
@@ -298,6 +330,13 @@ export class CommandRegistry {
298
330
 
299
331
  if (!registration) continue
300
332
 
333
+ if (
334
+ messageType !== undefined &&
335
+ !registration.messageTypes.includes(messageType)
336
+ ) {
337
+ continue
338
+ }
339
+
301
340
  const start = first.index ?? 0
302
341
  const end = (last.index ?? 0) + last[0].length
303
342
 
@@ -404,6 +443,7 @@ export class CommandRegistry {
404
443
  bases: string[],
405
444
  prefixes: string[],
406
445
  permission: Permission,
446
+ messageTypes: MessageType[],
407
447
  children: GroupChild[]
408
448
  ): GroupScope {
409
449
  const disposers: Array<() => void> = []
@@ -464,6 +504,10 @@ export class CommandRegistry {
464
504
  aliases: childBases.slice(1),
465
505
  prefixes: options.prefixes ?? prefixes,
466
506
  permission: options.permission ?? permission,
507
+ messageTypes:
508
+ options.messageType !== undefined
509
+ ? normalizeMessageTypes(options.messageType)
510
+ : [...messageTypes],
467
511
  ...(options.description !== undefined
468
512
  ? { description: options.description }
469
513
  : {}),
@@ -506,12 +550,17 @@ export class CommandRegistry {
506
550
  )
507
551
  const nestedPrefixes = options.prefixes ?? prefixes
508
552
  const nestedPermission = options.permission ?? permission
553
+ const nestedMessageTypes =
554
+ options.messageType !== undefined
555
+ ? normalizeMessageTypes(options.messageType)
556
+ : [...messageTypes]
509
557
  const nestedChildren: GroupChild[] = []
510
558
  const nestedScope = this.createGroupScope(
511
559
  pluginId,
512
560
  nestedBases,
513
561
  nestedPrefixes,
514
562
  nestedPermission,
563
+ nestedMessageTypes,
515
564
  nestedChildren
516
565
  )
517
566
 
@@ -523,6 +572,7 @@ export class CommandRegistry {
523
572
  nestedBases,
524
573
  nestedPrefixes,
525
574
  nestedPermission,
575
+ nestedMessageTypes,
526
576
  options.description,
527
577
  options.params,
528
578
  options.handler,
@@ -567,6 +617,7 @@ export class CommandRegistry {
567
617
  bases: string[],
568
618
  prefixes: string[],
569
619
  permission: Permission,
620
+ messageTypes: MessageType[],
570
621
  description: string | undefined,
571
622
  params: string | undefined,
572
623
  handler: AnyCommandHandler | undefined,
@@ -584,6 +635,7 @@ export class CommandRegistry {
584
635
  aliases: bases.slice(1),
585
636
  prefixes,
586
637
  permission,
638
+ messageTypes: [...messageTypes],
587
639
  ...(description !== undefined ? { description } : {}),
588
640
  ...(params !== undefined ? { params } : {}),
589
641
  handler: handler ?? createGroupUsageHandler(children),
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ OneBotMessageEvent,
2
3
  OneBotNoticeEvent,
3
4
  OneBotRequestEvent,
4
5
  SnowLumaEvent,
@@ -9,6 +10,7 @@ import type {
9
10
  EventContext,
10
11
  EventType,
11
12
  MessageHandler,
13
+ MessageType,
12
14
  NoticeHandler,
13
15
  RequestHandler,
14
16
  } from '../plugin/types.js'
@@ -16,6 +18,7 @@ import type { MessageSender } from '../messaging/sender.js'
16
18
 
17
19
  export interface MessageRegistration {
18
20
  pluginId: string
21
+ messageType?: MessageType | undefined
19
22
  handler: MessageHandler
20
23
  }
21
24
 
@@ -96,9 +99,14 @@ export class HandlerRegistry {
96
99
  private noticeRegistrations: NoticeRegistration[] = []
97
100
  private requestRegistrations: RequestRegistration[] = []
98
101
 
99
- registerMessage(pluginId: string, handler: MessageHandler): () => void {
102
+ registerMessage(
103
+ pluginId: string,
104
+ handler: MessageHandler,
105
+ messageType?: MessageType
106
+ ): () => void {
100
107
  const registration: MessageRegistration = {
101
108
  pluginId,
109
+ ...(messageType !== undefined ? { messageType } : {}),
102
110
  handler,
103
111
  }
104
112
 
@@ -156,6 +164,16 @@ export class HandlerRegistry {
156
164
  }
157
165
  }
158
166
 
167
+ export function isMessageOf(
168
+ event: OneBotMessageEvent,
169
+ registration: MessageRegistration
170
+ ): boolean {
171
+ return (
172
+ registration.messageType === undefined ||
173
+ registration.messageType === event.message_type
174
+ )
175
+ }
176
+
159
177
  export function isNoticeOf(
160
178
  event: OneBotNoticeEvent,
161
179
  registration: NoticeRegistration
@@ -15,6 +15,8 @@ import type {
15
15
  CommandInfo,
16
16
  EventType,
17
17
  MessageHandler,
18
+ MessageType,
19
+ MessageTypeFilter,
18
20
  MiddlewareOptions,
19
21
  NoticeHandler,
20
22
  NoticeOptions,
@@ -27,6 +29,7 @@ import { PermissionRefuser } from '../security/refuse.js'
27
29
  import type { Permission } from '../security/permission.js'
28
30
  import {
29
31
  CommandRegistry,
32
+ normalizeMessageTypes,
30
33
  type CommandGroupRegistration,
31
34
  type CommandRegistration,
32
35
  } from './command.js'
@@ -34,6 +37,7 @@ import {
34
37
  createEventContext,
35
38
  eventTypeOf,
36
39
  HandlerRegistry,
40
+ isMessageOf,
37
41
  isNoticeOf,
38
42
  isRequestOf,
39
43
  } from './handler.js'
@@ -64,6 +68,7 @@ export interface RegisterCommandOptions {
64
68
  aliases?: string[] | undefined
65
69
  prefixes?: string[] | undefined
66
70
  permission?: Permission | undefined
71
+ messageType?: MessageTypeFilter | undefined
67
72
  description?: string | undefined
68
73
  params?: string | undefined
69
74
  handler: AnyCommandHandler
@@ -75,6 +80,7 @@ export interface RegisterCommandGroupOptions {
75
80
  aliases?: string[] | undefined
76
81
  prefixes?: string[] | undefined
77
82
  permission?: Permission | undefined
83
+ messageType?: MessageTypeFilter | undefined
78
84
  description?: string | undefined
79
85
  params?: string | undefined
80
86
  handler?: AnyCommandHandler | undefined
@@ -160,7 +166,10 @@ export class Router {
160
166
  if (context.stopped) return
161
167
 
162
168
  if (isMessageEvent(event)) {
163
- const found = this.commands.match(event.raw_message)
169
+ const found = this.commands.match(
170
+ event.raw_message,
171
+ event.message_type
172
+ )
164
173
 
165
174
  if (found) {
166
175
  sdkContext.stopPropagation()
@@ -257,6 +266,7 @@ export class Router {
257
266
  aliases: options.aliases ?? [],
258
267
  prefixes: options.prefixes ?? ['/'],
259
268
  permission: options.permission ?? 'User',
269
+ messageTypes: normalizeMessageTypes(options.messageType),
260
270
  ...(options.description !== undefined
261
271
  ? { description: options.description }
262
272
  : {}),
@@ -277,6 +287,7 @@ export class Router {
277
287
  aliases: options.aliases ?? [],
278
288
  prefixes: options.prefixes ?? ['/'],
279
289
  permission: options.permission ?? 'User',
290
+ messageTypes: normalizeMessageTypes(options.messageType),
280
291
  ...(options.description !== undefined
281
292
  ? { description: options.description }
282
293
  : {}),
@@ -289,8 +300,12 @@ export class Router {
289
300
  return this.commands.group(registration, setup)
290
301
  }
291
302
 
292
- registerMessage(pluginId: string, handler: MessageHandler): () => void {
293
- return this.handlers.registerMessage(pluginId, handler)
303
+ registerMessage(
304
+ pluginId: string,
305
+ handler: MessageHandler,
306
+ messageType?: MessageType
307
+ ): () => void {
308
+ return this.handlers.registerMessage(pluginId, handler, messageType)
294
309
  }
295
310
 
296
311
  registerNotice(options: RegisterNoticeOptions): () => void {
@@ -431,6 +446,8 @@ export class Router {
431
446
  for (const registration of this.handlers.messages()) {
432
447
  if (messageContext.stopped) return
433
448
 
449
+ if (!isMessageOf(event, registration)) continue
450
+
434
451
  if (!this.gate.isEnabled(registration.pluginId, event)) {
435
452
  continue
436
453
  }
package/src/core/index.ts CHANGED
@@ -30,8 +30,11 @@ export type {
30
30
  EventContext,
31
31
  EventRegistrar,
32
32
  EventType,
33
+ GroupMessageHandler,
33
34
  InstalledPackageInfo,
34
35
  MessageHandler,
36
+ MessageType,
37
+ MessageTypeFilter,
35
38
  MiddlewareOptions,
36
39
  MiddlewareRegistrar,
37
40
  NoticeHandler,
@@ -46,6 +49,7 @@ export type {
46
49
  PluginStatus,
47
50
  PluginStatusEntry,
48
51
  PluginUpdateResult,
52
+ PrivateMessageHandler,
49
53
  RequestHandler,
50
54
  RequestOptions,
51
55
  } from './plugin/types.js'
@@ -1,4 +1,4 @@
1
- import type { SnowLumaEvent } from '@snowluma/sdk'
1
+ import { isMessageEvent, type SnowLumaEvent } from '@snowluma/sdk'
2
2
  import type { BotClient } from './client.js'
3
3
  import type { AppConfig } from './config/schema.js'
4
4
  import { createBotApi, type BotApi } from './api.js'
@@ -93,6 +93,13 @@ export class Kernel {
93
93
  .listCommands()
94
94
  .filter((command) =>
95
95
  gate.isEnabled(command.pluginId, event)
96
+ )
97
+ .filter(
98
+ (command) =>
99
+ !isMessageEvent(event) ||
100
+ command.messageTypes.includes(
101
+ event.message_type
102
+ )
96
103
  ),
97
104
  },
98
105
  plugins: {
@@ -12,6 +12,7 @@ import type {
12
12
  CommandHandler,
13
13
  CommandOptions,
14
14
  CoreServices,
15
+ MessageHandler,
15
16
  PluginContext,
16
17
  PluginDefinition,
17
18
  } from './types.js'
@@ -63,6 +64,9 @@ export function createPluginContext<TConfig>(
63
64
  ...(options.permission !== undefined
64
65
  ? { permission: options.permission }
65
66
  : {}),
67
+ ...(options.messageType !== undefined
68
+ ? { messageType: options.messageType }
69
+ : {}),
66
70
  ...(options.description !== undefined
67
71
  ? { description: options.description }
68
72
  : {}),
@@ -89,6 +93,9 @@ export function createPluginContext<TConfig>(
89
93
  ...(options.permission !== undefined
90
94
  ? { permission: options.permission }
91
95
  : {}),
96
+ ...(options.messageType !== undefined
97
+ ? { messageType: options.messageType }
98
+ : {}),
92
99
  ...(options.description !== undefined
93
100
  ? { description: options.description }
94
101
  : {}),
@@ -111,6 +118,20 @@ export function createPluginContext<TConfig>(
111
118
  onMessage(handler) {
112
119
  return deps.router.registerMessage(id, handler)
113
120
  },
121
+ onGroupMessage(handler) {
122
+ return deps.router.registerMessage(
123
+ id,
124
+ handler as MessageHandler,
125
+ 'group'
126
+ )
127
+ },
128
+ onPrivateMessage(handler) {
129
+ return deps.router.registerMessage(
130
+ id,
131
+ handler as MessageHandler,
132
+ 'private'
133
+ )
134
+ },
114
135
  onNotice(options, handler) {
115
136
  return deps.router.registerNotice({
116
137
  pluginId: id,
@@ -4,7 +4,7 @@ import { pathToFileURL } from 'node:url'
4
4
  import fg from 'fast-glob'
5
5
  import type { Logger } from '../logging/logger.js'
6
6
  import { collectPluginExports } from './exports.js'
7
- import { readInstallState, readJsonFile } from './install-dir.js'
7
+ import { readJsonFile } from './install-dir.js'
8
8
  import { NpmCliRunner, type NpmRunner } from './npm-runner.js'
9
9
  import type { AnyPluginDefinition } from './types.js'
10
10
 
@@ -13,7 +13,7 @@ type LoaderLogger = Pick<Logger, 'warn' | 'error'> & {
13
13
  }
14
14
 
15
15
  export interface LocalPluginLoaderOptions {
16
- /** Build local plugins that have a build script but no dist. Defaults to true. */
16
+ /** Rebuild local plugins that have a build script on every load. Defaults to true. */
17
17
  autoBuild?: boolean | undefined
18
18
  /** Timeout for a single local plugin build. Defaults to 120 seconds. */
19
19
  buildTimeoutMs?: number | undefined
@@ -49,19 +49,7 @@ async function readBuildScript(directory: string): Promise<string | undefined> {
49
49
  : undefined
50
50
  }
51
51
 
52
- async function readManagedDirectories(
53
- root: string
54
- ): Promise<Set<string> | null> {
55
- try {
56
- const state = await readInstallState(root)
57
-
58
- return new Set(
59
- Object.values(state.packages).map((record) => record.dir)
60
- )
61
- } catch {
62
- return null
63
- }
64
- }
52
+ type BuildOutcome = 'built' | 'missing-node-modules' | 'failed'
65
53
 
66
54
  async function buildLocalPlugin(
67
55
  directory: string,
@@ -69,22 +57,15 @@ async function buildLocalPlugin(
69
57
  logger: LoaderLogger | undefined,
70
58
  runner: NpmRunner,
71
59
  timeoutMs: number
72
- ): Promise<boolean> {
73
- if ((await readBuildScript(directory)) === undefined) {
74
- logger?.warn(
75
- `skipping local plugin ${name}: dist directory not found and package.json has no build script`
76
- )
77
- return false
78
- }
79
-
60
+ ): Promise<BuildOutcome> {
80
61
  if (!(await directoryExists(join(directory, 'node_modules')))) {
81
62
  logger?.warn(
82
- `skipping local plugin ${name}: dist directory not found and node_modules is missing; run npm install --prefix ${directory}`
63
+ `cannot build local plugin ${name}: node_modules is missing; run npm install --prefix ${directory}`
83
64
  )
84
- return false
65
+ return 'missing-node-modules'
85
66
  }
86
67
 
87
- logger?.info?.(`building local plugin ${name}: dist directory not found`)
68
+ logger?.info?.(`building local plugin ${name}`)
88
69
 
89
70
  try {
90
71
  await runner.run(['run', 'build'], {
@@ -93,13 +74,12 @@ async function buildLocalPlugin(
93
74
  })
94
75
  } catch (error) {
95
76
  logger?.error(`failed to build local plugin ${name}`, error)
96
- logger?.warn(`skipping local plugin ${name}: build failed`)
97
- return false
77
+ return 'failed'
98
78
  }
99
79
 
100
80
  logger?.info?.(`built local plugin ${name}`)
101
81
 
102
- return true
82
+ return 'built'
103
83
  }
104
84
 
105
85
  export async function loadPluginsFromDirectory(
@@ -127,7 +107,14 @@ export async function loadPluginsFromDirectory(
127
107
  let imported: unknown
128
108
 
129
109
  try {
130
- imported = await import(pathToFileURL(file).href)
110
+ const info = await stat(file).catch(() => null)
111
+ const url = pathToFileURL(file)
112
+
113
+ if (info !== null) {
114
+ url.searchParams.set('v', String(info.mtimeMs))
115
+ }
116
+
117
+ imported = await import(url.href)
131
118
  } catch (error) {
132
119
  logger?.error(`failed to import plugin file: ${file}`, error)
133
120
  invalid.push(
@@ -170,22 +157,7 @@ export async function loadLocalPlugins(
170
157
  )
171
158
  const plugins: AnyPluginDefinition[] = []
172
159
 
173
- let autoBuild = options.autoBuild !== false
174
- let managed = new Set<string>()
175
-
176
- if (autoBuild) {
177
- const directories = await readManagedDirectories(absolute)
178
-
179
- if (directories === null) {
180
- logger?.warn(
181
- 'cannot read plugin install state; automatic local plugin build is disabled'
182
- )
183
- autoBuild = false
184
- } else {
185
- managed = directories
186
- }
187
- }
188
-
160
+ const autoBuild = options.autoBuild !== false
189
161
  const runner = options.runner ?? new NpmCliRunner()
190
162
  const timeoutMs = options.buildTimeoutMs ?? DEFAULT_BUILD_TIMEOUT_MS
191
163
 
@@ -195,24 +167,11 @@ export async function loadLocalPlugins(
195
167
 
196
168
  const directory = join(absolute, entry.name)
197
169
  const dist = join(directory, 'dist')
170
+ const hasBuildScript = (await readBuildScript(directory)) !== undefined
198
171
  let distInfo = await stat(dist).catch(() => null)
199
172
 
200
- if (!distInfo?.isDirectory()) {
201
- if (!autoBuild) {
202
- logger?.warn(
203
- `skipping local plugin ${entry.name}: dist directory not found`
204
- )
205
- continue
206
- }
207
-
208
- if (managed.has(entry.name)) {
209
- logger?.warn(
210
- `skipping local plugin ${entry.name}: dist directory not found (installed package is expected to include dist)`
211
- )
212
- continue
213
- }
214
-
215
- const built = await buildLocalPlugin(
173
+ if (autoBuild && hasBuildScript) {
174
+ const outcome = await buildLocalPlugin(
216
175
  directory,
217
176
  entry.name,
218
177
  logger,
@@ -220,16 +179,32 @@ export async function loadLocalPlugins(
220
179
  timeoutMs
221
180
  )
222
181
 
223
- if (!built) continue
224
-
225
182
  distInfo = await stat(dist).catch(() => null)
226
183
 
227
184
  if (!distInfo?.isDirectory()) {
185
+ const reason =
186
+ outcome === 'built'
187
+ ? 'build finished but dist directory not found'
188
+ : outcome === 'missing-node-modules'
189
+ ? 'node_modules is missing and dist directory not found'
190
+ : 'build failed and dist directory not found'
191
+
192
+ logger?.warn(`skipping local plugin ${entry.name}: ${reason}`)
193
+ continue
194
+ }
195
+
196
+ if (outcome !== 'built') {
228
197
  logger?.warn(
229
- `skipping local plugin ${entry.name}: build finished but dist directory not found`
198
+ `using existing dist for local plugin ${entry.name}: rebuild failed`
230
199
  )
231
- continue
232
200
  }
201
+ } else if (!distInfo?.isDirectory()) {
202
+ logger?.warn(
203
+ hasBuildScript
204
+ ? `skipping local plugin ${entry.name}: dist directory not found and automatic build is disabled`
205
+ : `skipping local plugin ${entry.name}: dist directory not found and package.json has no build script`
206
+ )
207
+ continue
233
208
  }
234
209
 
235
210
  plugins.push(...(await loadPluginsFromDirectory(dist, logger)))
@@ -1,6 +1,8 @@
1
1
  import type {
2
+ OneBotGroupMessageEvent,
2
3
  OneBotMessageEvent,
3
4
  OneBotNoticeEvent,
5
+ OneBotPrivateMessageEvent,
4
6
  OneBotRequestEvent,
5
7
  OutgoingMessage,
6
8
  SnowLumaEvent,
@@ -17,6 +19,10 @@ import type { CommandParamArgs } from './command-params.js'
17
19
 
18
20
  export type EventType = 'message' | 'notice' | 'request' | 'meta'
19
21
 
22
+ export type MessageType = 'group' | 'private'
23
+
24
+ export type MessageTypeFilter = MessageType | readonly MessageType[]
25
+
20
26
  export interface CommandMatch {
21
27
  command: string
22
28
  prefix: string
@@ -28,6 +34,7 @@ export interface CommandInfo {
28
34
  name: string
29
35
  aliases: string[]
30
36
  permission: Permission
37
+ messageTypes: MessageType[]
31
38
  description?: string | undefined
32
39
  usage?: string | undefined
33
40
  pluginId: string
@@ -59,6 +66,16 @@ export type MessageHandler = (
59
66
  context: EventContext<OneBotMessageEvent>
60
67
  ) => void | Promise<void>
61
68
 
69
+ export type GroupMessageHandler = (
70
+ event: OneBotGroupMessageEvent,
71
+ context: EventContext<OneBotGroupMessageEvent>
72
+ ) => void | Promise<void>
73
+
74
+ export type PrivateMessageHandler = (
75
+ event: OneBotPrivateMessageEvent,
76
+ context: EventContext<OneBotPrivateMessageEvent>
77
+ ) => void | Promise<void>
78
+
62
79
  export type NoticeHandler = (
63
80
  event: OneBotNoticeEvent,
64
81
  context: EventContext<OneBotNoticeEvent>
@@ -80,6 +97,7 @@ export interface CommandOptions<Declaration extends string = string> {
80
97
  aliases?: string[] | undefined
81
98
  prefixes?: string[] | undefined
82
99
  permission?: Permission | undefined
100
+ messageType?: MessageTypeFilter | undefined
83
101
  description?: string | undefined
84
102
  params?: Declaration | undefined
85
103
  }
@@ -127,6 +145,8 @@ export interface CommandRegistrar extends CommandGroupRegistrar {
127
145
 
128
146
  export interface EventRegistrar {
129
147
  onMessage(handler: MessageHandler): () => void
148
+ onGroupMessage(handler: GroupMessageHandler): () => void
149
+ onPrivateMessage(handler: PrivateMessageHandler): () => void
130
150
  onNotice(options: NoticeOptions, handler: NoticeHandler): () => void
131
151
  onRequest(options: RequestOptions, handler: RequestHandler): () => void
132
152
  }
@@ -1 +0,0 @@
1
- import{Ki as e,Ri as t,Si as n,Ti as r,c as i,ci as a,d as o,f as s,ga as c,ii as l,ki as u,li as d,p as f,r as p,si as m,ti as h}from"./api-CNzxhTWe.js";var g={class:`result`},_=s(d({__name:`ActionsView`,setup(s){let d=e(`get_login_info`),_=e(`{}`),v=e(``),y=e(!1),b=e(!0),x=async()=>{let e={};if(_.value.trim().length>0&&_.value.trim()!==`{}`)try{e=JSON.parse(_.value)}catch{f.error(`params 必须是合法 JSON`);return}y.value=!0;try{let t=await p(`/api/actions`,{action:d.value,params:e});v.value=JSON.stringify(t.result,void 0,2)}catch(e){o(e)}finally{y.value=!1}};return n(()=>{i().then(e=>{b.value=e.runtime===null}).catch(()=>{b.value=!0})}),(e,n)=>{let i=u(`el-alert`),o=u(`el-input`),s=u(`el-form-item`),f=u(`el-button`),p=u(`el-form`),S=u(`el-divider`),C=u(`el-card`);return r(),l(`div`,null,[a(i,{title:`直接向 OneBot 调用任意 action。此功能等同完全特权接口,请谨慎使用。`,type:`warning`,closable:!1,class:`block`}),a(C,{class:`block`},{default:t(()=>[a(p,{"label-width":`100px`,size:`small`},{default:t(()=>[a(s,{label:`action`},{default:t(()=>[a(o,{modelValue:d.value,"onUpdate:modelValue":n[0]||=e=>d.value=e,placeholder:`如 get_login_info / send_private_msg`,style:{width:`320px`}},null,8,[`modelValue`])]),_:1}),a(s,{label:`params (JSON)`},{default:t(()=>[a(o,{modelValue:_.value,"onUpdate:modelValue":n[1]||=e=>_.value=e,type:`textarea`,rows:5,spellcheck:`false`,placeholder:`{}`},null,8,[`modelValue`])]),_:1}),a(s,null,{default:t(()=>[a(f,{type:`primary`,loading:y.value,disabled:b.value,onClick:x},{default:t(()=>[...n[2]||=[m(` 调用 `,-1)]]),_:1},8,[`loading`,`disabled`])]),_:1})]),_:1}),a(S,null,{default:t(()=>[...n[3]||=[m(`结果`,-1)]]),_:1}),h(`pre`,g,c(v.value),1)]),_:1})])}}}),[[`__scopeId`,`data-v-ceeaf662`]]);export{_ as default};
@@ -1 +0,0 @@
1
- import{Di as e,Ki as t,Ri as n,Si as r,Ti as i,Xr as a,ci as o,d as s,f as c,ga as l,i as u,ii as d,ki as f,li as p,n as m,ni as h,p as g,r as _,ri as v,si as y,ti as b}from"./api-CNzxhTWe.js";var x={class:`block`},S={class:`issues`},C=c(p({__name:`ConfigView`,setup(c){let p=t(`form`),C=t({url:``,accessToken:``,roles:{superadmin:[],admin:[]},message:{charThreshold:50,lineThreshold:3},webui:{enabled:!1,host:`127.0.0.1`,port:8787,username:``,password:``,sessionTtlHours:12,trustProxy:!1},installer:{enabled:!1,registry:`https://registry.npmjs.org/`,allowedPackages:[],allowScripts:!1,timeoutMs:12e4}}),w=t(``),T=t({path:``,hash:``,accessTokenSet:!1,webuiPasswordSet:!1}),E=t(``),D=t([]),O=t(!1),k=()=>{let e=JSON.parse(JSON.stringify(C.value)),t=e.webui;return w.value===``?delete t.password:t.password=w.value,e.accessToken===``&&delete e.accessToken,e},A=()=>{E.value=JSON.stringify(k(),null,4)},j=()=>{try{let e=JSON.parse(E.value),t=e.webui??{};typeof t.password==`string`&&(w.value=t.password===``?``:`00000000`),typeof e.accessToken==`string`&&e.accessToken===``?e.accessToken=``:typeof e.accessToken==`string`&&(e.accessToken=`00000000`),C.value=e,g.success(`已应用到表单`)}catch(e){g.error(`JSON 格式错误`),console.warn(e)}},M=async e=>{let t=await _(`/api/config/validate`,{config:e});return D.value=t.issues,t.ok},N=async()=>{O.value=!0;try{await M(k())&&g.success(`校验通过`)}catch(e){s(e)}finally{O.value=!1}},P=async()=>{let e;try{e=JSON.parse(E.value)}catch{g.error(`JSON 格式错误`);return}await I(e,w.value)},F=async()=>{let e=k();w.value=e.webui.password,await I(e,w.value),D.value=[]},I=async(e,t)=>{O.value=!0;try{if(!await M(e)&&D.value.length>0){g.error(`校验失败`);return}let t=await u(`/api/config`,{config:e,baseHash:T.value.hash});if(!t.ok){g.error(t.error??`保存失败`);return}g.success(`已保存并重启运行时`),await L()}catch(e){s(e)}finally{O.value=!1}},L=async()=>{try{let e=await m(`/api/config`);C.value=e.config,T.value=e.meta,w.value=(e.meta.webuiPasswordSet&&e.config.webui.password,``),E.value=JSON.stringify(e.config,null,4)}catch(e){s(e)}},R=e=>e.join(`, `);function z(e,t,n,r){let i=n.split(/[,,]/).map(e=>e.trim()).filter(e=>e.length>0);e[t]=r?i.map(r):i}return r(()=>void L()),(t,r)=>{let s=f(`el-divider`),c=f(`el-input`),u=f(`el-form-item`),m=f(`el-switch`),g=f(`el-input-number`),_=f(`el-space`),k=f(`el-button`),M=f(`el-form`),I=f(`el-tab-pane`),L=f(`el-tabs`),B=f(`el-alert`);return i(),d(`div`,null,[o(L,{modelValue:p.value,"onUpdate:modelValue":r[19]||=e=>p.value=e},{default:n(()=>[o(I,{label:`常用设置`,name:`form`},{default:n(()=>[o(M,{"label-width":`140px`,size:`small`,class:`form`},{default:n(()=>[o(s,{"content-position":`left`},{default:n(()=>[...r[20]||=[y(`连接`,-1)]]),_:1}),o(u,{label:`ws url`},{default:n(()=>[o(c,{modelValue:C.value.url,"onUpdate:modelValue":r[0]||=e=>C.value.url=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`accessToken`},{default:n(()=>[o(c,{modelValue:C.value.accessToken,"onUpdate:modelValue":r[1]||=e=>C.value.accessToken=e,placeholder:T.value.accessTokenSet?`留空保持不变`:`未设置`},null,8,[`modelValue`,`placeholder`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[21]||=[y(`WebUI`,-1)]]),_:1}),o(u,{label:`enabled`},{default:n(()=>[o(m,{modelValue:C.value.webui.enabled,"onUpdate:modelValue":r[2]||=e=>C.value.webui.enabled=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`host / port`},{default:n(()=>[o(_,null,{default:n(()=>[o(c,{modelValue:C.value.webui.host,"onUpdate:modelValue":r[3]||=e=>C.value.webui.host=e,style:{width:`160px`}},null,8,[`modelValue`]),o(g,{modelValue:C.value.webui.port,"onUpdate:modelValue":r[4]||=e=>C.value.webui.port=e,min:1,max:65535},null,8,[`modelValue`])]),_:1})]),_:1}),o(u,{label:`username`},{default:n(()=>[o(c,{modelValue:C.value.webui.username,"onUpdate:modelValue":r[5]||=e=>C.value.webui.username=e,style:{width:`200px`}},null,8,[`modelValue`])]),_:1}),o(u,{label:`password`},{default:n(()=>[o(c,{modelValue:w.value,"onUpdate:modelValue":r[6]||=e=>w.value=e,"show-password":``,placeholder:T.value.webuiPasswordSet?`留空保持不变`:`未设置`,style:{width:`240px`}},null,8,[`modelValue`,`placeholder`])]),_:1}),o(u,{label:`sessionTtlHours`},{default:n(()=>[o(g,{modelValue:C.value.webui.sessionTtlHours,"onUpdate:modelValue":r[7]||=e=>C.value.webui.sessionTtlHours=e,min:1,max:720},null,8,[`modelValue`])]),_:1}),o(u,{label:`trustProxy`},{default:n(()=>[o(m,{modelValue:C.value.webui.trustProxy,"onUpdate:modelValue":r[8]||=e=>C.value.webui.trustProxy=e},null,8,[`modelValue`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[22]||=[y(`消息聚合`,-1)]]),_:1}),o(u,{label:`charThreshold`},{default:n(()=>[o(g,{modelValue:C.value.message.charThreshold,"onUpdate:modelValue":r[9]||=e=>C.value.message.charThreshold=e,min:1},null,8,[`modelValue`])]),_:1}),o(u,{label:`lineThreshold`},{default:n(()=>[o(g,{modelValue:C.value.message.lineThreshold,"onUpdate:modelValue":r[10]||=e=>C.value.message.lineThreshold=e,min:1},null,8,[`modelValue`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[23]||=[y(`安装器`,-1)]]),_:1}),o(u,{label:`enabled`},{default:n(()=>[o(m,{modelValue:C.value.installer.enabled,"onUpdate:modelValue":r[11]||=e=>C.value.installer.enabled=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`registry`},{default:n(()=>[o(c,{modelValue:C.value.installer.registry,"onUpdate:modelValue":r[12]||=e=>C.value.installer.registry=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`allowedPackages`},{default:n(()=>[o(c,{"model-value":R(C.value.installer.allowedPackages),"onUpdate:modelValue":r[13]||=e=>z(C.value.installer,`allowedPackages`,e)},null,8,[`model-value`])]),_:1}),o(u,{label:`allowScripts`},{default:n(()=>[o(m,{modelValue:C.value.installer.allowScripts,"onUpdate:modelValue":r[14]||=e=>C.value.installer.allowScripts=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`timeoutMs`},{default:n(()=>[o(g,{modelValue:C.value.installer.timeoutMs,"onUpdate:modelValue":r[15]||=e=>C.value.installer.timeoutMs=e,min:1e3,max:6e5},null,8,[`modelValue`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[24]||=[y(`角色`,-1)]]),_:1}),o(u,{label:`superadmin`},{default:n(()=>[o(c,{"model-value":R(C.value.roles.superadmin),placeholder:`逗号分隔的 QQ 号`,"onUpdate:modelValue":r[16]||=e=>z(C.value.roles,`superadmin`,e,Number)},null,8,[`model-value`])]),_:1}),o(u,{label:`admin`},{default:n(()=>[o(c,{"model-value":R(C.value.roles.admin),placeholder:`逗号分隔的 QQ 号`,"onUpdate:modelValue":r[17]||=e=>z(C.value.roles,`admin`,e,Number)},null,8,[`model-value`])]),_:1}),o(u,null,{default:n(()=>[o(_,null,{default:n(()=>[o(k,{type:`primary`,loading:O.value,onClick:F},{default:n(()=>[...r[25]||=[y(` 校验并保存 `,-1)]]),_:1},8,[`loading`]),o(k,{onClick:N},{default:n(()=>[...r[26]||=[y(` 仅校验 `,-1)]]),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),o(I,{label:`JSON 编辑器`,name:`json`},{default:n(()=>[o(c,{modelValue:E.value,"onUpdate:modelValue":r[18]||=e=>E.value=e,type:`textarea`,rows:24,spellcheck:`false`,class:`json-editor`},null,8,[`modelValue`]),b(`div`,x,[o(_,null,{default:n(()=>[o(k,{onClick:A},{default:n(()=>[...r[27]||=[y(`从表单生成`,-1)]]),_:1}),o(k,{onClick:j},{default:n(()=>[...r[28]||=[y(`应用到表单`,-1)]]),_:1}),o(k,{type:`primary`,loading:O.value,onClick:P},{default:n(()=>[...r[29]||=[y(` 校验并保存 `,-1)]]),_:1},8,[`loading`])]),_:1})])]),_:1})]),_:1},8,[`modelValue`]),D.value.length>0?(i(),h(B,{key:0,type:`error`,closable:!1,class:`block`},{default:n(()=>[b(`ul`,S,[(i(!0),d(a,null,e(D.value,(e,t)=>(i(),d(`li`,{key:t},l(e.path?e.path+`: `:``)+l(e.message),1))),128))])]),_:1})):v(``,!0)])}}}),[[`__scopeId`,`data-v-3e321bed`]]);export{C as default};
@@ -1 +0,0 @@
1
- import{Ci as e,I as t,Ki as n,M as r,Q as i,Ri as a,Si as o,Ti as s,a as c,bt as l,c as u,ci as d,d as f,ea as p,ei as m,f as h,ga as g,ii as _,ki as v,l as y,li as b,ni as x,r as S,ri as C,s as w,si as T,ti as E,u as D}from"./api-CNzxhTWe.js";var O={class:`error-text`},k={class:`stat`},ee={class:`chip sky`},te={class:`value small`},A={class:`sub`},j={class:`stat`},M={class:`chip emerald`},N={class:`value`},P={class:`sub`},F={class:`stat`},I={class:`chip violet`},L={class:`value`},R={class:`unit`},z={class:`sub`},B={class:`stat`},V={class:`chip amber`},H={class:`value`},U={class:`unit`},W={class:`sub`},G={key:0,class:`sub warn-text`},K=h(b({__name:`DashboardView`,setup(h){let b=n(null),K=n([]),q=n([]),J=n(!1),Y=m(()=>b.value?.runtime??null),X=m(()=>Y.value?D(Y.value.uptimeMs):`-`),Z=async()=>{try{b.value=await u()}catch(e){f(e)}},ne=async()=>{J.value=!0;try{await S(`/api/runtime/restart`),await Z()}catch(e){f(e)}finally{J.value=!1}},re=async()=>{try{await S(`/api/runtime/pause`),await Z()}catch(e){f(e)}},ie=async()=>{try{await S(`/api/runtime/resume`),await Z()}catch(e){f(e)}},Q=null,$=null;return o(async()=>{await Z(),K.value=await w().catch(()=>[]),Q=c(`/api/events/stream?limit=20`,e=>{q.value.unshift(e),q.value.length>30&&q.value.pop()});let e=setInterval(()=>void Z(),1e4);$=()=>clearInterval(e)}),e(()=>{Q?.(),$?.()}),(e,n)=>{let o=v(`el-alert`),c=v(`el-icon`),u=v(`el-card`),f=v(`el-col`),m=v(`el-row`),h=v(`el-button`),S=v(`el-space`),w=v(`el-table-column`),D=v(`el-table`);return s(),_(`div`,null,[b.value?.startupError?(s(),x(o,{key:0,title:`运行时启动失败`,type:`error`,closable:!1,class:`block`},{default:a(()=>[E(`pre`,O,g(b.value.startupError),1)]),_:1})):b.value?.restarting?(s(),x(o,{key:1,title:`运行时正在重启…`,type:`warning`,closable:!1,class:`block`})):C(``,!0),d(m,{gutter:16,class:`block`},{default:a(()=>[d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,k,[E(`div`,ee,[d(c,{size:18},{default:a(()=>[d(p(i))]),_:1})]),E(`div`,null,[n[0]||=E(`p`,{class:`label`},`连接状态`,-1),E(`p`,te,g(Y.value?.connected?`已连接`:`未连接`),1),E(`p`,A,g(Y.value?.login?`${Y.value.login.nickname} · ${Y.value.login.userId}`:`—`),1)])])]),_:1})]),_:1}),d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,j,[E(`div`,M,[d(c,{size:18},{default:a(()=>[d(p(l))]),_:1})]),E(`div`,null,[n[1]||=E(`p`,{class:`label`},`运行时长`,-1),E(`p`,N,g(X.value),1),E(`p`,P,` state: `+g(Y.value?.state??`—`)+` · gen `+g(Y.value?.generation??`—`),1)])])]),_:1})]),_:1}),d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,F,[E(`div`,I,[d(c,{size:18},{default:a(()=>[d(p(r))]),_:1})]),E(`div`,null,[n[2]||=E(`p`,{class:`label`},`插件`,-1),E(`p`,L,[T(g(Y.value?.counts.loadedPlugins??`—`),1),E(`span`,R,` / `+g(Y.value?.counts.plugins??`—`)+` 已加载`,1)]),E(`p`,z,` 启用 `+g(Y.value?.counts.enabledPlugins??`—`),1)])])]),_:1})]),_:1}),d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,B,[E(`div`,V,[d(c,{size:18},{default:a(()=>[d(p(t))]),_:1})]),E(`div`,null,[n[3]||=E(`p`,{class:`label`},`会话`,-1),E(`p`,H,[T(g(Y.value?.counts.sessions??`—`),1),E(`span`,U,` · `+g(Y.value?.counts.kvPlugins??`—`)+` KV 插件`,1)]),n[4]||=E(`p`,{class:`sub`},`session 记录数`,-1)])])]),_:1})]),_:1})]),_:1}),d(u,{class:`block`},{header:a(()=>[...n[5]||=[T(`运行时控制`,-1)]]),default:a(()=>[d(S,null,{default:a(()=>[d(h,{type:`danger`,loading:J.value,onClick:ne},{default:a(()=>[...n[6]||=[T(` 重启运行时 `,-1)]]),_:1},8,[`loading`]),d(h,{onClick:re},{default:a(()=>[...n[7]||=[T(`暂停`,-1)]]),_:1}),d(h,{onClick:ie},{default:a(()=>[...n[8]||=[T(`恢复`,-1)]]),_:1})]),_:1}),E(`p`,W,` version: `+g(b.value?.version??`-`)+` · paths: `+g(b.value?.paths.config),1),b.value?.webui.requiresProcessRestart?(s(),_(`p`,G,` webui 绑定配置已修改,需要重启进程生效。 `)):C(``,!0)]),_:1}),d(u,{class:`block`},{header:a(()=>[...n[9]||=[T(`命令列表`,-1)]]),default:a(()=>[d(D,{data:K.value,size:`small`,"max-height":`320`},{default:a(()=>[d(w,{prop:`id`,label:`命令`,width:`220`}),d(w,{prop:`pluginId`,label:`插件`,width:`180`}),d(w,{prop:`description`,label:`说明`})]),_:1},8,[`data`])]),_:1}),d(u,{class:`block`},{header:a(()=>[...n[10]||=[T(`最近事件`,-1)]]),default:a(()=>[d(D,{data:q.value,size:`small`,"max-height":`320`},{default:a(()=>[d(w,{label:`时间`,width:`170`},{default:a(({row:e})=>[T(g(p(y)(e.time)),1)]),_:1}),d(w,{prop:`type`,label:`类型`,width:`100`}),d(w,{prop:`summary`,label:`摘要`})]),_:1},8,[`data`])]),_:1})])}}}),[[`__scopeId`,`data-v-5b803405`]]);export{K as default};