@nextclaw/extension-sdk 0.1.11 → 0.1.12-beta.1

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/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { ChannelConfigGetRequest, ChannelConfigGetResponse, ChannelFileContent, ChannelImageContent, ChannelMessageContent, ChannelSubmittedAttachment, ChannelSubmittedMessage, ChannelTextContent, ExtensionCapabilities, ExtensionCapabilityHandler, ExtensionCapabilityPayload, ExtensionChannel, ExtensionChannelConfig, ExtensionChannels, ExtensionRequest, ExtensionRequestHandler, ExtensionRequestResponse, ExtensionTransportEnvelope, NextClawExtensionOptions, NextClawExtensionWebSocketLike } from "./types/extension-sdk.types.js";
1
+ import { ChannelCommandExecuteRequest, ChannelCommandExecuteResponse, ChannelCommandListRequest, ChannelCommandListResponse, ChannelCommandOption, ChannelCommandOptionType, ChannelCommandSpec, ChannelConfigGetRequest, ChannelConfigGetResponse, ChannelFileContent, ChannelImageContent, ChannelMessageContent, ChannelSubmittedAttachment, ChannelSubmittedMessage, ChannelTextContent, ExtensionCapabilities, ExtensionCapabilityHandler, ExtensionCapabilityPayload, ExtensionChannel, ExtensionChannelCommands, ExtensionChannelConfig, ExtensionChannels, ExtensionRequest, ExtensionRequestHandler, ExtensionRequestResponse, ExtensionTransportEnvelope, NextClawExtensionOptions, NextClawExtensionWebSocketLike } from "./types/extension-sdk.types.js";
2
2
  import { NextClawExtension } from "./services/extension-client.service.js";
3
+ import { ChannelTypingController, ChannelTypingControllerOptions } from "./services/channel-typing-controller.service.js";
3
4
  import { BusChannelCreateContext, BusChannelExtensionDefinition, BusChannelInboundMessage, BusChannelMessageBus, BusChannelRuntime, ChannelExtensionContext, ChannelExtensionDefinition, ChannelSubmittedMessageInput, ExtensionChannelAdapter, ExtensionChannelController, startBusChannelExtension, startChannelExtension, warnNcpEventError } from "./services/extension-channel-controller.service.js";
4
- export { type BusChannelCreateContext, type BusChannelExtensionDefinition, type BusChannelInboundMessage, type BusChannelMessageBus, type BusChannelRuntime, type ChannelConfigGetRequest, type ChannelConfigGetResponse, type ChannelExtensionContext, type ChannelExtensionDefinition, type ChannelFileContent, type ChannelImageContent, type ChannelMessageContent, type ChannelSubmittedAttachment, type ChannelSubmittedMessage, type ChannelSubmittedMessageInput, type ChannelTextContent, type ExtensionCapabilities, type ExtensionCapabilityHandler, type ExtensionCapabilityPayload, type ExtensionChannel, type ExtensionChannelAdapter, type ExtensionChannelConfig, ExtensionChannelController, type ExtensionChannels, type ExtensionRequest, type ExtensionRequestHandler, type ExtensionRequestResponse, type ExtensionTransportEnvelope, NextClawExtension, type NextClawExtensionOptions, type NextClawExtensionWebSocketLike, startBusChannelExtension, startChannelExtension, warnNcpEventError };
5
+ export { type BusChannelCreateContext, type BusChannelExtensionDefinition, type BusChannelInboundMessage, type BusChannelMessageBus, type BusChannelRuntime, type ChannelCommandExecuteRequest, type ChannelCommandExecuteResponse, type ChannelCommandListRequest, type ChannelCommandListResponse, type ChannelCommandOption, type ChannelCommandOptionType, type ChannelCommandSpec, type ChannelConfigGetRequest, type ChannelConfigGetResponse, type ChannelExtensionContext, type ChannelExtensionDefinition, type ChannelFileContent, type ChannelImageContent, type ChannelMessageContent, type ChannelSubmittedAttachment, type ChannelSubmittedMessage, type ChannelSubmittedMessageInput, type ChannelTextContent, ChannelTypingController, type ChannelTypingControllerOptions, type ExtensionCapabilities, type ExtensionCapabilityHandler, type ExtensionCapabilityPayload, type ExtensionChannel, type ExtensionChannelAdapter, type ExtensionChannelCommands, type ExtensionChannelConfig, ExtensionChannelController, type ExtensionChannels, type ExtensionRequest, type ExtensionRequestHandler, type ExtensionRequestResponse, type ExtensionTransportEnvelope, NextClawExtension, type NextClawExtensionOptions, type NextClawExtensionWebSocketLike, startBusChannelExtension, startChannelExtension, warnNcpEventError };
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import { NextClawExtension } from "./services/extension-client.service.js";
2
+ import { ChannelTypingController } from "./services/channel-typing-controller.service.js";
2
3
  import { ExtensionChannelController, startBusChannelExtension, startChannelExtension, warnNcpEventError } from "./services/extension-channel-controller.service.js";
3
- export { ExtensionChannelController, NextClawExtension, startBusChannelExtension, startChannelExtension, warnNcpEventError };
4
+ export { ChannelTypingController, ExtensionChannelController, NextClawExtension, startBusChannelExtension, startChannelExtension, warnNcpEventError };
@@ -0,0 +1,19 @@
1
+ //#region src/services/channel-typing-controller.service.d.ts
2
+ type ChannelTypingControllerOptions = {
3
+ heartbeatMs: number;
4
+ autoStopMs: number;
5
+ sendTyping: (targetId: string) => Promise<void> | void;
6
+ };
7
+ declare class ChannelTypingController {
8
+ private readonly heartbeatMs;
9
+ private readonly autoStopMs;
10
+ private readonly sendTyping;
11
+ private readonly tasks;
12
+ constructor(options: ChannelTypingControllerOptions);
13
+ start: (targetId: string) => void;
14
+ stop: (targetId: string) => void;
15
+ stopAll: () => void;
16
+ }
17
+ //#endregion
18
+ export { ChannelTypingController, ChannelTypingControllerOptions };
19
+ //# sourceMappingURL=channel-typing-controller.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-typing-controller.service.d.ts","names":[],"sources":["../../src/services/channel-typing-controller.service.ts"],"mappings":";KAAY,8BAAA;EACV,WAAA;EACA,UAAA;EACA,UAAA,GAAa,QAAA,aAAqB,OAAA;AAAA;AAAA,cAQvB,uBAAA;EAAA,iBACM,WAAA;EAAA,iBACA,UAAA;EAAA,iBACA,UAAA;EAAA,iBACA,KAAA;cAEL,OAAA,EAAS,8BAAA;EAMrB,KAAA,GAAS,QAAA;EAkBT,IAAA,GAAQ,QAAA;EAUR,OAAA;AAAA"}
@@ -0,0 +1,40 @@
1
+ //#region src/services/channel-typing-controller.service.ts
2
+ var ChannelTypingController = class {
3
+ heartbeatMs;
4
+ autoStopMs;
5
+ sendTyping;
6
+ tasks = /* @__PURE__ */ new Map();
7
+ constructor(options) {
8
+ this.heartbeatMs = Math.max(1e3, Math.floor(options.heartbeatMs));
9
+ this.autoStopMs = Math.max(this.heartbeatMs, Math.floor(options.autoStopMs));
10
+ this.sendTyping = options.sendTyping;
11
+ }
12
+ start = (targetId) => {
13
+ this.stop(targetId);
14
+ this.sendTyping(targetId);
15
+ const heartbeat = setInterval(() => {
16
+ this.sendTyping(targetId);
17
+ }, this.heartbeatMs);
18
+ const autoStop = setTimeout(() => {
19
+ this.stop(targetId);
20
+ }, this.autoStopMs);
21
+ this.tasks.set(targetId, {
22
+ heartbeat,
23
+ autoStop
24
+ });
25
+ };
26
+ stop = (targetId) => {
27
+ const task = this.tasks.get(targetId);
28
+ if (!task) return;
29
+ clearInterval(task.heartbeat);
30
+ clearTimeout(task.autoStop);
31
+ this.tasks.delete(targetId);
32
+ };
33
+ stopAll = () => {
34
+ for (const targetId of this.tasks.keys()) this.stop(targetId);
35
+ };
36
+ };
37
+ //#endregion
38
+ export { ChannelTypingController };
39
+
40
+ //# sourceMappingURL=channel-typing-controller.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-typing-controller.service.js","names":[],"sources":["../../src/services/channel-typing-controller.service.ts"],"sourcesContent":["export type ChannelTypingControllerOptions = {\n heartbeatMs: number;\n autoStopMs: number;\n sendTyping: (targetId: string) => Promise<void> | void;\n};\n\ntype TypingTask = {\n heartbeat: NodeJS.Timeout;\n autoStop: NodeJS.Timeout;\n};\n\nexport class ChannelTypingController {\n private readonly heartbeatMs: number;\n private readonly autoStopMs: number;\n private readonly sendTyping: (targetId: string) => Promise<void> | void;\n private readonly tasks = new Map<string, TypingTask>();\n\n constructor(options: ChannelTypingControllerOptions) {\n this.heartbeatMs = Math.max(1000, Math.floor(options.heartbeatMs));\n this.autoStopMs = Math.max(this.heartbeatMs, Math.floor(options.autoStopMs));\n this.sendTyping = options.sendTyping;\n }\n\n start = (targetId: string): void => {\n this.stop(targetId);\n void this.sendTyping(targetId);\n\n const heartbeat = setInterval(() => {\n void this.sendTyping(targetId);\n }, this.heartbeatMs);\n\n const autoStop = setTimeout(() => {\n this.stop(targetId);\n }, this.autoStopMs);\n\n this.tasks.set(targetId, {\n heartbeat,\n autoStop,\n });\n };\n\n stop = (targetId: string): void => {\n const task = this.tasks.get(targetId);\n if (!task) {\n return;\n }\n clearInterval(task.heartbeat);\n clearTimeout(task.autoStop);\n this.tasks.delete(targetId);\n };\n\n stopAll = (): void => {\n for (const targetId of this.tasks.keys()) {\n this.stop(targetId);\n }\n };\n}\n"],"mappings":";AAWA,IAAa,0BAAb,MAAqC;CACnC;CACA;CACA;CACA,wBAAyB,IAAI,KAAyB;CAEtD,YAAY,SAAyC;AACnD,OAAK,cAAc,KAAK,IAAI,KAAM,KAAK,MAAM,QAAQ,YAAY,CAAC;AAClE,OAAK,aAAa,KAAK,IAAI,KAAK,aAAa,KAAK,MAAM,QAAQ,WAAW,CAAC;AAC5E,OAAK,aAAa,QAAQ;;CAG5B,SAAS,aAA2B;AAClC,OAAK,KAAK,SAAS;AACd,OAAK,WAAW,SAAS;EAE9B,MAAM,YAAY,kBAAkB;AAC7B,QAAK,WAAW,SAAS;KAC7B,KAAK,YAAY;EAEpB,MAAM,WAAW,iBAAiB;AAChC,QAAK,KAAK,SAAS;KAClB,KAAK,WAAW;AAEnB,OAAK,MAAM,IAAI,UAAU;GACvB;GACA;GACD,CAAC;;CAGJ,QAAQ,aAA2B;EACjC,MAAM,OAAO,KAAK,MAAM,IAAI,SAAS;AACrC,MAAI,CAAC,KACH;AAEF,gBAAc,KAAK,UAAU;AAC7B,eAAa,KAAK,SAAS;AAC3B,OAAK,MAAM,OAAO,SAAS;;CAG7B,gBAAsB;AACpB,OAAK,MAAM,YAAY,KAAK,MAAM,MAAM,CACtC,MAAK,KAAK,SAAS"}
@@ -32,6 +32,14 @@ type BusChannelMessageBus = {
32
32
  type BusChannelRuntime = {
33
33
  start: () => Promise<void>;
34
34
  stop: () => Promise<void>;
35
+ handleControlMessage?: (message: {
36
+ channel: string;
37
+ chatId: string;
38
+ content: string;
39
+ replyTo?: string | null;
40
+ media: string[];
41
+ metadata: Record<string, unknown>;
42
+ }) => Promise<boolean>;
35
43
  send: (message: {
36
44
  channel: string;
37
45
  chatId: string;
@@ -44,6 +52,7 @@ type BusChannelRuntime = {
44
52
  type BusChannelCreateContext<TConfig, TBus = BusChannelMessageBus> = {
45
53
  config: TConfig;
46
54
  bus: TBus;
55
+ channel: ExtensionChannel;
47
56
  };
48
57
  type BusChannelExtensionDefinition<TConfig, TBus = BusChannelMessageBus> = {
49
58
  channelId: string;
@@ -63,7 +72,7 @@ type ChannelExtensionContext = {
63
72
  };
64
73
  type ChannelExtensionDefinition<TConfig, TInbound> = {
65
74
  channelId: string;
66
- createAdapter: () => ExtensionChannelAdapter<TConfig, TInbound>;
75
+ createAdapter: (context: ChannelExtensionContext) => ExtensionChannelAdapter<TConfig, TInbound>;
67
76
  mapInbound: ExtensionChannelInboundMapper<TInbound>;
68
77
  createAuthCapability?: (context: ChannelExtensionContext) => object;
69
78
  onNcpEventError?: (error: unknown, event: NcpEndpointEvent) => void | Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"extension-channel-controller.service.d.ts","names":[],"sources":["../../src/services/extension-channel-controller.service.ts"],"mappings":"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"}
1
+ {"version":3,"file":"extension-channel-controller.service.d.ts","names":[],"sources":["../../src/services/extension-channel-controller.service.ts"],"mappings":"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"}
@@ -83,8 +83,9 @@ var ExtensionChannelController = class {
83
83
  var BusChannelAdapter = class {
84
84
  channel = null;
85
85
  messageHandler = null;
86
- constructor(definition) {
86
+ constructor(definition, extensionChannel) {
87
87
  this.definition = definition;
88
+ this.extensionChannel = extensionChannel;
88
89
  }
89
90
  configure = async (config) => {
90
91
  await this.stop();
@@ -92,7 +93,8 @@ var BusChannelAdapter = class {
92
93
  config,
93
94
  bus: { publishInbound: async (message) => {
94
95
  await this.messageHandler?.(message);
95
- } }
96
+ } },
97
+ channel: this.extensionChannel
96
98
  });
97
99
  };
98
100
  start = async () => {
@@ -136,7 +138,7 @@ var BusChannelAdapter = class {
136
138
  };
137
139
  sendOutboundText = async (params) => {
138
140
  const { accountId, media, metadata, replyTo, text, to } = params;
139
- await this.channel?.send({
141
+ const outbound = {
140
142
  channel: this.definition.channelId,
141
143
  chatId: to,
142
144
  content: text,
@@ -146,7 +148,9 @@ var BusChannelAdapter = class {
146
148
  ...metadata ?? {},
147
149
  ...accountId ? { accountId } : {}
148
150
  }
149
- });
151
+ };
152
+ if (await this.channel?.handleControlMessage?.(outbound)) return;
153
+ await this.channel?.send(outbound);
150
154
  };
151
155
  };
152
156
  async function startChannelExtension(definition, options = {}) {
@@ -154,7 +158,7 @@ async function startChannelExtension(definition, options = {}) {
154
158
  const channel = extension.channels.use(definition.channelId);
155
159
  const controller = new ExtensionChannelController({
156
160
  channel,
157
- adapter: definition.createAdapter(),
161
+ adapter: definition.createAdapter({ channel }),
158
162
  mapInbound: definition.mapInbound,
159
163
  onNcpEventError: definition.onNcpEventError
160
164
  });
@@ -172,7 +176,7 @@ async function startChannelExtension(definition, options = {}) {
172
176
  async function startBusChannelExtension(definition, options = {}) {
173
177
  await startChannelExtension({
174
178
  channelId: definition.channelId,
175
- createAdapter: () => new BusChannelAdapter(definition),
179
+ createAdapter: ({ channel }) => new BusChannelAdapter(definition, channel),
176
180
  mapInbound: definition.mapInbound ?? toSubmittedTextMessage
177
181
  }, options);
178
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"extension-channel-controller.service.js","names":[],"sources":["../../src/services/extension-channel-controller.service.ts"],"sourcesContent":["import { NcpEventType, type NcpEndpointEvent, type NcpMessagePart } from \"@nextclaw/ncp\";\nimport type {\n ChannelSubmittedMessage,\n ChannelSubmittedAttachment,\n ExtensionChannel,\n NextClawExtensionOptions,\n} from \"../types/extension-sdk.types.js\";\nimport { NextClawExtension } from \"./extension-client.service.js\";\n\nfunction readRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : {};\n}\n\nconst AGENT_ROUTE_KINDS = new Set([\"direct\", \"group\", \"channel\", \"thread\"]);\n\nfunction parseSessionDeliveryRoute(sessionId: string): {\n channel?: string;\n chatId?: string;\n accountId?: string;\n} {\n const parts = sessionId.trim().split(\":\");\n if (parts[0] !== \"agent\" || parts.length < 5) {\n return {};\n }\n const hasAccount = !AGENT_ROUTE_KINDS.has(parts[3]);\n const kind = parts[hasAccount ? 4 : 3];\n if (!AGENT_ROUTE_KINDS.has(kind ?? \"\")) {\n return {};\n }\n return {\n channel: parts[2],\n ...(hasAccount ? { accountId: parts[3] } : {}),\n chatId: parts.slice(hasAccount ? 5 : 4).join(\":\"),\n };\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction renderMessageText(parts: readonly NcpMessagePart[]): string {\n return (parts as Array<{ type: string; text?: string }>).map((part) =>\n (part.type === \"text\" || part.type === \"rich-text\") && part.text ? part.text : \"\",\n ).filter(Boolean).join(\"\\n\\n\");\n}\n\nexport type ExtensionChannelAdapter<TConfig, TInbound> = {\n configure: (config: TConfig) => Promise<void>;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n onMessage: (handler: (message: TInbound) => void | Promise<void>) => () => void;\n sendNcpEvent: (event: NcpEndpointEvent) => Promise<void>;\n sendOutboundText: (params: {\n to: string;\n text: string;\n accountId?: string | null;\n replyTo?: string | null;\n media?: string[];\n metadata?: Record<string, unknown>;\n }) => Promise<void>;\n};\n\nexport type ChannelSubmittedMessageInput = Omit<ChannelSubmittedMessage, \"channelId\">;\n\nexport type BusChannelInboundMessage = {\n channel: string;\n senderId: string;\n chatId: string;\n content: string;\n attachments?: ChannelSubmittedAttachment[];\n metadata?: Record<string, unknown>;\n};\n\nexport type BusChannelMessageBus = {\n publishInbound: (message: BusChannelInboundMessage) => Promise<void>;\n};\n\nexport type BusChannelRuntime = {\n start: () => Promise<void>;\n stop: () => Promise<void>;\n send: (message: {\n channel: string;\n chatId: string;\n content: string;\n replyTo?: string | null;\n media: string[];\n metadata: Record<string, unknown>;\n }) => Promise<void>;\n};\n\nexport type BusChannelCreateContext<TConfig, TBus = BusChannelMessageBus> = {\n config: TConfig;\n bus: TBus;\n};\n\nexport type BusChannelExtensionDefinition<TConfig, TBus = BusChannelMessageBus> = {\n channelId: string;\n createChannel: (context: BusChannelCreateContext<TConfig, TBus>) => BusChannelRuntime;\n mapInbound?: ExtensionChannelInboundMapper<BusChannelInboundMessage>;\n onChannelStartError?: (error: unknown) => void | Promise<void>;\n};\n\nexport type ExtensionChannelInboundMapper<TInbound> =\n (message: TInbound) => ChannelSubmittedMessageInput | Promise<ChannelSubmittedMessageInput>;\n\ntype ExtensionChannelControllerOptions<TConfig, TInbound> = {\n channel: ExtensionChannel;\n adapter: ExtensionChannelAdapter<TConfig, TInbound>;\n mapInbound: ExtensionChannelInboundMapper<TInbound>;\n onNcpEventError?: (error: unknown, event: NcpEndpointEvent) => void | Promise<void>;\n};\n\nexport type ChannelExtensionContext = {\n channel: ExtensionChannel;\n};\n\nexport type ChannelExtensionDefinition<TConfig, TInbound> = {\n channelId: string;\n createAdapter: () => ExtensionChannelAdapter<TConfig, TInbound>;\n mapInbound: ExtensionChannelInboundMapper<TInbound>;\n createAuthCapability?: (context: ChannelExtensionContext) => object;\n onNcpEventError?: (error: unknown, event: NcpEndpointEvent) => void | Promise<void>;\n};\n\nfunction defaultChannelEnabled(config: unknown): boolean {\n return !(\n config &&\n typeof config === \"object\" &&\n !Array.isArray(config) &&\n (config as { enabled?: unknown }).enabled === false\n );\n}\n\nexport class ExtensionChannelController<TConfig, TInbound> {\n private readonly cleanups: Array<() => void> = [];\n private started = false;\n\n constructor(\n private readonly options: ExtensionChannelControllerOptions<TConfig, TInbound>,\n ) {}\n\n start = async (): Promise<void> => {\n if (this.started) {\n return;\n }\n this.started = true;\n this.cleanups.push(this.options.adapter.onMessage(this.submitMessage));\n this.cleanups.push(this.options.channel.onNcpEvent(this.sendNcpEvent));\n this.cleanups.push(this.options.channel.config.onChange(async () => {\n await this.applyConfig();\n }));\n await this.applyConfig();\n };\n\n stop = async (): Promise<void> => {\n if (!this.started) {\n return;\n }\n this.started = false;\n this.drainCleanups();\n await this.options.adapter.stop();\n };\n\n sendOutboundText = async (params: {\n to: string;\n text: string;\n accountId?: string | null;\n replyTo?: string | null;\n media?: string[];\n metadata?: Record<string, unknown>;\n }): Promise<{ accepted: true }> => {\n await this.options.adapter.sendOutboundText(params);\n return { accepted: true };\n };\n\n private applyConfig = async (): Promise<void> => {\n const config = await this.options.channel.config.get<TConfig>();\n await this.options.adapter.configure(config);\n if (defaultChannelEnabled(config) === false) {\n await this.options.adapter.stop();\n return;\n }\n await this.options.adapter.start();\n };\n\n private submitMessage = async (message: TInbound): Promise<void> => {\n await this.options.channel.submitMessage(await this.options.mapInbound(message));\n };\n\n private sendNcpEvent = async (event: NcpEndpointEvent): Promise<void> => {\n try {\n await this.options.adapter.sendNcpEvent(event);\n } catch (error) {\n await this.options.onNcpEventError?.(error, event);\n }\n };\n\n private drainCleanups = (): void => {\n for (const cleanup of this.cleanups.splice(0).reverse()) {\n cleanup();\n }\n };\n}\n\nclass BusChannelAdapter<TConfig, TBus> implements ExtensionChannelAdapter<TConfig, BusChannelInboundMessage> {\n private channel: BusChannelRuntime | null = null;\n private messageHandler: ((message: BusChannelInboundMessage) => void | Promise<void>) | null = null;\n\n constructor(\n private readonly definition: BusChannelExtensionDefinition<TConfig, TBus>,\n ) {}\n\n configure = async (config: TConfig): Promise<void> => {\n await this.stop();\n this.channel = this.definition.createChannel({\n config,\n bus: {\n publishInbound: async (message: BusChannelInboundMessage) => {\n await this.messageHandler?.(message);\n },\n } as TBus,\n });\n };\n\n start = async (): Promise<void> => {\n const channel = this.channel;\n if (!channel) {\n return;\n }\n void channel.start().catch(async (error: unknown) => {\n await this.definition.onChannelStartError?.(error);\n });\n };\n\n stop = async (): Promise<void> => {\n const channel = this.channel;\n this.channel = null;\n await channel?.stop();\n };\n\n onMessage = (\n handler: (message: BusChannelInboundMessage) => void | Promise<void>,\n ): (() => void) => {\n this.messageHandler = handler;\n return () => {\n if (this.messageHandler === handler) {\n this.messageHandler = null;\n }\n };\n };\n\n sendNcpEvent = async (event: NcpEndpointEvent): Promise<void> => {\n if (event.type !== NcpEventType.MessageCompleted) {\n return;\n }\n const metadata = readRecord(event.payload.message.metadata);\n const sessionRoute = parseSessionDeliveryRoute(event.payload.message.sessionId);\n const eventChannel = readString(metadata.channel) ?? readString(metadata.channelId) ?? sessionRoute.channel;\n if (eventChannel !== this.definition.channelId) {\n return;\n }\n const chatId = readString(metadata.chatId) ?? readString(metadata.chat_id) ?? sessionRoute.chatId;\n const content = renderMessageText(event.payload.message.parts).trim();\n if (!chatId || !content) {\n return;\n }\n const replyTo = readString(metadata.message_id);\n await this.channel?.send({\n channel: this.definition.channelId,\n chatId,\n content,\n ...(replyTo ? { replyTo } : {}),\n media: [],\n metadata: {\n ...metadata,\n ...(sessionRoute.accountId && !metadata.accountId ? { accountId: sessionRoute.accountId } : {}),\n },\n });\n };\n\n sendOutboundText = async (params: {\n to: string;\n text: string;\n accountId?: string | null;\n replyTo?: string | null;\n media?: string[];\n metadata?: Record<string, unknown>;\n }): Promise<void> => {\n const { accountId, media, metadata, replyTo, text, to } = params;\n await this.channel?.send({\n channel: this.definition.channelId,\n chatId: to,\n content: text,\n ...(replyTo !== undefined ? { replyTo } : {}),\n media: media ?? [],\n metadata: {\n ...(metadata ?? {}),\n ...(accountId ? { accountId } : {}),\n },\n });\n };\n}\n\nexport async function startChannelExtension<TConfig, TInbound>(\n definition: ChannelExtensionDefinition<TConfig, TInbound>,\n options: NextClawExtensionOptions = {},\n): Promise<void> {\n const extension = new NextClawExtension(options);\n const channel = extension.channels.use(definition.channelId);\n const adapter = definition.createAdapter();\n const controller = new ExtensionChannelController({\n channel,\n adapter,\n mapInbound: definition.mapInbound,\n onNcpEventError: definition.onNcpEventError,\n });\n if (definition.createAuthCapability) {\n extension.capabilities.provide(\"channel.auth\", definition.createAuthCapability({ channel }));\n }\n extension.capabilities.provideHandler(\"channel.outbound.sendText\", async (payload) =>\n await controller.sendOutboundText({\n to: readRequiredPayloadString(payload.to, \"to\"),\n text: readRequiredPayloadString(payload.text, \"text\"),\n accountId: readOptionalPayloadString(payload.accountId),\n replyTo: readOptionalPayloadString(payload.replyTo),\n media: readStringArray(payload.media),\n metadata: readOptionalRecord(payload.metadata),\n }),\n );\n await controller.start();\n}\n\nexport async function startBusChannelExtension<TConfig, TBus = BusChannelMessageBus>(\n definition: BusChannelExtensionDefinition<TConfig, TBus>,\n options: NextClawExtensionOptions = {},\n): Promise<void> {\n await startChannelExtension(\n {\n channelId: definition.channelId,\n createAdapter: () => new BusChannelAdapter(definition),\n mapInbound: definition.mapInbound ?? toSubmittedTextMessage,\n },\n options,\n );\n}\n\nexport function warnNcpEventError(channelId: string): (error: unknown) => void {\n return (error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.warn(`[${channelId}] failed to send NCP event: ${message}`);\n };\n}\n\nfunction readRequiredPayloadString(value: unknown, name: string): string {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new Error(`${name} is required`);\n }\n return value.trim();\n}\n\nfunction readOptionalPayloadString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n return value.filter((item): item is string => typeof item === \"string\");\n}\n\nfunction readOptionalRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : undefined;\n}\n\nfunction toSubmittedTextMessage(message: BusChannelInboundMessage): ChannelSubmittedMessageInput {\n return {\n conversationId: message.chatId,\n senderId: message.senderId,\n content: {\n type: \"text\",\n text: message.content,\n },\n ...(message.attachments ? { attachments: message.attachments } : {}),\n ...(message.metadata ? { metadata: message.metadata } : {}),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension-channel-controller.service.js","names":[],"sources":["../../src/services/extension-channel-controller.service.ts"],"sourcesContent":["import { NcpEventType, type NcpEndpointEvent, type NcpMessagePart } from \"@nextclaw/ncp\";\nimport type {\n ChannelSubmittedMessage,\n ChannelSubmittedAttachment,\n ExtensionChannel,\n NextClawExtensionOptions,\n} from \"../types/extension-sdk.types.js\";\nimport { NextClawExtension } from \"./extension-client.service.js\";\n\nfunction readRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : {};\n}\n\nconst AGENT_ROUTE_KINDS = new Set([\"direct\", \"group\", \"channel\", \"thread\"]);\n\nfunction parseSessionDeliveryRoute(sessionId: string): {\n channel?: string;\n chatId?: string;\n accountId?: string;\n} {\n const parts = sessionId.trim().split(\":\");\n if (parts[0] !== \"agent\" || parts.length < 5) {\n return {};\n }\n const hasAccount = !AGENT_ROUTE_KINDS.has(parts[3]);\n const kind = parts[hasAccount ? 4 : 3];\n if (!AGENT_ROUTE_KINDS.has(kind ?? \"\")) {\n return {};\n }\n return {\n channel: parts[2],\n ...(hasAccount ? { accountId: parts[3] } : {}),\n chatId: parts.slice(hasAccount ? 5 : 4).join(\":\"),\n };\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction renderMessageText(parts: readonly NcpMessagePart[]): string {\n return (parts as Array<{ type: string; text?: string }>).map((part) =>\n (part.type === \"text\" || part.type === \"rich-text\") && part.text ? part.text : \"\",\n ).filter(Boolean).join(\"\\n\\n\");\n}\n\nexport type ExtensionChannelAdapter<TConfig, TInbound> = {\n configure: (config: TConfig) => Promise<void>;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n onMessage: (handler: (message: TInbound) => void | Promise<void>) => () => void;\n sendNcpEvent: (event: NcpEndpointEvent) => Promise<void>;\n sendOutboundText: (params: {\n to: string;\n text: string;\n accountId?: string | null;\n replyTo?: string | null;\n media?: string[];\n metadata?: Record<string, unknown>;\n }) => Promise<void>;\n};\n\nexport type ChannelSubmittedMessageInput = Omit<ChannelSubmittedMessage, \"channelId\">;\n\nexport type BusChannelInboundMessage = {\n channel: string;\n senderId: string;\n chatId: string;\n content: string;\n attachments?: ChannelSubmittedAttachment[];\n metadata?: Record<string, unknown>;\n};\n\nexport type BusChannelMessageBus = {\n publishInbound: (message: BusChannelInboundMessage) => Promise<void>;\n};\n\nexport type BusChannelRuntime = {\n start: () => Promise<void>;\n stop: () => Promise<void>;\n handleControlMessage?: (message: {\n channel: string;\n chatId: string;\n content: string;\n replyTo?: string | null;\n media: string[];\n metadata: Record<string, unknown>;\n }) => Promise<boolean>;\n send: (message: {\n channel: string;\n chatId: string;\n content: string;\n replyTo?: string | null;\n media: string[];\n metadata: Record<string, unknown>;\n }) => Promise<void>;\n};\n\nexport type BusChannelCreateContext<TConfig, TBus = BusChannelMessageBus> = {\n config: TConfig;\n bus: TBus;\n channel: ExtensionChannel;\n};\n\nexport type BusChannelExtensionDefinition<TConfig, TBus = BusChannelMessageBus> = {\n channelId: string;\n createChannel: (context: BusChannelCreateContext<TConfig, TBus>) => BusChannelRuntime;\n mapInbound?: ExtensionChannelInboundMapper<BusChannelInboundMessage>;\n onChannelStartError?: (error: unknown) => void | Promise<void>;\n};\n\nexport type ExtensionChannelInboundMapper<TInbound> =\n (message: TInbound) => ChannelSubmittedMessageInput | Promise<ChannelSubmittedMessageInput>;\n\ntype ExtensionChannelControllerOptions<TConfig, TInbound> = {\n channel: ExtensionChannel;\n adapter: ExtensionChannelAdapter<TConfig, TInbound>;\n mapInbound: ExtensionChannelInboundMapper<TInbound>;\n onNcpEventError?: (error: unknown, event: NcpEndpointEvent) => void | Promise<void>;\n};\n\nexport type ChannelExtensionContext = {\n channel: ExtensionChannel;\n};\n\nexport type ChannelExtensionDefinition<TConfig, TInbound> = {\n channelId: string;\n createAdapter: (context: ChannelExtensionContext) => ExtensionChannelAdapter<TConfig, TInbound>;\n mapInbound: ExtensionChannelInboundMapper<TInbound>;\n createAuthCapability?: (context: ChannelExtensionContext) => object;\n onNcpEventError?: (error: unknown, event: NcpEndpointEvent) => void | Promise<void>;\n};\n\nfunction defaultChannelEnabled(config: unknown): boolean {\n return !(\n config &&\n typeof config === \"object\" &&\n !Array.isArray(config) &&\n (config as { enabled?: unknown }).enabled === false\n );\n}\n\nexport class ExtensionChannelController<TConfig, TInbound> {\n private readonly cleanups: Array<() => void> = [];\n private started = false;\n\n constructor(\n private readonly options: ExtensionChannelControllerOptions<TConfig, TInbound>,\n ) {}\n\n start = async (): Promise<void> => {\n if (this.started) {\n return;\n }\n this.started = true;\n this.cleanups.push(this.options.adapter.onMessage(this.submitMessage));\n this.cleanups.push(this.options.channel.onNcpEvent(this.sendNcpEvent));\n this.cleanups.push(this.options.channel.config.onChange(async () => {\n await this.applyConfig();\n }));\n await this.applyConfig();\n };\n\n stop = async (): Promise<void> => {\n if (!this.started) {\n return;\n }\n this.started = false;\n this.drainCleanups();\n await this.options.adapter.stop();\n };\n\n sendOutboundText = async (params: {\n to: string;\n text: string;\n accountId?: string | null;\n replyTo?: string | null;\n media?: string[];\n metadata?: Record<string, unknown>;\n }): Promise<{ accepted: true }> => {\n await this.options.adapter.sendOutboundText(params);\n return { accepted: true };\n };\n\n private applyConfig = async (): Promise<void> => {\n const config = await this.options.channel.config.get<TConfig>();\n await this.options.adapter.configure(config);\n if (defaultChannelEnabled(config) === false) {\n await this.options.adapter.stop();\n return;\n }\n await this.options.adapter.start();\n };\n\n private submitMessage = async (message: TInbound): Promise<void> => {\n await this.options.channel.submitMessage(await this.options.mapInbound(message));\n };\n\n private sendNcpEvent = async (event: NcpEndpointEvent): Promise<void> => {\n try {\n await this.options.adapter.sendNcpEvent(event);\n } catch (error) {\n await this.options.onNcpEventError?.(error, event);\n }\n };\n\n private drainCleanups = (): void => {\n for (const cleanup of this.cleanups.splice(0).reverse()) {\n cleanup();\n }\n };\n}\n\nclass BusChannelAdapter<TConfig, TBus> implements ExtensionChannelAdapter<TConfig, BusChannelInboundMessage> {\n private channel: BusChannelRuntime | null = null;\n private messageHandler: ((message: BusChannelInboundMessage) => void | Promise<void>) | null = null;\n\n constructor(\n private readonly definition: BusChannelExtensionDefinition<TConfig, TBus>,\n private readonly extensionChannel: ExtensionChannel,\n ) {}\n\n configure = async (config: TConfig): Promise<void> => {\n await this.stop();\n this.channel = this.definition.createChannel({\n config,\n bus: {\n publishInbound: async (message: BusChannelInboundMessage) => {\n await this.messageHandler?.(message);\n },\n } as TBus,\n channel: this.extensionChannel,\n });\n };\n\n start = async (): Promise<void> => {\n const channel = this.channel;\n if (!channel) {\n return;\n }\n void channel.start().catch(async (error: unknown) => {\n await this.definition.onChannelStartError?.(error);\n });\n };\n\n stop = async (): Promise<void> => {\n const channel = this.channel;\n this.channel = null;\n await channel?.stop();\n };\n\n onMessage = (\n handler: (message: BusChannelInboundMessage) => void | Promise<void>,\n ): (() => void) => {\n this.messageHandler = handler;\n return () => {\n if (this.messageHandler === handler) {\n this.messageHandler = null;\n }\n };\n };\n\n sendNcpEvent = async (event: NcpEndpointEvent): Promise<void> => {\n if (event.type !== NcpEventType.MessageCompleted) {\n return;\n }\n const metadata = readRecord(event.payload.message.metadata);\n const sessionRoute = parseSessionDeliveryRoute(event.payload.message.sessionId);\n const eventChannel = readString(metadata.channel) ?? readString(metadata.channelId) ?? sessionRoute.channel;\n if (eventChannel !== this.definition.channelId) {\n return;\n }\n const chatId = readString(metadata.chatId) ?? readString(metadata.chat_id) ?? sessionRoute.chatId;\n const content = renderMessageText(event.payload.message.parts).trim();\n if (!chatId || !content) {\n return;\n }\n const replyTo = readString(metadata.message_id);\n await this.channel?.send({\n channel: this.definition.channelId,\n chatId,\n content,\n ...(replyTo ? { replyTo } : {}),\n media: [],\n metadata: {\n ...metadata,\n ...(sessionRoute.accountId && !metadata.accountId ? { accountId: sessionRoute.accountId } : {}),\n },\n });\n };\n\n sendOutboundText = async (params: {\n to: string;\n text: string;\n accountId?: string | null;\n replyTo?: string | null;\n media?: string[];\n metadata?: Record<string, unknown>;\n }): Promise<void> => {\n const { accountId, media, metadata, replyTo, text, to } = params;\n const outbound = {\n channel: this.definition.channelId,\n chatId: to,\n content: text,\n ...(replyTo !== undefined ? { replyTo } : {}),\n media: media ?? [],\n metadata: {\n ...(metadata ?? {}),\n ...(accountId ? { accountId } : {}),\n },\n };\n if (await this.channel?.handleControlMessage?.(outbound)) {\n return;\n }\n await this.channel?.send(outbound);\n };\n}\n\nexport async function startChannelExtension<TConfig, TInbound>(\n definition: ChannelExtensionDefinition<TConfig, TInbound>,\n options: NextClawExtensionOptions = {},\n): Promise<void> {\n const extension = new NextClawExtension(options);\n const channel = extension.channels.use(definition.channelId);\n const adapter = definition.createAdapter({ channel });\n const controller = new ExtensionChannelController({\n channel,\n adapter,\n mapInbound: definition.mapInbound,\n onNcpEventError: definition.onNcpEventError,\n });\n if (definition.createAuthCapability) {\n extension.capabilities.provide(\"channel.auth\", definition.createAuthCapability({ channel }));\n }\n extension.capabilities.provideHandler(\"channel.outbound.sendText\", async (payload) =>\n await controller.sendOutboundText({\n to: readRequiredPayloadString(payload.to, \"to\"),\n text: readRequiredPayloadString(payload.text, \"text\"),\n accountId: readOptionalPayloadString(payload.accountId),\n replyTo: readOptionalPayloadString(payload.replyTo),\n media: readStringArray(payload.media),\n metadata: readOptionalRecord(payload.metadata),\n }),\n );\n await controller.start();\n}\n\nexport async function startBusChannelExtension<TConfig, TBus = BusChannelMessageBus>(\n definition: BusChannelExtensionDefinition<TConfig, TBus>,\n options: NextClawExtensionOptions = {},\n): Promise<void> {\n await startChannelExtension(\n {\n channelId: definition.channelId,\n createAdapter: ({ channel }) => new BusChannelAdapter(definition, channel),\n mapInbound: definition.mapInbound ?? toSubmittedTextMessage,\n },\n options,\n );\n}\n\nexport function warnNcpEventError(channelId: string): (error: unknown) => void {\n return (error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.warn(`[${channelId}] failed to send NCP event: ${message}`);\n };\n}\n\nfunction readRequiredPayloadString(value: unknown, name: string): string {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new Error(`${name} is required`);\n }\n return value.trim();\n}\n\nfunction readOptionalPayloadString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n return value.filter((item): item is string => typeof item === \"string\");\n}\n\nfunction readOptionalRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : undefined;\n}\n\nfunction toSubmittedTextMessage(message: BusChannelInboundMessage): ChannelSubmittedMessageInput {\n return {\n conversationId: message.chatId,\n senderId: message.senderId,\n content: {\n type: \"text\",\n text: message.content,\n },\n ...(message.attachments ? { attachments: message.attachments } : {}),\n ...(message.metadata ? { metadata: message.metadata } : {}),\n };\n}\n"],"mappings":"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"}
@@ -14,13 +14,42 @@ var ChannelConfig = class {
14
14
  this.get().then((config) => handler(config));
15
15
  });
16
16
  };
17
+ var ChannelCommands = class {
18
+ constructor(params) {
19
+ this.params = params;
20
+ }
21
+ list = async () => {
22
+ return (await this.params.transport.postIngress(getKeyId(ingressKeys.extension.channelCommandList), { channelId: this.params.channelId })).commands;
23
+ };
24
+ execute = async (input) => await this.params.transport.postIngress(getKeyId(ingressKeys.extension.channelCommandExecute), {
25
+ channelId: this.params.channelId,
26
+ commandName: input.commandName,
27
+ args: input.args ?? {},
28
+ conversationId: input.conversationId,
29
+ senderId: input.senderId,
30
+ metadata: input.metadata ?? {}
31
+ });
32
+ executeText = async (input) => {
33
+ const rawText = input.rawText.trim();
34
+ if (!rawText.startsWith("/")) return null;
35
+ return await this.params.transport.postIngress(getKeyId(ingressKeys.extension.channelCommandExecute), {
36
+ channelId: this.params.channelId,
37
+ rawText,
38
+ conversationId: input.conversationId,
39
+ senderId: input.senderId,
40
+ metadata: input.metadata ?? {}
41
+ });
42
+ };
43
+ };
17
44
  var ExtensionChannelService = class {
18
45
  id;
19
46
  config;
47
+ commands;
20
48
  constructor(params) {
21
49
  this.params = params;
22
50
  this.id = params.channelId;
23
51
  this.config = new ChannelConfig(params);
52
+ this.commands = new ChannelCommands(params);
24
53
  }
25
54
  submitMessage = async (input) => {
26
55
  await this.params.transport.postIngress(getKeyId(ingressKeys.extension.channelMessageSubmit), {
@@ -1 +1 @@
1
- {"version":3,"file":"extension-channel.service.js","names":[],"sources":["../../src/services/extension-channel.service.ts"],"sourcesContent":["import {\n eventKeys,\n getKeyId,\n ingressKeys,\n type EventBus,\n type Unsubscribe,\n} from \"@nextclaw/shared\";\nimport type {\n ChannelConfigGetResponse,\n ChannelSubmittedMessage,\n ExtensionChannel,\n ExtensionChannelConfig,\n} from \"../types/extension-sdk.types.js\";\nimport type { ExtensionTransportService } from \"./extension-transport.service.js\";\n\nclass ChannelConfig implements ExtensionChannelConfig {\n constructor(\n private readonly params: {\n channelId: string;\n eventBus: EventBus;\n transport: ExtensionTransportService;\n },\n ) {}\n\n readonly get = async <TConfig = unknown>(): Promise<TConfig> => {\n const response = await this.params.transport.postIngress<ChannelConfigGetResponse<TConfig>>(\n getKeyId(ingressKeys.extension.channelConfigGet),\n { channelId: this.params.channelId },\n );\n return response.config;\n };\n\n readonly onChange = <TConfig = unknown>(\n handler: (config: TConfig) => void | Promise<void>,\n ): Unsubscribe =>\n this.params.eventBus.subscribeAll((event) => {\n if (event.type !== getKeyId(eventKeys.configUpdated)) {\n return;\n }\n const payload = event.payload as { path?: unknown };\n if (payload.path !== \"channels\" && payload.path !== `channels.${this.params.channelId}`) {\n return;\n }\n void this.get<TConfig>().then((config) => handler(config));\n });\n}\n\nexport class ExtensionChannelService implements ExtensionChannel {\n readonly id: string;\n readonly config: ExtensionChannelConfig;\n\n constructor(\n private readonly params: {\n channelId: string;\n eventBus: EventBus;\n transport: ExtensionTransportService;\n },\n ) {\n this.id = params.channelId;\n this.config = new ChannelConfig(params);\n }\n\n readonly submitMessage = async (\n input: Omit<ChannelSubmittedMessage, \"channelId\">,\n ): Promise<void> => {\n await this.params.transport.postIngress(getKeyId(ingressKeys.extension.channelMessageSubmit), {\n ...input,\n channelId: this.id,\n });\n };\n\n readonly onNcpEvent = (\n handler: Parameters<ExtensionChannel[\"onNcpEvent\"]>[0],\n ): Unsubscribe =>\n this.params.eventBus.on(eventKeys.ncpEvent, (event) => {\n void handler(event);\n });\n}\n"],"mappings":";;AAeA,IAAM,gBAAN,MAAsD;CACpD,YACE,QAKA;AALiB,OAAA,SAAA;;CAOnB,MAAe,YAAiD;AAK9D,UAJiB,MAAM,KAAK,OAAO,UAAU,YAC3C,SAAS,YAAY,UAAU,iBAAiB,EAChD,EAAE,WAAW,KAAK,OAAO,WAAW,CACrC,EACe;;CAGlB,YACE,YAEA,KAAK,OAAO,SAAS,cAAc,UAAU;AAC3C,MAAI,MAAM,SAAS,SAAS,UAAU,cAAc,CAClD;EAEF,MAAM,UAAU,MAAM;AACtB,MAAI,QAAQ,SAAS,cAAc,QAAQ,SAAS,YAAY,KAAK,OAAO,YAC1E;AAEG,OAAK,KAAc,CAAC,MAAM,WAAW,QAAQ,OAAO,CAAC;GAC1D;;AAGN,IAAa,0BAAb,MAAiE;CAC/D;CACA;CAEA,YACE,QAKA;AALiB,OAAA,SAAA;AAMjB,OAAK,KAAK,OAAO;AACjB,OAAK,SAAS,IAAI,cAAc,OAAO;;CAGzC,gBAAyB,OACvB,UACkB;AAClB,QAAM,KAAK,OAAO,UAAU,YAAY,SAAS,YAAY,UAAU,qBAAqB,EAAE;GAC5F,GAAG;GACH,WAAW,KAAK;GACjB,CAAC;;CAGJ,cACE,YAEA,KAAK,OAAO,SAAS,GAAG,UAAU,WAAW,UAAU;AAChD,UAAQ,MAAM;GACnB"}
1
+ {"version":3,"file":"extension-channel.service.js","names":[],"sources":["../../src/services/extension-channel.service.ts"],"sourcesContent":["import {\n eventKeys,\n getKeyId,\n ingressKeys,\n type EventBus,\n type Unsubscribe,\n} from \"@nextclaw/shared\";\nimport type {\n ChannelCommandExecuteResponse,\n ChannelCommandListResponse,\n ChannelConfigGetResponse,\n ChannelSubmittedMessage,\n ExtensionChannel,\n ExtensionChannelCommands,\n ExtensionChannelConfig,\n} from \"../types/extension-sdk.types.js\";\nimport type { ExtensionTransportService } from \"./extension-transport.service.js\";\n\nclass ChannelConfig implements ExtensionChannelConfig {\n constructor(\n private readonly params: {\n channelId: string;\n eventBus: EventBus;\n transport: ExtensionTransportService;\n },\n ) {}\n\n readonly get = async <TConfig = unknown>(): Promise<TConfig> => {\n const response = await this.params.transport.postIngress<ChannelConfigGetResponse<TConfig>>(\n getKeyId(ingressKeys.extension.channelConfigGet),\n { channelId: this.params.channelId },\n );\n return response.config;\n };\n\n readonly onChange = <TConfig = unknown>(\n handler: (config: TConfig) => void | Promise<void>,\n ): Unsubscribe =>\n this.params.eventBus.subscribeAll((event) => {\n if (event.type !== getKeyId(eventKeys.configUpdated)) {\n return;\n }\n const payload = event.payload as { path?: unknown };\n if (payload.path !== \"channels\" && payload.path !== `channels.${this.params.channelId}`) {\n return;\n }\n void this.get<TConfig>().then((config) => handler(config));\n });\n}\n\nclass ChannelCommands implements ExtensionChannelCommands {\n constructor(\n private readonly params: {\n channelId: string;\n transport: ExtensionTransportService;\n },\n ) {}\n\n readonly list = async () => {\n const response = await this.params.transport.postIngress<ChannelCommandListResponse>(\n getKeyId(ingressKeys.extension.channelCommandList),\n { channelId: this.params.channelId },\n );\n return response.commands;\n };\n\n readonly execute = async (input: {\n commandName: string;\n args?: Record<string, unknown>;\n conversationId: string;\n senderId: string;\n metadata?: Record<string, unknown>;\n }): Promise<ChannelCommandExecuteResponse> =>\n await this.params.transport.postIngress<ChannelCommandExecuteResponse>(\n getKeyId(ingressKeys.extension.channelCommandExecute),\n {\n channelId: this.params.channelId,\n commandName: input.commandName,\n args: input.args ?? {},\n conversationId: input.conversationId,\n senderId: input.senderId,\n metadata: input.metadata ?? {},\n },\n );\n\n readonly executeText = async (input: {\n rawText: string;\n conversationId: string;\n senderId: string;\n metadata?: Record<string, unknown>;\n }): Promise<ChannelCommandExecuteResponse | null> => {\n const rawText = input.rawText.trim();\n if (!rawText.startsWith(\"/\")) {\n return null;\n }\n return await this.params.transport.postIngress<ChannelCommandExecuteResponse>(\n getKeyId(ingressKeys.extension.channelCommandExecute),\n {\n channelId: this.params.channelId,\n rawText,\n conversationId: input.conversationId,\n senderId: input.senderId,\n metadata: input.metadata ?? {},\n },\n );\n };\n}\n\nexport class ExtensionChannelService implements ExtensionChannel {\n readonly id: string;\n readonly config: ExtensionChannelConfig;\n readonly commands: ExtensionChannelCommands;\n\n constructor(\n private readonly params: {\n channelId: string;\n eventBus: EventBus;\n transport: ExtensionTransportService;\n },\n ) {\n this.id = params.channelId;\n this.config = new ChannelConfig(params);\n this.commands = new ChannelCommands(params);\n }\n\n readonly submitMessage = async (\n input: Omit<ChannelSubmittedMessage, \"channelId\">,\n ): Promise<void> => {\n await this.params.transport.postIngress(getKeyId(ingressKeys.extension.channelMessageSubmit), {\n ...input,\n channelId: this.id,\n });\n };\n\n readonly onNcpEvent = (\n handler: Parameters<ExtensionChannel[\"onNcpEvent\"]>[0],\n ): Unsubscribe =>\n this.params.eventBus.on(eventKeys.ncpEvent, (event) => {\n void handler(event);\n });\n}\n"],"mappings":";;AAkBA,IAAM,gBAAN,MAAsD;CACpD,YACE,QAKA;AALiB,OAAA,SAAA;;CAOnB,MAAe,YAAiD;AAK9D,UAJiB,MAAM,KAAK,OAAO,UAAU,YAC3C,SAAS,YAAY,UAAU,iBAAiB,EAChD,EAAE,WAAW,KAAK,OAAO,WAAW,CACrC,EACe;;CAGlB,YACE,YAEA,KAAK,OAAO,SAAS,cAAc,UAAU;AAC3C,MAAI,MAAM,SAAS,SAAS,UAAU,cAAc,CAClD;EAEF,MAAM,UAAU,MAAM;AACtB,MAAI,QAAQ,SAAS,cAAc,QAAQ,SAAS,YAAY,KAAK,OAAO,YAC1E;AAEG,OAAK,KAAc,CAAC,MAAM,WAAW,QAAQ,OAAO,CAAC;GAC1D;;AAGN,IAAM,kBAAN,MAA0D;CACxD,YACE,QAIA;AAJiB,OAAA,SAAA;;CAMnB,OAAgB,YAAY;AAK1B,UAJiB,MAAM,KAAK,OAAO,UAAU,YAC3C,SAAS,YAAY,UAAU,mBAAmB,EAClD,EAAE,WAAW,KAAK,OAAO,WAAW,CACrC,EACe;;CAGlB,UAAmB,OAAO,UAOxB,MAAM,KAAK,OAAO,UAAU,YAC1B,SAAS,YAAY,UAAU,sBAAsB,EACrD;EACE,WAAW,KAAK,OAAO;EACvB,aAAa,MAAM;EACnB,MAAM,MAAM,QAAQ,EAAE;EACtB,gBAAgB,MAAM;EACtB,UAAU,MAAM;EAChB,UAAU,MAAM,YAAY,EAAE;EAC/B,CACF;CAEH,cAAuB,OAAO,UAKuB;EACnD,MAAM,UAAU,MAAM,QAAQ,MAAM;AACpC,MAAI,CAAC,QAAQ,WAAW,IAAI,CAC1B,QAAO;AAET,SAAO,MAAM,KAAK,OAAO,UAAU,YACjC,SAAS,YAAY,UAAU,sBAAsB,EACrD;GACE,WAAW,KAAK,OAAO;GACvB;GACA,gBAAgB,MAAM;GACtB,UAAU,MAAM;GAChB,UAAU,MAAM,YAAY,EAAE;GAC/B,CACF;;;AAIL,IAAa,0BAAb,MAAiE;CAC/D;CACA;CACA;CAEA,YACE,QAKA;AALiB,OAAA,SAAA;AAMjB,OAAK,KAAK,OAAO;AACjB,OAAK,SAAS,IAAI,cAAc,OAAO;AACvC,OAAK,WAAW,IAAI,gBAAgB,OAAO;;CAG7C,gBAAyB,OACvB,UACkB;AAClB,QAAM,KAAK,OAAO,UAAU,YAAY,SAAS,YAAY,UAAU,qBAAqB,EAAE;GAC5F,GAAG;GACH,WAAW,KAAK;GACjB,CAAC;;CAGJ,cACE,YAEA,KAAK,OAAO,SAAS,GAAG,UAAU,WAAW,UAAU;AAChD,UAAQ,MAAM;GACnB"}
@@ -1,4 +1,4 @@
1
- import { ExtensionChannelConfigGetIngressPayload as ChannelConfigGetRequest, ExtensionChannelFileContent as ChannelFileContent, ExtensionChannelImageContent as ChannelImageContent, ExtensionChannelMessageContent as ChannelMessageContent, ExtensionChannelMessageSubmitIngressPayload, ExtensionChannelMessageSubmitIngressPayload as ChannelSubmittedMessage, ExtensionChannelSubmittedAttachment as ChannelSubmittedAttachment, ExtensionChannelTextContent as ChannelTextContent, ExtensionResponseIngressPayload as ExtensionRequestResponse, Unsubscribe } from "@nextclaw/shared";
1
+ import { ExtensionChannelCommandExecuteIngressPayload as ChannelCommandExecuteRequest, ExtensionChannelCommandExecuteResponse, ExtensionChannelCommandExecuteResponse as ChannelCommandExecuteResponse, ExtensionChannelCommandListIngressPayload as ChannelCommandListRequest, ExtensionChannelCommandListResponse as ChannelCommandListResponse, ExtensionChannelCommandOption as ChannelCommandOption, ExtensionChannelCommandOptionType as ChannelCommandOptionType, ExtensionChannelCommandSpec, ExtensionChannelCommandSpec as ChannelCommandSpec, ExtensionChannelConfigGetIngressPayload as ChannelConfigGetRequest, ExtensionChannelFileContent as ChannelFileContent, ExtensionChannelImageContent as ChannelImageContent, ExtensionChannelMessageContent as ChannelMessageContent, ExtensionChannelMessageSubmitIngressPayload, ExtensionChannelMessageSubmitIngressPayload as ChannelSubmittedMessage, ExtensionChannelSubmittedAttachment as ChannelSubmittedAttachment, ExtensionChannelTextContent as ChannelTextContent, ExtensionResponseIngressPayload as ExtensionRequestResponse, Unsubscribe } from "@nextclaw/shared";
2
2
  import { NcpEndpointEvent } from "@nextclaw/ncp";
3
3
 
4
4
  //#region src/types/extension-sdk.types.d.ts
@@ -38,11 +38,28 @@ type ExtensionChannelConfig = {
38
38
  get: <TConfig = unknown>() => Promise<TConfig>;
39
39
  onChange: <TConfig = unknown>(handler: (config: TConfig) => void | Promise<void>) => Unsubscribe;
40
40
  };
41
+ type ExtensionChannelCommands = {
42
+ list: () => Promise<ExtensionChannelCommandSpec[]>;
43
+ execute: (input: {
44
+ commandName: string;
45
+ args?: Record<string, unknown>;
46
+ conversationId: string;
47
+ senderId: string;
48
+ metadata?: Record<string, unknown>;
49
+ }) => Promise<ExtensionChannelCommandExecuteResponse>;
50
+ executeText: (input: {
51
+ rawText: string;
52
+ conversationId: string;
53
+ senderId: string;
54
+ metadata?: Record<string, unknown>;
55
+ }) => Promise<ExtensionChannelCommandExecuteResponse | null>;
56
+ };
41
57
  type ExtensionChannel = {
42
58
  id: string;
43
59
  submitMessage: (input: Omit<ExtensionChannelMessageSubmitIngressPayload, "channelId">) => Promise<void>;
44
60
  onNcpEvent: (handler: (event: NcpEndpointEvent) => void | Promise<void>) => Unsubscribe;
45
61
  config: ExtensionChannelConfig;
62
+ commands: ExtensionChannelCommands;
46
63
  };
47
64
  type ExtensionChannels = {
48
65
  use: (channelId: string) => ExtensionChannel;
@@ -55,5 +72,5 @@ type ExtensionCapabilities = {
55
72
  provideHandler: (kind: string, handler: ExtensionCapabilityHandler) => Unsubscribe;
56
73
  };
57
74
  //#endregion
58
- export { type ChannelConfigGetRequest, ChannelConfigGetResponse, type ChannelFileContent, type ChannelImageContent, type ChannelMessageContent, type ChannelSubmittedAttachment, type ChannelSubmittedMessage, type ChannelTextContent, ExtensionCapabilities, ExtensionCapabilityHandler, ExtensionCapabilityPayload, ExtensionChannel, ExtensionChannelConfig, ExtensionChannels, ExtensionRequest, ExtensionRequestHandler, type ExtensionRequestResponse, ExtensionTransportEnvelope, NextClawExtensionOptions, NextClawExtensionWebSocketLike };
75
+ export { type ChannelCommandExecuteRequest, type ChannelCommandExecuteResponse, type ChannelCommandListRequest, type ChannelCommandListResponse, type ChannelCommandOption, type ChannelCommandOptionType, type ChannelCommandSpec, type ChannelConfigGetRequest, ChannelConfigGetResponse, type ChannelFileContent, type ChannelImageContent, type ChannelMessageContent, type ChannelSubmittedAttachment, type ChannelSubmittedMessage, type ChannelTextContent, ExtensionCapabilities, ExtensionCapabilityHandler, ExtensionCapabilityPayload, ExtensionChannel, ExtensionChannelCommands, ExtensionChannelConfig, ExtensionChannels, ExtensionRequest, ExtensionRequestHandler, type ExtensionRequestResponse, ExtensionTransportEnvelope, NextClawExtensionOptions, NextClawExtensionWebSocketLike };
59
76
  //# sourceMappingURL=extension-sdk.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension-sdk.types.d.ts","names":[],"sources":["../../src/types/extension-sdk.types.ts"],"mappings":";;;;KAgBY,wBAAA;EACV,QAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,UAAe,KAAA;EACf,gBAAA,IAAoB,GAAA,aAAgB,8BAAA;AAAA;AAAA,KAG1B,8BAAA;EACV,MAAA;EACA,SAAA,IAAa,KAAA;IAAS,IAAA;EAAA;EACtB,OAAA,IAAW,KAAA;EACX,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,0BAAA;EACV,IAAA;EACA,WAAA;EACA,OAAA,EAAS,QAAA;EACT,SAAA;EACA,MAAA;AAAA;AAAA,KAGU,gBAAA;EACV,SAAA;EACA,WAAA;EACA,IAAA;EACA,OAAA,GAAU,MAAA;AAAA;AAAA,KAGA,wBAAA;EACV,MAAA,EAAQ,OAAA;AAAA;AAAA,KAGE,sBAAA;EACV,GAAA,2BAA8B,OAAA,CAAQ,OAAA;EACtC,QAAA,sBACE,OAAA,GAAU,MAAA,EAAQ,OAAA,YAAmB,OAAA,WAClC,WAAA;AAAA;AAAA,KAGK,gBAAA;EACV,EAAA;EACA,aAAA,GAAgB,KAAA,EAAO,IAAA,CAAK,2CAAA,mBAA8D,OAAA;EAC1F,UAAA,GAAa,OAAA,GAAU,KAAA,EAAO,gBAAA,YAA4B,OAAA,WAAkB,WAAA;EAC5E,MAAA,EAAQ,sBAAA;AAAA;AAAA,KAGE,iBAAA;EACV,GAAA,GAAM,SAAA,aAAsB,gBAAA;AAAA;AAAA,KAGlB,uBAAA,IAA2B,OAAA,EAAS,gBAAA,eAA+B,OAAA;AAAA,KAEnE,0BAAA,GAA6B,MAAA;AAAA,KAE7B,0BAAA,kBAA4C,0BAAA,GAA6B,0BAAA,KACnF,OAAA,EAAS,QAAA,EACT,OAAA,EAAS,gBAAA,eACI,OAAA;AAAA,KAEH,qBAAA;EACV,OAAA,GAAU,SAAA,UAAmB,UAAA,aAAuB,WAAA;EACpD,cAAA,GAAiB,IAAA,UAAc,OAAA,EAAS,0BAAA,KAA+B,WAAA;AAAA"}
1
+ {"version":3,"file":"extension-sdk.types.d.ts","names":[],"sources":["../../src/types/extension-sdk.types.ts"],"mappings":";;;;KAyBY,wBAAA;EACV,QAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,UAAe,KAAA;EACf,gBAAA,IAAoB,GAAA,aAAgB,8BAAA;AAAA;AAAA,KAG1B,8BAAA;EACV,MAAA;EACA,SAAA,IAAa,KAAA;IAAS,IAAA;EAAA;EACtB,OAAA,IAAW,KAAA;EACX,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,0BAAA;EACV,IAAA;EACA,WAAA;EACA,OAAA,EAAS,QAAA;EACT,SAAA;EACA,MAAA;AAAA;AAAA,KAGU,gBAAA;EACV,SAAA;EACA,WAAA;EACA,IAAA;EACA,OAAA,GAAU,MAAA;AAAA;AAAA,KAGA,wBAAA;EACV,MAAA,EAAQ,OAAA;AAAA;AAAA,KAGE,sBAAA;EACV,GAAA,2BAA8B,OAAA,CAAQ,OAAA;EACtC,QAAA,sBACE,OAAA,GAAU,MAAA,EAAQ,OAAA,YAAmB,OAAA,WAClC,WAAA;AAAA;AAAA,KAGK,wBAAA;EACV,IAAA,QAAY,OAAA,CAAQ,2BAAA;EACpB,OAAA,GAAU,KAAA;IACR,WAAA;IACA,IAAA,GAAO,MAAA;IACP,cAAA;IACA,QAAA;IACA,QAAA,GAAW,MAAA;EAAA,MACP,OAAA,CAAQ,sCAAA;EACd,WAAA,GAAc,KAAA;IACZ,OAAA;IACA,cAAA;IACA,QAAA;IACA,QAAA,GAAW,MAAA;EAAA,MACP,OAAA,CAAQ,sCAAA;AAAA;AAAA,KAGJ,gBAAA;EACV,EAAA;EACA,aAAA,GAAgB,KAAA,EAAO,IAAA,CAAK,2CAAA,mBAA8D,OAAA;EAC1F,UAAA,GAAa,OAAA,GAAU,KAAA,EAAO,gBAAA,YAA4B,OAAA,WAAkB,WAAA;EAC5E,MAAA,EAAQ,sBAAA;EACR,QAAA,EAAU,wBAAA;AAAA;AAAA,KAGA,iBAAA;EACV,GAAA,GAAM,SAAA,aAAsB,gBAAA;AAAA;AAAA,KAGlB,uBAAA,IAA2B,OAAA,EAAS,gBAAA,eAA+B,OAAA;AAAA,KAEnE,0BAAA,GAA6B,MAAA;AAAA,KAE7B,0BAAA,kBAA4C,0BAAA,GAA6B,0BAAA,KACnF,OAAA,EAAS,QAAA,EACT,OAAA,EAAS,gBAAA,eACI,OAAA;AAAA,KAEH,qBAAA;EACV,OAAA,GAAU,SAAA,UAAmB,UAAA,aAAuB,WAAA;EACpD,cAAA,GAAiB,IAAA,UAAc,OAAA,EAAS,0BAAA,KAA+B,WAAA;AAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/extension-sdk",
3
- "version": "0.1.11",
3
+ "version": "0.1.12-beta.1",
4
4
  "private": false,
5
5
  "description": "Backend SDK for NextClaw extension server processes.",
6
6
  "type": "module",
@@ -35,8 +35,8 @@
35
35
  "README.md"
36
36
  ],
37
37
  "dependencies": {
38
- "@nextclaw/shared": "0.1.11",
39
- "@nextclaw/ncp": "0.5.17"
38
+ "@nextclaw/ncp": "0.5.18-beta.1",
39
+ "@nextclaw/shared": "0.1.12-beta.1"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^20.17.6",