@zhin.js/core 1.5.2 → 1.5.4

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 (97) hide show
  1. package/README.md +2 -2
  2. package/lib/adapter.d.ts +7 -1
  3. package/lib/adapter.js +28 -24
  4. package/lib/agent-prompt.d.ts +2 -3
  5. package/lib/agent-prompt.js +5 -0
  6. package/lib/built/ai-outbound/parse.d.ts +1 -1
  7. package/lib/built/ai-outbound/parse.js +2 -6
  8. package/lib/built/ai-outbound/plain-mention-rewrite.js +4 -4
  9. package/lib/built/ai-outbound/resolve.js +8 -8
  10. package/lib/built/ai-outbound/types.d.ts +3 -3
  11. package/lib/built/ai-trigger.d.ts +5 -0
  12. package/lib/built/ai-trigger.js +40 -13
  13. package/lib/built/authorization.js +4 -4
  14. package/lib/built/command.d.ts +2 -2
  15. package/lib/built/command.js +2 -2
  16. package/lib/built/common-adapter-tools.d.ts +11 -11
  17. package/lib/built/common-adapter-tools.js +13 -13
  18. package/lib/built/config.d.ts +0 -4
  19. package/lib/built/config.js +0 -4
  20. package/lib/built/dispatcher.d.ts +2 -0
  21. package/lib/built/dispatcher.js +1 -1
  22. package/lib/built/endpoint-commands.js +2 -2
  23. package/lib/built/endpoint-lifecycle-service.js +13 -13
  24. package/lib/built/endpoint-lifecycle.d.ts +3 -3
  25. package/lib/built/endpoint-lifecycle.js +2 -2
  26. package/lib/built/endpoint-manager.d.ts +1 -1
  27. package/lib/built/interactive-segments/index.d.ts +1 -1
  28. package/lib/built/interactive-segments/index.js +1 -1
  29. package/lib/built/interactive-segments/keyboard-segment.d.ts +0 -1
  30. package/lib/built/interactive-segments/keyboard-segment.js +0 -1
  31. package/lib/built/interactive-segments/onebot-keyboard.d.ts +0 -3
  32. package/lib/built/interactive-segments/onebot-keyboard.js +0 -2
  33. package/lib/built/interactive-segments/resolve.d.ts +0 -3
  34. package/lib/built/interactive-segments/resolve.js +0 -3
  35. package/lib/built/interactive-segments/types.d.ts +8 -20
  36. package/lib/built/interactive-segments/types.js +0 -4
  37. package/lib/built/login-assist.d.ts +2 -2
  38. package/lib/built/login-assist.js +2 -2
  39. package/lib/built/message-enrich.d.ts +1 -1
  40. package/lib/built/message-enrich.js +2 -7
  41. package/lib/built/permission.d.ts +0 -4
  42. package/lib/built/permission.js +0 -4
  43. package/lib/built/prepend-quote-context.js +5 -5
  44. package/lib/built/rich-segments/capabilities.js +0 -1
  45. package/lib/built/rich-segments/html-segment.js +1 -4
  46. package/lib/built/rich-segments/markdown-segment.js +1 -4
  47. package/lib/built/rich-segments/types.d.ts +0 -5
  48. package/lib/built/schema-endpoint-manager.js +6 -6
  49. package/lib/built/tool.d.ts +5 -3
  50. package/lib/built/tool.js +14 -23
  51. package/lib/command.d.ts +4 -4
  52. package/lib/command.js +8 -11
  53. package/lib/endpoint-capabilities.d.ts +2 -3
  54. package/lib/endpoint-capabilities.js +4 -4
  55. package/lib/endpoint.d.ts +2 -0
  56. package/lib/endpoint.js +1 -0
  57. package/lib/errors.d.ts +2 -2
  58. package/lib/errors.js +4 -4
  59. package/lib/host-plugin-registry.d.ts +6 -5
  60. package/lib/host-plugin-registry.js +9 -4
  61. package/lib/im-scene.d.ts +1 -1
  62. package/lib/im-scene.js +5 -5
  63. package/lib/im-session-id.d.ts +2 -2
  64. package/lib/im-session-id.js +4 -4
  65. package/lib/index.d.ts +1 -2
  66. package/lib/index.js +0 -2
  67. package/lib/jsx-runtime.d.ts +1 -0
  68. package/lib/jsx.d.ts +19 -21
  69. package/lib/message.d.ts +1 -1
  70. package/lib/message.js +1 -1
  71. package/lib/notice.d.ts +2 -2
  72. package/lib/plugin-context.d.ts +11 -13
  73. package/lib/plugin-context.js +21 -18
  74. package/lib/plugin-runtime/im/contracts.d.ts +91 -12
  75. package/lib/plugin-runtime/im/contracts.js +79 -1
  76. package/lib/plugin-runtime/im/im-runtime.d.ts +33 -23
  77. package/lib/plugin-runtime/im/im-runtime.js +104 -63
  78. package/lib/plugin-runtime/im/index.d.ts +2 -0
  79. package/lib/plugin-runtime/im/index.js +2 -0
  80. package/lib/plugin-runtime/im/message-bus.d.ts +38 -0
  81. package/lib/plugin-runtime/im/message-bus.js +40 -0
  82. package/lib/plugin-runtime/im/message-dispatcher.js +13 -73
  83. package/lib/plugin-runtime/im/outbound-renderer.d.ts +3 -2
  84. package/lib/plugin-runtime/im/outbound-renderer.js +44 -8
  85. package/lib/plugin-runtime/im/service-tokens.d.ts +18 -0
  86. package/lib/plugin-runtime/im/service-tokens.js +13 -0
  87. package/lib/plugin.d.ts +4 -7
  88. package/lib/plugin.js +7 -30
  89. package/lib/request.d.ts +2 -2
  90. package/lib/side-event/types.d.ts +0 -4
  91. package/lib/types.d.ts +6 -11
  92. package/lib/utils.js +3 -1
  93. package/package.json +13 -12
  94. package/lib/built/qrcode-segment.d.ts +0 -18
  95. package/lib/built/qrcode-segment.js +0 -78
  96. package/lib/types-generator.d.ts +0 -5
  97. package/lib/types-generator.js +0 -71
package/lib/command.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { SegmentMatcher } from 'segment-matcher';
2
+ import { toPermissionSubject } from '@zhin.js/permission';
2
3
  /**
3
4
  * MessageCommand类:经典命令系统(segment-matcher)。
4
5
  *
@@ -75,26 +76,22 @@ export class MessageCommand extends SegmentMatcher {
75
76
  return this.#permissions;
76
77
  }
77
78
  /** 与 handle 一致的 permit 校验,供帮助菜单等场景过滤不可见命令 */
78
- async checkPermits(message, plugin) {
79
+ async checkPermits(message, host) {
79
80
  if (!this.#permissions.length)
80
81
  return true;
81
- const auth = plugin.contextIsReady('permission') ? plugin.inject('permission') : null;
82
- if (!auth)
82
+ if (!host)
83
83
  return false;
84
- for (const permit of this.#permissions) {
85
- if (!(await auth.check(permit, message)))
86
- return false;
87
- }
88
- return true;
84
+ const subject = toPermissionSubject(message);
85
+ return host.checkAll(this.#permissions, subject);
89
86
  }
90
87
  /**
91
88
  * 处理消息,自动匹配命令并执行回调
92
89
  * @param message 消息对象
93
- * @param plugin 插件实例
90
+ * @param host PermissionHost(null 时有 permit 的命令 fail-closed)
94
91
  * @returns 命令返回内容或undefined
95
92
  */
96
- async handle(message, plugin) {
97
- if (!(await this.checkPermits(message, plugin))) {
93
+ async handle(message, host) {
94
+ if (!(await this.checkPermits(message, host))) {
98
95
  return;
99
96
  }
100
97
  const matched = this.match(message.$content);
@@ -22,15 +22,14 @@ export interface OutboundEndpoint<Config extends object = object> {
22
22
  $config: Config;
23
23
  $connected: boolean;
24
24
  $sendMessage(options: SendOptions): Promise<string>;
25
- $recallMessage(id: string): Promise<void>;
26
25
  }
27
26
  export type FullEndpoint<Config extends object = object, Event extends object = object> = InboundEndpoint<Config, Event> & OutboundEndpoint<Config>;
28
27
  export type CapableEndpoint<Config extends object, Event extends object, Caps extends readonly EndpointCapability[]> = ('inbound' extends Caps[number] ? InboundEndpoint<Config, Event> : object) & ('outbound' extends Caps[number] ? OutboundEndpoint<Config> : object);
29
28
  export declare class OutboundNotSupportedError extends Error {
30
- constructor(endpointId?: string);
29
+ constructor(endpointKey?: string);
31
30
  }
32
31
  export declare class InboundNotSupportedError extends Error {
33
- constructor(endpointId?: string);
32
+ constructor(endpointKey?: string);
34
33
  }
35
34
  export declare function registerEndpointCapabilities(endpoint: object, caps: readonly EndpointCapability[]): void;
36
35
  export declare function getEndpointCapabilities(endpoint: object): readonly EndpointCapability[] | undefined;
@@ -1,13 +1,13 @@
1
1
  export const DEFAULT_ENDPOINT_CAPABILITIES = ['inbound', 'outbound'];
2
2
  export class OutboundNotSupportedError extends Error {
3
- constructor(endpointId) {
4
- super(endpointId ? `Endpoint ${endpointId} does not support outbound` : 'Outbound not supported');
3
+ constructor(endpointKey) {
4
+ super(endpointKey ? `Endpoint ${endpointKey} does not support outbound` : 'Outbound not supported');
5
5
  this.name = 'OutboundNotSupportedError';
6
6
  }
7
7
  }
8
8
  export class InboundNotSupportedError extends Error {
9
- constructor(endpointId) {
10
- super(endpointId ? `Endpoint ${endpointId} does not support inbound` : 'Inbound not supported');
9
+ constructor(endpointKey) {
10
+ super(endpointKey ? `Endpoint ${endpointKey} does not support inbound` : 'Inbound not supported');
11
11
  this.name = 'InboundNotSupportedError';
12
12
  }
13
13
  }
package/lib/endpoint.d.ts CHANGED
@@ -3,6 +3,8 @@ import type { EndpointCapabilitiesConfig, FullEndpoint } from './endpoint-capabi
3
3
  import type { EndpointWithManagement } from '@zhin.js/adapter';
4
4
  export type { EndpointChannel, EndpointChannelParent, EndpointFriend, EndpointGroup, EndpointManagement, EndpointWithManagement, EndpointManagementCapability, } from '@zhin.js/adapter';
5
5
  export { endpointManagementCapabilityIds, listEndpointManagementCapabilities, resolveEndpointManagement, } from '@zhin.js/adapter';
6
+ export type { EndpointControl, EndpointWithControl } from '@zhin.js/adapter';
7
+ export { resolveEndpointControl } from '@zhin.js/adapter';
6
8
  export type { EndpointCapability, EndpointCapabilitiesConfig, InboundEndpoint, OutboundEndpoint, FullEndpoint, CapableEndpoint, } from './endpoint-capabilities.js';
7
9
  export { DEFAULT_ENDPOINT_CAPABILITIES, OutboundNotSupportedError, InboundNotSupportedError, resolveEndpointCapabilities, registerEndpointCapabilities, getEndpointCapabilities, getAdapterCapabilities, hasInbound, hasOutbound, assertInbound, assertOutbound, } from './endpoint-capabilities.js';
8
10
  /**
package/lib/endpoint.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { endpointManagementCapabilityIds, listEndpointManagementCapabilities, resolveEndpointManagement, } from '@zhin.js/adapter';
2
+ export { resolveEndpointControl } from '@zhin.js/adapter';
2
3
  export { DEFAULT_ENDPOINT_CAPABILITIES, OutboundNotSupportedError, InboundNotSupportedError, resolveEndpointCapabilities, registerEndpointCapabilities, getEndpointCapabilities, getAdapterCapabilities, hasInbound, hasOutbound, assertInbound, assertOutbound, } from './endpoint-capabilities.js';
package/lib/errors.d.ts CHANGED
@@ -8,8 +8,8 @@ import { ZhinError } from '@zhin.js/kernel';
8
8
  */
9
9
  export declare class AdapterError extends ZhinError {
10
10
  readonly adapterName: string;
11
- readonly endpointId?: string;
12
- constructor(message: string, adapterName: string, endpointId?: string, context?: Record<string, any>);
11
+ readonly endpointKey?: string;
12
+ constructor(message: string, adapterName: string, endpointKey?: string, context?: Record<string, any>);
13
13
  }
14
14
  /**
15
15
  * 消息处理错误
package/lib/errors.js CHANGED
@@ -8,11 +8,11 @@ import { ZhinError } from '@zhin.js/kernel';
8
8
  */
9
9
  export class AdapterError extends ZhinError {
10
10
  adapterName;
11
- endpointId;
12
- constructor(message, adapterName, endpointId, context) {
13
- super(message, 'ADAPTER_ERROR', { ...context, adapterName, endpointId });
11
+ endpointKey;
12
+ constructor(message, adapterName, endpointKey, context) {
13
+ super(message, 'ADAPTER_ERROR', { ...context, adapterName, endpointKey });
14
14
  this.adapterName = adapterName;
15
- this.endpointId = endpointId;
15
+ this.endpointKey = endpointKey;
16
16
  }
17
17
  }
18
18
  /**
@@ -1,7 +1,8 @@
1
1
  /**
2
- * 宿主根插件引用 Bot 启动/装配阶段注册,供运行时路径读取。
3
- * 避免在中间件、工具 execute、命令 action 等回调内调用 getPlugin()(ALS 易丢失)。
2
+ * @deprecated **已删除**。全局根插件注册表已移除;服务通过 Scope+Token 提供。
3
+ * 保留 no-op 签名供编译期过渡。
4
4
  */
5
- import type { Plugin } from './plugin.js';
6
- export declare function setHostRootPlugin(plugin: Plugin | null): void;
7
- export declare function getHostRootPlugin(): Plugin | null;
5
+ /** @deprecated 已删除——不做任何事。 */
6
+ export declare function setHostRootPlugin(_plugin: unknown): void;
7
+ /** @deprecated 已删除——总是返回 null。 */
8
+ export declare function getHostRootPlugin(): null;
@@ -1,7 +1,12 @@
1
- let hostRoot = null;
2
- export function setHostRootPlugin(plugin) {
3
- hostRoot = plugin ? (plugin.root ?? plugin) : null;
1
+ /**
2
+ * @deprecated **已删除**。全局根插件注册表已移除;服务通过 Scope+Token 提供。
3
+ * 保留 no-op 签名供编译期过渡。
4
+ */
5
+ /** @deprecated 已删除——不做任何事。 */
6
+ export function setHostRootPlugin(_plugin) {
7
+ // no-op: legacy host root plugin registry has been removed
4
8
  }
9
+ /** @deprecated 已删除——总是返回 null。 */
5
10
  export function getHostRootPlugin() {
6
- return hostRoot;
11
+ return null;
7
12
  }
package/lib/im-scene.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface IMSceneParentRef {
9
9
  }
10
10
  export interface IMSceneRef {
11
11
  platform: string;
12
- endpointId: string;
12
+ endpointKey: string;
13
13
  sceneId: string;
14
14
  kind: IMSceneKind;
15
15
  senderId?: string;
package/lib/im-scene.js CHANGED
@@ -12,9 +12,9 @@ export function normalizeIMSceneParentKind(value) {
12
12
  }
13
13
  export function sceneRefFromMessage(message) {
14
14
  const platform = nonEmptyString(message.$adapter);
15
- const endpointId = nonEmptyString(message.$endpoint);
15
+ const endpointKey = nonEmptyString(message.$endpoint);
16
16
  const kind = message.$channel?.type;
17
- if (!platform || !endpointId || !kind)
17
+ if (!platform || !endpointKey || !kind)
18
18
  return undefined;
19
19
  const senderId = nonEmptyString(message.$sender?.id);
20
20
  const channelId = nonEmptyString(message.$channel?.id);
@@ -34,7 +34,7 @@ export function sceneRefFromMessage(message) {
34
34
  : undefined;
35
35
  return {
36
36
  platform,
37
- endpointId,
37
+ endpointKey,
38
38
  sceneId,
39
39
  kind,
40
40
  ...(senderId ? { senderId } : {}),
@@ -45,7 +45,7 @@ export function sceneRefToSendOptions(target, content) {
45
45
  const { scene } = target;
46
46
  return {
47
47
  context: scene.platform,
48
- endpoint: scene.endpointId,
48
+ endpoint: scene.endpointKey,
49
49
  id: scene.sceneId,
50
50
  type: scene.kind,
51
51
  parent: scene.parent
@@ -59,7 +59,7 @@ export function sceneRefToSendOptions(target, content) {
59
59
  export function resolveIMSceneSessionId(scene) {
60
60
  return resolveIMSceneSessionIdKernel({
61
61
  platform: scene.platform,
62
- endpointId: scene.endpointId,
62
+ endpointKey: scene.endpointKey,
63
63
  sceneId: scene.sceneId,
64
64
  kind: scene.kind,
65
65
  });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * IM 会话 ID 解析(SSOT 在 @zhin.js/kernel + im-scene)
3
3
  *
4
- * 格式:`platform:endpointId:kind:sceneId`
4
+ * 格式:`platform:endpointKey:kind:sceneId`
5
5
  */
6
6
  import { type ResolveIMSessionIdInput } from '@zhin.js/kernel';
7
7
  import { type IMSceneKind, type IMSceneRef } from './im-scene.js';
@@ -33,7 +33,7 @@ export declare function resolveSceneFieldsFromMessage(message: {
33
33
  };
34
34
  }): {
35
35
  platform: string;
36
- endpointId: string;
36
+ endpointKey: string;
37
37
  sceneId: string;
38
38
  sceneType: IMSceneKind;
39
39
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * IM 会话 ID 解析(SSOT 在 @zhin.js/kernel + im-scene)
3
3
  *
4
- * 格式:`platform:endpointId:kind:sceneId`
4
+ * 格式:`platform:endpointKey:kind:sceneId`
5
5
  */
6
6
  import { resolveIMSceneIdForSession as resolveIMSceneIdForSessionKernel, resolveIMSessionId as resolveIMSessionIdKernel, } from '@zhin.js/kernel';
7
7
  import { resolveIMSceneSessionId, sceneRefFromMessage, } from './im-scene.js';
@@ -21,7 +21,7 @@ export function resolveIMSessionIdFromMessage(message) {
21
21
  const kind = (message.$channel?.type || 'private');
22
22
  return resolveIMSessionId({
23
23
  platform: String(message.$adapter || ''),
24
- endpointId: String(message.$endpoint || ''),
24
+ endpointKey: String(message.$endpoint || ''),
25
25
  kind,
26
26
  sceneId: resolveIMSceneIdForSession(kind, message.$channel?.id, message.$sender?.id),
27
27
  });
@@ -32,7 +32,7 @@ export function resolveSceneFieldsFromMessage(message) {
32
32
  if (scene) {
33
33
  return {
34
34
  platform: scene.platform,
35
- endpointId: scene.endpointId,
35
+ endpointKey: scene.endpointKey,
36
36
  sceneId: scene.sceneId,
37
37
  sceneType: scene.kind,
38
38
  };
@@ -40,7 +40,7 @@ export function resolveSceneFieldsFromMessage(message) {
40
40
  const sceneType = (message.$channel?.type || 'private');
41
41
  return {
42
42
  platform: String(message.$adapter || ''),
43
- endpointId: String(message.$endpoint || ''),
43
+ endpointKey: String(message.$endpoint || ''),
44
44
  sceneType,
45
45
  sceneId: resolveIMSceneIdForSession(sceneType, message.$channel?.id, message.$sender?.id),
46
46
  };
package/lib/index.d.ts CHANGED
@@ -20,7 +20,6 @@ export * from './built/schedule.js';
20
20
  export type { ScheduleDescriptor, ScheduleHandle, ScheduleContextExtensions } from './built/schedule.js';
21
21
  export * from './models/system-log.js';
22
22
  export * from './models/user.js';
23
- export * from './built/permission.js';
24
23
  export * from './built/permit-parse.js';
25
24
  export * from './built/permit-check.js';
26
25
  export * from './built/platform-permit.js';
@@ -42,7 +41,6 @@ export * from './built/dispatcher.js';
42
41
  export * from './built/schema-feature.js';
43
42
  export * from './built/login-assist.js';
44
43
  export * from './built/generated-qrcode.js';
45
- export * from './built/qrcode-segment.js';
46
44
  export * from './built/rich-segments/index.js';
47
45
  export * from './built/interactive-segments/index.js';
48
46
  export * from './built/ai-outbound/index.js';
@@ -52,6 +50,7 @@ export * from './built/outbound-media-utils.js';
52
50
  export * from './built/outbound-media-contract.js';
53
51
  export * from './built/interactive-segment-contract.js';
54
52
  export * from './built/segment-contract/index.js';
53
+ export type { SegmentMediaRef } from './built/segment-contract/media.js';
55
54
  export * from './built/generic-segment-mapper.js';
56
55
  export * from './built/adapter-process.js';
57
56
  export * from './built/component.js';
package/lib/index.js CHANGED
@@ -22,7 +22,6 @@ export * from './built/schedule.js';
22
22
  // Models
23
23
  export * from './models/system-log.js';
24
24
  export * from './models/user.js';
25
- export * from './built/permission.js';
26
25
  export * from './built/permit-parse.js';
27
26
  export * from './built/permit-check.js';
28
27
  export * from './built/platform-permit.js';
@@ -43,7 +42,6 @@ export * from './built/dispatcher.js';
43
42
  export * from './built/schema-feature.js';
44
43
  export * from './built/login-assist.js';
45
44
  export * from './built/generated-qrcode.js';
46
- export * from './built/qrcode-segment.js';
47
45
  export * from './built/rich-segments/index.js';
48
46
  export * from './built/interactive-segments/index.js';
49
47
  export * from './built/ai-outbound/index.js';
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs, Fragment, renderJSX } from './jsx.js';
2
2
  export { jsx, jsxs, Fragment, renderJSX };
3
+ export type { JSX } from './jsx.js';
3
4
  declare const _default: {
4
5
  jsx: typeof jsx;
5
6
  jsxs: typeof jsxs;
package/lib/jsx.d.ts CHANGED
@@ -1,30 +1,28 @@
1
- import { SendContent, MessageElement } from './types.js';
2
- import { MessageComponent } from './message.js';
3
- import { Component, ComponentContext } from './component.js';
1
+ import type { SendContent, MessageElement } from './types.js';
2
+ import type { MessageComponent } from './message.js';
3
+ import type { Component, ComponentContext } from './component.js';
4
4
  export type JSXChildren = MessageElement | string | number | boolean | null | undefined | JSXChildren[];
5
5
  export type JSXElementType = string | Component<any>;
6
6
  export type JSXProps = Record<string, any> & {
7
7
  children?: JSXChildren;
8
8
  };
9
9
  export { Fragment } from './component.js';
10
- declare global {
11
- namespace JSX {
12
- type Element = SendContent | Promise<SendContent>;
13
- interface ElementClass {
14
- render(props: any, context?: ComponentContext): Element;
15
- }
16
- interface ElementAttributesProperty {
17
- data: {};
18
- }
19
- interface ElementChildrenAttribute {
20
- children: {};
21
- }
22
- interface IntrinsicElements {
23
- [elemName: string]: any;
24
- }
25
- interface IntrinsicAttributes {
26
- key?: string | number;
27
- }
10
+ export declare namespace JSX {
11
+ type Element = SendContent | Promise<SendContent>;
12
+ interface ElementClass {
13
+ render(props: any, context?: ComponentContext): Element;
14
+ }
15
+ interface ElementAttributesProperty {
16
+ data: {};
17
+ }
18
+ interface ElementChildrenAttribute {
19
+ children: {};
20
+ }
21
+ interface IntrinsicElements {
22
+ [elemName: string]: any;
23
+ }
24
+ interface IntrinsicAttributes {
25
+ key?: string | number;
28
26
  }
29
27
  }
30
28
  export declare function jsx(type: JSXElementType, data: JSXProps): MessageComponent<any>;
package/lib/message.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { MessageElement, MessageSender, SendContent } from "./types.js";
1
+ import type { MessageElement, MessageSender, SendContent } from "./types.js";
2
2
  import { Component } from "./component.js";
3
3
  import { Adapters } from "./adapter.js";
4
4
  /**
package/lib/message.js CHANGED
@@ -6,7 +6,7 @@ export var Message;
6
6
  * 工具方法:合并自定义字段与基础消息结构
7
7
  */
8
8
  function from(input, format) {
9
- return Object.assign(input, format);
9
+ return Object.assign({}, input, format);
10
10
  }
11
11
  Message.from = from;
12
12
  function quoteIdFromContent(content) {
package/lib/notice.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Adapters } from './adapter.js';
2
2
  import type { NoticeKind } from './side-event/types.js';
3
3
  import type { SideEventBase } from './side-event/base.js';
4
- export type { NoticeKind, ComposedNoticeName, NoticeType } from './side-event/types.js';
4
+ export type { NoticeKind, ComposedNoticeName } from './side-event/types.js';
5
5
  export type { SideEventBase } from './side-event/base.js';
6
6
  export { composeSideEventName, formatSideEventName, matchesSideEventName, parseSideEventName, sideEventSendChannel, } from './side-event/base.js';
7
7
  /**
@@ -12,7 +12,7 @@ export { composeSideEventName, formatSideEventName, matchesSideEventName, parseS
12
12
  * const notice = Notice.from(rawEvent, {
13
13
  * $id: rawEvent.id,
14
14
  * $adapter: 'icqq',
15
- * $endpoint: endpointId,
15
+ * $endpoint: endpointKey,
16
16
  * $type: 'notice',
17
17
  * $scene_id: groupId,
18
18
  * $scene_type: 'group',
@@ -7,23 +7,21 @@
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
8
8
  import type { Plugin } from "./plugin.js";
9
9
  export declare const storage: AsyncLocalStorage<Plugin>;
10
+ /**
11
+ * Plugin Runtime (`zhin runtime start`) 启动时调用。
12
+ * 标记后 getPlugin()/usePlugin() 在 ALS 为空时抛出更明确的迁移提示,
13
+ * 而非通用的 "must be called within a plugin context"。
14
+ */
15
+ export declare function markPluginRuntimeActive(): void;
16
+ export declare function isPluginRuntimeActive(): boolean;
17
+ /** 测试重置 */
18
+ export declare function resetPluginRuntimeFlag(): void;
10
19
  /**
11
20
  * 获取当前文件路径(调用者)
12
21
  */
13
22
  export declare function getCurrentFile(metaUrl?: string): string;
14
23
  /**
15
- * getPlugin - 获取当前 AsyncLocalStorage 中的插件实例
16
- *
17
- * **调用时机(重要)**
18
- * - ✅ 插件**初始化/装配**阶段:模块顶层、register/init 函数内、注册命令/中间件/工具**之前**
19
- * - ❌ **运行时回调**内严禁调用:中间件、命令 `.action()`、工具 `.execute()`、Cron、生命周期 `.on()` 等
20
- *
21
- * 运行时回调应使用初始化时捕获的 `plugin` / `root` 闭包引用,而非再次 `getPlugin()`。
22
- * AsyncLocalStorage 在跨 await、线程池、部分平台适配器回调中可能丢失,导致线上 `getPlugin() must be called within a plugin context`。
23
- *
24
- * 插件作者优先在模块顶层使用 `usePlugin()` 解构 API,一般不需要 `getPlugin()`。
25
- * Bot 启动时框架调用 `setHostRootPlugin(root)`;运行时模块用 `getHostRootPlugin()` 代替 `getPlugin()`。
26
- *
27
- * @see docs/guide/plugin-development.md#getplugin-与-useplugin
24
+ * @deprecated **已删除**。请使用 `definePlugin` + 约定目录;运行时通过 Scope+Token 访问服务。
25
+ * @throws 总是抛出——仅保留签名供编译期过渡。
28
26
  */
29
27
  export declare function getPlugin(): Plugin;
@@ -11,6 +11,22 @@ import { fileURLToPath } from "node:url";
11
11
  // AsyncLocalStorage 上下文
12
12
  // ============================================================================
13
13
  export const storage = new AsyncLocalStorage();
14
+ let _pluginRuntimeActive = false;
15
+ /**
16
+ * Plugin Runtime (`zhin runtime start`) 启动时调用。
17
+ * 标记后 getPlugin()/usePlugin() 在 ALS 为空时抛出更明确的迁移提示,
18
+ * 而非通用的 "must be called within a plugin context"。
19
+ */
20
+ export function markPluginRuntimeActive() {
21
+ _pluginRuntimeActive = true;
22
+ }
23
+ export function isPluginRuntimeActive() {
24
+ return _pluginRuntimeActive;
25
+ }
26
+ /** 测试重置 */
27
+ export function resetPluginRuntimeFlag() {
28
+ _pluginRuntimeActive = false;
29
+ }
14
30
  /**
15
31
  * 获取当前文件路径(调用者)
16
32
  */
@@ -38,24 +54,11 @@ export function getCurrentFile(metaUrl = import.meta.url) {
38
54
  }
39
55
  }
40
56
  /**
41
- * getPlugin - 获取当前 AsyncLocalStorage 中的插件实例
42
- *
43
- * **调用时机(重要)**
44
- * - ✅ 插件**初始化/装配**阶段:模块顶层、register/init 函数内、注册命令/中间件/工具**之前**
45
- * - ❌ **运行时回调**内严禁调用:中间件、命令 `.action()`、工具 `.execute()`、Cron、生命周期 `.on()` 等
46
- *
47
- * 运行时回调应使用初始化时捕获的 `plugin` / `root` 闭包引用,而非再次 `getPlugin()`。
48
- * AsyncLocalStorage 在跨 await、线程池、部分平台适配器回调中可能丢失,导致线上 `getPlugin() must be called within a plugin context`。
49
- *
50
- * 插件作者优先在模块顶层使用 `usePlugin()` 解构 API,一般不需要 `getPlugin()`。
51
- * Bot 启动时框架调用 `setHostRootPlugin(root)`;运行时模块用 `getHostRootPlugin()` 代替 `getPlugin()`。
52
- *
53
- * @see docs/guide/plugin-development.md#getplugin-与-useplugin
57
+ * @deprecated **已删除**。请使用 `definePlugin` + 约定目录;运行时通过 Scope+Token 访问服务。
58
+ * @throws 总是抛出——仅保留签名供编译期过渡。
54
59
  */
55
60
  export function getPlugin() {
56
- const plugin = storage.getStore();
57
- if (!plugin) {
58
- throw new Error('getPlugin() must be called within a plugin context');
59
- }
60
- return plugin;
61
+ throw new Error('getPlugin() has been removed. Use `definePlugin` + convention directories, '
62
+ + 'and access services via Scope+Token. '
63
+ + 'See docs/contributing/public-api-surface.md');
61
64
  }
@@ -1,4 +1,4 @@
1
- import type { PluginId, RuntimeSnapshot } from '@zhin.js/plugin-runtime';
1
+ import type { PluginId } from '@zhin.js/plugin-runtime';
2
2
  import type { ConversationRef, DeliveryReceipt, MessageRef } from '@zhin.js/im-contract';
3
3
  import type { MediaRef, Segment } from '../../built/segment-contract/types.js';
4
4
  export type { MediaRef, Segment };
@@ -24,22 +24,56 @@ export declare function isComponentCall(value: SendContent): value is ComponentC
24
24
  export declare function isRawContent(value: SendContent): value is RawContent;
25
25
  /** canonical Segment 一等公民判定(与 ComponentCall/RawContent 的 $content brand 互斥)。 */
26
26
  export declare function isSegmentContent(value: unknown): value is Segment;
27
+ export interface MessageSenderRef {
28
+ readonly id: string;
29
+ readonly name?: string;
30
+ readonly roles?: readonly string[];
31
+ }
27
32
  export interface IncomingMessage {
28
33
  readonly conversation: ConversationRef;
29
34
  readonly message?: MessageRef;
30
35
  readonly content: string;
31
36
  readonly segments?: readonly Segment[];
32
- readonly sender?: string;
37
+ readonly sender?: MessageSenderRef;
38
+ /** Endpoint 实例名(如 ICQQ uin、sandbox bot name),区别于 conversation.endpoint.id(CapabilityId)。 */
39
+ readonly endpointId?: string;
40
+ /** 消息是否 @了机器人。 */
41
+ readonly mentioned?: boolean;
42
+ /** 引用/回复的原始消息。 */
43
+ readonly replyTo?: {
44
+ readonly id: string;
45
+ };
33
46
  readonly metadata?: Readonly<Record<string, unknown>>;
34
47
  }
48
+ /**
49
+ * 入站消息上下文快照 — 由 reply 闭包捕获,沿出站链路传递到模板编译。
50
+ * 定时任务 / 跨通道发送时整个 incoming 为 undefined。
51
+ */
52
+ export interface IncomingContext {
53
+ readonly sender?: MessageSenderRef;
54
+ /** 收到的消息纯文本内容。 */
55
+ readonly content: string;
56
+ /** 结构化消息段(图片、@、引用等)。 */
57
+ readonly segments?: readonly Segment[];
58
+ /** 平台原生消息 ID。 */
59
+ readonly messageId?: string;
60
+ /** 消息到达时间戳(ms)。 */
61
+ readonly timestamp: number;
62
+ /** Endpoint 实例名(如 ICQQ uin、sandbox bot name)。 */
63
+ readonly endpointId?: string;
64
+ /** 消息是否 @了机器人。 */
65
+ readonly mentioned?: boolean;
66
+ }
35
67
  export interface SendRequest {
36
68
  readonly conversation: ConversationRef;
37
69
  readonly requester: PluginId;
38
70
  readonly content: SendContent;
71
+ /** Incoming message context (absent for scheduled / cross-channel sends). */
72
+ readonly incoming?: IncomingContext;
39
73
  }
40
74
  /**
41
75
  * Host 侧未锚定 endpoint 的会话地址(Console RPC / OutboundHost 入参);
42
- * ImRuntime 解析 adapter/endpointId 后锚定为完整 ConversationRef。
76
+ * ImRuntime 解析 adapter/endpointKey 后锚定为完整 ConversationRef。
43
77
  */
44
78
  export type ConversationAddress = Omit<ConversationRef, 'endpoint'>;
45
79
  export interface OutboundEnvelope {
@@ -58,12 +92,6 @@ export interface MessageGateway {
58
92
  * payload 都会路由到这里。
59
93
  */
60
94
  registerInteractiveHandler(prefix: string, handler: (message: Message) => Promise<boolean> | boolean): () => void;
61
- /**
62
- * Command miss(或非前缀文本)后的回退处理:Host AI 对话、单文件 bot 用。
63
- * 返回 true 表示已处理(回复已发送);后注册者覆盖前者。
64
- * `requester` 是消息所属 Adapter Endpoint 的 owner(用于 CapabilityIngress 继承)。
65
- */
66
- setUnmatchedHandler(handler: (message: Message, snapshot: RuntimeSnapshot, requester: PluginId) => Promise<boolean>): void;
67
95
  }
68
96
  export interface MessageDispatchResult {
69
97
  readonly matched: boolean;
@@ -75,7 +103,7 @@ export declare class Message {
75
103
  readonly conversation: ConversationRef;
76
104
  readonly content: string;
77
105
  readonly generation: number;
78
- readonly sender?: string | undefined;
106
+ readonly sender?: MessageSenderRef | undefined;
79
107
  readonly metadata: Readonly<Record<string, unknown>>;
80
108
  /**
81
109
  * 结构化段视图(与 `content` 纯文本视图同源,见 IncomingMessage.segments)。
@@ -84,17 +112,68 @@ export declare class Message {
84
112
  readonly segments?: readonly Segment[] | undefined;
85
113
  /** 结构化入站消息身份(平台原生 message id 经 MessageRef 传递)。 */
86
114
  readonly message?: MessageRef | undefined;
87
- constructor(conversation: ConversationRef, content: string, generation: number, reply: (content: SendContent, requester?: PluginId) => Promise<DeliveryReceipt>, sender?: string | undefined, metadata?: Readonly<Record<string, unknown>>,
115
+ readonly endpointId?: string | undefined;
116
+ readonly mentioned?: boolean | undefined;
117
+ readonly replyTo?: {
118
+ readonly id: string;
119
+ } | undefined;
120
+ constructor(conversation: ConversationRef, content: string, generation: number, reply: (content: SendContent, requester?: PluginId, targetConversation?: ConversationAddress) => Promise<DeliveryReceipt>, sender?: MessageSenderRef | undefined, metadata?: Readonly<Record<string, unknown>>,
88
121
  /**
89
122
  * 结构化段视图(与 `content` 纯文本视图同源,见 IncomingMessage.segments)。
90
123
  * Command dispatcher 优先使用此字段,以支持 mention、image 等结构化参数。
91
124
  */
92
125
  segments?: readonly Segment[] | undefined,
93
126
  /** 结构化入站消息身份(平台原生 message id 经 MessageRef 传递)。 */
94
- message?: MessageRef | undefined);
127
+ message?: MessageRef | undefined, endpointId?: string | undefined, mentioned?: boolean | undefined, replyTo?: {
128
+ readonly id: string;
129
+ } | undefined);
95
130
  /** 平台原生消息 id(`message` 未提供时为 undefined)。 */
96
131
  get id(): string | undefined;
97
132
  readonly $reply: (content: SendContent) => Promise<DeliveryReceipt>;
98
133
  readonly $replyFrom: (requester: PluginId, content: SendContent) => Promise<DeliveryReceipt>;
134
+ /**
135
+ * 向同 Endpoint 的另一个通道发送消息(通用)。
136
+ *
137
+ * ```ts
138
+ * await message.$sendTo({ kind: 'channel', id: 'ch-1', parent: { kind: 'channel', id: 'guild-1' } }, '频道通知');
139
+ * ```
140
+ */
141
+ readonly $sendTo: (conversation: ConversationAddress, content: SendContent) => Promise<DeliveryReceipt>;
142
+ /**
143
+ * 私信当前消息的发送者(同 Endpoint)。
144
+ *
145
+ * @param content 消息内容
146
+ * @param from 会话上下文:
147
+ * - `true` — 用当前群/频道作为 parent(要求当前不在私聊中)
148
+ * - `{ kind, id }` — 显式指定 parent(群或子频道)
149
+ * - 省略 — 直接私信
150
+ *
151
+ * ```ts
152
+ * await message.$replyToPrivate('直接私信');
153
+ * await message.$replyToPrivate('群临时私信', true);
154
+ * await message.$replyToPrivate('频道私信', { kind: 'channel', id: '子频道ID' });
155
+ * ```
156
+ */
157
+ readonly $replyToPrivate: (content: SendContent, from?: boolean | {
158
+ readonly kind: 'group' | 'channel';
159
+ readonly id: string;
160
+ }) => Promise<DeliveryReceipt>;
161
+ /**
162
+ * 向指定群发送消息(同 Endpoint)。
163
+ *
164
+ * ```ts
165
+ * await message.$replyToGroup('67890', '群通知');
166
+ * ```
167
+ */
168
+ readonly $replyToGroup: (groupId: string, content: SendContent) => Promise<DeliveryReceipt>;
169
+ /**
170
+ * 向指定频道/子频道发送消息(同 Endpoint)。
171
+ *
172
+ * ```ts
173
+ * await message.$replyToChannel('channel-1', 'guild-1', '频道通知');
174
+ * await message.$replyToChannel('channel-1', 'guild-1', '话题回复', 'thread-1');
175
+ * ```
176
+ */
177
+ readonly $replyToChannel: (channelId: string, guildId: string, content: SendContent, threadId?: string) => Promise<DeliveryReceipt>;
99
178
  }
100
179
  export declare function createOutboundEnvelope(request: Omit<OutboundEnvelope, 'payload' | 'replace'>, initialPayload: unknown): OutboundEnvelope;