@vibearound/plugin-channel-sdk 0.1.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @vibearound/plugin-channel-sdk
2
2
 
3
- Base classes and utilities for building [VibeAround](https://github.com/anthropics/vibearound) channel plugins.
3
+ SDK for building [VibeAround](https://github.com/jazzenchen/VibeAround) channel plugins.
4
4
 
5
- VibeAround channel plugins bridge messaging platforms (Telegram, Feishu, WeChat, etc.) to the VibeAround agent runtime via the [Agent Client Protocol (ACP)](https://github.com/anthropics/agent-client-protocol). This SDK extracts the shared patterns so you can focus on platform integration.
5
+ Channel plugins bridge IM platforms (Feishu, Telegram, Slack, Discord, etc.) to the VibeAround agent runtime via [ACP](https://agentclientprotocol.com). This SDK handles the ACP lifecycle so you only implement platform-specific message transport.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,141 +10,95 @@ VibeAround channel plugins bridge messaging platforms (Telegram, Feishu, WeChat,
10
10
  npm install @vibearound/plugin-channel-sdk
11
11
  ```
12
12
 
13
- ## What it provides
14
-
15
- - **`connectToHost()`** — Sets up the ACP stdio connection, performs the initialize handshake, extracts plugin config from the host, and redirects console output to stderr.
16
- - **`BlockRenderer<TRef>`** — Abstract base class that handles block-based message rendering: accumulation of streaming deltas, kind-change detection, debounced flushing, edit throttling, and ordered delivery via a serialized Promise chain.
17
- - **`normalizeExtMethod()`** — Strips the `_` prefix the ACP SDK adds to extension method names.
18
- - **Types** — Re-exports common ACP SDK types (`Agent`, `Client`, `SessionNotification`, etc.) plus SDK-specific types (`BlockKind`, `VerboseConfig`, `PluginManifest`, etc.).
19
-
20
13
  ## Quick start
21
14
 
22
15
  ```ts
23
- import {
24
- connectToHost,
25
- BlockRenderer,
26
- normalizeExtMethod,
27
- type Agent,
28
- type BlockKind,
29
- type SessionNotification,
30
- } from "@vibearound/plugin-channel-sdk";
16
+ import { runChannelPlugin, BlockRenderer, type BlockKind, type VerboseConfig } from "@vibearound/plugin-channel-sdk";
31
17
 
32
18
  // 1. Implement a renderer for your platform
33
19
  class MyRenderer extends BlockRenderer<string> {
34
- protected async sendBlock(channelId: string, kind: BlockKind, content: string) {
35
- const msg = await myPlatform.send(channelId, content);
36
- return msg.id; // platform message reference for future edits
20
+ constructor(private bot: MyBot, log: Function, verbose?: Partial<VerboseConfig>) {
21
+ super({ streaming: true, flushIntervalMs: 500, minEditIntervalMs: 1000, verbose });
37
22
  }
38
23
 
39
- // Optional omit for platforms that don't support editing
40
- protected async editBlock(channelId: string, ref: string, kind: BlockKind, content: string, sealed: boolean) {
41
- await myPlatform.edit(ref, content);
24
+ protected async sendText(chatId: string, text: string) {
25
+ await this.bot.send(chatId, text);
26
+ }
27
+
28
+ protected async sendBlock(chatId: string, kind: BlockKind, content: string) {
29
+ const msg = await this.bot.send(chatId, content);
30
+ return msg.id;
42
31
  }
43
- }
44
32
 
45
- // 2. Connect to the VibeAround host
46
- const renderer = new MyRenderer({ minEditIntervalMs: 600 });
47
-
48
- const { agent, meta, agentInfo, conn } = await connectToHost(
49
- { name: "vibearound-myplatform", version: "0.1.0" },
50
- (_agent) => ({
51
- async sessionUpdate(params: SessionNotification) {
52
- renderer.onSessionUpdate(params);
53
- },
54
- async requestPermission(params) {
55
- return { outcome: { outcome: "selected", optionId: params.options![0].optionId } };
56
- },
57
- async extNotification(method, params) {
58
- switch (normalizeExtMethod(method)) {
59
- case "channel/system_text":
60
- await myPlatform.send(params.channelId as string, params.text as string);
61
- break;
62
- }
63
- },
64
- }),
65
- );
66
-
67
- // 3. Use the config and start your platform bot
68
- const botToken = meta.config.bot_token as string;
69
- // ... initialize your platform SDK ...
70
-
71
- // 4. On each incoming message:
72
- renderer.onPromptSent(channelId);
73
- try {
74
- await agent.prompt({ sessionId: chatId, prompt: contentBlocks });
75
- await renderer.onTurnEnd(channelId);
76
- } catch (e) {
77
- await renderer.onTurnError(channelId, String(e));
33
+ protected async editBlock(chatId: string, ref: string, kind: BlockKind, content: string, sealed: boolean) {
34
+ await this.bot.edit(chatId, ref, content);
35
+ }
78
36
  }
79
37
 
80
- // 5. Keep alive until host disconnects
81
- await conn.closed;
38
+ // 2. Run the plugin
39
+ runChannelPlugin({
40
+ name: "vibearound-myplatform",
41
+ version: "0.1.0",
42
+ requiredConfig: ["bot_token"],
43
+ createBot: ({ config, agent, log, cacheDir }) =>
44
+ new MyBot(config.bot_token as string, agent, log, cacheDir),
45
+ createRenderer: (bot, log, verbose) =>
46
+ new MyRenderer(bot, log, verbose),
47
+ });
82
48
  ```
83
49
 
50
+ That's it. The SDK handles ACP connection, config validation, event routing, and shutdown.
51
+
84
52
  ## BlockRenderer
85
53
 
86
- The `BlockRenderer<TRef>` groups streaming ACP events into contiguous blocks by kind (`text`, `thinking`, `tool`), then renders them to your platform via `sendBlock` / `editBlock`.
54
+ Abstract base class that renders agent responses to your IM platform.
87
55
 
88
- ### Constructor options
56
+ ### Required methods
89
57
 
90
- | Option | Default | Description |
58
+ | Method | Description |
59
+ |---|---|
60
+ | `sendText(chatId, text)` | Send a plain text message (system notifications, errors) |
61
+ | `sendBlock(chatId, kind, content)` | Send a new streaming block, return a platform ref for editing |
62
+
63
+ ### Optional methods
64
+
65
+ | Method | Default | Description |
91
66
  |---|---|---|
92
- | `flushIntervalMs` | `500` | Debounce interval before flushing an in-progress block |
93
- | `minEditIntervalMs` | `1000` | Minimum gap between consecutive edits (rate limit protection) |
94
- | `verbose.showThinking` | `false` | Render agent thinking/reasoning blocks |
95
- | `verbose.showToolUse` | `false` | Render tool call/result blocks |
67
+ | `editBlock(chatId, ref, kind, content, sealed)` | | Edit a message in-place (omit for send-only platforms) |
68
+ | `formatContent(kind, content, sealed)` | Emoji prefixes | Format block content before send/edit |
69
+ | `onAfterTurnEnd(chatId)` | No-op | Cleanup after turn completes |
70
+ | `onAfterTurnError(chatId, error)` | `sendText(chatId, "❌ ...")` | Custom error rendering |
71
+ | `onCommandMenu(chatId, systemCmds, agentCmds)` | Plain text list | Custom command menu rendering |
96
72
 
97
- ### Methods to implement
73
+ ### Constructor options
98
74
 
99
- | Method | Required | Description |
75
+ | Option | Default | Description |
100
76
  |---|---|---|
101
- | `sendBlock(channelId, kind, content)` | Yes | Send a new message, return a platform ref (or `null` if no editing) |
102
- | `editBlock(channelId, ref, kind, content, sealed)` | No | Edit an existing message in-place |
103
- | `formatContent(kind, content, sealed)` | No | Format block content before send/edit (default: emoji prefixes) |
77
+ | `streaming` | `true` | `true`: send + edit in real-time. `false`: hold each block until complete, then send once |
78
+ | `flushIntervalMs` | `500` | Debounce interval before flushing |
79
+ | `minEditIntervalMs` | `1000` | Minimum gap between edits (rate limit protection) |
80
+ | `verbose.showThinking` | `false` | Show agent thinking blocks |
81
+ | `verbose.showToolUse` | `false` | Show tool call blocks |
104
82
 
105
- ### Lifecycle hooks
83
+ ## ChannelBot interface
106
84
 
107
- | Hook | Description |
108
- |---|---|
109
- | `onAfterTurnEnd(channelId)` | Cleanup after all blocks are flushed (e.g. remove typing indicator) |
110
- | `onAfterTurnError(channelId, error)` | Send error message to user |
111
- | `sessionIdToChannelId(sessionId)` | Map ACP session ID to your channel ID (default: identity) |
112
-
113
- ## Plugin manifest
114
-
115
- Each channel plugin needs a `plugin.json` at its root:
116
-
117
- ```json
118
- {
119
- "id": "my-platform",
120
- "name": "My Platform Channel",
121
- "version": "0.1.0",
122
- "kind": "channel",
123
- "runtime": "node",
124
- "entry": "dist/main.js",
125
- "build": "npm install && npm run build",
126
- "configSchema": {
127
- "type": "object",
128
- "properties": {
129
- "bot_token": { "type": "string" }
130
- },
131
- "required": ["bot_token"]
132
- },
133
- "capabilities": {
134
- "streaming": true,
135
- "editMessage": true,
136
- "media": false
137
- }
85
+ Your bot class should implement:
86
+
87
+ ```ts
88
+ interface ChannelBot {
89
+ setStreamHandler(handler: BlockRenderer): void;
90
+ start(): Promise<void> | void;
91
+ stop(): Promise<void> | void;
138
92
  }
139
93
  ```
140
94
 
141
- ## Examples
95
+ ## Advanced usage
142
96
 
143
- See the official channel plugins for real-world usage:
97
+ For plugins that need custom ACP lifecycle control:
144
98
 
145
- - **Feishu** — Interactive cards, streaming updates, reactions
146
- - **Telegram** Plain text messages with inline editing
147
- - **WeChat** — Send-only mode (no editing), typing indicators
99
+ ```ts
100
+ import { connectToHost, stripExtPrefix } from "@vibearound/plugin-channel-sdk/advanced";
101
+ ```
148
102
 
149
103
  ## License
150
104
 
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @vibearound/plugin-channel-sdk — Advanced / low-level API
3
+ *
4
+ * For plugins that need custom ACP lifecycle control instead of
5
+ * the standard `runChannelPlugin()` flow.
6
+ *
7
+ * Normal plugins should use the main entry point instead:
8
+ * ```ts
9
+ * import { runChannelPlugin, BlockRenderer } from "@vibearound/plugin-channel-sdk";
10
+ * ```
11
+ */
12
+ export { connectToHost, stripExtPrefix, redirectConsoleToStderr } from "./connection.js";
13
+ export type { PluginInfo, ConnectResult, AgentInfo } from "./connection.js";
14
+ export type { Agent, Client, ContentBlock, SessionNotification, RequestPermissionRequest, RequestPermissionResponse, BlockKind, VerboseConfig, BlockRendererOptions, PluginCapabilities, PluginManifest, PluginInitMeta, } from "./types.js";
15
+ export { runChannelPlugin } from "./plugin.js";
16
+ export { BlockRenderer } from "./renderer.js";
17
+ export { extractErrorMessage } from "./errors.js";
18
+ export type { ChannelBot, ChannelPluginLogger, CreateBotContext, RunChannelPluginSpec, VerboseOptions, } from "./plugin.js";
19
+ //# sourceMappingURL=advanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACzF,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5E,YAAY,EACV,KAAK,EACL,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @vibearound/plugin-channel-sdk — Advanced / low-level API
3
+ *
4
+ * For plugins that need custom ACP lifecycle control instead of
5
+ * the standard `runChannelPlugin()` flow.
6
+ *
7
+ * Normal plugins should use the main entry point instead:
8
+ * ```ts
9
+ * import { runChannelPlugin, BlockRenderer } from "@vibearound/plugin-channel-sdk";
10
+ * ```
11
+ */
12
+ // Low-level ACP connection
13
+ export { connectToHost, stripExtPrefix, redirectConsoleToStderr } from "./connection.js";
14
+ // Re-export high-level API too (so advanced users don't need two imports)
15
+ export { runChannelPlugin } from "./plugin.js";
16
+ export { BlockRenderer } from "./renderer.js";
17
+ export { extractErrorMessage } from "./errors.js";
18
+ //# sourceMappingURL=advanced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.js","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAmBzF,0EAA0E;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -52,11 +52,17 @@ export interface ConnectResult {
52
52
  */
53
53
  export declare function connectToHost(pluginInfo: PluginInfo, makeClient: (agent: Agent) => Client): Promise<ConnectResult>;
54
54
  /**
55
- * Normalize ACP ext notification method names.
55
+ * Strip the `_` prefix from ACP extension method names.
56
56
  *
57
- * The ACP SDK prepends "_" to ext method names (e.g. "_channel/system_text").
58
- * Strip the prefix to get the canonical method name used in plugin.json.
57
+ * The Rust ACP SDK adds `_` when sending ext notifications on the wire,
58
+ * but the TypeScript ACP SDK does not strip it on receipt. This function
59
+ * normalizes the received method name so handlers can match the canonical
60
+ * name (e.g. `_va/system_text` → `va/system_text`).
61
+ *
62
+ * Note: when sending ext notifications FROM TypeScript TO the Rust host,
63
+ * the method name must include the `_` prefix manually (e.g. `_va/callback`)
64
+ * because the TypeScript SDK does not add it automatically.
59
65
  */
60
- export declare function normalizeExtMethod(method: string): string;
66
+ export declare function stripExtPrefix(method: string): string;
61
67
  export declare function redirectConsoleToStderr(): void;
62
68
  //# sourceMappingURL=connection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,KAAK,EAAE,KAAK,CAAC;IACb,mEAAmE;IACnE,IAAI,EAAE,cAAc,CAAC;IACrB,4EAA4E;IAC5E,SAAS,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GACnC,OAAO,CAAC,aAAa,CAAC,CAqCxB;AAMD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAWD,wBAAgB,uBAAuB,IAAI,IAAI,CAe9C"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,KAAK,EAAE,KAAK,CAAC;IACb,mEAAmE;IACnE,IAAI,EAAE,cAAc,CAAC;IACrB,4EAA4E;IAC5E,SAAS,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GACnC,OAAO,CAAC,aAAa,CAAC,CAqCxB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAWD,wBAAgB,uBAAuB,IAAI,IAAI,CAe9C"}
@@ -59,12 +59,18 @@ export async function connectToHost(pluginInfo, makeClient) {
59
59
  // Utilities
60
60
  // ---------------------------------------------------------------------------
61
61
  /**
62
- * Normalize ACP ext notification method names.
62
+ * Strip the `_` prefix from ACP extension method names.
63
63
  *
64
- * The ACP SDK prepends "_" to ext method names (e.g. "_channel/system_text").
65
- * Strip the prefix to get the canonical method name used in plugin.json.
64
+ * The Rust ACP SDK adds `_` when sending ext notifications on the wire,
65
+ * but the TypeScript ACP SDK does not strip it on receipt. This function
66
+ * normalizes the received method name so handlers can match the canonical
67
+ * name (e.g. `_va/system_text` → `va/system_text`).
68
+ *
69
+ * Note: when sending ext notifications FROM TypeScript TO the Rust host,
70
+ * the method name must include the `_` prefix manually (e.g. `_va/callback`)
71
+ * because the TypeScript SDK does not add it automatically.
66
72
  */
67
- export function normalizeExtMethod(method) {
73
+ export function stripExtPrefix(method) {
68
74
  return method.startsWith("_") ? method.slice(1) : method;
69
75
  }
70
76
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Error normalization for channel plugins.
3
+ *
4
+ * Every plugin had an ad-hoc ladder that tried `instanceof Error`, then
5
+ * `typeof error === "object"`, then fell back to `String(error)`. That
6
+ * ladder lived in five slightly-different forms across bot.ts files and
7
+ * drifted over time. Centralize it here.
8
+ */
9
+ /**
10
+ * Extract a human-readable message from an unknown thrown value.
11
+ *
12
+ * Prefers `Error.message`, falls back to a non-circular JSON stringify for
13
+ * objects, and finally to `String(e)` for primitives.
14
+ */
15
+ export declare function extractErrorMessage(e: unknown): string;
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAatD"}
package/dist/errors.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Error normalization for channel plugins.
3
+ *
4
+ * Every plugin had an ad-hoc ladder that tried `instanceof Error`, then
5
+ * `typeof error === "object"`, then fell back to `String(error)`. That
6
+ * ladder lived in five slightly-different forms across bot.ts files and
7
+ * drifted over time. Centralize it here.
8
+ */
9
+ /**
10
+ * Extract a human-readable message from an unknown thrown value.
11
+ *
12
+ * Prefers `Error.message`, falls back to a non-circular JSON stringify for
13
+ * objects, and finally to `String(e)` for primitives.
14
+ */
15
+ export function extractErrorMessage(e) {
16
+ if (e instanceof Error)
17
+ return e.message;
18
+ if (typeof e === "string")
19
+ return e;
20
+ if (e && typeof e === "object") {
21
+ const msg = e.message;
22
+ if (typeof msg === "string")
23
+ return msg;
24
+ try {
25
+ return JSON.stringify(e);
26
+ }
27
+ catch {
28
+ return String(e);
29
+ }
30
+ }
31
+ return String(e);
32
+ }
33
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,CAAU;IAC5C,IAAI,CAAC,YAAY,KAAK;QAAE,OAAO,CAAC,CAAC,OAAO,CAAC;IACzC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAI,CAA2B,CAAC,OAAO,CAAC;QACjD,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC;QACxC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,59 +1,45 @@
1
1
  /**
2
2
  * @vibearound/plugin-channel-sdk
3
3
  *
4
- * Base classes and utilities for building VibeAround channel plugins.
4
+ * SDK for building VibeAround channel plugins.
5
5
  *
6
6
  * ## Quick start
7
7
  *
8
8
  * ```ts
9
9
  * import {
10
- * connectToHost,
10
+ * runChannelPlugin,
11
11
  * BlockRenderer,
12
- * normalizeExtMethod,
13
- * type Agent,
14
- * type SessionNotification,
12
+ * type ChannelBot,
13
+ * type BlockKind,
15
14
  * } from "@vibearound/plugin-channel-sdk";
16
15
  *
17
16
  * class MyRenderer extends BlockRenderer<string> {
18
- * protected async sendBlock(channelId, kind, content) {
19
- * const msg = await myPlatform.send(channelId, content);
20
- * return msg.id;
21
- * }
22
- * protected async editBlock(channelId, ref, kind, content, sealed) {
23
- * await myPlatform.edit(ref, content);
24
- * }
17
+ * protected async sendText(chatId: string, text: string) { ... }
18
+ * protected async sendBlock(chatId: string, kind: BlockKind, content: string) { ... }
25
19
  * }
26
20
  *
27
- * let agent!: Agent;
28
- * const renderer = new MyRenderer();
29
- *
30
- * const { meta, conn } = await connectToHost(
31
- * { name: "vibearound-mybot", version: "0.1.0" },
32
- * (a) => {
33
- * agent = a;
34
- * return {
35
- * sessionUpdate: async (n) => renderer.onSessionUpdate(n),
36
- * requestPermission: async (p) => ({
37
- * outcome: { outcome: "selected", optionId: p.options![0].optionId },
38
- * }),
39
- * extNotification: async (method, params) => {
40
- * switch (normalizeExtMethod(method)) {
41
- * case "channel/system_text":
42
- * await myPlatform.send(params.channelId as string, params.text as string);
43
- * break;
44
- * }
45
- * },
46
- * };
47
- * },
48
- * );
49
- *
50
- * const botToken = meta.config.bot_token as string;
51
- * // … start your platform bot …
52
- * await conn.closed;
21
+ * runChannelPlugin({
22
+ * name: "vibearound-mybot",
23
+ * version: "0.1.0",
24
+ * requiredConfig: ["bot_token"],
25
+ * createBot: ({ config, agent, log, cacheDir }) => new MyBot(...),
26
+ * createRenderer: (bot, log, verbose) => new MyRenderer(bot, log, verbose),
27
+ * });
28
+ * ```
29
+ *
30
+ * ## Advanced / low-level usage
31
+ *
32
+ * For plugins that need custom ACP lifecycle control (e.g. weixin-openclaw-bridge),
33
+ * import from the `advanced` subpath:
34
+ *
35
+ * ```ts
36
+ * import { connectToHost } from "@vibearound/plugin-channel-sdk/advanced";
53
37
  * ```
54
38
  */
55
- export { connectToHost, normalizeExtMethod, redirectConsoleToStderr } from "./connection.js";
56
- export type { PluginInfo, ConnectResult, AgentInfo } from "./connection.js";
39
+ export { runChannelPlugin } from "./plugin.js";
57
40
  export { BlockRenderer } from "./renderer.js";
58
- export type { Agent, Client, ContentBlock, SessionNotification, RequestPermissionRequest, RequestPermissionResponse, BlockKind, VerboseConfig, BlockRendererOptions, PluginCapabilities, PluginManifest, PluginInitMeta, } from "./types.js";
41
+ export type { ChannelBot, ChannelPluginLogger, CreateBotContext, RunChannelPluginSpec, VerboseOptions, } from "./plugin.js";
42
+ export type { BlockKind, CommandEntry, VerboseConfig, BlockRendererOptions, } from "./types.js";
43
+ export type { Agent, ContentBlock, SessionNotification, } from "./types.js";
44
+ export { extractErrorMessage } from "./errors.js";
59
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAGH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC7F,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5E,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,YAAY,EAEV,KAAK,EACL,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EAEzB,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAOH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,SAAS,EACT,YAAY,EACZ,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,KAAK,EACL,YAAY,EACZ,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,59 +1,48 @@
1
1
  /**
2
2
  * @vibearound/plugin-channel-sdk
3
3
  *
4
- * Base classes and utilities for building VibeAround channel plugins.
4
+ * SDK for building VibeAround channel plugins.
5
5
  *
6
6
  * ## Quick start
7
7
  *
8
8
  * ```ts
9
9
  * import {
10
- * connectToHost,
10
+ * runChannelPlugin,
11
11
  * BlockRenderer,
12
- * normalizeExtMethod,
13
- * type Agent,
14
- * type SessionNotification,
12
+ * type ChannelBot,
13
+ * type BlockKind,
15
14
  * } from "@vibearound/plugin-channel-sdk";
16
15
  *
17
16
  * class MyRenderer extends BlockRenderer<string> {
18
- * protected async sendBlock(channelId, kind, content) {
19
- * const msg = await myPlatform.send(channelId, content);
20
- * return msg.id;
21
- * }
22
- * protected async editBlock(channelId, ref, kind, content, sealed) {
23
- * await myPlatform.edit(ref, content);
24
- * }
17
+ * protected async sendText(chatId: string, text: string) { ... }
18
+ * protected async sendBlock(chatId: string, kind: BlockKind, content: string) { ... }
25
19
  * }
26
20
  *
27
- * let agent!: Agent;
28
- * const renderer = new MyRenderer();
29
- *
30
- * const { meta, conn } = await connectToHost(
31
- * { name: "vibearound-mybot", version: "0.1.0" },
32
- * (a) => {
33
- * agent = a;
34
- * return {
35
- * sessionUpdate: async (n) => renderer.onSessionUpdate(n),
36
- * requestPermission: async (p) => ({
37
- * outcome: { outcome: "selected", optionId: p.options![0].optionId },
38
- * }),
39
- * extNotification: async (method, params) => {
40
- * switch (normalizeExtMethod(method)) {
41
- * case "channel/system_text":
42
- * await myPlatform.send(params.channelId as string, params.text as string);
43
- * break;
44
- * }
45
- * },
46
- * };
47
- * },
48
- * );
49
- *
50
- * const botToken = meta.config.bot_token as string;
51
- * // … start your platform bot …
52
- * await conn.closed;
21
+ * runChannelPlugin({
22
+ * name: "vibearound-mybot",
23
+ * version: "0.1.0",
24
+ * requiredConfig: ["bot_token"],
25
+ * createBot: ({ config, agent, log, cacheDir }) => new MyBot(...),
26
+ * createRenderer: (bot, log, verbose) => new MyRenderer(bot, log, verbose),
27
+ * });
28
+ * ```
29
+ *
30
+ * ## Advanced / low-level usage
31
+ *
32
+ * For plugins that need custom ACP lifecycle control (e.g. weixin-openclaw-bridge),
33
+ * import from the `advanced` subpath:
34
+ *
35
+ * ```ts
36
+ * import { connectToHost } from "@vibearound/plugin-channel-sdk/advanced";
53
37
  * ```
54
38
  */
55
- // Connection helpers
56
- export { connectToHost, normalizeExtMethod, redirectConsoleToStderr } from "./connection.js";
57
- // Block renderer
39
+ // ---------------------------------------------------------------------------
40
+ // High-level API what plugin developers use
41
+ // ---------------------------------------------------------------------------
42
+ // Entry point
43
+ export { runChannelPlugin } from "./plugin.js";
44
+ // Base class for stream rendering
58
45
  export { BlockRenderer } from "./renderer.js";
46
+ // Error utility
47
+ export { extractErrorMessage } from "./errors.js";
59
48
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,qBAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAG7F,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,kCAAkC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA0B9C,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}