@zhin.js/adapter-satori 1.1.0 → 1.1.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,89 @@
1
1
  # @zhin.js/adapter-satori
2
2
 
3
+ ## 1.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a9e4a40: Derive Command user routes only from explicit `commands/**/*/index.ts(x)` entry paths instead of prepending the plugin owner. Child plugins can now publish top-level static or dynamic commands, while duplicate routes across owners fail during generation construction. Adapter endpoint commands move to explicit paths such as `commands/qq/endpoint/list/index.ts` and are invoked as `qq endpoint list`.
8
+ - 8740059: Standardize TypeScript capabilities on named module directories such as `commands/foo/index.ts`, `middlewares/audit/index.ts`, `handlers/message-receive/index.ts`, `pages/workroom/index.tsx`, and `mcps/filesystem/index.ts`. Only the fixed `index` entry is discovered; sibling files remain private helpers.
9
+
10
+ Command route segments come from directories, while `[name]`, `[[name]]`, `[...name]`, and `[[...name]]` directories declare dynamic parameters. Plugin owners do not enter the route unless their config explicitly sets `commandNamespace`; Endpoint `commandPrefix` remains platform-owned and defaults to an empty string.
11
+
12
+ Migrate the built-in adapters, plugins, examples, generators, migration tooling, hot reload classification, Agent authoring surfaces, documentation, and release artifacts to the explicit entry convention.
13
+
14
+ Make Tool ownership and progressive disclosure explicit across all four supported locations: plugin-public `tools/`, Agent-private `agents/<name>/tools/`, Skill-private `skills/<name>/tools/`, and Agent-Skill-private `agents/<name>/skills/<name>/tools/`. Move adapter and group-suite operations that require domain instructions into their owning Skills so `load_skill` is the only path that unlocks their schemas.
15
+
16
+ Remove the package-root `agent/` convention. Public capabilities now use named package-root directories, schedules use `schedules/<name>/index.ts` or `plugin.ts` injection, MCP connections use `mcps/<name>/index.ts`, Prompt Sections use `prompt-sections/<name>/index.ts`, Agent definitions use `agents/<name>/`, and permission vocabulary is published as `PERMITS.md`.
17
+
18
+ - 25a845a: Unify Skills on `skills/<name>/SKILL.md`, support Agent-private Skills and nested Skill-private Tools, publish and mount existing plugin Skills, add governed Skill metadata and Turn access filtering, unlock only already-admitted same-owner Tools, and make `on-risk` and `once` approval behavior precise.
19
+ - 4380cf9: Colocate adapter command definitions and Agent Skill handlers with their owning capabilities, and provide a shared validated platform permission constructor.
20
+ - 2acae54: Require the canonical expanded Satori endpoint configuration. The protocol no longer reinterprets nested `endpoints` or reads endpoint identity, base URL, and token from `process.env`. The public config type is now `SatoriEndpointConfig`, and each schema entry uses `id` as its identity.
21
+ - 5c3858e: Make `@zhin.js/im-contract` the explicit zero-dependency owner of transport identities, canonical segments, media guards, conversation facts, stores, and delivery contracts. Platform adapters now read media contracts from that foundation instead of reaching through Core.
22
+ - Updated dependencies [c861789]
23
+ - Updated dependencies [1414ccb]
24
+ - Updated dependencies [743d470]
25
+ - Updated dependencies [62dee52]
26
+ - Updated dependencies [cd54131]
27
+ - Updated dependencies [244e475]
28
+ - Updated dependencies [a9e4a40]
29
+ - Updated dependencies [5855db7]
30
+ - Updated dependencies [ec921d2]
31
+ - Updated dependencies [8740059]
32
+ - Updated dependencies [25a845a]
33
+ - Updated dependencies [103f2c3]
34
+ - Updated dependencies [9110ab8]
35
+ - Updated dependencies [cd2a888]
36
+ - Updated dependencies [eb3227a]
37
+ - Updated dependencies [b853dba]
38
+ - Updated dependencies [e561309]
39
+ - Updated dependencies [d4c6175]
40
+ - Updated dependencies [7a0e1ca]
41
+ - Updated dependencies [103b5d3]
42
+ - Updated dependencies [5a7a7f7]
43
+ - Updated dependencies [b076eae]
44
+ - Updated dependencies [73a24b7]
45
+ - Updated dependencies [2dbbc15]
46
+ - Updated dependencies [1cb1163]
47
+ - Updated dependencies [be3061e]
48
+ - Updated dependencies [75f8332]
49
+ - Updated dependencies [81935e2]
50
+ - Updated dependencies [f9ed01b]
51
+ - Updated dependencies [ac0ab50]
52
+ - Updated dependencies [5140ce1]
53
+ - Updated dependencies [522d75f]
54
+ - Updated dependencies [a7611b3]
55
+ - Updated dependencies [8823044]
56
+ - Updated dependencies [379439b]
57
+ - Updated dependencies [11c9352]
58
+ - Updated dependencies [6b70e46]
59
+ - Updated dependencies [135ac91]
60
+ - Updated dependencies [140cf0f]
61
+ - Updated dependencies [251e4d2]
62
+ - Updated dependencies [203ad34]
63
+ - Updated dependencies [e6c5113]
64
+ - Updated dependencies [e0f6478]
65
+ - Updated dependencies [baef56b]
66
+ - Updated dependencies [da0a8e3]
67
+ - Updated dependencies [2fd8017]
68
+ - Updated dependencies [5c3858e]
69
+ - Updated dependencies [507d602]
70
+ - Updated dependencies [df9f76b]
71
+ - @zhin.js/core@1.1.37
72
+ - @zhin.js/host-http@1.1.1
73
+ - @zhin.js/adapter@1.1.14
74
+ - @zhin.js/feature-kit@1.1.1
75
+ - @zhin.js/skill@1.1.1
76
+ - @zhin.js/logger@1.1.1
77
+ - @zhin.js/im-contract@1.1.1
78
+
79
+ ## 1.1.1
80
+
81
+ ### Patch Changes
82
+
83
+ - Updated dependencies [769e67f]
84
+ - @zhin.js/adapter@1.1.13
85
+ - @zhin.js/core@1.1.36
86
+
3
87
  ## 1.1.0
4
88
 
5
89
  ### Minor Changes
package/README.md CHANGED
@@ -21,7 +21,7 @@ pnpm add @zhin.js/adapter-satori
21
21
 
22
22
  ## Plugin Runtime
23
23
 
24
- - `@zhin.js/adapter` — 约定式 `adapters/satori.ts`(`defineAdapter`)
24
+ - `@zhin.js/adapter` — 约定式 `adapters/satori/index.ts`(`defineAdapter`)
25
25
  - `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
26
26
  - `zhin.js` — `plugin.ts`(`definePlugin`)
27
27
  - `@zhin.js/host-http` — Webhook 模式需 `httpHostToken` 注册 POST 路由
@@ -51,7 +51,7 @@ plugins:
51
51
  connection: ws
52
52
  heartbeat_interval: 10000
53
53
  endpoints:
54
- - name: satori-bot
54
+ - id: satori-bot
55
55
  baseUrl: "http://127.0.0.1:5140"
56
56
  token: "${SATORI_TOKEN}"
57
57
  ```
@@ -63,7 +63,7 @@ plugins:
63
63
  | 字段 | 说明 |
64
64
  |------|------|
65
65
  | `heartbeat_interval` | WS PING 间隔(毫秒),默认 `10000` |
66
- | `token` | Bearer;也可设环境变量 `SATORI_TOKEN` |
66
+ | `token` | Bearer;可在 YAML 中引用 `${SATORI_TOKEN}` |
67
67
 
68
68
  ### Webhook
69
69
 
@@ -72,7 +72,7 @@ plugins:
72
72
  satori:
73
73
  connection: webhook
74
74
  endpoints:
75
- - name: satori-bot
75
+ - id: satori-bot
76
76
  baseUrl: "http://127.0.0.1:5140"
77
77
  path: "/satori/webhook"
78
78
  token: "${SATORI_TOKEN}"
@@ -92,7 +92,7 @@ SDK 会向 `path` 发送 POST,请求头 `Satori-Opcode: 0` 表示事件;适
92
92
 
93
93
  ## AI 工具
94
94
 
95
- 技能说明见 `agent/skills/satori.md`。
95
+ 技能说明见 `skills/satori/SKILL.md`。
96
96
 
97
97
  ## 协议文档
98
98
 
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  /**
3
- * Convention entry: discover `adapters/satori.ts` → defineAdapter.
3
+ * Convention entry: discover `adapters/satori/index.ts` → defineAdapter.
4
4
  */
5
5
  import { defineAdapter } from 'zhin.js/adapter';
6
6
  import { httpHostToken } from '@zhin.js/host-http';
7
- import { SatoriWebhookEndpoint, SatoriWsEndpoint } from "../lib/endpoint.js";
8
- import { resolveSatoriConfig, } from "../lib/protocol.js";
9
- import { satoriRuntimeStateToken } from "../lib/satori-runtime-state.js";
10
- export { SatoriWebhookEndpoint, SatoriWsEndpoint } from "../lib/endpoint.js";
7
+ import { SatoriWebhookEndpoint, SatoriWsEndpoint } from "../../lib/endpoint.js";
8
+ import { resolveSatoriConfig, } from "../../lib/protocol.js";
9
+ import { satoriRuntimeStateToken } from "../../lib/satori-runtime-state.js";
10
+ export { SatoriWebhookEndpoint, SatoriWsEndpoint } from "../../lib/endpoint.js";
11
11
  export default defineAdapter({
12
12
  capabilities: ['inbound', 'outbound'],
13
13
  operations: ['recall'],
@@ -18,7 +18,7 @@ export default defineAdapter({
18
18
  },
19
19
  create(context) {
20
20
  const config = resolveSatoriConfig(context.config);
21
- // 注册到插件运行时状态(satori.endpoint list 的"运行中"数据源)
21
+ // 注册到插件运行时状态(satori endpoint list 的"运行中"数据源)
22
22
  context.use(satoriRuntimeStateToken).endpoints.set(config.id, {
23
23
  id: config.id,
24
24
  mode: config.connection,
@@ -1,25 +1,25 @@
1
1
  /**
2
- * Convention entry: discover `adapters/satori.ts` → defineAdapter.
2
+ * Convention entry: discover `adapters/satori/index.ts` → defineAdapter.
3
3
  */
4
4
  import { defineAdapter } from 'zhin.js/adapter';
5
5
  import { httpHostToken } from '@zhin.js/host-http';
6
- import { SatoriWebhookEndpoint, SatoriWsEndpoint } from '../src/endpoint.js';
6
+ import { SatoriWebhookEndpoint, SatoriWsEndpoint } from '../../src/endpoint.js';
7
7
  import {
8
8
  resolveSatoriConfig,
9
- type SatoriAdapterConfig,
10
- } from '../src/protocol.js';
11
- import { satoriRuntimeStateToken } from '../src/satori-runtime-state.js';
9
+ type SatoriEndpointConfig,
10
+ } from '../../src/protocol.js';
11
+ import { satoriRuntimeStateToken } from '../../src/satori-runtime-state.js';
12
12
 
13
- export { SatoriWebhookEndpoint, SatoriWsEndpoint } from '../src/endpoint.js';
13
+ export { SatoriWebhookEndpoint, SatoriWsEndpoint } from '../../src/endpoint.js';
14
14
  export type {
15
15
  CreateSatoriWebSocket,
16
16
  SatoriApiCaller,
17
17
  SatoriWebhookEndpointOptions,
18
18
  SatoriWsEndpointOptions,
19
19
  SatoriWsSocket,
20
- } from '../src/endpoint.js';
20
+ } from '../../src/endpoint.js';
21
21
 
22
- export default defineAdapter<SatoriAdapterConfig>({
22
+ export default defineAdapter<SatoriEndpointConfig>({
23
23
  capabilities: ['inbound', 'outbound'],
24
24
  operations: ['recall'],
25
25
  // Satori 协议 img/file 元素消费 url 与 base64 内联数据;无卡片交互面,交互段降级纯文本。
@@ -29,7 +29,7 @@ export default defineAdapter<SatoriAdapterConfig>({
29
29
  },
30
30
  create(context) {
31
31
  const config = resolveSatoriConfig(context.config);
32
- // 注册到插件运行时状态(satori.endpoint list 的"运行中"数据源)
32
+ // 注册到插件运行时状态(satori endpoint list 的"运行中"数据源)
33
33
  context.use(satoriRuntimeStateToken).endpoints.set(config.id, {
34
34
  id: config.id,
35
35
  mode: config.connection,
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { satoriEndpointCommands } from "../../../lib/satori-endpoint-commands.js";
2
+ import { satoriEndpointCommands } from '../../definition.js';
3
3
  export default satoriEndpointCommands.add;
@@ -0,0 +1,3 @@
1
+ import { satoriEndpointCommands } from '../../definition.js';
2
+
3
+ export default satoriEndpointCommands.add;
@@ -1,10 +1,11 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
1
2
  /**
2
- * `satori.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
3
+ * `satori endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
4
+ * commands/satori/endpoint/ 下的 list / add / remove 直接默认导出这三项。
4
5
  */
5
6
  import { createEndpointCommands } from 'zhin.js/adapter';
6
7
  import { defineCommand } from 'zhin.js/command';
7
- import { satoriRuntimeStateToken } from './satori-runtime-state.js';
8
+ import { satoriRuntimeStateToken } from "../../../lib/satori-runtime-state.js";
8
9
  export const satoriEndpointCommands = createEndpointCommands({
9
10
  adapterKey: 'satori',
10
11
  adapterDisplayName: 'Satori',
@@ -1,10 +1,10 @@
1
1
  /**
2
- * `satori.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
2
+ * `satori endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
+ * commands/satori/endpoint/ 下的 list / add / remove 直接默认导出这三项。
4
4
  */
5
5
  import { createEndpointCommands } from 'zhin.js/adapter';
6
6
  import { defineCommand } from 'zhin.js/command';
7
- import { satoriRuntimeStateToken } from './satori-runtime-state.js';
7
+ import { satoriRuntimeStateToken } from '../../../src/satori-runtime-state.js';
8
8
 
9
9
  export const satoriEndpointCommands = createEndpointCommands({
10
10
  adapterKey: 'satori',
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { satoriEndpointCommands } from "../../lib/satori-endpoint-commands.js";
2
+ import { satoriEndpointCommands } from '../definition.js';
3
3
  export default satoriEndpointCommands.list;
@@ -0,0 +1,3 @@
1
+ import { satoriEndpointCommands } from '../definition.js';
2
+
3
+ export default satoriEndpointCommands.list;
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { satoriEndpointCommands } from "../../../lib/satori-endpoint-commands.js";
2
+ import { satoriEndpointCommands } from '../../definition.js';
3
3
  export default satoriEndpointCommands.remove;
@@ -0,0 +1,3 @@
1
+ import { satoriEndpointCommands } from '../../definition.js';
2
+
3
+ export default satoriEndpointCommands.remove;
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, formatInboundContent, formatSatoriOutbound, isMessageEvent, isPrivateChannel, resolveInboundSender, resolveSatoriConfig, satoriInboundConversation, type ResolvedSatoriWebhookConfig, type ResolvedSatoriWsConfig, type SatoriAdapterConfig, type SatoriApiOptions, type SatoriChannel, type SatoriEventBody, type SatoriLogin, type SatoriMessage, type SatoriSignal, type SatoriUser, type SatoriWireSegment, } from './protocol.js';
1
+ export { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, formatInboundContent, formatSatoriOutbound, isMessageEvent, isPrivateChannel, resolveInboundSender, resolveSatoriConfig, satoriInboundConversation, type ResolvedSatoriWebhookConfig, type ResolvedSatoriWsConfig, type SatoriEndpointConfig, type SatoriApiOptions, type SatoriChannel, type SatoriEventBody, type SatoriLogin, type SatoriMessage, type SatoriSignal, type SatoriUser, type SatoriWireSegment, } from './protocol.js';
2
2
  export { SatoriWebhookEndpoint, SatoriWsEndpoint, type CreateSatoriWebSocket, type SatoriApiCaller, type SatoriWebhookEndpointOptions, type SatoriWsEndpointOptions, type SatoriWsSocket, } from './endpoint.js';
3
3
  export { handleSatoriWebhookRequest, registerSatoriWebhookRoutes, resolveSatoriOpcode, verifySatoriToken, type SatoriWebhookHandler, } from './webhook.js';
4
4
  export { WS_OPEN, defaultCreateWebSocket, } from './ws.js';
package/lib/protocol.d.ts CHANGED
@@ -1,9 +1,5 @@
1
- /**
2
- * Satori protocol helpers (no legacy Adapter/Endpoint / segment-mapper).
3
- * Canonicalization is owned by gateway/core before endpoint.send.
4
- * Spec: https://satori.chat/zh-CN/protocol/overview.html
5
- */
6
- import type { ConversationRef } from '@zhin.js/im-contract';
1
+ /** Satori protocol helpers. Spec: https://satori.chat/zh-CN/protocol/overview.html */
2
+ import { type ConversationRef } from '@zhin.js/im-contract';
7
3
  /** Opcode:EVENT=0, PING=1, PONG=2, IDENTIFY=3, READY=4, META=5 */
8
4
  export declare const SatoriOpcode: {
9
5
  readonly EVENT: 0;
@@ -76,21 +72,15 @@ export interface SatoriWireSegment {
76
72
  readonly type: string;
77
73
  readonly data?: Record<string, unknown>;
78
74
  }
79
- /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
80
- export interface SatoriAdapterConfig {
81
- readonly id?: string;
75
+ /** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
76
+ export interface SatoriEndpointConfig {
77
+ readonly id: string;
82
78
  readonly connection?: 'ws' | 'webhook';
83
- readonly baseUrl?: string;
79
+ readonly baseUrl: string;
84
80
  readonly token?: string;
85
81
  readonly heartbeat_interval?: number;
86
82
  /** Webhook POST path (connection: webhook). */
87
83
  readonly path?: string;
88
- /** Transitional: legacy root `endpoints[]` with `context: satori`. */
89
- readonly endpoints?: ReadonlyArray<Partial<ResolvedSatoriWsConfig> & {
90
- readonly context?: string;
91
- readonly connection?: 'ws' | 'webhook';
92
- readonly path?: string;
93
- }>;
94
84
  }
95
85
  export interface ResolvedSatoriWsConfig {
96
86
  readonly context: 'satori';
@@ -109,7 +99,7 @@ export interface ResolvedSatoriWebhookConfig {
109
99
  readonly path: string;
110
100
  }
111
101
  export type ResolvedSatoriConfig = ResolvedSatoriWsConfig | ResolvedSatoriWebhookConfig;
112
- export declare function resolveSatoriConfig(config?: SatoriAdapterConfig): ResolvedSatoriConfig;
102
+ export declare function resolveSatoriConfig(config: SatoriEndpointConfig): ResolvedSatoriConfig;
113
103
  /** Channel.type 1 = DIRECT (private). */
114
104
  export declare function isPrivateChannel(channel?: SatoriChannel): boolean;
115
105
  export declare function isMessageEvent(body: SatoriEventBody): body is SatoriEventBody & {
package/lib/protocol.js CHANGED
@@ -1,10 +1,5 @@
1
- /**
2
- * Satori protocol helpers (no legacy Adapter/Endpoint / segment-mapper).
3
- * Canonicalization is owned by gateway/core before endpoint.send.
4
- * Spec: https://satori.chat/zh-CN/protocol/overview.html
5
- */
6
- import { pickCredential } from 'zhin.js/adapter';
7
- import { isMediaRef } from '@zhin.js/core';
1
+ /** Satori protocol helpers. Spec: https://satori.chat/zh-CN/protocol/overview.html */
2
+ import { isMediaRef } from '@zhin.js/im-contract';
8
3
  import { formatCompact, getLogger } from '@zhin.js/logger';
9
4
  const logger = getLogger('satori');
10
5
  /** Opcode:EVENT=0, PING=1, PONG=2, IDENTIFY=3, READY=4, META=5 */
@@ -16,26 +11,15 @@ export const SatoriOpcode = {
16
11
  READY: 4,
17
12
  META: 5,
18
13
  };
19
- export function resolveSatoriConfig(config = {}) {
20
- const entry = config.endpoints?.find((item) => item.context === 'satori');
21
- const connection = config.connection ?? entry?.connection ?? 'ws';
22
- const baseUrl = pickCredential(config.baseUrl, entry?.baseUrl, process.env.SATORI_BASE_URL);
23
- if (!baseUrl) {
24
- throw new TypeError('Satori adapter requires baseUrl (plugins.<key>.baseUrl or endpoints with context: satori)');
25
- }
26
- const id = (typeof config.id === 'string' && config.id)
27
- || (typeof entry?.id === 'string' && entry.id)
28
- || process.env.SATORI_BOT_NAME
29
- || 'satori-bot';
30
- const token = (typeof config.token === 'string' && config.token)
31
- || (typeof entry?.token === 'string' && entry.token)
32
- || process.env.SATORI_TOKEN
33
- || undefined;
14
+ export function resolveSatoriConfig(config) {
15
+ const connection = config.connection ?? 'ws';
16
+ const id = requiredEndpointField(config.id, 'id');
17
+ const baseUrl = requiredEndpointField(config.baseUrl, 'baseUrl');
18
+ const token = typeof config.token === 'string' && config.token.trim()
19
+ ? config.token.trim()
20
+ : undefined;
34
21
  if (connection === 'webhook') {
35
- const path = config.path ?? entry?.path;
36
- if (!path) {
37
- throw new TypeError('Satori connection:webhook requires path');
38
- }
22
+ const path = requiredEndpointField(config.path, 'path');
39
23
  return {
40
24
  context: 'satori',
41
25
  connection: 'webhook',
@@ -45,9 +29,7 @@ export function resolveSatoriConfig(config = {}) {
45
29
  path,
46
30
  };
47
31
  }
48
- const heartbeat = config.heartbeat_interval
49
- ?? entry?.heartbeat_interval
50
- ?? 10_000;
32
+ const heartbeat = config.heartbeat_interval ?? 10_000;
51
33
  return {
52
34
  context: 'satori',
53
35
  connection: 'ws',
@@ -57,6 +39,12 @@ export function resolveSatoriConfig(config = {}) {
57
39
  heartbeat_interval: heartbeat,
58
40
  };
59
41
  }
42
+ function requiredEndpointField(value, field) {
43
+ if (typeof value !== 'string' || !value.trim()) {
44
+ throw new TypeError(`Satori endpoint requires a non-empty ${field}`);
45
+ }
46
+ return value.trim();
47
+ }
60
48
  /** Channel.type 1 = DIRECT (private). */
61
49
  export function isPrivateChannel(channel) {
62
50
  return channel?.type === 1;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Satori 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
3
- * 由 plugin.ts setup() provide,adapter create 与 `satori.endpoint` 命令共享(同一 owner generation)。
3
+ * 由 plugin.ts setup() provide,adapter create 与 `satori endpoint` 命令共享(同一 owner generation)。
4
4
  */
5
5
  import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
6
6
  export const satoriRuntimeStateToken = defineEndpointRuntimeStateToken('satori');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-satori",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Zhin.js Satori adapter for Plugin Runtime (WebSocket client)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -19,7 +19,7 @@
19
19
  "schema.json",
20
20
  "src",
21
21
  "lib",
22
- "agent",
22
+ "skills",
23
23
  "README.md",
24
24
  "CHANGELOG.md"
25
25
  ],
@@ -41,26 +41,27 @@
41
41
  "@imhelper/satori-v1": "1.0.7",
42
42
  "imhelper": "1.0.7",
43
43
  "ws": "^8.21.1",
44
- "@zhin.js/adapter": "1.1.12",
45
- "@zhin.js/core": "1.1.35",
46
- "@zhin.js/feature-kit": "1.1.0",
47
- "@zhin.js/host-http": "1.1.0",
48
- "@zhin.js/im-contract": "1.1.0",
49
- "@zhin.js/logger": "1.1.0"
44
+ "@zhin.js/adapter": "1.1.14",
45
+ "@zhin.js/core": "1.1.37",
46
+ "@zhin.js/feature-kit": "1.1.1",
47
+ "@zhin.js/host-http": "1.1.1",
48
+ "@zhin.js/im-contract": "1.1.1",
49
+ "@zhin.js/logger": "1.1.1",
50
+ "@zhin.js/skill": "1.1.1"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@types/node": "^26.1.2",
53
54
  "@types/ws": "^8.18.1",
54
55
  "typescript": "^6.0.3",
55
56
  "vitest": "^4.1.10",
56
- "@zhin.js/host-http": "1.1.0",
57
- "zhin.js": "1.1.0"
57
+ "@zhin.js/host-http": "1.1.1",
58
+ "zhin.js": "1.1.2"
58
59
  },
59
60
  "peerDependencies": {
60
- "@zhin.js/adapter": "^1.1.12",
61
- "@zhin.js/command": "^1.1.0",
62
- "@zhin.js/core": "^1.1.35",
63
- "zhin.js": "^1.1.0"
61
+ "@zhin.js/adapter": "^1.1.14",
62
+ "@zhin.js/command": "^1.1.1",
63
+ "@zhin.js/core": "^1.1.37",
64
+ "zhin.js": "^1.1.2"
64
65
  },
65
66
  "peerDependenciesMeta": {
66
67
  "@zhin.js/command": {
@@ -96,6 +97,10 @@
96
97
  {
97
98
  "package": "@zhin.js/command",
98
99
  "api": "^1.0.0"
100
+ },
101
+ {
102
+ "package": "@zhin.js/skill",
103
+ "api": "^1.0.0"
99
104
  }
100
105
  ],
101
106
  "plugins": []
package/plugin.js CHANGED
@@ -8,7 +8,7 @@ export default definePlugin({
8
8
  displayName: 'Satori Adapter',
9
9
  },
10
10
  setup(context) {
11
- // 运行中 endpoint 注册表(satori.endpoint list 的"运行中"数据源)
11
+ // 运行中 endpoint 注册表(satori endpoint list 的"运行中"数据源)
12
12
  context.resources.provide(satoriRuntimeStateToken, createEndpointRuntimeState());
13
13
  },
14
14
  });
package/schema.json CHANGED
@@ -37,10 +37,11 @@
37
37
  },
38
38
  "endpoints": {
39
39
  "type": "array",
40
- "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
40
+ "minItems": 1,
41
+ "description": "多账号:每项定义一个 endpoint,id/baseUrl 必填,其余字段覆盖实例默认值",
41
42
  "items": {
42
43
  "type": "object",
43
- "additionalProperties": true,
44
+ "additionalProperties": false,
44
45
  "properties": {
45
46
  "master": {
46
47
  "type": [
@@ -64,6 +65,13 @@
64
65
  "type": "string",
65
66
  "description": "Satori SDK HTTP/WS base URL (e.g. http://127.0.0.1:5140)"
66
67
  },
68
+ "connection": {
69
+ "type": "string",
70
+ "enum": [
71
+ "ws",
72
+ "webhook"
73
+ ]
74
+ },
67
75
  "token": {
68
76
  "type": "string",
69
77
  "description": "Bearer token for API and WS IDENTIFY"
@@ -72,6 +80,12 @@
72
80
  "type": "string",
73
81
  "description": "Webhook POST path (connection: webhook)"
74
82
  },
83
+ "heartbeat_interval": {
84
+ "type": "number"
85
+ },
86
+ "commandPrefix": {
87
+ "type": "string"
88
+ },
75
89
  "id": {
76
90
  "type": "string",
77
91
  "description": "Satori bot name"
package/src/index.ts CHANGED
@@ -12,7 +12,7 @@ export {
12
12
  satoriInboundConversation,
13
13
  type ResolvedSatoriWebhookConfig,
14
14
  type ResolvedSatoriWsConfig,
15
- type SatoriAdapterConfig,
15
+ type SatoriEndpointConfig,
16
16
  type SatoriApiOptions,
17
17
  type SatoriChannel,
18
18
  type SatoriEventBody,
package/src/protocol.ts CHANGED
@@ -1,12 +1,6 @@
1
- /**
2
- * Satori protocol helpers (no legacy Adapter/Endpoint / segment-mapper).
3
- * Canonicalization is owned by gateway/core before endpoint.send.
4
- * Spec: https://satori.chat/zh-CN/protocol/overview.html
5
- */
1
+ /** Satori protocol helpers. Spec: https://satori.chat/zh-CN/protocol/overview.html */
6
2
 
7
- import { pickCredential } from 'zhin.js/adapter';
8
- import { isMediaRef } from '@zhin.js/core';
9
- import type { ConversationKind, ConversationRef } from '@zhin.js/im-contract';
3
+ import { isMediaRef, type ConversationKind, type ConversationRef } from '@zhin.js/im-contract';
10
4
  import { formatCompact, getLogger } from '@zhin.js/logger';
11
5
 
12
6
  const logger = getLogger('satori');
@@ -82,21 +76,15 @@ export interface SatoriWireSegment {
82
76
  readonly data?: Record<string, unknown>;
83
77
  }
84
78
 
85
- /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
86
- export interface SatoriAdapterConfig {
87
- readonly id?: string;
79
+ /** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
80
+ export interface SatoriEndpointConfig {
81
+ readonly id: string;
88
82
  readonly connection?: 'ws' | 'webhook';
89
- readonly baseUrl?: string;
83
+ readonly baseUrl: string;
90
84
  readonly token?: string;
91
85
  readonly heartbeat_interval?: number;
92
86
  /** Webhook POST path (connection: webhook). */
93
87
  readonly path?: string;
94
- /** Transitional: legacy root `endpoints[]` with `context: satori`. */
95
- readonly endpoints?: ReadonlyArray<Partial<ResolvedSatoriWsConfig> & {
96
- readonly context?: string;
97
- readonly connection?: 'ws' | 'webhook';
98
- readonly path?: string;
99
- }>;
100
88
  }
101
89
 
102
90
  export interface ResolvedSatoriWsConfig {
@@ -119,29 +107,16 @@ export interface ResolvedSatoriWebhookConfig {
119
107
 
120
108
  export type ResolvedSatoriConfig = ResolvedSatoriWsConfig | ResolvedSatoriWebhookConfig;
121
109
 
122
- export function resolveSatoriConfig(config: SatoriAdapterConfig = {}): ResolvedSatoriConfig {
123
- const entry = config.endpoints?.find((item) => item.context === 'satori');
124
- const connection = config.connection ?? entry?.connection ?? 'ws';
125
- const baseUrl = pickCredential(config.baseUrl, entry?.baseUrl, process.env.SATORI_BASE_URL);
126
- if (!baseUrl) {
127
- throw new TypeError(
128
- 'Satori adapter requires baseUrl (plugins.<key>.baseUrl or endpoints with context: satori)',
129
- );
130
- }
131
- const id = (typeof config.id === 'string' && config.id)
132
- || (typeof entry?.id === 'string' && entry.id)
133
- || process.env.SATORI_BOT_NAME
134
- || 'satori-bot';
135
- const token = (typeof config.token === 'string' && config.token)
136
- || (typeof entry?.token === 'string' && entry.token)
137
- || process.env.SATORI_TOKEN
138
- || undefined;
110
+ export function resolveSatoriConfig(config: SatoriEndpointConfig): ResolvedSatoriConfig {
111
+ const connection = config.connection ?? 'ws';
112
+ const id = requiredEndpointField(config.id, 'id');
113
+ const baseUrl = requiredEndpointField(config.baseUrl, 'baseUrl');
114
+ const token = typeof config.token === 'string' && config.token.trim()
115
+ ? config.token.trim()
116
+ : undefined;
139
117
 
140
118
  if (connection === 'webhook') {
141
- const path = config.path ?? entry?.path;
142
- if (!path) {
143
- throw new TypeError('Satori connection:webhook requires path');
144
- }
119
+ const path = requiredEndpointField(config.path, 'path');
145
120
  return {
146
121
  context: 'satori',
147
122
  connection: 'webhook',
@@ -152,9 +127,7 @@ export function resolveSatoriConfig(config: SatoriAdapterConfig = {}): ResolvedS
152
127
  };
153
128
  }
154
129
 
155
- const heartbeat = config.heartbeat_interval
156
- ?? entry?.heartbeat_interval
157
- ?? 10_000;
130
+ const heartbeat = config.heartbeat_interval ?? 10_000;
158
131
  return {
159
132
  context: 'satori',
160
133
  connection: 'ws',
@@ -165,6 +138,16 @@ export function resolveSatoriConfig(config: SatoriAdapterConfig = {}): ResolvedS
165
138
  };
166
139
  }
167
140
 
141
+ function requiredEndpointField(
142
+ value: unknown,
143
+ field: 'id' | 'baseUrl' | 'path',
144
+ ): string {
145
+ if (typeof value !== 'string' || !value.trim()) {
146
+ throw new TypeError(`Satori endpoint requires a non-empty ${field}`);
147
+ }
148
+ return value.trim();
149
+ }
150
+
168
151
  /** Channel.type 1 = DIRECT (private). */
169
152
  export function isPrivateChannel(channel?: SatoriChannel): boolean {
170
153
  return channel?.type === 1;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Satori 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
3
- * 由 plugin.ts setup() provide,adapter create 与 `satori.endpoint` 命令共享(同一 owner generation)。
3
+ * 由 plugin.ts setup() provide,adapter create 与 `satori endpoint` 命令共享(同一 owner generation)。
4
4
  */
5
5
  import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
6
6
 
@@ -1,33 +0,0 @@
1
- ---
2
- name: satori
3
- platforms:
4
- - satori
5
- description: >-
6
- Satori 协议适配器:支持 WebSocket(正向)和 Webhook 两种连接方式,
7
- 实现 Satori 标准协议的消息收发。纯消息通道,无额外 AI 工具。
8
- Satori 是跨平台的统一协议,可对接多种 IM 后端。
9
- keywords:
10
- - satori
11
- - adapter:satori
12
- - protocol
13
- - websocket
14
- - webhook
15
- - 协议
16
- - 跨平台
17
- tags:
18
- - satori
19
- - protocol
20
- - adapter
21
- tools: []
22
- ---
23
-
24
- # Satori 协议适配器
25
-
26
- 纯协议适配器,收发消息。无 AI 工具可调用。
27
-
28
- ## 连接模式
29
-
30
- - **WS 正向**:Bot 主动连接 Satori 服务端
31
- - **Webhook**:Satori 向配置的 URL 推送事件
32
-
33
- Satori 是跨平台统一协议,可作为中间层对接 QQ、Discord、Telegram 等后端。
@@ -1,3 +0,0 @@
1
- import { satoriEndpointCommands } from '../../../src/satori-endpoint-commands.js';
2
-
3
- export default satoriEndpointCommands.add;
@@ -1,3 +0,0 @@
1
- import { satoriEndpointCommands } from '../../src/satori-endpoint-commands.js';
2
-
3
- export default satoriEndpointCommands.list;
@@ -1,3 +0,0 @@
1
- import { satoriEndpointCommands } from '../../../src/satori-endpoint-commands.js';
2
-
3
- export default satoriEndpointCommands.remove;
@@ -1 +0,0 @@
1
- export declare const satoriEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;