@zhin.js/core 1.1.34 → 1.1.35
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.
- package/README.md +121 -65
- package/lib/adapter.d.ts +72 -23
- package/lib/adapter.js +222 -62
- package/lib/built/adapter-process.d.ts +20 -5
- package/lib/built/adapter-process.js +54 -7
- package/lib/built/agent-preset.d.ts +1 -2
- package/lib/built/agent-preset.js +1 -2
- package/lib/built/ai-access.d.ts +36 -0
- package/lib/built/ai-access.js +46 -0
- package/lib/built/ai-outbound/adapter-access.d.ts +3 -0
- package/lib/built/ai-outbound/adapter-access.js +9 -0
- package/lib/built/ai-outbound/extensions/onebot-keyboard.d.ts +2 -0
- package/lib/built/ai-outbound/extensions/onebot-keyboard.js +67 -0
- package/lib/built/ai-outbound/extensions/qq-message.d.ts +3 -0
- package/lib/built/ai-outbound/extensions/qq-message.js +23 -0
- package/lib/built/ai-outbound/index.d.ts +9 -0
- package/lib/built/ai-outbound/index.js +9 -0
- package/lib/built/ai-outbound/parse.d.ts +13 -0
- package/lib/built/ai-outbound/parse.js +104 -0
- package/lib/built/ai-outbound/plain-mention-rewrite.d.ts +6 -0
- package/lib/built/ai-outbound/plain-mention-rewrite.js +37 -0
- package/lib/built/ai-outbound/prompt.d.ts +11 -0
- package/lib/built/ai-outbound/prompt.js +44 -0
- package/lib/built/ai-outbound/resolve.d.ts +4 -0
- package/lib/built/ai-outbound/resolve.js +64 -0
- package/lib/built/ai-outbound/structured-detect.d.ts +3 -0
- package/lib/built/ai-outbound/structured-detect.js +6 -0
- package/lib/built/ai-outbound/types.d.ts +58 -0
- package/lib/built/ai-outbound/types.js +5 -0
- package/lib/built/ai-trigger.d.ts +17 -17
- package/lib/built/ai-trigger.js +65 -70
- package/lib/built/authorization.d.ts +10 -0
- package/lib/built/authorization.js +76 -0
- package/lib/built/command.d.ts +9 -5
- package/lib/built/command.js +20 -7
- package/lib/built/common-adapter-tools.d.ts +35 -29
- package/lib/built/common-adapter-tools.js +83 -67
- package/lib/built/component.d.ts +1 -3
- package/lib/built/component.js +2 -4
- package/lib/built/config.d.ts +4 -5
- package/lib/built/config.js +26 -9
- package/lib/built/connect-endpoint-instance.d.ts +17 -0
- package/lib/built/connect-endpoint-instance.js +42 -0
- package/lib/built/database.d.ts +5 -3
- package/lib/built/database.js +10 -4
- package/lib/built/dispatcher.d.ts +10 -8
- package/lib/built/dispatcher.js +31 -9
- package/lib/built/endpoint-commands.d.ts +3 -0
- package/lib/built/endpoint-commands.js +99 -0
- package/lib/built/endpoint-lifecycle-service.d.ts +28 -0
- package/lib/built/endpoint-lifecycle-service.js +242 -0
- package/lib/built/endpoint-lifecycle.d.ts +27 -0
- package/lib/built/endpoint-lifecycle.js +36 -0
- package/lib/built/endpoint-manager.d.ts +34 -0
- package/lib/built/endpoint-manager.js +1 -0
- package/lib/built/generated-qrcode.d.ts +24 -0
- package/lib/built/generated-qrcode.js +45 -0
- package/lib/built/generic-segment-mapper.d.ts +4 -0
- package/lib/built/generic-segment-mapper.js +190 -0
- package/lib/built/html-renderer-loader.d.ts +13 -0
- package/lib/built/html-renderer-loader.js +33 -0
- package/lib/built/html-segment-fallback.d.ts +2 -2
- package/lib/built/html-segment-fallback.js +0 -1
- package/lib/built/html-to-text.d.ts +0 -1
- package/lib/built/html-to-text.js +15 -15
- package/lib/built/inbound-pipeline.d.ts +37 -0
- package/lib/built/inbound-pipeline.js +63 -0
- package/lib/built/inbound-runner.d.ts +0 -1
- package/lib/built/inbound-runner.js +0 -3
- package/lib/built/interactive-segment-contract.d.ts +6 -0
- package/lib/built/interactive-segment-contract.js +9 -0
- package/lib/built/interactive-segments/action.d.ts +17 -0
- package/lib/built/interactive-segments/action.js +69 -0
- package/lib/built/interactive-segments/button-spec.d.ts +10 -0
- package/lib/built/interactive-segments/button-spec.js +21 -0
- package/lib/built/interactive-segments/fallback-store.d.ts +29 -0
- package/lib/built/interactive-segments/fallback-store.js +63 -0
- package/lib/built/interactive-segments/handlers.d.ts +16 -0
- package/lib/built/interactive-segments/handlers.js +74 -0
- package/lib/built/interactive-segments/index.d.ts +8 -0
- package/lib/built/interactive-segments/index.js +8 -0
- package/lib/built/interactive-segments/keyboard-segment.d.ts +11 -0
- package/lib/built/interactive-segments/keyboard-segment.js +12 -0
- package/lib/built/interactive-segments/onebot-keyboard.d.ts +7 -0
- package/lib/built/interactive-segments/onebot-keyboard.js +51 -0
- package/lib/built/interactive-segments/resolve.d.ts +15 -0
- package/lib/built/interactive-segments/resolve.js +110 -0
- package/lib/built/interactive-segments/types.d.ts +50 -0
- package/lib/built/interactive-segments/types.js +9 -0
- package/lib/built/introspection-format.d.ts +10 -0
- package/lib/built/introspection-format.js +28 -0
- package/lib/built/login-assist.d.ts +43 -9
- package/lib/built/login-assist.js +113 -11
- package/lib/built/management-command-guard.d.ts +15 -0
- package/lib/built/management-command-guard.js +25 -0
- package/lib/built/message-enrich.d.ts +38 -0
- package/lib/built/message-enrich.js +75 -0
- package/lib/built/message-filter.d.ts +4 -5
- package/lib/built/message-filter.js +5 -7
- package/lib/built/optional-peer-import.d.ts +3 -0
- package/lib/built/optional-peer-import.js +33 -0
- package/lib/built/outbound-media-contract.d.ts +22 -0
- package/lib/built/outbound-media-contract.js +10 -0
- package/lib/built/outbound-media-utils.d.ts +9 -0
- package/lib/built/outbound-media-utils.js +62 -0
- package/lib/built/permission.d.ts +3 -7
- package/lib/built/permission.js +39 -52
- package/lib/built/permit-check.d.ts +7 -0
- package/lib/built/permit-check.js +35 -0
- package/lib/built/permit-parse.d.ts +16 -0
- package/lib/built/permit-parse.js +32 -0
- package/lib/built/platform-permit.d.ts +20 -0
- package/lib/built/platform-permit.js +91 -0
- package/lib/built/queue-im-field-contract.d.ts +7 -2
- package/lib/built/queue-im-field-contract.js +13 -4
- package/lib/built/rich-segments/adapter-policies.d.ts +9 -0
- package/lib/built/rich-segments/adapter-policies.js +27 -0
- package/lib/built/rich-segments/base.d.ts +11 -0
- package/lib/built/rich-segments/base.js +24 -0
- package/lib/built/rich-segments/builtins.d.ts +4 -0
- package/lib/built/rich-segments/builtins.js +40 -0
- package/lib/built/rich-segments/capabilities.d.ts +6 -0
- package/lib/built/rich-segments/capabilities.js +38 -0
- package/lib/built/rich-segments/html-segment.d.ts +15 -0
- package/lib/built/rich-segments/html-segment.js +62 -0
- package/lib/built/rich-segments/index.d.ts +13 -0
- package/lib/built/rich-segments/index.js +13 -0
- package/lib/built/rich-segments/markdown-segment.d.ts +14 -0
- package/lib/built/rich-segments/markdown-segment.js +58 -0
- package/lib/built/rich-segments/markdown-to-text.d.ts +3 -0
- package/lib/built/rich-segments/markdown-to-text.js +27 -0
- package/lib/built/rich-segments/qrcode-segment.d.ts +18 -0
- package/lib/built/rich-segments/qrcode-segment.js +73 -0
- package/lib/built/rich-segments/registry.d.ts +16 -0
- package/lib/built/rich-segments/registry.js +52 -0
- package/lib/built/rich-segments/resolve.d.ts +5 -0
- package/lib/built/rich-segments/resolve.js +87 -0
- package/lib/built/rich-segments/tts-segment.d.ts +13 -0
- package/lib/built/rich-segments/tts-segment.js +51 -0
- package/lib/built/rich-segments/types.d.ts +79 -0
- package/lib/built/rich-segments/types.js +17 -0
- package/lib/built/roles.d.ts +4 -5
- package/lib/built/roles.js +4 -5
- package/lib/built/runtime-io.d.ts +0 -1
- package/lib/built/runtime-io.js +0 -1
- package/lib/built/schedule.d.ts +54 -0
- package/lib/built/schedule.js +112 -0
- package/lib/built/schema-endpoint-manager.d.ts +17 -0
- package/lib/built/schema-endpoint-manager.js +73 -0
- package/lib/built/schema-feature.d.ts +0 -1
- package/lib/built/schema-feature.js +1 -3
- package/lib/built/segment-contract/assert.d.ts +7 -0
- package/lib/built/segment-contract/assert.js +39 -0
- package/lib/built/segment-contract/delivery.d.ts +5 -0
- package/lib/built/segment-contract/delivery.js +40 -0
- package/lib/built/segment-contract/image.d.ts +5 -0
- package/lib/built/segment-contract/image.js +10 -0
- package/lib/built/segment-contract/index.d.ts +10 -0
- package/lib/built/segment-contract/index.js +9 -0
- package/lib/built/segment-contract/json-schema.d.ts +28 -0
- package/lib/built/segment-contract/json-schema.js +128 -0
- package/lib/built/segment-contract/media.d.ts +12 -0
- package/lib/built/segment-contract/media.js +22 -0
- package/lib/built/segment-contract/mention.d.ts +10 -0
- package/lib/built/segment-contract/mention.js +26 -0
- package/lib/built/segment-contract/preview.d.ts +3 -0
- package/lib/built/segment-contract/preview.js +159 -0
- package/lib/built/segment-contract/text.d.ts +7 -0
- package/lib/built/segment-contract/text.js +34 -0
- package/lib/built/segment-contract/types.d.ts +58 -0
- package/lib/built/segment-contract/types.js +1 -0
- package/lib/built/segment-contract/validate.d.ts +229 -0
- package/lib/built/segment-contract/validate.js +174 -0
- package/lib/built/skill.d.ts +0 -1
- package/lib/built/skill.js +0 -1
- package/lib/built/speech-loader.d.ts +14 -0
- package/lib/built/speech-loader.js +32 -0
- package/lib/built/tool.d.ts +14 -13
- package/lib/built/tool.js +30 -25
- package/lib/built/user-interaction.d.ts +30 -0
- package/lib/built/user-interaction.js +248 -0
- package/lib/command.d.ts +19 -11
- package/lib/command.js +42 -11
- package/lib/component.d.ts +0 -1
- package/lib/component.js +30 -14
- package/lib/endpoint-capabilities.d.ts +46 -0
- package/lib/endpoint-capabilities.js +55 -0
- package/lib/endpoint.d.ts +19 -0
- package/lib/endpoint.js +3 -0
- package/lib/errors.d.ts +2 -3
- package/lib/errors.js +4 -5
- package/lib/feature/adapter.d.ts +2 -0
- package/lib/feature/adapter.js +2 -0
- package/lib/feature/command.d.ts +2 -0
- package/lib/feature/command.js +2 -0
- package/lib/feature/component.d.ts +2 -0
- package/lib/feature/component.js +2 -0
- package/lib/feature/handler.d.ts +52 -0
- package/lib/feature/handler.js +26 -0
- package/lib/feature/middleware.d.ts +2 -0
- package/lib/feature/middleware.js +2 -0
- package/lib/host-plugin-registry.d.ts +8 -0
- package/lib/host-plugin-registry.js +12 -0
- package/lib/im-scene.d.ts +29 -0
- package/lib/im-scene.js +75 -0
- package/lib/im-session-id.d.ts +39 -0
- package/lib/im-session-id.js +47 -0
- package/lib/index.d.ts +59 -25
- package/lib/index.js +53 -31
- package/lib/jsx-dev-runtime.d.ts +0 -1
- package/lib/jsx-dev-runtime.js +0 -1
- package/lib/jsx-runtime.d.ts +1 -1
- package/lib/jsx-runtime.js +0 -1
- package/lib/jsx.d.ts +19 -22
- package/lib/jsx.js +0 -1
- package/lib/message.d.ts +16 -10
- package/lib/message.js +16 -13
- package/lib/models/system-log.d.ts +0 -1
- package/lib/models/system-log.js +0 -1
- package/lib/models/user.d.ts +0 -1
- package/lib/models/user.js +0 -1
- package/lib/notice.d.ts +16 -59
- package/lib/notice.js +1 -4
- package/lib/plugin-context.d.ts +27 -0
- package/lib/plugin-context.js +64 -0
- package/lib/plugin-runtime/im/contracts.d.ts +191 -0
- package/lib/plugin-runtime/im/contracts.js +169 -0
- package/lib/plugin-runtime/im/im-runtime.d.ts +177 -0
- package/lib/plugin-runtime/im/im-runtime.js +1204 -0
- package/lib/plugin-runtime/im/index.d.ts +9 -0
- package/lib/plugin-runtime/im/index.js +9 -0
- package/lib/plugin-runtime/im/interactive.d.ts +26 -0
- package/lib/plugin-runtime/im/interactive.js +46 -0
- package/lib/plugin-runtime/im/login-assist-host.d.ts +6 -0
- package/lib/plugin-runtime/im/login-assist-host.js +6 -0
- package/lib/plugin-runtime/im/message-bus.d.ts +38 -0
- package/lib/plugin-runtime/im/message-bus.js +40 -0
- package/lib/plugin-runtime/im/message-dispatcher.d.ts +18 -0
- package/lib/plugin-runtime/im/message-dispatcher.js +107 -0
- package/lib/plugin-runtime/im/outbound-renderer.d.ts +7 -0
- package/lib/plugin-runtime/im/outbound-renderer.js +70 -0
- package/lib/plugin-runtime/im/outbound-segments.d.ts +72 -0
- package/lib/plugin-runtime/im/outbound-segments.js +220 -0
- package/lib/plugin-runtime/im/public-api.d.ts +6 -0
- package/lib/plugin-runtime/im/public-api.js +6 -0
- package/lib/plugin-runtime/im/service-tokens.d.ts +18 -0
- package/lib/plugin-runtime/im/service-tokens.js +13 -0
- package/lib/plugin.d.ts +34 -24
- package/lib/plugin.js +119 -224
- package/lib/request.d.ts +17 -61
- package/lib/request.js +0 -4
- package/lib/{prompt.d.ts → schema-interaction.d.ts} +6 -7
- package/lib/{prompt.js → schema-interaction.js} +20 -17
- package/lib/side-event/base.d.ts +52 -0
- package/lib/side-event/base.js +30 -0
- package/lib/side-event/dispatch.d.ts +15 -0
- package/lib/side-event/dispatch.js +140 -0
- package/lib/side-event/index.d.ts +4 -0
- package/lib/side-event/index.js +4 -0
- package/lib/side-event/normalize.d.ts +42 -0
- package/lib/side-event/normalize.js +121 -0
- package/lib/side-event/types.d.ts +23 -0
- package/lib/side-event/types.js +55 -0
- package/lib/system-event.d.ts +15 -0
- package/lib/system-event.js +7 -0
- package/lib/tool-zod.d.ts +18 -3
- package/lib/tool-zod.js +140 -54
- package/lib/types.d.ts +44 -95
- package/lib/types.js +0 -1
- package/lib/utils.d.ts +61 -13
- package/lib/utils.js +66 -25
- package/package.json +98 -10
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js.map +0 -1
- package/lib/agent-prompt.d.ts +0 -37
- package/lib/agent-prompt.d.ts.map +0 -1
- package/lib/agent-prompt.js +0 -2
- package/lib/agent-prompt.js.map +0 -1
- package/lib/bot.d.ts +0 -38
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -2
- package/lib/bot.js.map +0 -1
- package/lib/built/adapter-process.d.ts.map +0 -1
- package/lib/built/adapter-process.js.map +0 -1
- package/lib/built/agent-preset.d.ts.map +0 -1
- package/lib/built/agent-preset.js.map +0 -1
- package/lib/built/ai-trigger.d.ts.map +0 -1
- package/lib/built/ai-trigger.js.map +0 -1
- package/lib/built/command.d.ts.map +0 -1
- package/lib/built/command.js.map +0 -1
- package/lib/built/common-adapter-tools.d.ts.map +0 -1
- package/lib/built/common-adapter-tools.js.map +0 -1
- package/lib/built/component.d.ts.map +0 -1
- package/lib/built/component.js.map +0 -1
- package/lib/built/config.d.ts.map +0 -1
- package/lib/built/config.js.map +0 -1
- package/lib/built/cron.d.ts +0 -75
- package/lib/built/cron.d.ts.map +0 -1
- package/lib/built/cron.js +0 -122
- package/lib/built/cron.js.map +0 -1
- package/lib/built/database.d.ts.map +0 -1
- package/lib/built/database.js.map +0 -1
- package/lib/built/dispatcher.d.ts.map +0 -1
- package/lib/built/dispatcher.js.map +0 -1
- package/lib/built/html-segment-fallback.d.ts.map +0 -1
- package/lib/built/html-segment-fallback.js.map +0 -1
- package/lib/built/html-to-text.d.ts.map +0 -1
- package/lib/built/html-to-text.js.map +0 -1
- package/lib/built/inbound-runner.d.ts.map +0 -1
- package/lib/built/inbound-runner.js.map +0 -1
- package/lib/built/login-assist.d.ts.map +0 -1
- package/lib/built/login-assist.js.map +0 -1
- package/lib/built/mcp-mesh-registrar.d.ts +0 -9
- package/lib/built/mcp-mesh-registrar.d.ts.map +0 -1
- package/lib/built/mcp-mesh-registrar.js +0 -17
- package/lib/built/mcp-mesh-registrar.js.map +0 -1
- package/lib/built/message-filter.d.ts.map +0 -1
- package/lib/built/message-filter.js.map +0 -1
- package/lib/built/permission.d.ts.map +0 -1
- package/lib/built/permission.js.map +0 -1
- package/lib/built/prepend-quote-context.d.ts +0 -35
- package/lib/built/prepend-quote-context.d.ts.map +0 -1
- package/lib/built/prepend-quote-context.js +0 -131
- package/lib/built/prepend-quote-context.js.map +0 -1
- package/lib/built/queue-im-field-contract.d.ts.map +0 -1
- package/lib/built/queue-im-field-contract.js.map +0 -1
- package/lib/built/roles.d.ts.map +0 -1
- package/lib/built/roles.js.map +0 -1
- package/lib/built/runtime-io.d.ts.map +0 -1
- package/lib/built/runtime-io.js.map +0 -1
- package/lib/built/schema-feature.d.ts.map +0 -1
- package/lib/built/schema-feature.js.map +0 -1
- package/lib/built/skill.d.ts.map +0 -1
- package/lib/built/skill.js.map +0 -1
- package/lib/built/tool.d.ts.map +0 -1
- package/lib/built/tool.js.map +0 -1
- package/lib/command.d.ts.map +0 -1
- package/lib/command.js.map +0 -1
- package/lib/component.d.ts.map +0 -1
- package/lib/component.js.map +0 -1
- package/lib/errors.d.ts.map +0 -1
- package/lib/errors.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/jsx-dev-runtime.d.ts.map +0 -1
- package/lib/jsx-dev-runtime.js.map +0 -1
- package/lib/jsx-runtime.d.ts.map +0 -1
- package/lib/jsx-runtime.js.map +0 -1
- package/lib/jsx.d.ts.map +0 -1
- package/lib/jsx.js.map +0 -1
- package/lib/message-quote.d.ts +0 -11
- package/lib/message-quote.d.ts.map +0 -1
- package/lib/message-quote.js +0 -91
- package/lib/message-quote.js.map +0 -1
- package/lib/message.d.ts.map +0 -1
- package/lib/message.js.map +0 -1
- package/lib/models/system-log.d.ts.map +0 -1
- package/lib/models/system-log.js.map +0 -1
- package/lib/models/user.d.ts.map +0 -1
- package/lib/models/user.js.map +0 -1
- package/lib/notice.d.ts.map +0 -1
- package/lib/notice.js.map +0 -1
- package/lib/plugin.d.ts.map +0 -1
- package/lib/plugin.js.map +0 -1
- package/lib/prompt.d.ts.map +0 -1
- package/lib/prompt.js.map +0 -1
- package/lib/request.d.ts.map +0 -1
- package/lib/request.js.map +0 -1
- package/lib/scheduler/scheduler.d.ts +0 -49
- package/lib/scheduler/scheduler.d.ts.map +0 -1
- package/lib/scheduler/scheduler.js +0 -352
- package/lib/scheduler/scheduler.js.map +0 -1
- package/lib/scheduler/types.d.ts +0 -71
- package/lib/scheduler/types.d.ts.map +0 -1
- package/lib/scheduler/types.js +0 -8
- package/lib/scheduler/types.js.map +0 -1
- package/lib/tool-zod.d.ts.map +0 -1
- package/lib/tool-zod.js.map +0 -1
- package/lib/types-generator.d.ts +0 -6
- package/lib/types-generator.d.ts.map +0 -1
- package/lib/types-generator.js +0 -72
- package/lib/types-generator.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js.map +0 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createWarnOnce, resetWarnOnceForTests } from '@zhin.js/logger';
|
|
2
|
+
import { importOptionalPeerPackage } from './optional-peer-import.js';
|
|
3
|
+
/** 动态 import 时使用的包名(与 @zhin.js/speech package.json 一致) */
|
|
4
|
+
export const SPEECH_PACKAGE = '@zhin.js/speech';
|
|
5
|
+
let cached;
|
|
6
|
+
const speechPeerWarnOnce = createWarnOnce('speech');
|
|
7
|
+
/** zhin 启动时已创建 pipeline 时注入 */
|
|
8
|
+
export function seedSpeechPipeline(pipeline) {
|
|
9
|
+
cached = pipeline;
|
|
10
|
+
}
|
|
11
|
+
/** 动态加载 @zhin.js/speech;未安装时 warn 一次并返回 undefined */
|
|
12
|
+
export async function loadSpeechPipeline(opts) {
|
|
13
|
+
if (cached !== undefined) {
|
|
14
|
+
return cached ?? undefined;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const mod = await importOptionalPeerPackage(SPEECH_PACKAGE);
|
|
18
|
+
const speechConfig = opts?.getConfig?.()?.speech;
|
|
19
|
+
cached = mod.createSpeechPipeline(speechConfig);
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
speechPeerWarnOnce(opts?.warn, `未安装 ${SPEECH_PACKAGE},STT/TTS 已降级。安装: pnpm add ${SPEECH_PACKAGE}`);
|
|
24
|
+
cached = null;
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** 测试用:重置加载缓存 */
|
|
29
|
+
export function resetSpeechLoaderForTests() {
|
|
30
|
+
cached = undefined;
|
|
31
|
+
resetWarnOnceForTests('speech');
|
|
32
|
+
}
|
package/lib/built/tool.d.ts
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
* 工具仅面向 AI(通过 MCP 注册),不再与 Command 互转
|
|
4
4
|
*/
|
|
5
5
|
import { Feature, FeatureJSON } from "@zhin.js/kernel";
|
|
6
|
-
import type { Tool,
|
|
6
|
+
import type { Tool, ToolJsonSchema, ToolParametersSchema, PropertySchema, MaybePromise, ToolScope } from "../types.js";
|
|
7
|
+
import type { Message } from "../message.js";
|
|
8
|
+
import { type PermissionHost } from '@zhin.js/permission';
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* 检查工具是否可被当前 Message 通讯上下文访问。
|
|
11
|
+
* `host` 为 PermissionHost 实例;无 host 且有 permissions → deny。
|
|
9
12
|
*/
|
|
10
|
-
export declare function canAccessTool(tool: Tool,
|
|
13
|
+
export declare function canAccessTool(tool: Tool, message?: Message<any>, host?: PermissionHost | null): Promise<boolean>;
|
|
11
14
|
/**
|
|
12
15
|
* 从参数定义中提取参数信息
|
|
13
16
|
*/
|
|
@@ -38,7 +41,6 @@ export declare class ZhinTool {
|
|
|
38
41
|
param(name: string, schema: PropertySchema, required?: boolean): this;
|
|
39
42
|
platform(...platforms: string[]): this;
|
|
40
43
|
scope(...scopes: ToolScope[]): this;
|
|
41
|
-
requireAnyRole(...roles: import('./roles.js').SenderRole[]): this;
|
|
42
44
|
permit(...permissions: string[]): this;
|
|
43
45
|
tag(...tags: string[]): this;
|
|
44
46
|
keyword(...keywords: string[]): this;
|
|
@@ -51,7 +53,7 @@ export declare class ZhinTool {
|
|
|
51
53
|
preExec(value?: boolean): this;
|
|
52
54
|
/** 设置工具分类(如 file / shell / web),用于展示与 TOOLS.md 协同 */
|
|
53
55
|
kind(value: string): this;
|
|
54
|
-
execute(callback: (args: Record<string, any>,
|
|
56
|
+
execute(callback: (args: Record<string, any>, message?: Message<any>) => MaybePromise<any>): this;
|
|
55
57
|
toTool(): Tool;
|
|
56
58
|
toJSON(): {
|
|
57
59
|
name: string;
|
|
@@ -59,7 +61,7 @@ export declare class ZhinTool {
|
|
|
59
61
|
parameters: ToolParametersSchema;
|
|
60
62
|
platforms?: string[];
|
|
61
63
|
scopes?: ToolScope[];
|
|
62
|
-
|
|
64
|
+
permissions?: string[];
|
|
63
65
|
tags?: string[];
|
|
64
66
|
};
|
|
65
67
|
get help(): string;
|
|
@@ -71,15 +73,15 @@ export declare function isZhinTool(obj: any): obj is ZhinTool;
|
|
|
71
73
|
*/
|
|
72
74
|
export type ToolInput = Tool | ZhinTool;
|
|
73
75
|
/**
|
|
74
|
-
*
|
|
76
|
+
* Message 工具扩展方法类型
|
|
75
77
|
*/
|
|
76
|
-
export interface
|
|
78
|
+
export interface MessageToolExtensions {
|
|
77
79
|
/** 添加工具 */
|
|
78
80
|
addTool(tool: ToolInput): () => void;
|
|
79
81
|
}
|
|
80
82
|
declare module "../plugin.js" {
|
|
81
83
|
namespace Plugin {
|
|
82
|
-
interface Extensions extends
|
|
84
|
+
interface Extensions extends MessageToolExtensions {
|
|
83
85
|
}
|
|
84
86
|
interface Contexts {
|
|
85
87
|
tool: ToolFeature;
|
|
@@ -118,11 +120,11 @@ export declare class ToolFeature extends Feature<Tool> {
|
|
|
118
120
|
/**
|
|
119
121
|
* 执行工具
|
|
120
122
|
*/
|
|
121
|
-
execute(name: string, args: Record<string, any>,
|
|
123
|
+
execute(name: string, args: Record<string, any>, message?: Message<any>): Promise<any>;
|
|
122
124
|
/**
|
|
123
|
-
*
|
|
125
|
+
* 根据 Message 通讯上下文过滤工具
|
|
124
126
|
*/
|
|
125
|
-
filterByContext(tools: Tool[],
|
|
127
|
+
filterByContext(tools: Tool[], message?: Message<any>, host?: PermissionHost | null): Promise<Tool[]>;
|
|
126
128
|
/**
|
|
127
129
|
* 按插件名获取工具
|
|
128
130
|
*/
|
|
@@ -147,4 +149,3 @@ export declare class ToolFeature extends Feature<Tool> {
|
|
|
147
149
|
};
|
|
148
150
|
}
|
|
149
151
|
export {};
|
|
150
|
-
//# sourceMappingURL=tool.d.ts.map
|
package/lib/built/tool.js
CHANGED
|
@@ -3,19 +3,28 @@
|
|
|
3
3
|
* 工具仅面向 AI(通过 MCP 注册),不再与 Command 互转
|
|
4
4
|
*/
|
|
5
5
|
import { Feature } from "@zhin.js/kernel";
|
|
6
|
-
import {
|
|
7
|
-
import { roleSatisfies, resolveRolesFromContext } from './roles.js';
|
|
6
|
+
import { toPermissionSubject } from '@zhin.js/permission';
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
8
|
+
* 检查工具是否可被当前 Message 通讯上下文访问。
|
|
9
|
+
* `host` 为 PermissionHost 实例;无 host 且有 permissions → deny。
|
|
10
10
|
*/
|
|
11
|
-
export function canAccessTool(tool,
|
|
12
|
-
if (
|
|
11
|
+
export async function canAccessTool(tool, message, host) {
|
|
12
|
+
if (!message)
|
|
13
|
+
return !tool.platforms?.length && !tool.scopes?.length && !tool.permissions?.length;
|
|
14
|
+
const adapter = String(message.$adapter);
|
|
15
|
+
const scope = (message.$channel?.type || 'private');
|
|
16
|
+
if (tool.platforms?.length && !tool.platforms.includes(adapter)) {
|
|
13
17
|
return false;
|
|
14
18
|
}
|
|
15
|
-
if (tool.scopes?.length &&
|
|
19
|
+
if (tool.scopes?.length && !tool.scopes.includes(scope)) {
|
|
16
20
|
return false;
|
|
17
21
|
}
|
|
18
|
-
|
|
22
|
+
if (!tool.permissions?.length)
|
|
23
|
+
return true;
|
|
24
|
+
if (!host)
|
|
25
|
+
return false;
|
|
26
|
+
const subject = toPermissionSubject(message);
|
|
27
|
+
return host.checkAll(tool.permissions, subject);
|
|
19
28
|
}
|
|
20
29
|
// ============================================================================
|
|
21
30
|
// Tool 工具函数
|
|
@@ -54,7 +63,6 @@ export class ZhinTool {
|
|
|
54
63
|
#execute;
|
|
55
64
|
#platforms = [];
|
|
56
65
|
#scopes = [];
|
|
57
|
-
#requiredAnyRole = [];
|
|
58
66
|
#permissions = [];
|
|
59
67
|
#tags = [];
|
|
60
68
|
#keywords = [];
|
|
@@ -96,10 +104,6 @@ export class ZhinTool {
|
|
|
96
104
|
this.#scopes.push(...scopes);
|
|
97
105
|
return this;
|
|
98
106
|
}
|
|
99
|
-
requireAnyRole(...roles) {
|
|
100
|
-
this.#requiredAnyRole = [...roles];
|
|
101
|
-
return this;
|
|
102
|
-
}
|
|
103
107
|
permit(...permissions) {
|
|
104
108
|
this.#permissions.push(...permissions);
|
|
105
109
|
return this;
|
|
@@ -170,8 +174,6 @@ export class ZhinTool {
|
|
|
170
174
|
tool.platforms = this.#platforms;
|
|
171
175
|
if (this.#scopes.length > 0)
|
|
172
176
|
tool.scopes = this.#scopes;
|
|
173
|
-
if (this.#requiredAnyRole.length > 0)
|
|
174
|
-
tool.requiredAnyRole = [...this.#requiredAnyRole];
|
|
175
177
|
if (this.#permissions.length > 0)
|
|
176
178
|
tool.permissions = this.#permissions;
|
|
177
179
|
if (this.#tags.length > 0)
|
|
@@ -198,8 +200,8 @@ export class ZhinTool {
|
|
|
198
200
|
json.platforms = this.#platforms;
|
|
199
201
|
if (this.#scopes.length > 0)
|
|
200
202
|
json.scopes = this.#scopes;
|
|
201
|
-
if (this.#
|
|
202
|
-
json.
|
|
203
|
+
if (this.#permissions.length > 0)
|
|
204
|
+
json.permissions = [...this.#permissions];
|
|
203
205
|
if (this.#tags.length > 0)
|
|
204
206
|
json.tags = this.#tags;
|
|
205
207
|
return json;
|
|
@@ -216,8 +218,8 @@ export class ZhinTool {
|
|
|
216
218
|
lines.push(` ${param.name}: ${param.schema.type} ${required} ${desc}`);
|
|
217
219
|
}
|
|
218
220
|
}
|
|
219
|
-
if (this.#
|
|
220
|
-
lines.push(`
|
|
221
|
+
if (this.#permissions.length > 0) {
|
|
222
|
+
lines.push(` 权限: ${this.#permissions.join(', ')}`);
|
|
221
223
|
}
|
|
222
224
|
if (this.#platforms.length > 0) {
|
|
223
225
|
lines.push(` 平台: ${this.#platforms.join(', ')}`);
|
|
@@ -305,18 +307,22 @@ export class ToolFeature extends Feature {
|
|
|
305
307
|
/**
|
|
306
308
|
* 执行工具
|
|
307
309
|
*/
|
|
308
|
-
async execute(name, args,
|
|
310
|
+
async execute(name, args, message) {
|
|
309
311
|
const tool = this.byName.get(name);
|
|
310
312
|
if (!tool) {
|
|
311
313
|
throw new Error(`Tool "${name}" not found`);
|
|
312
314
|
}
|
|
313
|
-
return tool.execute(args,
|
|
315
|
+
return tool.execute(args, message);
|
|
314
316
|
}
|
|
315
317
|
/**
|
|
316
|
-
*
|
|
318
|
+
* 根据 Message 通讯上下文过滤工具
|
|
317
319
|
*/
|
|
318
|
-
filterByContext(tools,
|
|
319
|
-
|
|
320
|
+
async filterByContext(tools, message, host) {
|
|
321
|
+
const results = await Promise.all(tools.map(async (tool) => ({
|
|
322
|
+
tool,
|
|
323
|
+
allowed: await canAccessTool(tool, message, host),
|
|
324
|
+
})));
|
|
325
|
+
return results.filter((r) => r.allowed).map((r) => r.tool);
|
|
320
326
|
}
|
|
321
327
|
/**
|
|
322
328
|
* 按插件名获取工具
|
|
@@ -370,7 +376,7 @@ export class ToolFeature extends Feature {
|
|
|
370
376
|
const feature = this;
|
|
371
377
|
return {
|
|
372
378
|
addTool(tool) {
|
|
373
|
-
const plugin =
|
|
379
|
+
const plugin = this;
|
|
374
380
|
const toolObj = isZhinTool(tool) ? tool.toTool() : tool;
|
|
375
381
|
const dispose = feature.addTool(tool, plugin.name);
|
|
376
382
|
plugin.recordFeatureContribution(feature.name, toolObj.name);
|
|
@@ -380,4 +386,3 @@ export class ToolFeature extends Feature {
|
|
|
380
386
|
};
|
|
381
387
|
}
|
|
382
388
|
}
|
|
383
|
-
//# sourceMappingURL=tool.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { UserInteractionContent, UserInteractionRequest } from '@zhin.js/interaction';
|
|
2
|
+
import type { SendContent } from '../plugin-runtime/im/contracts.js';
|
|
3
|
+
import type { ButtonStyle } from './interactive-segments/types.js';
|
|
4
|
+
export interface UserInteractionAction {
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly value: string;
|
|
7
|
+
readonly style?: ButtonStyle;
|
|
8
|
+
}
|
|
9
|
+
export interface UserInteractionView extends UserInteractionContent {
|
|
10
|
+
readonly actions?: readonly UserInteractionAction[];
|
|
11
|
+
}
|
|
12
|
+
export interface UserInteractionProgress extends UserInteractionContent {
|
|
13
|
+
readonly index: number;
|
|
14
|
+
readonly total: number;
|
|
15
|
+
}
|
|
16
|
+
export type UserInteractionParseResult = Readonly<{
|
|
17
|
+
ok: true;
|
|
18
|
+
value: unknown;
|
|
19
|
+
}> | Readonly<{
|
|
20
|
+
ok: false;
|
|
21
|
+
message: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** Fail early for interaction definitions that could never produce an unambiguous answer. */
|
|
24
|
+
export declare function assertUserInteractionRequest(request: UserInteractionRequest): void;
|
|
25
|
+
/** Project semantic content into canonical Markdown + keyboard segments. */
|
|
26
|
+
export declare function renderUserInteraction(view: UserInteractionView): SendContent;
|
|
27
|
+
/** Derive presentation and controls from one discriminated request. */
|
|
28
|
+
export declare function projectUserInteraction(request: UserInteractionRequest, progress?: UserInteractionProgress): UserInteractionView;
|
|
29
|
+
/** Parse and validate one user reply without transport knowledge. */
|
|
30
|
+
export declare function parseUserInteractionAnswer(request: UserInteractionRequest, rawInput: string): UserInteractionParseResult;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/** Fail early for interaction definitions that could never produce an unambiguous answer. */
|
|
2
|
+
export function assertUserInteractionRequest(request) {
|
|
3
|
+
if (!request.title.trim())
|
|
4
|
+
throw new TypeError('User interaction title must not be empty');
|
|
5
|
+
if (request.timeout !== undefined && (!Number.isFinite(request.timeout) || request.timeout <= 0)) {
|
|
6
|
+
throw new RangeError('User interaction timeout must be a positive finite number');
|
|
7
|
+
}
|
|
8
|
+
if (request.type === 'text' && !validRange(request.minLength, request.maxLength)) {
|
|
9
|
+
throw new RangeError('User interaction text length range is invalid');
|
|
10
|
+
}
|
|
11
|
+
if (request.type === 'number' && !validBounds(request.min, request.max)) {
|
|
12
|
+
throw new RangeError('User interaction number range is invalid');
|
|
13
|
+
}
|
|
14
|
+
if (request.type === 'select' || request.type === 'multiselect') {
|
|
15
|
+
if (request.options.length === 0)
|
|
16
|
+
throw new TypeError('User interaction options must not be empty');
|
|
17
|
+
const labels = new Set();
|
|
18
|
+
for (const option of request.options) {
|
|
19
|
+
const label = option.label.trim().toLocaleLowerCase();
|
|
20
|
+
if (!label)
|
|
21
|
+
throw new TypeError('User interaction option label must not be empty');
|
|
22
|
+
if (labels.has(label))
|
|
23
|
+
throw new TypeError(`Duplicate user interaction option label: ${option.label}`);
|
|
24
|
+
labels.add(label);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (request.type === 'multiselect') {
|
|
28
|
+
if (request.separator === '')
|
|
29
|
+
throw new TypeError('User interaction separator must not be empty');
|
|
30
|
+
if (!validRange(request.minSelections, request.maxSelections)) {
|
|
31
|
+
throw new RangeError('User interaction selection range is invalid');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (request.type === 'list') {
|
|
35
|
+
if (request.separator === '')
|
|
36
|
+
throw new TypeError('User interaction separator must not be empty');
|
|
37
|
+
if (!validRange(request.minItems, request.maxItems)) {
|
|
38
|
+
throw new RangeError('User interaction list length range is invalid');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Project semantic content into canonical Markdown + keyboard segments. */
|
|
43
|
+
export function renderUserInteraction(view) {
|
|
44
|
+
const markdown = [
|
|
45
|
+
`### ${view.title}`,
|
|
46
|
+
view.description?.trim(),
|
|
47
|
+
view.tip?.trim() ? quoteTip(view.tip.trim()) : undefined,
|
|
48
|
+
].filter((part) => !!part).join('\n\n');
|
|
49
|
+
const actions = view.actions ?? [];
|
|
50
|
+
if (actions.length === 0) {
|
|
51
|
+
return [{ type: 'markdown', data: { content: markdown } }];
|
|
52
|
+
}
|
|
53
|
+
const buttons = actions.map((action, index) => ({
|
|
54
|
+
id: `interaction-${index + 1}`,
|
|
55
|
+
label: action.label,
|
|
56
|
+
payload: action.value,
|
|
57
|
+
...(action.style ? { style: action.style } : {}),
|
|
58
|
+
mode: 'command',
|
|
59
|
+
command: { enter: true, reply: false },
|
|
60
|
+
}));
|
|
61
|
+
return [
|
|
62
|
+
{ type: 'markdown', data: { content: markdown } },
|
|
63
|
+
{
|
|
64
|
+
type: 'keyboard',
|
|
65
|
+
data: {
|
|
66
|
+
rows: chunk(buttons, 5),
|
|
67
|
+
fallback: {
|
|
68
|
+
hint: '也可以直接回复对应内容。',
|
|
69
|
+
map: Object.fromEntries(actions.map((action, index) => [String(index + 1), action.value])),
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
/** Derive presentation and controls from one discriminated request. */
|
|
76
|
+
export function projectUserInteraction(request, progress) {
|
|
77
|
+
const instruction = instructionFor(request);
|
|
78
|
+
const optionList = request.type === 'select' || request.type === 'multiselect'
|
|
79
|
+
? renderOptions(request.options)
|
|
80
|
+
: undefined;
|
|
81
|
+
const optionsHaveDescriptions = request.type === 'select' || request.type === 'multiselect'
|
|
82
|
+
? request.options.some((option) => !!option.description)
|
|
83
|
+
: false;
|
|
84
|
+
const actions = actionsFor(request);
|
|
85
|
+
const stepDescription = [
|
|
86
|
+
progress ? `**${progress.index}/${progress.total} · ${request.title}**` : undefined,
|
|
87
|
+
request.description,
|
|
88
|
+
optionList && (!actions || optionsHaveDescriptions) ? optionList : undefined,
|
|
89
|
+
].filter((part) => !!part).join('\n\n');
|
|
90
|
+
return Object.freeze({
|
|
91
|
+
title: progress?.title ?? request.title,
|
|
92
|
+
description: progress
|
|
93
|
+
? [progress.description, stepDescription].filter(Boolean).join('\n\n')
|
|
94
|
+
: stepDescription || undefined,
|
|
95
|
+
tip: [request.tip, instruction, progress?.tip].filter(Boolean).join('\n'),
|
|
96
|
+
...(actions ? { actions: Object.freeze(actions) } : {}),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/** Parse and validate one user reply without transport knowledge. */
|
|
100
|
+
export function parseUserInteractionAnswer(request, rawInput) {
|
|
101
|
+
const raw = rawInput.trim();
|
|
102
|
+
switch (request.type) {
|
|
103
|
+
case 'text': {
|
|
104
|
+
if (raw.length < (request.minLength ?? 0))
|
|
105
|
+
return invalid(`请至少输入 ${request.minLength} 个字符`);
|
|
106
|
+
if (request.maxLength !== undefined && raw.length > request.maxLength) {
|
|
107
|
+
return invalid(`请不要超过 ${request.maxLength} 个字符`);
|
|
108
|
+
}
|
|
109
|
+
if (request.pattern) {
|
|
110
|
+
request.pattern.lastIndex = 0;
|
|
111
|
+
if (!request.pattern.test(raw))
|
|
112
|
+
return invalid('输入格式不正确');
|
|
113
|
+
}
|
|
114
|
+
return valid(raw);
|
|
115
|
+
}
|
|
116
|
+
case 'number': {
|
|
117
|
+
const value = Number(raw);
|
|
118
|
+
if (!raw || !Number.isFinite(value))
|
|
119
|
+
return invalid('请输入有效数字');
|
|
120
|
+
if (request.integer && !Number.isInteger(value))
|
|
121
|
+
return invalid('请输入整数');
|
|
122
|
+
if (request.min !== undefined && value < request.min)
|
|
123
|
+
return invalid(`请输入不小于 ${request.min} 的数字`);
|
|
124
|
+
if (request.max !== undefined && value > request.max)
|
|
125
|
+
return invalid(`请输入不大于 ${request.max} 的数字`);
|
|
126
|
+
return valid(value);
|
|
127
|
+
}
|
|
128
|
+
case 'confirm': {
|
|
129
|
+
const normalized = raw.toLocaleLowerCase();
|
|
130
|
+
const confirmLabel = request.confirmLabel?.trim().toLocaleLowerCase();
|
|
131
|
+
const cancelLabel = request.cancelLabel?.trim().toLocaleLowerCase();
|
|
132
|
+
if (CONFIRM_VALUES.has(normalized) || (confirmLabel && normalized === confirmLabel))
|
|
133
|
+
return valid(true);
|
|
134
|
+
if (CANCEL_VALUES.has(normalized) || (cancelLabel && normalized === cancelLabel))
|
|
135
|
+
return valid(false);
|
|
136
|
+
return invalid('请选择确认或取消');
|
|
137
|
+
}
|
|
138
|
+
case 'select': {
|
|
139
|
+
const option = resolveOption(request.options, raw);
|
|
140
|
+
return option ? valid(option.value) : invalid('请选择一个有效选项');
|
|
141
|
+
}
|
|
142
|
+
case 'multiselect': {
|
|
143
|
+
const separator = request.separator ?? ',';
|
|
144
|
+
const tokens = raw.split(separator).map((token) => token.trim()).filter(Boolean);
|
|
145
|
+
const selected = uniqueOptions(tokens.map((token) => resolveOption(request.options, token)));
|
|
146
|
+
if (selected.length !== tokens.length)
|
|
147
|
+
return invalid('多选中包含无效选项');
|
|
148
|
+
if (selected.length < (request.minSelections ?? 0))
|
|
149
|
+
return invalid(`请至少选择 ${request.minSelections} 项`);
|
|
150
|
+
if (request.maxSelections !== undefined && selected.length > request.maxSelections) {
|
|
151
|
+
return invalid(`请最多选择 ${request.maxSelections} 项`);
|
|
152
|
+
}
|
|
153
|
+
return valid(Object.freeze(selected.map((option) => option.value)));
|
|
154
|
+
}
|
|
155
|
+
case 'list': {
|
|
156
|
+
const separator = request.separator ?? ',';
|
|
157
|
+
const tokens = raw.split(separator).map((token) => token.trim()).filter(Boolean);
|
|
158
|
+
if (tokens.length < (request.minItems ?? 0))
|
|
159
|
+
return invalid(`请至少输入 ${request.minItems} 项`);
|
|
160
|
+
if (request.maxItems !== undefined && tokens.length > request.maxItems)
|
|
161
|
+
return invalid(`请最多输入 ${request.maxItems} 项`);
|
|
162
|
+
if (request.valueType === 'number') {
|
|
163
|
+
const values = tokens.map(Number);
|
|
164
|
+
return values.every(Number.isFinite) ? valid(Object.freeze(values)) : invalid('列表中包含无效数字');
|
|
165
|
+
}
|
|
166
|
+
if (request.valueType === 'boolean') {
|
|
167
|
+
const values = tokens.map(parseBoolean);
|
|
168
|
+
return values.every((value) => value !== undefined)
|
|
169
|
+
? valid(Object.freeze(values))
|
|
170
|
+
: invalid('布尔列表只接受 true/false、yes/no 或 是/否');
|
|
171
|
+
}
|
|
172
|
+
return valid(Object.freeze(tokens));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function actionsFor(request) {
|
|
177
|
+
if (request.type === 'confirm') {
|
|
178
|
+
return [
|
|
179
|
+
{ label: request.confirmLabel ?? '确认', value: 'yes', style: 'primary' },
|
|
180
|
+
{ label: request.cancelLabel ?? '取消', value: 'no', style: 'danger' },
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
if (request.type === 'select' && request.options.length <= 10) {
|
|
184
|
+
return request.options.map((option, index) => ({ label: option.label, value: String(index + 1), style: 'secondary' }));
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
function instructionFor(request) {
|
|
189
|
+
switch (request.type) {
|
|
190
|
+
case 'confirm': return '请选择确认或取消。';
|
|
191
|
+
case 'select': return '可以点击按钮,或回复序号/选项名称。';
|
|
192
|
+
case 'multiselect': return `回复序号或选项名称,多项用“${request.separator ?? ','}”分隔。`;
|
|
193
|
+
case 'list': return `多项用“${request.separator ?? ','}”分隔。`;
|
|
194
|
+
default: return undefined;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function renderOptions(options) {
|
|
198
|
+
return options.map((option, index) => `${index + 1}. ${option.label}${option.description ? ` — ${option.description}` : ''}`).join('\n');
|
|
199
|
+
}
|
|
200
|
+
function resolveOption(options, raw) {
|
|
201
|
+
const index = Number(raw);
|
|
202
|
+
if (Number.isInteger(index) && index >= 1 && index <= options.length)
|
|
203
|
+
return options[index - 1];
|
|
204
|
+
const normalized = raw.toLocaleLowerCase();
|
|
205
|
+
return options.find((option) => option.label.trim().toLocaleLowerCase() === normalized);
|
|
206
|
+
}
|
|
207
|
+
function uniqueOptions(options) {
|
|
208
|
+
const result = [];
|
|
209
|
+
for (const option of options)
|
|
210
|
+
if (option && !result.includes(option))
|
|
211
|
+
result.push(option);
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
function parseBoolean(raw) {
|
|
215
|
+
const normalized = raw.toLocaleLowerCase();
|
|
216
|
+
if (CONFIRM_VALUES.has(normalized))
|
|
217
|
+
return true;
|
|
218
|
+
if (CANCEL_VALUES.has(normalized))
|
|
219
|
+
return false;
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
function quoteTip(tip) {
|
|
223
|
+
return tip.split('\n').map((line) => `> 💡 ${line}`).join('\n');
|
|
224
|
+
}
|
|
225
|
+
function valid(value) {
|
|
226
|
+
return Object.freeze({ ok: true, value });
|
|
227
|
+
}
|
|
228
|
+
function invalid(message) {
|
|
229
|
+
return Object.freeze({ ok: false, message });
|
|
230
|
+
}
|
|
231
|
+
function validRange(minimum, maximum) {
|
|
232
|
+
return (minimum === undefined || (Number.isFinite(minimum) && minimum >= 0))
|
|
233
|
+
&& (maximum === undefined || (Number.isFinite(maximum) && maximum >= 0))
|
|
234
|
+
&& (minimum === undefined || maximum === undefined || minimum <= maximum);
|
|
235
|
+
}
|
|
236
|
+
function validBounds(minimum, maximum) {
|
|
237
|
+
return (minimum === undefined || Number.isFinite(minimum))
|
|
238
|
+
&& (maximum === undefined || Number.isFinite(maximum))
|
|
239
|
+
&& (minimum === undefined || maximum === undefined || minimum <= maximum);
|
|
240
|
+
}
|
|
241
|
+
const CONFIRM_VALUES = new Set(['1', 'y', 'yes', 'true', '是', '确认', '同意']);
|
|
242
|
+
const CANCEL_VALUES = new Set(['2', 'n', 'no', 'false', '否', '取消', '拒绝']);
|
|
243
|
+
function chunk(items, size) {
|
|
244
|
+
const rows = [];
|
|
245
|
+
for (let index = 0; index < items.length; index += size)
|
|
246
|
+
rows.push(items.slice(index, index + size));
|
|
247
|
+
return rows;
|
|
248
|
+
}
|
package/lib/command.d.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import { MatchResult, SegmentMatcher } from
|
|
2
|
-
import { AdapterMessage, SendContent } from
|
|
3
|
-
import {
|
|
4
|
-
import type
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { MatchResult, SegmentMatcher } from 'segment-matcher';
|
|
2
|
+
import { AdapterMessage, SendContent, RegisteredAdapter, MaybePromise } from './types.js';
|
|
3
|
+
import type { Message } from './message.js';
|
|
4
|
+
import { type PermissionHost } from '@zhin.js/permission';
|
|
5
|
+
type ConstructFirstParam<T extends new (...args: any[]) => any> = T extends new (...args: [infer U, ...any[]]) => any ? U : never;
|
|
6
|
+
type ConstructSecondParam<T extends new (...args: any[]) => any> = T extends new (...args: [any, infer V, ...any[]]) => any ? V : never;
|
|
7
7
|
/**
|
|
8
|
-
* MessageCommand
|
|
9
|
-
*
|
|
8
|
+
* MessageCommand类:经典命令系统(segment-matcher)。
|
|
9
|
+
*
|
|
10
|
+
* @deprecated 新插件请用 `defineCommand`(`zhin.js/command`)+ `commands/` 约定目录。
|
|
11
|
+
* 本类仍供 Agent init / game-kit hub / legacy `CommandFeature` 使用;计划随经典
|
|
12
|
+
* Plugin 路径一并退役。见 `docs/contributing/public-api-surface.md`。
|
|
10
13
|
*/
|
|
11
14
|
export declare class MessageCommand<T extends RegisteredAdapter = RegisteredAdapter> extends SegmentMatcher {
|
|
12
15
|
#private;
|
|
13
16
|
get helpInfo(): MessageCommand.HelpInfo;
|
|
17
|
+
constructor(C: ConstructFirstParam<typeof SegmentMatcher>, P?: ConstructSecondParam<typeof SegmentMatcher>);
|
|
14
18
|
get help(): string;
|
|
15
19
|
desc(...desc: string[]): MessageCommand<T>;
|
|
16
20
|
usage(...usage: string[]): MessageCommand<T>;
|
|
@@ -21,13 +25,17 @@ export declare class MessageCommand<T extends RegisteredAdapter = RegisteredAdap
|
|
|
21
25
|
*/
|
|
22
26
|
action(callback: MessageCommand.Callback<T>): MessageCommand<T>;
|
|
23
27
|
permit(...permissions: string[]): MessageCommand<T>;
|
|
28
|
+
/** 命令要求的 permit 列表(空表示所有人可用) */
|
|
29
|
+
get requiredPermits(): readonly string[];
|
|
30
|
+
/** 与 handle 一致的 permit 校验,供帮助菜单等场景过滤不可见命令 */
|
|
31
|
+
checkPermits(message: Message<AdapterMessage<T>>, host: PermissionHost | null): Promise<boolean>;
|
|
24
32
|
/**
|
|
25
33
|
* 处理消息,自动匹配命令并执行回调
|
|
26
34
|
* @param message 消息对象
|
|
27
|
-
* @param
|
|
35
|
+
* @param host PermissionHost(null 时有 permit 的命令 fail-closed)
|
|
28
36
|
* @returns 命令返回内容或undefined
|
|
29
37
|
*/
|
|
30
|
-
handle(message: Message<AdapterMessage<T>>,
|
|
38
|
+
handle(message: Message<AdapterMessage<T>>, host: PermissionHost | null): Promise<SendContent | undefined>;
|
|
31
39
|
}
|
|
32
40
|
export declare namespace MessageCommand {
|
|
33
41
|
type Callback<T extends RegisteredAdapter> = (message: Message<AdapterMessage<T>>, result: MatchResult) => SendContent | undefined | Promise<SendContent | undefined>;
|
|
@@ -39,4 +47,4 @@ export declare namespace MessageCommand {
|
|
|
39
47
|
examples: string[];
|
|
40
48
|
};
|
|
41
49
|
}
|
|
42
|
-
|
|
50
|
+
export {};
|
package/lib/command.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { SegmentMatcher } from
|
|
1
|
+
import { SegmentMatcher } from 'segment-matcher';
|
|
2
|
+
import { toPermissionSubject } from '@zhin.js/permission';
|
|
2
3
|
/**
|
|
3
|
-
* MessageCommand
|
|
4
|
-
*
|
|
4
|
+
* MessageCommand类:经典命令系统(segment-matcher)。
|
|
5
|
+
*
|
|
6
|
+
* @deprecated 新插件请用 `defineCommand`(`zhin.js/command`)+ `commands/` 约定目录。
|
|
7
|
+
* 本类仍供 Agent init / game-kit hub / legacy `CommandFeature` 使用;计划随经典
|
|
8
|
+
* Plugin 路径一并退役。见 `docs/contributing/public-api-surface.md`。
|
|
5
9
|
*/
|
|
6
10
|
export class MessageCommand extends SegmentMatcher {
|
|
7
11
|
#callbacks = [];
|
|
@@ -17,6 +21,24 @@ export class MessageCommand extends SegmentMatcher {
|
|
|
17
21
|
examples: this.#examples
|
|
18
22
|
};
|
|
19
23
|
}
|
|
24
|
+
constructor(C, P = {}) {
|
|
25
|
+
super(C, {
|
|
26
|
+
at: ['qq', 'user_id'],
|
|
27
|
+
face: ['id'],
|
|
28
|
+
mention: ['qq', 'user_id'],
|
|
29
|
+
html: ['content'],
|
|
30
|
+
markdown: ['content'],
|
|
31
|
+
image: ['file', 'src', 'url'],
|
|
32
|
+
video: ['file', 'src', 'url'],
|
|
33
|
+
audio: ['file', 'src', 'url'],
|
|
34
|
+
file: ['file', 'src', 'url'],
|
|
35
|
+
reply: ['id', 'reply_id', 'message_id'],
|
|
36
|
+
quote: ['id', 'reply_id', 'message_id'],
|
|
37
|
+
forward: ['id', 'res_id', 'message_id'],
|
|
38
|
+
location: ['latitude', 'longitude'],
|
|
39
|
+
...P,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
20
42
|
get help() {
|
|
21
43
|
return [
|
|
22
44
|
this.pattern,
|
|
@@ -49,18 +71,28 @@ export class MessageCommand extends SegmentMatcher {
|
|
|
49
71
|
this.#permissions.push(...permissions);
|
|
50
72
|
return this;
|
|
51
73
|
}
|
|
74
|
+
/** 命令要求的 permit 列表(空表示所有人可用) */
|
|
75
|
+
get requiredPermits() {
|
|
76
|
+
return this.#permissions;
|
|
77
|
+
}
|
|
78
|
+
/** 与 handle 一致的 permit 校验,供帮助菜单等场景过滤不可见命令 */
|
|
79
|
+
async checkPermits(message, host) {
|
|
80
|
+
if (!this.#permissions.length)
|
|
81
|
+
return true;
|
|
82
|
+
if (!host)
|
|
83
|
+
return false;
|
|
84
|
+
const subject = toPermissionSubject(message);
|
|
85
|
+
return host.checkAll(this.#permissions, subject);
|
|
86
|
+
}
|
|
52
87
|
/**
|
|
53
88
|
* 处理消息,自动匹配命令并执行回调
|
|
54
89
|
* @param message 消息对象
|
|
55
|
-
* @param
|
|
90
|
+
* @param host PermissionHost(null 时有 permit 的命令 fail-closed)
|
|
56
91
|
* @returns 命令返回内容或undefined
|
|
57
92
|
*/
|
|
58
|
-
async handle(message,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const passed = await auth?.check(permit, message);
|
|
62
|
-
if (!passed)
|
|
63
|
-
return;
|
|
93
|
+
async handle(message, host) {
|
|
94
|
+
if (!(await this.checkPermits(message, host))) {
|
|
95
|
+
return;
|
|
64
96
|
}
|
|
65
97
|
const matched = this.match(message.$content);
|
|
66
98
|
if (!matched)
|
|
@@ -72,4 +104,3 @@ export class MessageCommand extends SegmentMatcher {
|
|
|
72
104
|
}
|
|
73
105
|
}
|
|
74
106
|
}
|
|
75
|
-
//# sourceMappingURL=command.js.map
|
package/lib/component.d.ts
CHANGED