@vibearound/plugin-channel-sdk 0.1.2 → 0.3.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.
@@ -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
@@ -54,6 +54,9 @@
54
54
  */
55
55
  export { connectToHost, normalizeExtMethod, redirectConsoleToStderr } from "./connection.js";
56
56
  export type { PluginInfo, ConnectResult, AgentInfo } from "./connection.js";
57
+ export { extractErrorMessage } from "./errors.js";
58
+ export { runChannelPlugin } from "./run-plugin.js";
59
+ export type { ChannelBot, ChannelPluginLogger, ChannelStreamHandler, CreateBotContext, RunChannelPluginSpec, VerboseOptions, } from "./run-plugin.js";
57
60
  export { BlockRenderer } from "./renderer.js";
58
61
  export type { Agent, Client, ContentBlock, SessionNotification, RequestPermissionRequest, RequestPermissionResponse, BlockKind, VerboseConfig, BlockRendererOptions, PluginCapabilities, PluginManifest, PluginInitMeta, } from "./types.js";
59
62
  //# 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,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"}
package/dist/index.js CHANGED
@@ -54,6 +54,10 @@
54
54
  */
55
55
  // Connection helpers
56
56
  export { connectToHost, normalizeExtMethod, redirectConsoleToStderr } from "./connection.js";
57
+ // Error normalization
58
+ export { extractErrorMessage } from "./errors.js";
59
+ // Plugin runner (absorbs the main.ts boilerplate)
60
+ export { runChannelPlugin } from "./run-plugin.js";
57
61
  // Block renderer
58
62
  export { BlockRenderer } from "./renderer.js";
59
63
  //# 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,qBAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAG7F,sBAAsB;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,kDAAkD;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAUnD,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAuCjF;;;;;;GAMG;AACH,8BAAsB,aAAa,CAAC,IAAI,GAAG,MAAM;IAC/C,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAyC;gBAE3C,OAAO,GAAE,oBAAyB;IAa9C;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAEvB;;;;;;;;OAQG;IACH,SAAS,CAAC,SAAS,CAAC,CAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAEhB;;;;;;;;;OASG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM;IAQnF;;;;OAIG;IACH,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;OAGG;IACH,SAAS,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E;;;;;;;OAOG;IACH,SAAS,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAQzD;;;;;;;OAOG;IACH,eAAe,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;IAqCxD;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAWrC;;;;;OAKG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjD;;;;;OAKG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlE,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,YAAY;YAMN,UAAU;CAqBzB"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6EjF;;;;;;GAMG;AACH,8BAAsB,aAAa,CAAC,IAAI,GAAG,MAAM;IAC/C,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAyC;gBAE3C,OAAO,GAAE,oBAAyB;IAa9C;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAEvB;;;;;;;;OAQG;IACH,SAAS,CAAC,SAAS,CAAC,CAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAEhB;;;;;;;;;OASG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM;IAQnF;;;;OAIG;IACH,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;OAGG;IACH,SAAS,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E;;;;;;;OAOG;IACH,SAAS,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAQzD;;;;;;;OAOG;IACH,eAAe,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;IAgDxD;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAWrC;;;;;OAKG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjD;;;;;OAKG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlE,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,KAAK;IA+Bb,OAAO,CAAC,YAAY;YAMN,UAAU;CAqBzB"}
package/dist/renderer.js CHANGED
@@ -136,13 +136,23 @@ export class BlockRenderer {
136
136
  */
137
137
  onSessionUpdate(notification) {
138
138
  const sessionId = notification.sessionId;
139
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
140
- const update = notification.update;
141
- const variant = update.sessionUpdate;
139
+ // Narrow through the local ConsumedSessionUpdate union — see the type
140
+ // declaration above this class for why we re-declare it locally instead
141
+ // of importing the SDK's own union. Variants other than the four we
142
+ // handle are treated as no-ops.
143
+ const rawUpdate = notification.update;
144
+ const variant = rawUpdate.sessionUpdate;
145
+ if (variant !== "agent_message_chunk" &&
146
+ variant !== "agent_thought_chunk" &&
147
+ variant !== "tool_call" &&
148
+ variant !== "tool_call_update") {
149
+ return;
150
+ }
151
+ const update = rawUpdate;
142
152
  const channelId = this.sessionIdToChannelId(sessionId);
143
- switch (variant) {
153
+ switch (update.sessionUpdate) {
144
154
  case "agent_message_chunk": {
145
- const delta = (update.content?.text ?? "");
155
+ const delta = update.content?.text ?? "";
146
156
  if (delta)
147
157
  this.appendToBlock(channelId, "text", delta);
148
158
  break;
@@ -150,7 +160,7 @@ export class BlockRenderer {
150
160
  case "agent_thought_chunk": {
151
161
  if (!this.verbose.showThinking)
152
162
  return; // skip — no block, no boundary
153
- const delta = (update.content?.text ?? "");
163
+ const delta = update.content?.text ?? "";
154
164
  if (delta)
155
165
  this.appendToBlock(channelId, "thinking", delta);
156
166
  break;
@@ -158,21 +168,20 @@ export class BlockRenderer {
158
168
  case "tool_call": {
159
169
  if (!this.verbose.showToolUse)
160
170
  return; // skip
161
- const title = update.title;
162
- if (title)
163
- this.appendToBlock(channelId, "tool", `🔧 ${title}\n`);
171
+ if (update.title)
172
+ this.appendToBlock(channelId, "tool", `🔧 ${update.title}\n`);
164
173
  break;
165
174
  }
166
175
  case "tool_call_update": {
167
176
  if (!this.verbose.showToolUse)
168
177
  return; // skip
169
- const title = (update.title ?? "tool");
170
- const status = update.status;
171
- if (status === "completed" || status === "error") {
178
+ const title = update.title ?? "tool";
179
+ if (update.status === "completed" || update.status === "error") {
172
180
  this.appendToBlock(channelId, "tool", `✅ ${title}\n`);
173
181
  }
174
182
  break;
175
183
  }
184
+ // Unknown / unconsumed variant — ignore.
176
185
  }
177
186
  }
178
187
  /**
@@ -271,6 +280,16 @@ export class BlockRenderer {
271
280
  const block = state.blocks.at(-1);
272
281
  if (!block || block.sealed || !block.content)
273
282
  return;
283
+ // Send-only mode: subclasses that don't override `editBlock` (e.g.
284
+ // QQ Bot, where the platform has no edit support) would otherwise
285
+ // POST a new message for every debounced flush, so the user sees a
286
+ // partial chunk followed by the full message as two separate
287
+ // deliveries. Defer intermediate sends; only `onTurnEnd` and block
288
+ // boundary transitions inside `appendToBlock` (which seal the block
289
+ // first) will actually POST.
290
+ if (!this.editBlock) {
291
+ return;
292
+ }
274
293
  const now = Date.now();
275
294
  if (now - state.lastEditMs < this.minEditIntervalMs) {
276
295
  // Throttled — reschedule for the remaining window
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * runChannelPlugin — shared main.ts boilerplate for every channel plugin.
3
+ *
4
+ * Each channel plugin used to have a ~120-line `main.ts` that was 85%
5
+ * identical across Slack, Telegram, Discord, DingTalk, WeCom, etc:
6
+ * connect to host, validate config keys, wire the standard sessionUpdate
7
+ * and extNotification handlers, create the stream handler, start the bot,
8
+ * wait for disconnect, stop. This helper absorbs that boilerplate so each
9
+ * plugin's `main.ts` reduces to ~20 lines — a factory for the bot and a
10
+ * factory for the stream handler.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { runChannelPlugin } from "@vibearound/plugin-channel-sdk";
16
+ * import { SlackBot } from "./bot.js";
17
+ * import { AgentStreamHandler } from "./agent-stream.js";
18
+ *
19
+ * runChannelPlugin({
20
+ * name: "vibearound-slack",
21
+ * version: "0.1.0",
22
+ * requiredConfig: ["bot_token", "app_token"],
23
+ * createBot: ({ config, agent, log, cacheDir }) =>
24
+ * new SlackBot(
25
+ * { bot_token: config.bot_token as string, app_token: config.app_token as string },
26
+ * agent,
27
+ * log,
28
+ * cacheDir,
29
+ * ),
30
+ * createStreamHandler: (bot, log, verbose) =>
31
+ * new AgentStreamHandler(bot, log, verbose),
32
+ * });
33
+ * ```
34
+ */
35
+ import type { Agent } from "@agentclientprotocol/sdk";
36
+ import type { SessionNotification } from "./types.js";
37
+ export type ChannelPluginLogger = (level: string, msg: string) => void;
38
+ export interface ChannelStreamHandler {
39
+ onSessionUpdate(params: SessionNotification): void;
40
+ onSystemText(text: string): void;
41
+ onAgentReady(agent: string, version: string): void;
42
+ onSessionReady(sessionId: string): void;
43
+ }
44
+ export interface ChannelBot<THandler extends ChannelStreamHandler = ChannelStreamHandler> {
45
+ setStreamHandler(handler: THandler): void;
46
+ start(): Promise<void> | void;
47
+ stop(): Promise<void> | void;
48
+ }
49
+ export interface CreateBotContext {
50
+ config: Record<string, unknown>;
51
+ agent: Agent;
52
+ log: ChannelPluginLogger;
53
+ cacheDir: string;
54
+ }
55
+ export interface VerboseOptions {
56
+ showThinking: boolean;
57
+ showToolUse: boolean;
58
+ }
59
+ export interface RunChannelPluginSpec<TBot extends ChannelBot<THandler>, THandler extends ChannelStreamHandler> {
60
+ /** Plugin name reported during ACP initialize (e.g. "vibearound-slack"). */
61
+ name: string;
62
+ /** Plugin version reported during ACP initialize. */
63
+ version: string;
64
+ /**
65
+ * Config keys that MUST be present on `meta.config`. Plugin startup
66
+ * fails with a clear error if any are missing. Keep to primitives
67
+ * (strings/booleans); deeper validation belongs in the bot constructor.
68
+ */
69
+ requiredConfig?: string[];
70
+ /** Factory: build the platform bot from host-supplied config + agent. */
71
+ createBot: (ctx: CreateBotContext) => TBot | Promise<TBot>;
72
+ /**
73
+ * Factory: build the agent stream handler for this plugin. The handler
74
+ * is wired to the bot via `bot.setStreamHandler(handler)` before the
75
+ * bot is started.
76
+ */
77
+ createStreamHandler: (bot: TBot, log: ChannelPluginLogger, verbose: VerboseOptions) => THandler;
78
+ /**
79
+ * Optional hook invoked after the bot has been constructed but before
80
+ * `start()` is called. Use this for one-off initialization that needs
81
+ * to log diagnostic info (e.g. Telegram's `probe()`).
82
+ */
83
+ afterCreate?: (bot: TBot, log: ChannelPluginLogger) => Promise<void> | void;
84
+ }
85
+ /**
86
+ * Run a channel plugin to completion.
87
+ *
88
+ * Performs the ACP initialize handshake, validates required config,
89
+ * constructs the bot + stream handler, starts the bot, waits for the host
90
+ * connection to close, then stops the bot and exits the process.
91
+ *
92
+ * Never returns under normal operation — the process exits at the end.
93
+ */
94
+ export declare function runChannelPlugin<TBot extends ChannelBot<THandler>, THandler extends ChannelStreamHandler>(spec: RunChannelPluginSpec<TBot, THandler>): Promise<void>;
95
+ //# sourceMappingURL=run-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-plugin.d.ts","sourceRoot":"","sources":["../src/run-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAItD,OAAO,KAAK,EAGV,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAMpB,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,eAAe,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACnD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,UAAU,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB;IACtF,gBAAgB,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,mBAAmB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB,CACnC,IAAI,SAAS,UAAU,CAAC,QAAQ,CAAC,EACjC,QAAQ,SAAS,oBAAoB;IAErC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IAEb,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,yEAAyE;IACzE,SAAS,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;OAIG;IACH,mBAAmB,EAAE,CACnB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,mBAAmB,EACxB,OAAO,EAAE,cAAc,KACpB,QAAQ,CAAC;IAEd;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7E;AAMD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,SAAS,UAAU,CAAC,QAAQ,CAAC,EACjC,QAAQ,SAAS,oBAAoB,EACrC,IAAI,EAAE,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3D"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * runChannelPlugin — shared main.ts boilerplate for every channel plugin.
3
+ *
4
+ * Each channel plugin used to have a ~120-line `main.ts` that was 85%
5
+ * identical across Slack, Telegram, Discord, DingTalk, WeCom, etc:
6
+ * connect to host, validate config keys, wire the standard sessionUpdate
7
+ * and extNotification handlers, create the stream handler, start the bot,
8
+ * wait for disconnect, stop. This helper absorbs that boilerplate so each
9
+ * plugin's `main.ts` reduces to ~20 lines — a factory for the bot and a
10
+ * factory for the stream handler.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { runChannelPlugin } from "@vibearound/plugin-channel-sdk";
16
+ * import { SlackBot } from "./bot.js";
17
+ * import { AgentStreamHandler } from "./agent-stream.js";
18
+ *
19
+ * runChannelPlugin({
20
+ * name: "vibearound-slack",
21
+ * version: "0.1.0",
22
+ * requiredConfig: ["bot_token", "app_token"],
23
+ * createBot: ({ config, agent, log, cacheDir }) =>
24
+ * new SlackBot(
25
+ * { bot_token: config.bot_token as string, app_token: config.app_token as string },
26
+ * agent,
27
+ * log,
28
+ * cacheDir,
29
+ * ),
30
+ * createStreamHandler: (bot, log, verbose) =>
31
+ * new AgentStreamHandler(bot, log, verbose),
32
+ * });
33
+ * ```
34
+ */
35
+ import os from "node:os";
36
+ import path from "node:path";
37
+ import { connectToHost, normalizeExtMethod } from "./connection.js";
38
+ import { extractErrorMessage } from "./errors.js";
39
+ // ---------------------------------------------------------------------------
40
+ // Implementation
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * Run a channel plugin to completion.
44
+ *
45
+ * Performs the ACP initialize handshake, validates required config,
46
+ * constructs the bot + stream handler, starts the bot, waits for the host
47
+ * connection to close, then stops the bot and exits the process.
48
+ *
49
+ * Never returns under normal operation — the process exits at the end.
50
+ */
51
+ export async function runChannelPlugin(spec) {
52
+ const prefix = `[${spec.name.replace(/^vibearound-/, "")}-plugin]`;
53
+ const log = (level, msg) => {
54
+ process.stderr.write(`${prefix}[${level}] ${msg}\n`);
55
+ };
56
+ try {
57
+ await runInner(spec, log);
58
+ }
59
+ catch (err) {
60
+ log("error", `fatal: ${extractErrorMessage(err)}`);
61
+ process.exit(1);
62
+ }
63
+ }
64
+ async function runInner(spec, log) {
65
+ log("info", "initializing ACP connection...");
66
+ let streamHandler = null;
67
+ const { agent, meta, agentInfo, conn } = await connectToHost({ name: spec.name, version: spec.version }, () => ({
68
+ async sessionUpdate(params) {
69
+ streamHandler?.onSessionUpdate(params);
70
+ },
71
+ async requestPermission(params) {
72
+ const first = params.options?.[0];
73
+ if (first) {
74
+ return { outcome: { outcome: "selected", optionId: first.optionId } };
75
+ }
76
+ throw new Error("No permission options provided");
77
+ },
78
+ async extNotification(method, params) {
79
+ switch (normalizeExtMethod(method)) {
80
+ case "channel/system_text": {
81
+ const text = params.text;
82
+ streamHandler?.onSystemText(text);
83
+ break;
84
+ }
85
+ case "channel/agent_ready": {
86
+ const agentName = params.agent;
87
+ const version = params.version;
88
+ log("info", `agent_ready: ${agentName} v${version}`);
89
+ streamHandler?.onAgentReady(agentName, version);
90
+ break;
91
+ }
92
+ case "channel/session_ready": {
93
+ const sessionId = params.sessionId;
94
+ log("info", `session_ready: ${sessionId}`);
95
+ streamHandler?.onSessionReady(sessionId);
96
+ break;
97
+ }
98
+ default:
99
+ log("warn", `unhandled ext_notification: ${method}`);
100
+ }
101
+ },
102
+ }));
103
+ const config = meta.config;
104
+ // Validate required config keys up front so a misconfigured plugin fails
105
+ // with a clear error instead of some downstream "undefined is not a
106
+ // string" crash in the bot constructor.
107
+ for (const key of spec.requiredConfig ?? []) {
108
+ if (config[key] === undefined || config[key] === null || config[key] === "") {
109
+ throw new Error(`${key} is required in config`);
110
+ }
111
+ }
112
+ const cacheDir = meta.cacheDir ?? path.join(os.homedir(), ".vibearound", ".cache");
113
+ log("info", `initialized, host=${agentInfo.name ?? "unknown"} cacheDir=${cacheDir}`);
114
+ const bot = await spec.createBot({ config, agent, log, cacheDir });
115
+ if (spec.afterCreate) {
116
+ await spec.afterCreate(bot, log);
117
+ }
118
+ const verboseRaw = config.verbose;
119
+ const verbose = {
120
+ showThinking: verboseRaw?.show_thinking ?? false,
121
+ showToolUse: verboseRaw?.show_tool_use ?? false,
122
+ };
123
+ streamHandler = spec.createStreamHandler(bot, log, verbose);
124
+ bot.setStreamHandler(streamHandler);
125
+ await bot.start();
126
+ log("info", "plugin started");
127
+ await conn.closed;
128
+ log("info", "connection closed, shutting down");
129
+ await bot.stop();
130
+ process.exit(0);
131
+ }
132
+ //# sourceMappingURL=run-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-plugin.js","sourceRoot":"","sources":["../src/run-plugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibearound/plugin-channel-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "VibeAround Plugin SDK — base classes and utilities for building channel plugins",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/errors.ts ADDED
@@ -0,0 +1,29 @@
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
+ /**
11
+ * Extract a human-readable message from an unknown thrown value.
12
+ *
13
+ * Prefers `Error.message`, falls back to a non-circular JSON stringify for
14
+ * objects, and finally to `String(e)` for primitives.
15
+ */
16
+ export function extractErrorMessage(e: unknown): string {
17
+ if (e instanceof Error) return e.message;
18
+ if (typeof e === "string") return e;
19
+ if (e && typeof e === "object") {
20
+ const msg = (e as { message?: unknown }).message;
21
+ if (typeof msg === "string") return msg;
22
+ try {
23
+ return JSON.stringify(e);
24
+ } catch {
25
+ return String(e);
26
+ }
27
+ }
28
+ return String(e);
29
+ }
package/src/index.ts CHANGED
@@ -57,9 +57,24 @@
57
57
  export { connectToHost, normalizeExtMethod, redirectConsoleToStderr } from "./connection.js";
58
58
  export type { PluginInfo, ConnectResult, AgentInfo } from "./connection.js";
59
59
 
60
+ // Error normalization
61
+ export { extractErrorMessage } from "./errors.js";
62
+
63
+ // Plugin runner (absorbs the main.ts boilerplate)
64
+ export { runChannelPlugin } from "./run-plugin.js";
65
+ export type {
66
+ ChannelBot,
67
+ ChannelPluginLogger,
68
+ ChannelStreamHandler,
69
+ CreateBotContext,
70
+ RunChannelPluginSpec,
71
+ VerboseOptions,
72
+ } from "./run-plugin.js";
73
+
60
74
  // Block renderer
61
75
  export { BlockRenderer } from "./renderer.js";
62
76
 
77
+
63
78
  // Types (re-exports ACP SDK types + SDK-specific types)
64
79
  export type {
65
80
  // ACP SDK
package/src/renderer.ts CHANGED
@@ -56,6 +56,44 @@
56
56
  import type { SessionNotification } from "@agentclientprotocol/sdk";
57
57
  import type { BlockKind, BlockRendererOptions, VerboseConfig } from "./types.js";
58
58
 
59
+ // ---------------------------------------------------------------------------
60
+ // Local ACP session-update narrowing
61
+ // ---------------------------------------------------------------------------
62
+ //
63
+ // The ACP SDK's `SessionNotification.update` is a discriminated union keyed on
64
+ // the `sessionUpdate` field, but the shape we get back at runtime varies by
65
+ // version. We only consume four variants here, so we define a narrow local
66
+ // view that documents exactly the fields this renderer depends on. A mismatch
67
+ // against the upstream type will show up as a compile error when the SDK is
68
+ // bumped, instead of silently producing `undefined` at runtime.
69
+
70
+ interface AgentMessageChunk {
71
+ sessionUpdate: "agent_message_chunk";
72
+ content?: { text?: string };
73
+ }
74
+
75
+ interface AgentThoughtChunk {
76
+ sessionUpdate: "agent_thought_chunk";
77
+ content?: { text?: string };
78
+ }
79
+
80
+ interface ToolCall {
81
+ sessionUpdate: "tool_call";
82
+ title?: string;
83
+ }
84
+
85
+ interface ToolCallUpdate {
86
+ sessionUpdate: "tool_call_update";
87
+ title?: string;
88
+ status?: string;
89
+ }
90
+
91
+ type ConsumedSessionUpdate =
92
+ | AgentMessageChunk
93
+ | AgentThoughtChunk
94
+ | ToolCall
95
+ | ToolCallUpdate;
96
+
59
97
  // ---------------------------------------------------------------------------
60
98
  // Internal state types
61
99
  // ---------------------------------------------------------------------------
@@ -210,38 +248,49 @@ export abstract class BlockRenderer<TRef = string> {
210
248
  */
211
249
  onSessionUpdate(notification: SessionNotification): void {
212
250
  const sessionId = notification.sessionId;
213
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
214
- const update = notification.update as any;
215
- const variant = update.sessionUpdate as string;
251
+ // Narrow through the local ConsumedSessionUpdate union — see the type
252
+ // declaration above this class for why we re-declare it locally instead
253
+ // of importing the SDK's own union. Variants other than the four we
254
+ // handle are treated as no-ops.
255
+ const rawUpdate = notification.update as unknown as { sessionUpdate: string };
256
+ const variant = rawUpdate.sessionUpdate;
257
+ if (
258
+ variant !== "agent_message_chunk" &&
259
+ variant !== "agent_thought_chunk" &&
260
+ variant !== "tool_call" &&
261
+ variant !== "tool_call_update"
262
+ ) {
263
+ return;
264
+ }
265
+ const update = rawUpdate as ConsumedSessionUpdate;
216
266
  const channelId = this.sessionIdToChannelId(sessionId);
217
267
 
218
- switch (variant) {
268
+ switch (update.sessionUpdate) {
219
269
  case "agent_message_chunk": {
220
- const delta = (update.content?.text ?? "") as string;
270
+ const delta = update.content?.text ?? "";
221
271
  if (delta) this.appendToBlock(channelId, "text", delta);
222
272
  break;
223
273
  }
224
274
  case "agent_thought_chunk": {
225
275
  if (!this.verbose.showThinking) return; // skip — no block, no boundary
226
- const delta = (update.content?.text ?? "") as string;
276
+ const delta = update.content?.text ?? "";
227
277
  if (delta) this.appendToBlock(channelId, "thinking", delta);
228
278
  break;
229
279
  }
230
280
  case "tool_call": {
231
281
  if (!this.verbose.showToolUse) return; // skip
232
- const title = update.title as string | undefined;
233
- if (title) this.appendToBlock(channelId, "tool", `🔧 ${title}\n`);
282
+ if (update.title) this.appendToBlock(channelId, "tool", `🔧 ${update.title}\n`);
234
283
  break;
235
284
  }
236
285
  case "tool_call_update": {
237
286
  if (!this.verbose.showToolUse) return; // skip
238
- const title = (update.title ?? "tool") as string;
239
- const status = update.status as string | undefined;
240
- if (status === "completed" || status === "error") {
287
+ const title = update.title ?? "tool";
288
+ if (update.status === "completed" || update.status === "error") {
241
289
  this.appendToBlock(channelId, "tool", `✅ ${title}\n`);
242
290
  }
243
291
  break;
244
292
  }
293
+ // Unknown / unconsumed variant — ignore.
245
294
  }
246
295
  }
247
296
 
@@ -349,6 +398,17 @@ export abstract class BlockRenderer<TRef = string> {
349
398
  const block = state.blocks.at(-1);
350
399
  if (!block || block.sealed || !block.content) return;
351
400
 
401
+ // Send-only mode: subclasses that don't override `editBlock` (e.g.
402
+ // QQ Bot, where the platform has no edit support) would otherwise
403
+ // POST a new message for every debounced flush, so the user sees a
404
+ // partial chunk followed by the full message as two separate
405
+ // deliveries. Defer intermediate sends; only `onTurnEnd` and block
406
+ // boundary transitions inside `appendToBlock` (which seal the block
407
+ // first) will actually POST.
408
+ if (!this.editBlock) {
409
+ return;
410
+ }
411
+
352
412
  const now = Date.now();
353
413
  if (now - state.lastEditMs < this.minEditIntervalMs) {
354
414
  // Throttled — reschedule for the remaining window
@@ -0,0 +1,249 @@
1
+ /**
2
+ * runChannelPlugin — shared main.ts boilerplate for every channel plugin.
3
+ *
4
+ * Each channel plugin used to have a ~120-line `main.ts` that was 85%
5
+ * identical across Slack, Telegram, Discord, DingTalk, WeCom, etc:
6
+ * connect to host, validate config keys, wire the standard sessionUpdate
7
+ * and extNotification handlers, create the stream handler, start the bot,
8
+ * wait for disconnect, stop. This helper absorbs that boilerplate so each
9
+ * plugin's `main.ts` reduces to ~20 lines — a factory for the bot and a
10
+ * factory for the stream handler.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { runChannelPlugin } from "@vibearound/plugin-channel-sdk";
16
+ * import { SlackBot } from "./bot.js";
17
+ * import { AgentStreamHandler } from "./agent-stream.js";
18
+ *
19
+ * runChannelPlugin({
20
+ * name: "vibearound-slack",
21
+ * version: "0.1.0",
22
+ * requiredConfig: ["bot_token", "app_token"],
23
+ * createBot: ({ config, agent, log, cacheDir }) =>
24
+ * new SlackBot(
25
+ * { bot_token: config.bot_token as string, app_token: config.app_token as string },
26
+ * agent,
27
+ * log,
28
+ * cacheDir,
29
+ * ),
30
+ * createStreamHandler: (bot, log, verbose) =>
31
+ * new AgentStreamHandler(bot, log, verbose),
32
+ * });
33
+ * ```
34
+ */
35
+
36
+ import os from "node:os";
37
+ import path from "node:path";
38
+ import type { Agent } from "@agentclientprotocol/sdk";
39
+
40
+ import { connectToHost, normalizeExtMethod } from "./connection.js";
41
+ import { extractErrorMessage } from "./errors.js";
42
+ import type {
43
+ RequestPermissionRequest,
44
+ RequestPermissionResponse,
45
+ SessionNotification,
46
+ } from "./types.js";
47
+
48
+ // ---------------------------------------------------------------------------
49
+ // Public types
50
+ // ---------------------------------------------------------------------------
51
+
52
+ export type ChannelPluginLogger = (level: string, msg: string) => void;
53
+
54
+ export interface ChannelStreamHandler {
55
+ onSessionUpdate(params: SessionNotification): void;
56
+ onSystemText(text: string): void;
57
+ onAgentReady(agent: string, version: string): void;
58
+ onSessionReady(sessionId: string): void;
59
+ }
60
+
61
+ export interface ChannelBot<THandler extends ChannelStreamHandler = ChannelStreamHandler> {
62
+ setStreamHandler(handler: THandler): void;
63
+ start(): Promise<void> | void;
64
+ stop(): Promise<void> | void;
65
+ }
66
+
67
+ export interface CreateBotContext {
68
+ config: Record<string, unknown>;
69
+ agent: Agent;
70
+ log: ChannelPluginLogger;
71
+ cacheDir: string;
72
+ }
73
+
74
+ export interface VerboseOptions {
75
+ showThinking: boolean;
76
+ showToolUse: boolean;
77
+ }
78
+
79
+ export interface RunChannelPluginSpec<
80
+ TBot extends ChannelBot<THandler>,
81
+ THandler extends ChannelStreamHandler,
82
+ > {
83
+ /** Plugin name reported during ACP initialize (e.g. "vibearound-slack"). */
84
+ name: string;
85
+
86
+ /** Plugin version reported during ACP initialize. */
87
+ version: string;
88
+
89
+ /**
90
+ * Config keys that MUST be present on `meta.config`. Plugin startup
91
+ * fails with a clear error if any are missing. Keep to primitives
92
+ * (strings/booleans); deeper validation belongs in the bot constructor.
93
+ */
94
+ requiredConfig?: string[];
95
+
96
+ /** Factory: build the platform bot from host-supplied config + agent. */
97
+ createBot: (ctx: CreateBotContext) => TBot | Promise<TBot>;
98
+
99
+ /**
100
+ * Factory: build the agent stream handler for this plugin. The handler
101
+ * is wired to the bot via `bot.setStreamHandler(handler)` before the
102
+ * bot is started.
103
+ */
104
+ createStreamHandler: (
105
+ bot: TBot,
106
+ log: ChannelPluginLogger,
107
+ verbose: VerboseOptions,
108
+ ) => THandler;
109
+
110
+ /**
111
+ * Optional hook invoked after the bot has been constructed but before
112
+ * `start()` is called. Use this for one-off initialization that needs
113
+ * to log diagnostic info (e.g. Telegram's `probe()`).
114
+ */
115
+ afterCreate?: (bot: TBot, log: ChannelPluginLogger) => Promise<void> | void;
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Implementation
120
+ // ---------------------------------------------------------------------------
121
+
122
+ /**
123
+ * Run a channel plugin to completion.
124
+ *
125
+ * Performs the ACP initialize handshake, validates required config,
126
+ * constructs the bot + stream handler, starts the bot, waits for the host
127
+ * connection to close, then stops the bot and exits the process.
128
+ *
129
+ * Never returns under normal operation — the process exits at the end.
130
+ */
131
+ export async function runChannelPlugin<
132
+ TBot extends ChannelBot<THandler>,
133
+ THandler extends ChannelStreamHandler,
134
+ >(spec: RunChannelPluginSpec<TBot, THandler>): Promise<void> {
135
+ const prefix = `[${spec.name.replace(/^vibearound-/, "")}-plugin]`;
136
+ const log: ChannelPluginLogger = (level, msg) => {
137
+ process.stderr.write(`${prefix}[${level}] ${msg}\n`);
138
+ };
139
+
140
+ try {
141
+ await runInner(spec, log);
142
+ } catch (err) {
143
+ log("error", `fatal: ${extractErrorMessage(err)}`);
144
+ process.exit(1);
145
+ }
146
+ }
147
+
148
+ async function runInner<
149
+ TBot extends ChannelBot<THandler>,
150
+ THandler extends ChannelStreamHandler,
151
+ >(
152
+ spec: RunChannelPluginSpec<TBot, THandler>,
153
+ log: ChannelPluginLogger,
154
+ ): Promise<void> {
155
+ log("info", "initializing ACP connection...");
156
+
157
+ let streamHandler: THandler | null = null;
158
+
159
+ const { agent, meta, agentInfo, conn } = await connectToHost(
160
+ { name: spec.name, version: spec.version },
161
+ () => ({
162
+ async sessionUpdate(params: SessionNotification): Promise<void> {
163
+ streamHandler?.onSessionUpdate(params);
164
+ },
165
+
166
+ async requestPermission(
167
+ params: RequestPermissionRequest,
168
+ ): Promise<RequestPermissionResponse> {
169
+ const first = params.options?.[0];
170
+ if (first) {
171
+ return { outcome: { outcome: "selected", optionId: first.optionId } };
172
+ }
173
+ throw new Error("No permission options provided");
174
+ },
175
+
176
+ async extNotification(
177
+ method: string,
178
+ params: Record<string, unknown>,
179
+ ): Promise<void> {
180
+ switch (normalizeExtMethod(method)) {
181
+ case "channel/system_text": {
182
+ const text = params.text as string;
183
+ streamHandler?.onSystemText(text);
184
+ break;
185
+ }
186
+ case "channel/agent_ready": {
187
+ const agentName = params.agent as string;
188
+ const version = params.version as string;
189
+ log("info", `agent_ready: ${agentName} v${version}`);
190
+ streamHandler?.onAgentReady(agentName, version);
191
+ break;
192
+ }
193
+ case "channel/session_ready": {
194
+ const sessionId = params.sessionId as string;
195
+ log("info", `session_ready: ${sessionId}`);
196
+ streamHandler?.onSessionReady(sessionId);
197
+ break;
198
+ }
199
+ default:
200
+ log("warn", `unhandled ext_notification: ${method}`);
201
+ }
202
+ },
203
+ }),
204
+ );
205
+
206
+ const config = meta.config;
207
+
208
+ // Validate required config keys up front so a misconfigured plugin fails
209
+ // with a clear error instead of some downstream "undefined is not a
210
+ // string" crash in the bot constructor.
211
+ for (const key of spec.requiredConfig ?? []) {
212
+ if (config[key] === undefined || config[key] === null || config[key] === "") {
213
+ throw new Error(`${key} is required in config`);
214
+ }
215
+ }
216
+
217
+ const cacheDir =
218
+ meta.cacheDir ?? path.join(os.homedir(), ".vibearound", ".cache");
219
+
220
+ log(
221
+ "info",
222
+ `initialized, host=${agentInfo.name ?? "unknown"} cacheDir=${cacheDir}`,
223
+ );
224
+
225
+ const bot = await spec.createBot({ config, agent, log, cacheDir });
226
+
227
+ if (spec.afterCreate) {
228
+ await spec.afterCreate(bot, log);
229
+ }
230
+
231
+ const verboseRaw = config.verbose as
232
+ | { show_thinking?: boolean; show_tool_use?: boolean }
233
+ | undefined;
234
+ const verbose: VerboseOptions = {
235
+ showThinking: verboseRaw?.show_thinking ?? false,
236
+ showToolUse: verboseRaw?.show_tool_use ?? false,
237
+ };
238
+
239
+ streamHandler = spec.createStreamHandler(bot, log, verbose);
240
+ bot.setStreamHandler(streamHandler);
241
+
242
+ await bot.start();
243
+ log("info", "plugin started");
244
+
245
+ await conn.closed;
246
+ log("info", "connection closed, shutting down");
247
+ await bot.stop();
248
+ process.exit(0);
249
+ }