@openacp/cli 2026.327.3 → 2026.327.5
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/{adapter-LC2QSDAS.js → adapter-JQFQ3JAO.js} +3 -3
- package/dist/{adapter-Y55NXX6I.js → adapter-UORRGHNH.js} +32 -8
- package/dist/adapter-UORRGHNH.js.map +1 -0
- package/dist/{chunk-TRXBJEZ5.js → chunk-32LVIEPW.js} +49 -19
- package/dist/chunk-32LVIEPW.js.map +1 -0
- package/dist/{chunk-UMT7RU77.js → chunk-HRKAXFWR.js} +2 -2
- package/dist/{chunk-36YQ44D7.js → chunk-P2G275VD.js} +2 -2
- package/dist/{chunk-HUWOFP2H.js → chunk-S3ZGPPXY.js} +3 -3
- package/dist/{chunk-LP45RCA4.js → chunk-XWDW3XBE.js} +338 -414
- package/dist/chunk-XWDW3XBE.js.map +1 -0
- package/dist/{chunk-3ASUU6WW.js → chunk-ZNSO2QVC.js} +2 -2
- package/dist/cli.js +60 -40
- package/dist/cli.js.map +1 -1
- package/dist/{config-editor-3IKBPZA7.js → config-editor-7PKW42GZ.js} +2 -2
- package/dist/{core-plugins-ROU4GPLT.js → core-plugins-Y5US6RED.js} +4 -4
- package/dist/index.d.ts +4 -5
- package/dist/index.js +35 -5
- package/dist/index.js.map +1 -1
- package/dist/{main-UVTZ46WP.js → main-3GF3EQTE.js} +8 -8
- package/dist/plugin-installer-QVJP6VKV.js +42 -0
- package/dist/plugin-installer-QVJP6VKV.js.map +1 -0
- package/dist/{setup-EYAFK2WI.js → setup-A7VPW46C.js} +8 -6
- package/dist/setup-A7VPW46C.js.map +1 -0
- package/dist/{slack-37ZWBDUI.js → slack-2XNWBOWH.js} +2 -2
- package/dist/{telegram-2ZCCCZIY.js → telegram-E65IWFBW.js} +2 -2
- package/package.json +1 -1
- package/dist/adapter-Y55NXX6I.js.map +0 -1
- package/dist/chunk-LP45RCA4.js.map +0 -1
- package/dist/chunk-TRXBJEZ5.js.map +0 -1
- package/dist/plugin-installer-GQ2P3Q3E.js +0 -23
- package/dist/plugin-installer-GQ2P3Q3E.js.map +0 -1
- package/dist/setup-EYAFK2WI.js.map +0 -1
- /package/dist/{adapter-LC2QSDAS.js.map → adapter-JQFQ3JAO.js.map} +0 -0
- /package/dist/{chunk-UMT7RU77.js.map → chunk-HRKAXFWR.js.map} +0 -0
- /package/dist/{chunk-36YQ44D7.js.map → chunk-P2G275VD.js.map} +0 -0
- /package/dist/{chunk-HUWOFP2H.js.map → chunk-S3ZGPPXY.js.map} +0 -0
- /package/dist/{chunk-3ASUU6WW.js.map → chunk-ZNSO2QVC.js.map} +0 -0
- /package/dist/{config-editor-3IKBPZA7.js.map → config-editor-7PKW42GZ.js.map} +0 -0
- /package/dist/{core-plugins-ROU4GPLT.js.map → core-plugins-Y5US6RED.js.map} +0 -0
- /package/dist/{main-UVTZ46WP.js.map → main-3GF3EQTE.js.map} +0 -0
- /package/dist/{slack-37ZWBDUI.js.map → slack-2XNWBOWH.js.map} +0 -0
- /package/dist/{telegram-2ZCCCZIY.js.map → telegram-E65IWFBW.js.map} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TelegramAdapter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XWDW3XBE.js";
|
|
4
4
|
import "./chunk-AFKX424Q.js";
|
|
5
5
|
import "./chunk-QAQDGPB4.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-32LVIEPW.js";
|
|
7
7
|
import "./chunk-APS6UEFU.js";
|
|
8
8
|
import "./chunk-ODUM3D6X.js";
|
|
9
9
|
import "./chunk-QVMEF6FB.js";
|
|
@@ -12,4 +12,4 @@ import "./chunk-VUNV25KB.js";
|
|
|
12
12
|
export {
|
|
13
13
|
TelegramAdapter
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=adapter-
|
|
15
|
+
//# sourceMappingURL=adapter-JQFQ3JAO.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseRenderer,
|
|
3
3
|
MessagingAdapter
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-32LVIEPW.js";
|
|
5
5
|
import {
|
|
6
6
|
createChildLogger
|
|
7
7
|
} from "./chunk-XMMAGAT4.js";
|
|
@@ -161,7 +161,7 @@ var SlackRenderer = class extends BaseRenderer {
|
|
|
161
161
|
components: blocks
|
|
162
162
|
};
|
|
163
163
|
}
|
|
164
|
-
renderPlan(content
|
|
164
|
+
renderPlan(content) {
|
|
165
165
|
const blocks = this.formatter.formatOutgoing(content);
|
|
166
166
|
return {
|
|
167
167
|
body: content.text ?? "",
|
|
@@ -199,7 +199,11 @@ var SlackRenderer = class extends BaseRenderer {
|
|
|
199
199
|
body: request.description,
|
|
200
200
|
format: "structured",
|
|
201
201
|
components: blocks,
|
|
202
|
-
actions: request.options.map((o) => ({
|
|
202
|
+
actions: request.options.map((o) => ({
|
|
203
|
+
id: o.id,
|
|
204
|
+
label: o.label,
|
|
205
|
+
isAllow: o.isAllow
|
|
206
|
+
}))
|
|
203
207
|
};
|
|
204
208
|
}
|
|
205
209
|
renderNotification(notification) {
|
|
@@ -225,7 +229,12 @@ ${notification.summary}`;
|
|
|
225
229
|
return {
|
|
226
230
|
body: mrkdwn,
|
|
227
231
|
format: "structured",
|
|
228
|
-
components: [
|
|
232
|
+
components: [
|
|
233
|
+
{
|
|
234
|
+
type: "section",
|
|
235
|
+
text: { type: "mrkdwn", text: mrkdwn }
|
|
236
|
+
}
|
|
237
|
+
]
|
|
229
238
|
};
|
|
230
239
|
}
|
|
231
240
|
renderModeChange(content) {
|
|
@@ -234,7 +243,12 @@ ${notification.summary}`;
|
|
|
234
243
|
return {
|
|
235
244
|
body: text,
|
|
236
245
|
format: "structured",
|
|
237
|
-
components: [
|
|
246
|
+
components: [
|
|
247
|
+
{
|
|
248
|
+
type: "context",
|
|
249
|
+
elements: [{ type: "mrkdwn", text }]
|
|
250
|
+
}
|
|
251
|
+
]
|
|
238
252
|
};
|
|
239
253
|
}
|
|
240
254
|
renderConfigUpdate() {
|
|
@@ -242,7 +256,12 @@ ${notification.summary}`;
|
|
|
242
256
|
return {
|
|
243
257
|
body: text,
|
|
244
258
|
format: "structured",
|
|
245
|
-
components: [
|
|
259
|
+
components: [
|
|
260
|
+
{
|
|
261
|
+
type: "context",
|
|
262
|
+
elements: [{ type: "mrkdwn", text }]
|
|
263
|
+
}
|
|
264
|
+
]
|
|
246
265
|
};
|
|
247
266
|
}
|
|
248
267
|
renderModelUpdate(content) {
|
|
@@ -251,7 +270,12 @@ ${notification.summary}`;
|
|
|
251
270
|
return {
|
|
252
271
|
body: text,
|
|
253
272
|
format: "structured",
|
|
254
|
-
components: [
|
|
273
|
+
components: [
|
|
274
|
+
{
|
|
275
|
+
type: "context",
|
|
276
|
+
elements: [{ type: "mrkdwn", text }]
|
|
277
|
+
}
|
|
278
|
+
]
|
|
255
279
|
};
|
|
256
280
|
}
|
|
257
281
|
};
|
|
@@ -1003,4 +1027,4 @@ ${notification.summary}`;
|
|
|
1003
1027
|
export {
|
|
1004
1028
|
SlackAdapter
|
|
1005
1029
|
};
|
|
1006
|
-
//# sourceMappingURL=adapter-
|
|
1030
|
+
//# sourceMappingURL=adapter-UORRGHNH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/slack/adapter.ts","../../src/plugins/slack/utils.ts","../../src/plugins/slack/formatter.ts","../../src/plugins/slack/renderer.ts","../../src/plugins/slack/send-queue.ts","../../src/plugins/slack/slug.ts","../../src/plugins/slack/channel-manager.ts","../../src/plugins/slack/permission-handler.ts","../../src/plugins/slack/event-router.ts","../../src/plugins/slack/text-buffer.ts"],"sourcesContent":["// src/adapters/slack/adapter.ts\nimport fs from \"node:fs\";\nimport { App } from \"@slack/bolt\";\nimport { WebClient } from \"@slack/web-api\";\nimport type { OpenACPCore } from \"../../core/core.js\";\nimport type {\n OutgoingMessage,\n PermissionRequest,\n NotificationMessage,\n Attachment,\n} from \"../../core/types.js\";\nimport type { AdapterCapabilities } from \"../../core/channel.js\";\nimport type { FileServiceInterface } from \"../../core/plugin/types.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\nimport { MessagingAdapter, type MessagingAdapterConfig } from \"../../core/adapter-primitives/messaging-adapter.js\";\nimport type { DisplayVerbosity } from \"../../core/adapter-primitives/format-types.js\";\nimport type { IRenderer } from \"../../core/adapter-primitives/rendering/renderer.js\";\nimport { SlackRenderer } from \"./renderer.js\";\nconst log = createChildLogger({ module: \"slack\" });\n\nimport type { SlackChannelConfig } from \"./types.js\";\nimport type { SlackSessionMeta, SlackFileInfo } from \"./types.js\";\nimport { SlackSendQueue } from \"./send-queue.js\";\nimport { SlackFormatter } from \"./formatter.js\";\nimport { SlackChannelManager } from \"./channel-manager.js\";\nimport { SlackPermissionHandler } from \"./permission-handler.js\";\nimport { SlackEventRouter } from \"./event-router.js\";\nimport { SlackTextBuffer } from \"./text-buffer.js\";\nimport { toSlug } from \"./slug.js\";\nimport { isAudioClip } from \"./utils.js\";\n\nexport class SlackAdapter extends MessagingAdapter {\n readonly name = 'slack';\n readonly renderer!: IRenderer;\n readonly capabilities: AdapterCapabilities = {\n streaming: true, richFormatting: true, threads: true,\n reactions: false, fileUpload: true, voice: true,\n };\n\n private core: OpenACPCore;\n private app!: App;\n private webClient!: WebClient;\n private queue!: SlackSendQueue;\n private formatter: SlackFormatter;\n private channelManager!: SlackChannelManager;\n private permissionHandler!: SlackPermissionHandler;\n private eventRouter!: SlackEventRouter;\n private sessions = new Map<string, SlackSessionMeta>();\n private textBuffers = new Map<string, SlackTextBuffer>();\n private botUserId = \"\";\n private slackConfig: SlackChannelConfig;\n private fileService!: FileServiceInterface;\n\n constructor(core: OpenACPCore, config: SlackChannelConfig) {\n super(\n { configManager: core.configManager },\n { ...config as Record<string, unknown>, maxMessageLength: 3000, enabled: config.enabled ?? true } as MessagingAdapterConfig,\n );\n this.core = core;\n this.slackConfig = config;\n this.formatter = new SlackFormatter();\n (this as { renderer: IRenderer }).renderer = new SlackRenderer(this.formatter);\n }\n\n async start(): Promise<void> {\n const { botToken, appToken, signingSecret } = this.slackConfig;\n\n if (!botToken || !appToken || !signingSecret) {\n throw new Error(\"Slack adapter requires botToken, appToken, and signingSecret\");\n }\n\n this.app = new App({\n token: botToken,\n appToken,\n signingSecret,\n socketMode: true,\n });\n\n this.webClient = new WebClient(botToken);\n this.queue = new SlackSendQueue(this.webClient);\n this.fileService = this.core.fileService;\n\n // Resolve bot user ID — required to filter bot's own messages (prevent infinite loop)\n const authResult = await this.webClient.auth.test();\n if (!authResult.user_id) {\n throw new Error(\"Slack auth.test() did not return user_id — verify botToken is valid\");\n }\n this.botUserId = authResult.user_id as string;\n log.info({ botUserId: this.botUserId }, \"Slack bot authenticated\");\n\n this.channelManager = new SlackChannelManager(this.queue, this.slackConfig);\n\n // Permission handler — resolve permission gate when user clicks a button\n this.permissionHandler = new SlackPermissionHandler(\n this.queue,\n (requestId, optionId) => {\n for (const [sessionId, _meta] of this.sessions) {\n const session = this.core.sessionManager.getSession(sessionId);\n if (session && session.permissionGate.requestId === requestId) {\n session.permissionGate.resolve(optionId);\n log.info({ sessionId, requestId, optionId }, \"Permission resolved\");\n return;\n }\n }\n log.warn({ requestId, optionId }, \"No matching session found for permission response\");\n },\n );\n this.permissionHandler.register(this.app);\n\n // Event router — dispatch incoming messages from session channels to core\n this.eventRouter = new SlackEventRouter(\n (slackChannelId) => {\n for (const meta of this.sessions.values()) {\n if (meta.channelId === slackChannelId) return meta;\n }\n return undefined;\n },\n (sessionChannelSlug, text, userId, files) => {\n const processFiles = async (): Promise<Attachment[] | undefined> => {\n if (!files?.length) return undefined;\n const audioFiles = files.filter((f) => isAudioClip(f));\n if (!audioFiles.length) return undefined;\n\n const attachments: Attachment[] = [];\n for (const file of audioFiles) {\n const buffer = await this.downloadSlackFile(file.url_private);\n if (!buffer) continue;\n const mimeType = file.mimetype === \"video/mp4\" ? \"audio/mp4\" : file.mimetype;\n const sessionId = this.core.sessionManager.getSessionByThread(\"slack\", sessionChannelSlug)?.id;\n if (!sessionId) continue;\n const att = await this.fileService.saveFile(sessionId, file.name, buffer, mimeType);\n attachments.push(att);\n }\n return attachments.length > 0 ? attachments : undefined;\n };\n\n processFiles()\n .then((attachments) => {\n this.core\n .handleMessage({\n channelId: \"slack\",\n threadId: sessionChannelSlug,\n userId,\n text,\n attachments,\n })\n .catch((err) => log.error({ err }, \"handleMessage error\"));\n })\n .catch((err) => log.error({ err }, \"Failed to process audio files\"));\n },\n this.botUserId,\n this.slackConfig.notificationChannelId,\n // onNewSession: reply with guidance when user messages the notification channel\n async (_text, _userId) => {\n if (this.slackConfig.notificationChannelId) {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.slackConfig.notificationChannelId,\n text: \"💬 To start a new session, use the `/openacp-new` slash command in any channel.\",\n }).catch((err: unknown) => log.warn({ err }, \"Failed to send onNewSession reply\"));\n }\n },\n this.slackConfig,\n this.core.configManager.get().security.allowedUserIds,\n );\n this.eventRouter.register(this.app);\n\n // Start Bolt (Socket Mode)\n await this.app.start();\n log.info(\"Slack adapter started (Socket Mode)\");\n\n // Create startup session + channel (configurable — set autoCreateSession: false to skip)\n if (this.slackConfig.autoCreateSession !== false) {\n await this._createStartupSession();\n }\n }\n\n private async downloadSlackFile(url: string): Promise<Buffer | null> {\n try {\n const resp = await fetch(url, {\n headers: { Authorization: `Bearer ${this.slackConfig.botToken}` },\n });\n if (!resp.ok) {\n log.warn({ status: resp.status }, \"Failed to download Slack file\");\n return null;\n }\n // Slack returns 200 with HTML login page if bot lacks files:read scope\n const contentType = resp.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/html\")) {\n log.warn(\"Slack file download returned HTML instead of binary — bot likely missing files:read scope. Reinstall the Slack app with files:read scope.\");\n return null;\n }\n return Buffer.from(await resp.arrayBuffer());\n } catch (err) {\n log.error({ err }, \"Error downloading Slack file\");\n return null;\n }\n }\n\n private async uploadAudioFile(channelId: string, att: Attachment): Promise<void> {\n const fileBuffer = await fs.promises.readFile(att.filePath);\n await this.webClient.files.uploadV2({\n channel_id: channelId,\n file: fileBuffer,\n filename: att.fileName,\n });\n }\n\n private async _createStartupSession(): Promise<void> {\n try {\n let reuseChannelId = this.slackConfig.startupChannelId;\n\n // Try to reuse existing startup channel (Telegram ensureTopics pattern)\n if (reuseChannelId) {\n try {\n const info = await this.queue.enqueue<Record<string, unknown>>(\n \"conversations.info\", { channel: reuseChannelId },\n );\n const channel = (info as Record<string, unknown>)?.channel as Record<string, unknown> | undefined;\n if (!channel || typeof channel.is_archived !== \"boolean\") {\n log.warn({ reuseChannelId }, \"Unexpected conversations.info response shape, creating new channel\");\n reuseChannelId = undefined;\n } else if (channel.is_archived) {\n await this.queue.enqueue(\"conversations.unarchive\", { channel: reuseChannelId });\n log.info({ channelId: reuseChannelId }, \"Unarchived startup channel for reuse\");\n }\n } catch {\n // Channel deleted or inaccessible — will create new\n reuseChannelId = undefined;\n }\n }\n\n if (reuseChannelId) {\n // Reuse existing channel — create session pointing to it\n let hasSession = false;\n for (const m of this.sessions.values()) {\n if (m.channelId === reuseChannelId) { hasSession = true; break; }\n }\n if (!hasSession) {\n const session = await this.core.handleNewSession(\"slack\", undefined, undefined, { createThread: false });\n const slug = `startup-${session.id.slice(0, 8)}`;\n this.sessions.set(session.id, { channelId: reuseChannelId, channelSlug: slug });\n session.threadId = slug;\n // Persist slug to session store so session resume after restart can find it\n await this.core.sessionManager.patchRecord(session.id, {\n platform: { topicId: slug },\n });\n log.info({ sessionId: session.id, channelId: reuseChannelId }, \"Reused startup channel\");\n }\n } else {\n // Create new channel + session\n const session = await this.core.handleNewSession(\"slack\", undefined, undefined, { createThread: true });\n if (!session.threadId) {\n log.error({ sessionId: session.id }, \"Startup session created without threadId\");\n return;\n }\n\n // Persist channel ID to config for reuse on next restart\n const meta = this.sessions.get(session.id);\n if (meta) {\n await this.core.configManager.save(\n { channels: { slack: { startupChannelId: meta.channelId } } },\n );\n log.info({ sessionId: session.id, channelId: meta.channelId }, \"Saved startup channel to config\");\n }\n }\n\n // Notify\n if (this.slackConfig.notificationChannelId) {\n const startupMeta = [...this.sessions.values()].find(m =>\n m.channelId === (reuseChannelId ?? this.slackConfig.startupChannelId)\n );\n if (startupMeta) {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.slackConfig.notificationChannelId,\n text: `✅ OpenACP ready — chat with the agent in <#${startupMeta.channelId}>`,\n });\n }\n }\n } catch (err) {\n log.error({ err }, \"Failed to create/reuse Slack startup session\");\n }\n }\n\n async stop(): Promise<void> {\n // Flush all active text buffers before stopping to prevent data loss\n for (const [sessionId, buf] of this.textBuffers) {\n try {\n await buf.flush();\n } catch (err) {\n log.warn({ err, sessionId }, \"Flush failed during stop\");\n }\n buf.destroy();\n }\n this.textBuffers.clear();\n await this.app.stop();\n log.info(\"Slack adapter stopped\");\n }\n\n // --- MessagingAdapter implementations ---\n\n async createSessionThread(sessionId: string, name: string): Promise<string> {\n const meta = await this.channelManager.createChannel(sessionId, name);\n this.sessions.set(sessionId, meta);\n log.info({ sessionId, channelId: meta.channelId, slug: meta.channelSlug }, \"Session channel created\");\n // Return the slug as the threadId so that lookups via getSessionByThread work\n return meta.channelSlug;\n }\n\n async renameSessionThread(sessionId: string, newName: string): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) return;\n\n const newSlug = toSlug(newName, this.slackConfig.channelPrefix ?? \"openacp\");\n\n try {\n await this.queue.enqueue(\"conversations.rename\", {\n channel: meta.channelId,\n name: newSlug,\n });\n meta.channelSlug = newSlug;\n // Update session.threadId so getSessionByThread() keeps working after rename\n const session = this.core.sessionManager.getSession(sessionId);\n if (session) session.threadId = newSlug;\n const existingRecord = this.core.sessionManager.getSessionRecord(sessionId);\n await this.core.sessionManager.patchRecord(sessionId, {\n name: newName,\n platform: { ...(existingRecord?.platform ?? {}), topicId: newSlug },\n });\n log.info({ sessionId, newSlug }, \"Session channel renamed\");\n } catch (err) {\n log.warn({ err, sessionId }, \"Failed to rename Slack channel\");\n }\n }\n\n async deleteSessionThread(sessionId: string): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) return;\n\n try {\n await this.permissionHandler.cleanupSession(meta.channelId);\n } catch (err) {\n log.warn({ err, sessionId }, \"Failed to clean up permission buttons\");\n }\n\n try {\n await this.channelManager.archiveChannel(meta.channelId);\n log.info({ sessionId, channelId: meta.channelId }, \"Session channel archived\");\n } catch (err) {\n log.warn({ err, sessionId }, \"Failed to archive Slack channel\");\n }\n this.sessions.delete(sessionId);\n const buf = this.textBuffers.get(sessionId);\n if (buf) { buf.destroy(); this.textBuffers.delete(sessionId); }\n }\n\n private _sessionMetas = new Map<string, SlackSessionMeta>();\n\n private getSessionMeta(sessionId: string): SlackSessionMeta | undefined {\n return this._sessionMetas.get(sessionId);\n }\n\n private getTextBuffer(sessionId: string, channelId: string): SlackTextBuffer {\n let buf = this.textBuffers.get(sessionId);\n if (!buf) {\n buf = new SlackTextBuffer(channelId, sessionId, this.queue);\n this.textBuffers.set(sessionId, buf);\n }\n return buf;\n }\n\n async sendMessage(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) {\n log.warn({ sessionId }, \"No Slack channel for session, skipping message\");\n return;\n }\n\n // Store meta per-session so concurrent calls for different sessions don't overwrite each other\n this._sessionMetas.set(sessionId, meta);\n try {\n await super.sendMessage(sessionId, content);\n } finally {\n this._sessionMetas.delete(sessionId);\n }\n }\n\n // --- Handler overrides (dispatched by base class) ---\n\n protected async handleText(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n // Text chunks are buffered and flushed as a single message after idle timeout\n const buf = this.getTextBuffer(sessionId, meta.channelId);\n buf.append(content.text ?? \"\");\n }\n\n protected async handleSessionEnd(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n // Flush any pending text first\n await this.flushTextBuffer(sessionId);\n\n const blocks = this.formatter.formatOutgoing(content);\n if (blocks.length === 0) return;\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: content.text ?? content.type,\n blocks,\n });\n } catch (err) {\n log.error({ err, sessionId, type: content.type }, \"Failed to post Slack message\");\n }\n }\n\n protected async handleError(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n // Flush any pending text first\n await this.flushTextBuffer(sessionId);\n\n const blocks = this.formatter.formatOutgoing(content);\n if (blocks.length === 0) return;\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: content.text ?? content.type,\n blocks,\n });\n } catch (err) {\n log.error({ err, sessionId, type: content.type }, \"Failed to post Slack message\");\n }\n }\n\n protected async handleAttachment(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta || !content.attachment) return;\n if (content.attachment.type === \"audio\") {\n try {\n await this.uploadAudioFile(meta.channelId, content.attachment);\n const buf = this.textBuffers.get(sessionId);\n if (buf) await buf.stripTtsBlock();\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to upload audio to Slack\");\n }\n }\n }\n\n protected async handleThought(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleToolCall(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleToolUpdate(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handlePlan(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleUsage(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleSystem(sessionId: string, content: OutgoingMessage): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n // --- Private helpers ---\n\n private async flushTextBuffer(sessionId: string): Promise<void> {\n const buf = this.textBuffers.get(sessionId);\n if (buf) {\n try {\n await buf.flush();\n } catch (err) {\n log.warn({ err, sessionId }, \"Flush failed on session_end\");\n }\n buf.destroy();\n this.textBuffers.delete(sessionId);\n }\n }\n\n private async postFormattedMessage(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n const blocks = this.formatter.formatOutgoing(content);\n if (blocks.length === 0) return;\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: content.text ?? content.type,\n blocks,\n });\n } catch (err) {\n log.error({ err, sessionId, type: content.type }, \"Failed to post Slack message\");\n }\n }\n\n // NOTE: Async flow — different from Telegram adapter.\n // Telegram: sendPermissionRequest awaits user response inline.\n // Slack: posts interactive buttons and returns immediately.\n // Resolution happens asynchronously via the Bolt action handler in\n // SlackPermissionHandler, which calls the PermissionResponseCallback\n // passed during construction. The callback iterates sessions to find\n // the matching permissionGate and resolves it.\n async sendPermissionRequest(\n sessionId: string,\n request: PermissionRequest,\n ): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) return;\n\n log.info({ sessionId, requestId: request.id }, \"Sending Slack permission request\");\n const blocks = this.formatter.formatPermissionRequest(request);\n\n try {\n const result = await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: `Permission request: ${request.description}`,\n blocks,\n });\n const ts = (result as { ts?: string })?.ts;\n if (ts) {\n this.permissionHandler.trackPendingMessage(request.id, meta.channelId, ts);\n }\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to post Slack permission request\");\n }\n }\n\n async sendNotification(notification: NotificationMessage): Promise<void> {\n if (!this.slackConfig.notificationChannelId) return;\n\n const emoji: Record<string, string> = {\n completed: \"✅\",\n error: \"❌\",\n permission: \"🔐\",\n input_required: \"💬\",\n };\n const icon = emoji[notification.type] ?? \"ℹ️\";\n const text = `${icon} *${notification.sessionName ?? \"Session\"}*\\n${notification.summary}`;\n const blocks = this.formatter.formatNotification(text);\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.slackConfig.notificationChannelId,\n text,\n blocks,\n });\n } catch (err) {\n log.warn({ err, sessionId: notification.sessionId }, \"Failed to send Slack notification\");\n }\n }\n}\n\nexport type { SlackChannelConfig } from \"./types.js\";\n","// src/adapters/slack/utils.ts\n// Shared utilities for Slack adapter modules.\n\nimport type { SlackFileInfo } from \"./types.js\";\n\n/** Detect Slack audio clips — MIME type or filename pattern */\nexport function isAudioClip(file: SlackFileInfo): boolean {\n return (file.mimetype === \"video/mp4\" && file.name?.startsWith(\"audio_message\")) ||\n file.mimetype?.startsWith(\"audio/\");\n}\n\nconst SECTION_LIMIT = 3000;\n\n/**\n * Split text at nearest newline boundary before `limit`.\n * Does NOT track code fence state — a triple-backtick block straddling\n * the boundary will be split mid-block.\n * Used by SlackFormatter and SlackTextBuffer to avoid exceeding Slack's\n * 3000-char section limit.\n */\nexport function splitSafe(text: string, limit = SECTION_LIMIT): string[] {\n if (text.length <= limit) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= limit) { chunks.push(remaining); break; }\n let cut = remaining.lastIndexOf(\"\\n\", limit);\n if (cut <= 0) cut = limit;\n chunks.push(remaining.slice(0, cut));\n remaining = remaining.slice(cut).trimStart();\n }\n return chunks;\n}\n","// src/adapters/slack/formatter.ts\nimport type { types } from \"@slack/bolt\";\nimport type { OutgoingMessage, PermissionRequest } from \"../../core/types.js\";\nimport { splitSafe } from \"./utils.js\";\n\ntype KnownBlock = types.KnownBlock;\n\nexport interface ISlackFormatter {\n formatOutgoing(message: OutgoingMessage): KnownBlock[];\n formatPermissionRequest(req: PermissionRequest): KnownBlock[];\n formatNotification(text: string): KnownBlock[];\n formatSessionEnd(reason?: string): KnownBlock[];\n}\n\n/**\n * Convert a markdown string to Slack mrkdwn format.\n * Handles the most common patterns from AI responses.\n */\nexport function markdownToMrkdwn(text: string): string {\n return text\n // Fenced code blocks — preserve as-is (Slack supports ``` natively)\n // Headers: # H1 → placeholder (protected from italic regex)\n .replace(/^#{1,6}\\s+(.+)$/gm, \"\\x00BOLD\\x00$1\\x00BOLD\\x00\")\n // Bold: **text** → placeholder\n .replace(/\\*\\*(.+?)\\*\\*/g, \"\\x00BOLD\\x00$1\\x00BOLD\\x00\")\n // Italic: *text* → _text_ (won't match placeholder tokens)\n .replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, \"_$1_\")\n // Restore bold/header placeholders → *text*\n .replace(/\\x00BOLD\\x00(.+?)\\x00BOLD\\x00/g, \"*$1*\")\n // Inline code: `code` — kept as-is (Slack supports backtick)\n // Strikethrough: ~~text~~ → ~text~\n .replace(/~~(.+?)~~/g, \"~$1~\")\n // Links: [text](url) → <url|text>\n .replace(/\\[([^\\]]+)\\]\\((https?:\\/\\/[^)]+)\\)/g, \"<$2|$1>\")\n // Unordered lists: \"- item\" or \"* item\" → \"• item\"\n .replace(/^[ \\t]*[-*]\\s+/gm, \"• \")\n // Ordered lists: \"1. item\" → \"1. item\" (already fine in mrkdwn)\n .trim();\n}\n\n// Slack mrkdwn text block, max 3000 chars per section\nconst SECTION_LIMIT = 3000;\n\nfunction section(text: string): KnownBlock {\n return { type: \"section\", text: { type: \"mrkdwn\", text: text.slice(0, SECTION_LIMIT) } };\n}\n\nfunction context(text: string): KnownBlock {\n return { type: \"context\", elements: [{ type: \"mrkdwn\", text }] };\n}\n\nexport class SlackFormatter implements ISlackFormatter {\n formatOutgoing(message: OutgoingMessage): KnownBlock[] {\n switch (message.type) {\n case \"text\": {\n const text = message.text ?? \"\";\n if (!text.trim()) return [];\n const converted = markdownToMrkdwn(text);\n return splitSafe(converted).map(chunk => section(chunk));\n }\n\n case \"thought\":\n return [context(`💭 _${(message.text ?? \"\").slice(0, 500)}_`)];\n\n case \"tool_call\": {\n const name = (message as OutgoingMessage & { metadata?: { name?: string; input?: unknown } }).metadata?.name ?? \"tool\";\n const input = (message as OutgoingMessage & { metadata?: { input?: unknown } }).metadata?.input;\n const inputStr = input ? `\\n\\`\\`\\`\\n${JSON.stringify(input, null, 2).slice(0, 500)}\\n\\`\\`\\`` : \"\";\n return [context(`🔧 \\`${name}\\`${inputStr}`)];\n }\n\n case \"tool_update\": {\n const name = (message as OutgoingMessage & { metadata?: { name?: string; status?: string } }).metadata?.name ?? \"tool\";\n const status = (message as OutgoingMessage & { metadata?: { status?: string } }).metadata?.status ?? \"done\";\n const icon = status === \"error\" ? \"❌\" : \"✅\";\n return [context(`${icon} \\`${name}\\` — ${status}`)];\n }\n\n case \"plan\":\n return [\n { type: \"divider\" },\n section(`📋 *Plan*\\n${message.text ?? \"\"}`),\n ];\n\n case \"usage\": {\n const meta = (message as OutgoingMessage & { metadata?: { input_tokens?: number; output_tokens?: number; cost_usd?: number } }).metadata ?? {};\n const parts = [\n meta.input_tokens != null ? `in: ${meta.input_tokens}` : null,\n meta.output_tokens != null ? `out: ${meta.output_tokens}` : null,\n meta.cost_usd != null ? `$${Number(meta.cost_usd).toFixed(4)}` : null,\n ].filter((p): p is string => p !== null);\n return parts.length ? [context(`📊 ${parts.join(\" · \")}`)] : [];\n }\n\n case \"session_end\":\n return this.formatSessionEnd(message.text);\n\n case \"error\":\n return [section(`⚠️ *Error:* ${message.text ?? \"Unknown error\"}`)];\n\n default:\n return [];\n }\n }\n\n formatPermissionRequest(req: PermissionRequest): KnownBlock[] {\n return [\n section(`🔐 *Permission Request*\\n${req.description}`),\n {\n type: \"actions\",\n block_id: `perm_${req.id}`,\n elements: req.options.map(opt => ({\n type: \"button\" as const,\n text: { type: \"plain_text\" as const, text: opt.label, emoji: true },\n value: `${req.id}:${opt.id}`,\n action_id: `perm_action_${opt.id}_${req.id}`,\n style: (opt.isAllow ? \"primary\" : \"danger\") as \"primary\" | \"danger\",\n })),\n } as KnownBlock,\n ];\n }\n\n formatNotification(text: string): KnownBlock[] {\n return [section(text)];\n }\n\n formatSessionEnd(reason?: string): KnownBlock[] {\n return [\n { type: \"divider\" },\n context(`✅ Session ended${reason ? ` — ${reason}` : \"\"}`),\n ];\n }\n}\n","import { BaseRenderer } from \"../../core/adapter-primitives/rendering/renderer.js\";\nimport type {\n RenderedMessage,\n RenderedPermission,\n} from \"../../core/adapter-primitives/rendering/renderer.js\";\nimport type {\n OutgoingMessage,\n PermissionRequest,\n NotificationMessage,\n} from \"../../core/types.js\";\nimport type { DisplayVerbosity } from \"../../core/adapter-primitives/format-types.js\";\nimport { SlackFormatter, markdownToMrkdwn } from \"./formatter.js\";\n\n/**\n * SlackRenderer — renders messages as Slack Block Kit structures.\n * Delegates to the existing SlackFormatter for block generation,\n * wrapping results into RenderedMessage with format: 'structured'.\n */\nexport class SlackRenderer extends BaseRenderer {\n private formatter: SlackFormatter;\n\n constructor(formatter?: SlackFormatter) {\n super();\n this.formatter = formatter ?? new SlackFormatter();\n }\n\n renderText(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderThought(\n content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderToolCall(\n content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderToolUpdate(\n content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderPlan(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderUsage(\n content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderError(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content);\n return {\n body: content.text ?? \"\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderSessionEnd(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatSessionEnd(content.text);\n return {\n body: content.text ?? \"Session ended\",\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderPermission(request: PermissionRequest): RenderedPermission {\n const blocks = this.formatter.formatPermissionRequest(request);\n return {\n body: request.description,\n format: \"structured\",\n components: blocks,\n actions: request.options.map((o) => ({\n id: o.id,\n label: o.label,\n isAllow: o.isAllow,\n })),\n };\n }\n\n renderNotification(notification: NotificationMessage): RenderedMessage {\n const emoji: Record<string, string> = {\n completed: \"✅\",\n error: \"❌\",\n permission: \"🔐\",\n input_required: \"💬\",\n budget_warning: \"⚠️\",\n };\n const icon = emoji[notification.type] || \"ℹ️\";\n const text = `${icon} *${notification.sessionName ?? \"Session\"}*\\n${notification.summary}`;\n const blocks = this.formatter.formatNotification(text);\n return {\n body: text,\n format: \"structured\",\n components: blocks,\n };\n }\n\n renderSystemMessage(content: OutgoingMessage): RenderedMessage {\n const mrkdwn = markdownToMrkdwn(content.text ?? \"\");\n return {\n body: mrkdwn,\n format: \"structured\",\n components: [\n {\n type: \"section\" as const,\n text: { type: \"mrkdwn\" as const, text: mrkdwn },\n },\n ],\n };\n }\n\n renderModeChange(content: OutgoingMessage): RenderedMessage {\n const modeId = (content.metadata as Record<string, unknown>)?.modeId ?? \"\";\n const text = `🔄 *Mode:* ${modeId}`;\n return {\n body: text,\n format: \"structured\",\n components: [\n {\n type: \"context\" as const,\n elements: [{ type: \"mrkdwn\" as const, text }],\n },\n ],\n };\n }\n\n renderConfigUpdate(): RenderedMessage {\n const text = \"⚙️ *Config updated*\";\n return {\n body: text,\n format: \"structured\",\n components: [\n {\n type: \"context\" as const,\n elements: [{ type: \"mrkdwn\" as const, text }],\n },\n ],\n };\n }\n\n renderModelUpdate(content: OutgoingMessage): RenderedMessage {\n const modelId =\n (content.metadata as Record<string, unknown>)?.modelId ?? \"\";\n const text = `🤖 *Model:* ${modelId}`;\n return {\n body: text,\n format: \"structured\",\n components: [\n {\n type: \"context\" as const,\n elements: [{ type: \"mrkdwn\" as const, text }],\n },\n ],\n };\n }\n}\n","import PQueue from \"p-queue\";\nimport type { WebClient } from \"@slack/web-api\";\n\nexport type SlackMethod =\n | \"chat.postMessage\"\n | \"chat.update\"\n | \"conversations.create\"\n | \"conversations.rename\"\n | \"conversations.archive\"\n | \"conversations.invite\"\n | \"conversations.join\"\n | \"conversations.unarchive\"\n | \"conversations.info\";\n\n// Requests per minute per method (Slack Tier definitions)\nconst METHOD_RPM: Record<SlackMethod, number> = {\n \"chat.postMessage\": 50, // Tier 3\n \"chat.update\": 50, // Tier 3\n \"conversations.create\": 20, // Tier 2\n \"conversations.rename\": 20, // Tier 2\n \"conversations.archive\": 20, // Tier 2\n \"conversations.invite\": 20, // Tier 2\n \"conversations.join\": 20, // Tier 2\n \"conversations.unarchive\": 20, // Tier 2\n \"conversations.info\": 50, // Tier 3\n};\n\nexport interface ISlackSendQueue {\n enqueue<T = unknown>(method: SlackMethod, params: Record<string, unknown>): Promise<T>;\n}\n\nexport class SlackSendQueue implements ISlackSendQueue {\n private queues = new Map<SlackMethod, PQueue>();\n\n constructor(private client: WebClient) {\n for (const [method, rpm] of Object.entries(METHOD_RPM) as [SlackMethod, number][]) {\n // Spread requests evenly across the minute\n this.queues.set(method, new PQueue({\n interval: Math.ceil(60_000 / rpm),\n intervalCap: 1,\n carryoverConcurrencyCount: true,\n }));\n }\n }\n\n async enqueue<T = unknown>(method: SlackMethod, params: Record<string, unknown>): Promise<T> {\n const queue = this.queues.get(method);\n if (!queue) throw new Error(`Unknown Slack method: ${method}`);\n return queue.add(() => this.client.apiCall(method, params) as Promise<T>);\n }\n}\n","// src/adapters/slack/slug.ts\nimport { customAlphabet } from \"nanoid\";\n\nconst nanoidAlpha = customAlphabet(\"abcdefghijklmnopqrstuvwxyz0123456789\", 4);\n\n/**\n * Convert a human-readable session name to a valid Slack channel name.\n * Rules: lowercase, ≤80 chars, only [a-z0-9-], unique suffix appended.\n *\n * Examples:\n * \"Fix authentication bug\" → \"openacp-fix-authentication-bug-a3k9\"\n * \"New Session\" → \"openacp-new-session-x7p2\"\n * \"Implement OAuth 2.0 & JWT refresh\" → \"openacp-implement-oauth-20-jwt-refresh-b8qr\"\n */\nexport function toSlug(name: string, prefix = \"openacp\"): string {\n const base = name\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\") // strip special chars\n .trim()\n .replace(/\\s+/g, \"-\") // spaces → dashes\n .replace(/-+/g, \"-\") // collapse consecutive dashes\n .slice(0, 60); // leave room for prefix and suffix\n\n const suffix = nanoidAlpha();\n return `${prefix}-${base}-${suffix}`.replace(/-+/g, \"-\");\n}\n","// src/adapters/slack/channel-manager.ts\nimport type { ISlackSendQueue } from \"./send-queue.js\";\nimport { toSlug } from \"./slug.js\";\nimport type { SlackSessionMeta } from \"./types.js\";\nimport type { SlackChannelConfig } from \"./types.js\";\n\nexport interface ISlackChannelManager {\n createChannel(sessionId: string, sessionName: string): Promise<SlackSessionMeta>;\n archiveChannel(channelId: string): Promise<void>;\n notifyChannel(text: string): Promise<void>;\n}\n\nexport class SlackChannelManager implements ISlackChannelManager {\n constructor(\n private queue: ISlackSendQueue,\n private config: SlackChannelConfig,\n ) {}\n\n async createChannel(sessionId: string, sessionName: string): Promise<SlackSessionMeta> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const finalSlug = toSlug(sessionName, this.config.channelPrefix ?? \"openacp\");\n\n try {\n const res = await this.queue.enqueue<{ channel: { id: string } }>(\n \"conversations.create\",\n { name: finalSlug, is_private: true },\n );\n const channelId = res.channel.id;\n\n // Bot is automatically a member of private channels it creates — no join/invite needed.\n // Invite configured users so they can access the channel.\n const userIds = this.config.allowedUserIds ?? [];\n if (userIds.length > 0) {\n await this.queue.enqueue(\"conversations.invite\", {\n channel: channelId,\n users: userIds.join(\",\"),\n });\n }\n\n return { channelId, channelSlug: finalSlug };\n } catch (err: any) {\n if (err?.data?.error === \"name_taken\" && attempt < 2) {\n lastError = err;\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n async archiveChannel(channelId: string): Promise<void> {\n await this.queue.enqueue(\"conversations.archive\", { channel: channelId });\n }\n\n async notifyChannel(text: string): Promise<void> {\n if (this.config.notificationChannelId) {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.config.notificationChannelId,\n text,\n });\n }\n }\n}\n","import type { App, BlockAction, ButtonAction } from \"@slack/bolt\";\nimport type { ISlackSendQueue } from \"./send-queue.js\";\n\nexport type PermissionResponseCallback = (requestId: string, optionId: string) => void;\n\nexport interface ISlackPermissionHandler {\n register(app: App): void;\n trackPendingMessage(requestId: string, channelId: string, messageTs: string): void;\n cleanupSession(channelId: string): Promise<void>;\n}\n\nexport class SlackPermissionHandler implements ISlackPermissionHandler {\n private pendingMessages = new Map<string, { channelId: string; messageTs: string }>();\n\n constructor(\n private queue: ISlackSendQueue,\n private onResponse: PermissionResponseCallback,\n ) {}\n\n trackPendingMessage(requestId: string, channelId: string, messageTs: string): void {\n this.pendingMessages.set(requestId, { channelId, messageTs });\n }\n\n async cleanupSession(channelId: string): Promise<void> {\n for (const [requestId, info] of this.pendingMessages) {\n if (info.channelId !== channelId) continue;\n await this.queue.enqueue(\"chat.update\", {\n channel: info.channelId,\n ts: info.messageTs,\n blocks: [],\n });\n this.pendingMessages.delete(requestId);\n }\n }\n\n register(app: App): void {\n // Match any action starting with \"perm_action_\"\n app.action<BlockAction<ButtonAction>>(\n /^perm_action_/,\n async ({ ack, body, action }) => {\n await ack();\n\n const value: string = action.value ?? \"\";\n const colonIdx = value.indexOf(\":\");\n if (colonIdx === -1) return;\n\n const requestId = value.slice(0, colonIdx);\n const optionId = value.slice(colonIdx + 1);\n\n this.onResponse(requestId, optionId);\n\n // Remove from pending tracking since the user has responded\n this.pendingMessages.delete(requestId);\n\n // Update message to remove action buttons and show confirmation\n const message = body.message;\n if (message) {\n await this.queue.enqueue(\"chat.update\", {\n channel: body.channel?.id ?? \"\",\n ts: message.ts,\n text: `✅ Permission response: *${optionId}*`,\n blocks: [],\n });\n }\n }\n );\n }\n}\n","// src/adapters/slack/event-router.ts\nimport type { App } from \"@slack/bolt\";\nimport type { SlackSessionMeta, SlackFileInfo } from \"./types.js\";\nimport type { SlackChannelConfig } from \"./types.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\nconst log = createChildLogger({ module: \"slack-event-router\" });\n\n/** Subset of Bolt's message event fields used by the router */\ninterface SlackMessageEvent {\n bot_id?: string;\n subtype?: string;\n channel: string;\n text?: string;\n user?: string;\n files?: Array<{\n id: string;\n name: string;\n mimetype: string;\n size: number;\n url_private: string;\n }>;\n}\n\n// Callback to look up which session (if any) owns a Slack channelId\nexport type SessionLookup = (channelId: string) => SlackSessionMeta | undefined;\n\n// Callback to dispatch an incoming message to core\nexport type IncomingMessageCallback = (sessionId: string, text: string, userId: string, files?: SlackFileInfo[]) => void;\n\n// Callback to create a new session when user messages the notification channel\nexport type NewSessionCallback = (text: string, userId: string) => void;\n\nexport interface ISlackEventRouter {\n register(app: App): void;\n}\n\nexport class SlackEventRouter implements ISlackEventRouter {\n constructor(\n private sessionLookup: SessionLookup,\n private onIncoming: IncomingMessageCallback,\n private botUserId: string,\n private notificationChannelId: string | undefined,\n private onNewSession: NewSessionCallback,\n private config: SlackChannelConfig,\n private globalAllowedUserIds: string[] = [],\n ) {}\n\n private isAllowedUser(userId: string): boolean {\n const slackAllowed = this.config.allowedUserIds ?? [];\n const allowed = slackAllowed.length > 0 ? slackAllowed : this.globalAllowedUserIds;\n if (allowed.length === 0) return true;\n return allowed.includes(userId);\n }\n\n register(app: App): void {\n app.message(async ({ message }) => {\n log.debug({ message }, \"Slack raw message event\");\n\n const msg = message as unknown as SlackMessageEvent;\n\n if (msg.bot_id) return;\n const subtype = msg.subtype;\n if (subtype && subtype !== \"file_share\") return; // edited, deleted, etc.\n\n const channelId = msg.channel;\n const text: string = msg.text ?? \"\";\n const userId: string = msg.user ?? \"\";\n\n const files: SlackFileInfo[] | undefined = msg.files?.map((f) => ({\n id: f.id,\n name: f.name,\n mimetype: f.mimetype,\n size: f.size,\n url_private: f.url_private,\n }));\n\n log.debug({ channelId, userId, text }, \"Slack message received\");\n\n // Ignore messages from the bot itself\n if (userId === this.botUserId) return;\n\n // Enforce allowedUserIds\n if (!this.isAllowedUser(userId)) {\n log.warn({ userId }, \"slack: message from non-allowed user rejected\");\n return;\n }\n\n const session = this.sessionLookup(channelId);\n if (session) {\n // Message to an existing session channel\n log.debug({ channelId, sessionSlug: session.channelSlug }, \"Routing to session\");\n this.onIncoming(session.channelSlug, text, userId, files);\n return;\n }\n\n log.debug({ channelId, notificationChannelId: this.notificationChannelId }, \"No session found for channel\");\n\n // Message to the notification channel → create new session\n if (this.notificationChannelId && channelId === this.notificationChannelId) {\n this.onNewSession(text, userId);\n return;\n }\n });\n }\n}\n","// src/adapters/slack/text-buffer.ts\n// Buffers streamed text chunks per session and flushes as a single Slack message.\n// This prevents the \"many tiny messages\" problem from streaming AI responses.\n\nimport type { ISlackSendQueue } from \"./send-queue.js\";\nimport { markdownToMrkdwn } from \"./formatter.js\";\nimport { splitSafe } from \"./utils.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\n\nconst log = createChildLogger({ module: \"slack-text-buffer\" });\n\nconst FLUSH_IDLE_MS = 2000; // flush after 2s of no new chunks\n\nexport class SlackTextBuffer {\n private buffer = \"\";\n private timer: ReturnType<typeof setTimeout> | undefined;\n private flushPromise: Promise<void> | undefined;\n private lastMessageTs: string | undefined;\n private lastPostedText: string | undefined;\n\n constructor(\n private channelId: string,\n private sessionId: string,\n private queue: ISlackSendQueue,\n ) {}\n\n append(text: string): void {\n if (!text) return;\n this.buffer += text;\n this.resetTimer();\n }\n\n private resetTimer(): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.timer = undefined;\n this.flush().catch((err) => log.error({ err, sessionId: this.sessionId }, \"Text buffer flush error\"));\n }, FLUSH_IDLE_MS);\n }\n\n async flush(): Promise<void> {\n if (this.flushPromise) return this.flushPromise;\n const text = this.buffer.trim();\n if (!text) return;\n this.buffer = \"\";\n if (this.timer) { clearTimeout(this.timer); this.timer = undefined; }\n\n this.flushPromise = (async () => {\n try {\n const converted = markdownToMrkdwn(text);\n const chunks = splitSafe(converted);\n for (const chunk of chunks) {\n if (!chunk.trim()) continue;\n const result = await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.channelId,\n text: chunk,\n blocks: [{ type: \"section\", text: { type: \"mrkdwn\", text: chunk } }],\n });\n // Track last posted message for potential TTS block editing\n this.lastMessageTs = (result as { ts?: string } | undefined)?.ts;\n this.lastPostedText = chunk;\n }\n } finally {\n this.flushPromise = undefined;\n // Re-flush if content arrived while we were flushing\n if (this.buffer.trim()) {\n await this.flush();\n }\n }\n })();\n\n return this.flushPromise;\n }\n\n destroy(): void {\n if (this.timer) { clearTimeout(this.timer); this.timer = undefined; }\n this.buffer = \"\";\n }\n\n /** Remove [TTS]...[/TTS] blocks — from buffer if unflushed, or edit posted message */\n async stripTtsBlock(): Promise<void> {\n // Case 1: TTS block still in unflushed buffer\n if (/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/.test(this.buffer)) {\n this.buffer = this.buffer.replace(/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/g, \"\").replace(/\\s{2,}/g, \" \").trim();\n return;\n }\n\n // Case 2: Already flushed — edit the posted message via chat.update\n if (this.lastMessageTs && this.lastPostedText && /\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/.test(this.lastPostedText)) {\n const cleaned = this.lastPostedText.replace(/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/g, \"\").replace(/\\s{2,}/g, \" \").trim();\n if (cleaned) {\n await this.queue.enqueue(\"chat.update\", {\n channel: this.channelId,\n ts: this.lastMessageTs,\n text: cleaned,\n blocks: [{ type: \"section\", text: { type: \"mrkdwn\", text: cleaned } }],\n });\n }\n this.lastPostedText = cleaned;\n }\n }\n}\n"],"mappings":"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","names":["SECTION_LIMIT","log","log"]}
|
|
@@ -69,6 +69,7 @@ var KIND_ICONS = {
|
|
|
69
69
|
execute: "\u25B6\uFE0F",
|
|
70
70
|
command: "\u25B6\uFE0F",
|
|
71
71
|
bash: "\u25B6\uFE0F",
|
|
72
|
+
terminal: "\u25B6\uFE0F",
|
|
72
73
|
search: "\u{1F50D}",
|
|
73
74
|
web: "\u{1F310}",
|
|
74
75
|
fetch: "\u{1F310}",
|
|
@@ -137,9 +138,9 @@ function formatToolSummary(name, rawInput, displaySummary) {
|
|
|
137
138
|
const fp = args.file_path ?? args.filePath ?? "";
|
|
138
139
|
return fp ? `\u{1F4DD} Write ${fp}` : `\u{1F527} ${name}`;
|
|
139
140
|
}
|
|
140
|
-
if (lowerName === "bash") {
|
|
141
|
-
const cmd = String(args.command ?? "").slice(0, 60);
|
|
142
|
-
return cmd ? `\u25B6\uFE0F Run: ${cmd}` : `\
|
|
141
|
+
if (lowerName === "bash" || lowerName === "terminal") {
|
|
142
|
+
const cmd = String(args.command ?? args.cmd ?? "").slice(0, 60);
|
|
143
|
+
return cmd ? `\u25B6\uFE0F Run: ${cmd}` : `\u25B6\uFE0F Terminal`;
|
|
143
144
|
}
|
|
144
145
|
if (lowerName === "grep") {
|
|
145
146
|
const pattern = args.pattern ?? "";
|
|
@@ -173,8 +174,8 @@ function formatToolTitle(name, rawInput, displayTitle) {
|
|
|
173
174
|
if (["read", "edit", "write"].includes(lowerName)) {
|
|
174
175
|
return String(args.file_path ?? args.filePath ?? name);
|
|
175
176
|
}
|
|
176
|
-
if (lowerName === "bash") {
|
|
177
|
-
return String(args.command ?? name).slice(0, 60);
|
|
177
|
+
if (lowerName === "bash" || lowerName === "terminal") {
|
|
178
|
+
return String(args.command ?? args.cmd ?? name).slice(0, 60);
|
|
178
179
|
}
|
|
179
180
|
if (lowerName === "grep") {
|
|
180
181
|
const pattern = args.pattern ?? "";
|
|
@@ -218,7 +219,11 @@ var NOISE_RULES = [
|
|
|
218
219
|
},
|
|
219
220
|
{
|
|
220
221
|
match: (name) => name.toLowerCase() === "glob",
|
|
221
|
-
action: "
|
|
222
|
+
action: "hide"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
match: (name) => name.toLowerCase() === "grep",
|
|
226
|
+
action: "hide"
|
|
222
227
|
}
|
|
223
228
|
];
|
|
224
229
|
function evaluateNoise(name, kind, rawInput) {
|
|
@@ -229,7 +234,7 @@ function evaluateNoise(name, kind, rawInput) {
|
|
|
229
234
|
}
|
|
230
235
|
|
|
231
236
|
// src/core/adapter-primitives/messaging-adapter.ts
|
|
232
|
-
var HIDDEN_ON_LOW = /* @__PURE__ */ new Set(["thought", "
|
|
237
|
+
var HIDDEN_ON_LOW = /* @__PURE__ */ new Set(["thought", "usage"]);
|
|
233
238
|
var MessagingAdapter = class {
|
|
234
239
|
constructor(context, adapterConfig) {
|
|
235
240
|
this.context = context;
|
|
@@ -341,22 +346,34 @@ var BaseRenderer = class {
|
|
|
341
346
|
const meta = content.metadata ?? {};
|
|
342
347
|
const name = meta.name ?? content.text ?? "Tool";
|
|
343
348
|
const icon = resolveToolIcon(meta);
|
|
344
|
-
const label = verbosity === "low" ? formatToolTitle(
|
|
349
|
+
const label = verbosity === "low" ? formatToolTitle(
|
|
350
|
+
name,
|
|
351
|
+
meta.rawInput,
|
|
352
|
+
meta.displayTitle
|
|
353
|
+
) : formatToolSummary(
|
|
354
|
+
name,
|
|
355
|
+
meta.rawInput,
|
|
356
|
+
meta.displaySummary
|
|
357
|
+
);
|
|
345
358
|
return { body: `${icon} ${label}`, format: "plain" };
|
|
346
359
|
}
|
|
347
360
|
renderToolUpdate(content, verbosity) {
|
|
348
361
|
const meta = content.metadata ?? {};
|
|
349
362
|
const name = meta.name ?? content.text ?? "Tool";
|
|
350
363
|
const icon = resolveToolIcon(meta);
|
|
351
|
-
const label = verbosity === "low" ? formatToolTitle(
|
|
364
|
+
const label = verbosity === "low" ? formatToolTitle(
|
|
365
|
+
name,
|
|
366
|
+
meta.rawInput,
|
|
367
|
+
meta.displayTitle
|
|
368
|
+
) : formatToolSummary(
|
|
369
|
+
name,
|
|
370
|
+
meta.rawInput,
|
|
371
|
+
meta.displaySummary
|
|
372
|
+
);
|
|
352
373
|
return { body: `${icon} ${label}`, format: "plain" };
|
|
353
374
|
}
|
|
354
|
-
renderPlan(content
|
|
375
|
+
renderPlan(content) {
|
|
355
376
|
const entries = content.metadata?.entries ?? [];
|
|
356
|
-
const done = entries.filter((e) => e.status === "completed").length;
|
|
357
|
-
if (verbosity === "medium" || verbosity === "low") {
|
|
358
|
-
return { body: `\u{1F4CB} Plan: ${done}/${entries.length} steps completed`, format: "plain" };
|
|
359
|
-
}
|
|
360
377
|
const lines = entries.map((e, i) => {
|
|
361
378
|
const icon = e.status === "completed" ? "\u2705" : e.status === "in_progress" ? "\u{1F504}" : "\u2B1C";
|
|
362
379
|
return `${icon} ${i + 1}. ${e.content}`;
|
|
@@ -366,12 +383,20 @@ ${lines.join("\n")}`, format: "plain" };
|
|
|
366
383
|
}
|
|
367
384
|
renderUsage(content, verbosity) {
|
|
368
385
|
const meta = content.metadata;
|
|
369
|
-
if (!meta?.tokensUsed)
|
|
386
|
+
if (!meta?.tokensUsed)
|
|
387
|
+
return { body: "\u{1F4CA} Usage data unavailable", format: "plain" };
|
|
370
388
|
const costStr = meta.cost != null ? ` \xB7 $${meta.cost.toFixed(2)}` : "";
|
|
371
389
|
if (verbosity === "medium") {
|
|
372
|
-
return {
|
|
390
|
+
return {
|
|
391
|
+
body: `\u{1F4CA} ${formatTokens(meta.tokensUsed)} tokens${costStr}`,
|
|
392
|
+
format: "plain"
|
|
393
|
+
};
|
|
373
394
|
}
|
|
374
|
-
if (!meta.contextSize)
|
|
395
|
+
if (!meta.contextSize)
|
|
396
|
+
return {
|
|
397
|
+
body: `\u{1F4CA} ${formatTokens(meta.tokensUsed)} tokens`,
|
|
398
|
+
format: "plain"
|
|
399
|
+
};
|
|
375
400
|
const ratio = meta.tokensUsed / meta.contextSize;
|
|
376
401
|
const pct = Math.round(ratio * 100);
|
|
377
402
|
const bar = progressBar(ratio);
|
|
@@ -385,7 +410,11 @@ ${bar} ${pct}%`;
|
|
|
385
410
|
return {
|
|
386
411
|
body: request.description,
|
|
387
412
|
format: "plain",
|
|
388
|
-
actions: request.options.map((o) => ({
|
|
413
|
+
actions: request.options.map((o) => ({
|
|
414
|
+
id: o.id,
|
|
415
|
+
label: o.label,
|
|
416
|
+
isAllow: o.isAllow
|
|
417
|
+
}))
|
|
389
418
|
};
|
|
390
419
|
}
|
|
391
420
|
renderError(content) {
|
|
@@ -441,7 +470,8 @@ export {
|
|
|
441
470
|
formatToolSummary,
|
|
442
471
|
formatToolTitle,
|
|
443
472
|
resolveToolIcon,
|
|
473
|
+
evaluateNoise,
|
|
444
474
|
MessagingAdapter,
|
|
445
475
|
BaseRenderer
|
|
446
476
|
};
|
|
447
|
-
//# sourceMappingURL=chunk-
|
|
477
|
+
//# sourceMappingURL=chunk-32LVIEPW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/adapter-primitives/format-utils.ts","../../src/core/adapter-primitives/format-types.ts","../../src/core/adapter-primitives/message-formatter.ts","../../src/core/adapter-primitives/messaging-adapter.ts","../../src/core/adapter-primitives/rendering/renderer.ts"],"sourcesContent":["export function progressBar(ratio: number, length = 10): string {\n const filled = Math.round(Math.min(ratio, 1) * length);\n return \"▓\".repeat(filled) + \"░\".repeat(length - filled);\n}\n\nexport function formatTokens(n: number): string {\n return n >= 1000 ? `${Math.round(n / 1000)}k` : String(n);\n}\n\nexport function stripCodeFences(text: string): string {\n return text\n .replace(/```\\w*\\n?/g, \"\")\n .replace(/```$/gm, \"\")\n .trim();\n}\n\nexport function truncateContent(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return text.slice(0, maxLen) + \"\\n… (truncated)\";\n}\n\nexport function splitMessage(text: string, maxLength: number): string[] {\n if (text.length <= maxLength) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n\n const wouldLeaveSmall = remaining.length < maxLength * 1.3;\n const searchLimit = wouldLeaveSmall\n ? Math.floor(remaining.length / 2) + 300\n : maxLength;\n\n const threshold = maxLength * 0.2;\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", searchLimit);\n if (splitAt === -1 || splitAt < threshold) {\n splitAt = remaining.lastIndexOf(\"\\n\", searchLimit);\n }\n if (splitAt === -1 || splitAt < threshold) {\n splitAt = searchLimit;\n }\n\n const candidate = remaining.slice(0, splitAt);\n const fences = candidate.match(/```/g);\n if (fences && fences.length % 2 !== 0) {\n const closingFence = remaining.indexOf(\"```\", splitAt);\n if (closingFence !== -1) {\n const afterFence = remaining.indexOf(\"\\n\", closingFence + 3);\n const fenceSplit =\n afterFence !== -1 ? afterFence + 1 : closingFence + 3;\n // Only extend to include the closing fence if it doesn't exceed 2x maxLength\n if (fenceSplit <= maxLength * 2) {\n splitAt = fenceSplit;\n }\n }\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).replace(/^\\n+/, \"\");\n }\n return chunks;\n}\n","// src/adapters/shared/format-types.ts\n\nexport type DisplayVerbosity = \"low\" | \"medium\" | \"high\";\n\nexport type NoiseAction = \"hide\" | \"collapse\";\n\nexport interface NoiseRule {\n match: (name: string, kind: string, rawInput: unknown) => boolean;\n action: NoiseAction;\n}\n\nexport type MessageStyle =\n | \"text\"\n | \"thought\"\n | \"tool\"\n | \"plan\"\n | \"usage\"\n | \"system\"\n | \"error\"\n | \"attachment\";\n\nexport interface MessageMetadata {\n toolName?: string;\n toolStatus?: string;\n toolKind?: string;\n filePath?: string;\n command?: string;\n planEntries?: { content: string; status: string }[];\n tokens?: number;\n contextSize?: number;\n cost?: number;\n viewerLinks?: ViewerLinks;\n viewerFilePath?: string;\n}\n\n/** summary and detail are always plain text (never pre-escaped HTML/markdown) — renderers handle escaping */\nexport interface FormattedMessage {\n summary: string;\n detail?: string;\n viewerLinks?: ViewerLinks;\n icon: string;\n originalType: string;\n style: MessageStyle;\n metadata?: MessageMetadata;\n}\n\nexport const STATUS_ICONS: Record<string, string> = {\n pending: \"⏳\",\n in_progress: \"🔄\",\n completed: \"✅\",\n failed: \"❌\",\n cancelled: \"🚫\",\n running: \"🔄\",\n done: \"✅\",\n error: \"❌\",\n};\n\nexport const KIND_ICONS: Record<string, string> = {\n read: \"📖\",\n edit: \"✏️\",\n write: \"✏️\",\n delete: \"🗑️\",\n execute: \"▶️\",\n command: \"▶️\",\n bash: \"▶️\",\n terminal: \"▶️\",\n search: \"🔍\",\n web: \"🌐\",\n fetch: \"🌐\",\n agent: \"🧠\",\n think: \"🧠\",\n install: \"📦\",\n move: \"📦\",\n other: \"🛠️\",\n};\n\nexport interface ViewerLinks {\n file?: string;\n diff?: string;\n}\n\nexport interface ToolCallMeta {\n id: string;\n name: string;\n kind?: string;\n status?: string;\n content?: unknown;\n rawInput?: unknown;\n viewerLinks?: ViewerLinks;\n viewerFilePath?: string;\n displaySummary?: string;\n displayTitle?: string;\n displayKind?: string;\n}\n\nexport interface ToolUpdateMeta extends ToolCallMeta {\n status: string;\n}\n","import type { NoiseAction, NoiseRule } from \"./format-types.js\";\nimport { STATUS_ICONS, KIND_ICONS } from \"./format-types.js\";\n\nexport function extractContentText(content: unknown, depth = 0): string {\n if (!content || depth > 5) return \"\";\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((c) => extractContentText(c, depth + 1))\n .filter(Boolean)\n .join(\"\\n\");\n }\n if (typeof content !== \"object\") return String(content);\n\n const obj = content as Record<string, unknown>;\n if (obj.text && typeof obj.text === \"string\") return obj.text;\n if (obj.content) {\n if (typeof obj.content === \"string\") return obj.content;\n if (Array.isArray(obj.content)) {\n return obj.content\n .map((c) => extractContentText(c, depth + 1))\n .filter(Boolean)\n .join(\"\\n\");\n }\n return extractContentText(obj.content, depth + 1);\n }\n if (obj.input) return extractContentText(obj.input, depth + 1);\n if (obj.output) return extractContentText(obj.output, depth + 1);\n\n // Skip objects with only a 'type' key and no content fields\n const keys = Object.keys(obj).filter((k) => k !== \"type\");\n if (keys.length === 0) return \"\";\n\n // Fallback: serialize unrecognized objects so edge-case agent responses are not silently dropped\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return \"\";\n }\n}\n\nfunction parseRawInput(rawInput: unknown): Record<string, unknown> {\n try {\n if (typeof rawInput === \"string\") {\n return JSON.parse(rawInput) as Record<string, unknown>;\n }\n if (typeof rawInput === \"object\" && rawInput !== null) {\n return rawInput as Record<string, unknown>;\n }\n } catch {\n // fall through\n }\n return {};\n}\n\n// --- Step 5: formatToolSummary with displaySummary override ---\n\nexport function formatToolSummary(\n name: string,\n rawInput: unknown,\n displaySummary?: string,\n): string {\n if (displaySummary && typeof displaySummary === \"string\") {\n return displaySummary;\n }\n\n const args = parseRawInput(rawInput);\n const lowerName = name.toLowerCase();\n\n if (lowerName === \"read\") {\n const fp = args.file_path ?? args.filePath ?? \"\";\n const limit = args.limit ? ` (${args.limit} lines)` : \"\";\n return fp ? `📖 Read ${fp}${limit}` : `🔧 ${name}`;\n }\n if (lowerName === \"edit\") {\n const fp = args.file_path ?? args.filePath ?? \"\";\n return fp ? `✏️ Edit ${fp}` : `🔧 ${name}`;\n }\n if (lowerName === \"write\") {\n const fp = args.file_path ?? args.filePath ?? \"\";\n return fp ? `📝 Write ${fp}` : `🔧 ${name}`;\n }\n if (lowerName === \"bash\" || lowerName === \"terminal\") {\n const cmd = String(args.command ?? args.cmd ?? \"\").slice(0, 60);\n return cmd ? `▶️ Run: ${cmd}` : `▶️ Terminal`;\n }\n if (lowerName === \"grep\") {\n const pattern = args.pattern ?? \"\";\n const path = args.path ?? \"\";\n return pattern\n ? `🔍 Grep \"${pattern}\"${path ? ` in ${path}` : \"\"}`\n : `🔧 ${name}`;\n }\n if (lowerName === \"glob\") {\n const pattern = args.pattern ?? \"\";\n return pattern ? `🔍 Glob ${pattern}` : `🔧 ${name}`;\n }\n if (lowerName === \"agent\") {\n const desc = String(args.description ?? \"\").slice(0, 60);\n return desc ? `🧠 Agent: ${desc}` : `🔧 ${name}`;\n }\n if (lowerName === \"webfetch\" || lowerName === \"web_fetch\") {\n const url = String(args.url ?? \"\").slice(0, 60);\n return url ? `🌐 Fetch ${url}` : `🔧 ${name}`;\n }\n if (lowerName === \"websearch\" || lowerName === \"web_search\") {\n const query = String(args.query ?? \"\").slice(0, 60);\n return query ? `🌐 Search \"${query}\"` : `🔧 ${name}`;\n }\n\n return `🔧 ${name}`;\n}\n\n// --- Step 6: formatToolTitle for low verbosity ---\n\nexport function formatToolTitle(\n name: string,\n rawInput: unknown,\n displayTitle?: string,\n): string {\n if (displayTitle && typeof displayTitle === \"string\") {\n return displayTitle;\n }\n\n const args = parseRawInput(rawInput);\n const lowerName = name.toLowerCase();\n\n if ([\"read\", \"edit\", \"write\"].includes(lowerName)) {\n return String(args.file_path ?? args.filePath ?? name);\n }\n if (lowerName === \"bash\" || lowerName === \"terminal\") {\n return String(args.command ?? args.cmd ?? name).slice(0, 60);\n }\n if (lowerName === \"grep\") {\n const pattern = args.pattern ?? \"\";\n const path = args.path ?? \"\";\n return pattern ? `\"${pattern}\"${path ? ` in ${path}` : \"\"}` : name;\n }\n if (lowerName === \"glob\") {\n return String(args.pattern ?? name);\n }\n if (lowerName === \"agent\") {\n return String(args.description ?? name).slice(0, 60);\n }\n if ([\"webfetch\", \"web_fetch\"].includes(lowerName)) {\n return String(args.url ?? name).slice(0, 60);\n }\n if ([\"websearch\", \"web_search\"].includes(lowerName)) {\n return String(args.query ?? name).slice(0, 60);\n }\n\n return name;\n}\n\n// --- Step 7: resolveToolIcon ---\n\nexport function resolveToolIcon(tool: {\n status?: string;\n displayKind?: string;\n kind?: string;\n}): string {\n const statusIcon = STATUS_ICONS[tool.status || \"\"];\n if (statusIcon) return statusIcon;\n const kind = tool.displayKind ?? tool.kind;\n if (kind && KIND_ICONS[kind]) return KIND_ICONS[kind];\n return \"🔧\";\n}\n\n// --- Step 8: Noise filtering ---\n\nconst NOISE_RULES: NoiseRule[] = [\n {\n match: (name) => name.toLowerCase() === \"ls\",\n action: \"hide\",\n },\n {\n match: (_name, kind, rawInput) => {\n if (kind !== \"read\") return false;\n const args = parseRawInput(rawInput);\n const p = String(args.file_path ?? args.filePath ?? args.path ?? \"\");\n return p.endsWith(\"/\");\n },\n action: \"hide\",\n },\n {\n match: (name) => name.toLowerCase() === \"glob\",\n action: \"hide\",\n },\n {\n match: (name) => name.toLowerCase() === \"grep\",\n action: \"hide\",\n },\n];\n\nexport function evaluateNoise(\n name: string,\n kind: string,\n rawInput: unknown,\n): NoiseAction | null {\n for (const rule of NOISE_RULES) {\n if (rule.match(name, kind, rawInput)) return rule.action;\n }\n return null;\n}\n","import type {\n IChannelAdapter,\n ChannelConfig,\n AdapterCapabilities,\n} from \"../channel.js\";\nimport type {\n OutgoingMessage,\n PermissionRequest,\n NotificationMessage,\n} from \"../types.js\";\nimport type { DisplayVerbosity, ToolCallMeta } from \"./format-types.js\";\nimport type { IRenderer } from \"./rendering/renderer.js\";\nimport { evaluateNoise } from \"./message-formatter.js\";\n\nexport interface AdapterContext {\n configManager: { get(): Record<string, unknown> };\n fileService?: unknown;\n}\n\nexport interface MessagingAdapterConfig extends ChannelConfig {\n maxMessageLength: number;\n flushInterval?: number;\n sendInterval?: number;\n thinkingRefreshInterval?: number;\n thinkingDuration?: number;\n displayVerbosity?: DisplayVerbosity;\n}\n\nexport interface SentMessage {\n messageId: string;\n}\n\nconst HIDDEN_ON_LOW = new Set([\"thought\", \"usage\"]);\n\nexport abstract class MessagingAdapter implements IChannelAdapter {\n abstract readonly name: string;\n abstract readonly renderer: IRenderer;\n abstract readonly capabilities: AdapterCapabilities;\n\n constructor(\n protected context: AdapterContext,\n protected adapterConfig: MessagingAdapterConfig,\n ) {}\n\n // === Message dispatch flow ===\n\n async sendMessage(\n sessionId: string,\n content: OutgoingMessage,\n ): Promise<void> {\n const verbosity = this.getVerbosity();\n if (!this.shouldDisplay(content, verbosity)) return;\n await this.dispatchMessage(sessionId, content, verbosity);\n }\n\n protected async dispatchMessage(\n sessionId: string,\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): Promise<void> {\n switch (content.type) {\n case \"text\":\n return this.handleText(sessionId, content);\n case \"thought\":\n return this.handleThought(sessionId, content, verbosity);\n case \"tool_call\":\n return this.handleToolCall(sessionId, content, verbosity);\n case \"tool_update\":\n return this.handleToolUpdate(sessionId, content, verbosity);\n case \"plan\":\n return this.handlePlan(sessionId, content, verbosity);\n case \"usage\":\n return this.handleUsage(sessionId, content, verbosity);\n case \"error\":\n return this.handleError(sessionId, content);\n case \"attachment\":\n return this.handleAttachment(sessionId, content);\n case \"system_message\":\n return this.handleSystem(sessionId, content);\n case \"session_end\":\n return this.handleSessionEnd(sessionId, content);\n case \"mode_change\":\n return this.handleModeChange(sessionId, content);\n case \"config_update\":\n return this.handleConfigUpdate(sessionId, content);\n case \"model_update\":\n return this.handleModelUpdate(sessionId, content);\n case \"user_replay\":\n return this.handleUserReplay(sessionId, content);\n case \"resource\":\n return this.handleResource(sessionId, content);\n case \"resource_link\":\n return this.handleResourceLink(sessionId, content);\n }\n }\n\n // === Default handlers — all protected, all overridable ===\n\n protected async handleText(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleThought(\n _sessionId: string,\n _content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): Promise<void> {}\n protected async handleToolCall(\n _sessionId: string,\n _content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): Promise<void> {}\n protected async handleToolUpdate(\n _sessionId: string,\n _content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): Promise<void> {}\n protected async handlePlan(\n _sessionId: string,\n _content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): Promise<void> {}\n protected async handleUsage(\n _sessionId: string,\n _content: OutgoingMessage,\n _verbosity: DisplayVerbosity,\n ): Promise<void> {}\n protected async handleError(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleAttachment(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleSystem(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleSessionEnd(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleModeChange(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleConfigUpdate(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleModelUpdate(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleUserReplay(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleResource(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n protected async handleResourceLink(\n _sessionId: string,\n _content: OutgoingMessage,\n ): Promise<void> {}\n\n // === Helpers ===\n\n protected getVerbosity(): DisplayVerbosity {\n const config = this.context.configManager.get();\n const channelConfig = (config as Record<string, unknown>).channels as\n | Record<string, Record<string, unknown>>\n | undefined;\n const v =\n channelConfig?.[this.name]?.displayVerbosity ??\n this.adapterConfig.displayVerbosity;\n if (v === \"low\" || v === \"high\") return v;\n return \"medium\";\n }\n\n protected shouldDisplay(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): boolean {\n if (verbosity === \"low\" && HIDDEN_ON_LOW.has(content.type)) return false;\n\n if (content.type === \"tool_call\") {\n const meta = (content.metadata ?? {}) as Partial<ToolCallMeta>;\n const toolName = meta.name ?? content.text ?? \"\";\n const toolKind = String(meta.kind ?? \"other\");\n const noiseAction = evaluateNoise(toolName, toolKind, meta.rawInput);\n if (noiseAction === \"hide\" && verbosity !== \"high\") return false;\n if (noiseAction === \"collapse\" && verbosity === \"low\") return false;\n }\n\n return true;\n }\n\n // === Abstract — adapter MUST implement ===\n\n abstract start(): Promise<void>;\n abstract stop(): Promise<void>;\n abstract createSessionThread(\n sessionId: string,\n name: string,\n ): Promise<string>;\n abstract renameSessionThread(\n sessionId: string,\n newName: string,\n ): Promise<void>;\n abstract sendPermissionRequest(\n sessionId: string,\n request: PermissionRequest,\n ): Promise<void>;\n abstract sendNotification(notification: NotificationMessage): Promise<void>;\n}\n","import type {\n OutgoingMessage,\n PermissionRequest,\n NotificationMessage,\n} from \"../../types.js\";\nimport type {\n DisplayVerbosity,\n ToolCallMeta,\n ToolUpdateMeta,\n} from \"../format-types.js\";\nimport {\n formatToolSummary,\n formatToolTitle,\n resolveToolIcon,\n} from \"../message-formatter.js\";\nimport { progressBar, formatTokens } from \"../format-utils.js\";\n\nexport interface RenderedMessage<TComponents = unknown> {\n body: string;\n format: \"html\" | \"markdown\" | \"plain\" | \"structured\";\n attachments?: RenderedAttachment[];\n components?: TComponents;\n}\n\nexport interface RenderedPermission<\n TComponents = unknown,\n> extends RenderedMessage<TComponents> {\n actions: RenderedAction[];\n}\n\nexport interface RenderedAction {\n id: string;\n label: string;\n isAllow?: boolean;\n}\n\nexport interface RenderedAttachment {\n type: \"file\" | \"image\" | \"audio\";\n data: Buffer | string;\n mimeType?: string;\n filename?: string;\n}\n\nexport interface IRenderer {\n renderText(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderToolCall(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderToolUpdate(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderPlan(content: OutgoingMessage): RenderedMessage;\n renderUsage(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderPermission(request: PermissionRequest): RenderedPermission;\n renderError(content: OutgoingMessage): RenderedMessage;\n renderNotification(notification: NotificationMessage): RenderedMessage;\n renderThought?(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderAttachment?(content: OutgoingMessage): RenderedMessage;\n renderSessionEnd?(content: OutgoingMessage): RenderedMessage;\n renderSystemMessage?(content: OutgoingMessage): RenderedMessage;\n renderModeChange?(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderConfigUpdate?(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderModelUpdate?(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage;\n renderResource?(content: OutgoingMessage): RenderedMessage;\n renderResourceLink?(content: OutgoingMessage): RenderedMessage;\n}\n\n/**\n * BaseRenderer — plain text defaults. Extend for platform-specific rendering.\n */\nexport class BaseRenderer implements IRenderer {\n renderText(content: OutgoingMessage): RenderedMessage {\n return { body: content.text, format: \"plain\" };\n }\n\n renderToolCall(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const meta = (content.metadata ?? {}) as Partial<ToolCallMeta>;\n const name = meta.name ?? content.text ?? \"Tool\";\n const icon = resolveToolIcon(meta);\n const label =\n verbosity === \"low\"\n ? formatToolTitle(\n name,\n meta.rawInput,\n meta.displayTitle as string | undefined,\n )\n : formatToolSummary(\n name,\n meta.rawInput,\n meta.displaySummary as string | undefined,\n );\n return { body: `${icon} ${label}`, format: \"plain\" };\n }\n\n renderToolUpdate(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const meta = (content.metadata ?? {}) as Partial<ToolUpdateMeta>;\n const name = meta.name ?? content.text ?? \"Tool\";\n const icon = resolveToolIcon(meta);\n const label =\n verbosity === \"low\"\n ? formatToolTitle(\n name,\n meta.rawInput,\n meta.displayTitle as string | undefined,\n )\n : formatToolSummary(\n name,\n meta.rawInput,\n meta.displaySummary as string | undefined,\n );\n return { body: `${icon} ${label}`, format: \"plain\" };\n }\n\n renderPlan(content: OutgoingMessage): RenderedMessage {\n const entries =\n (\n content.metadata as {\n entries?: Array<{ content: string; status: string }>;\n }\n )?.entries ?? [];\n const lines = entries.map((e, i) => {\n const icon =\n e.status === \"completed\"\n ? \"✅\"\n : e.status === \"in_progress\"\n ? \"🔄\"\n : \"⬜\";\n return `${icon} ${i + 1}. ${e.content}`;\n });\n return { body: `📋 Plan\\n${lines.join(\"\\n\")}`, format: \"plain\" };\n }\n\n renderUsage(\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): RenderedMessage {\n const meta = content.metadata as\n | { tokensUsed?: number; contextSize?: number; cost?: number }\n | undefined;\n if (!meta?.tokensUsed)\n return { body: \"📊 Usage data unavailable\", format: \"plain\" };\n const costStr = meta.cost != null ? ` · $${meta.cost.toFixed(2)}` : \"\";\n if (verbosity === \"medium\") {\n return {\n body: `📊 ${formatTokens(meta.tokensUsed)} tokens${costStr}`,\n format: \"plain\",\n };\n }\n if (!meta.contextSize)\n return {\n body: `📊 ${formatTokens(meta.tokensUsed)} tokens`,\n format: \"plain\",\n };\n const ratio = meta.tokensUsed / meta.contextSize;\n const pct = Math.round(ratio * 100);\n const bar = progressBar(ratio);\n let text = `📊 ${formatTokens(meta.tokensUsed)} / ${formatTokens(meta.contextSize)} tokens\\n${bar} ${pct}%`;\n if (meta.cost != null) text += `\\n💰 $${meta.cost.toFixed(2)}`;\n return { body: text, format: \"plain\" };\n }\n\n renderPermission(request: PermissionRequest): RenderedPermission {\n return {\n body: request.description,\n format: \"plain\",\n actions: request.options.map((o) => ({\n id: o.id,\n label: o.label,\n isAllow: o.isAllow,\n })),\n };\n }\n\n renderError(content: OutgoingMessage): RenderedMessage {\n return { body: `❌ Error: ${content.text}`, format: \"plain\" };\n }\n\n renderNotification(notification: NotificationMessage): RenderedMessage {\n const emoji: Record<string, string> = {\n completed: \"✅\",\n error: \"❌\",\n permission: \"🔐\",\n input_required: \"💬\",\n budget_warning: \"⚠️\",\n };\n return {\n body: `${emoji[notification.type] || \"ℹ️\"} ${notification.sessionName || \"Session\"}\\n${notification.summary}`,\n format: \"plain\",\n };\n }\n\n renderSystemMessage(content: OutgoingMessage): RenderedMessage {\n return { body: content.text, format: \"plain\" };\n }\n\n renderModeChange(content: OutgoingMessage): RenderedMessage {\n const modeId = (content.metadata as Record<string, unknown>)?.modeId ?? \"\";\n return { body: `🔄 Mode: ${modeId}`, format: \"plain\" };\n }\n\n renderConfigUpdate(): RenderedMessage {\n return { body: \"⚙️ Config updated\", format: \"plain\" };\n }\n\n renderModelUpdate(content: OutgoingMessage): RenderedMessage {\n const modelId =\n (content.metadata as Record<string, unknown>)?.modelId ?? \"\";\n return { body: `🤖 Model: ${modelId}`, format: \"plain\" };\n }\n\n renderResource(content: OutgoingMessage): RenderedMessage {\n const uri = (content.metadata as Record<string, unknown>)?.uri ?? \"\";\n return { body: `📄 Resource: ${content.text} (${uri})`, format: \"plain\" };\n }\n\n renderResourceLink(content: OutgoingMessage): RenderedMessage {\n const uri = (content.metadata as Record<string, unknown>)?.uri ?? \"\";\n return { body: `🔗 ${content.text}: ${uri}`, format: \"plain\" };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -167,7 +167,7 @@ async function ensureDiscordPlugin() {
|
|
|
167
167
|
}
|
|
168
168
|
try {
|
|
169
169
|
console.log(dim(`Installing ${DISCORD_PACKAGE}...`));
|
|
170
|
-
const { installNpmPlugin } = await import("./plugin-installer-
|
|
170
|
+
const { installNpmPlugin } = await import("./plugin-installer-QVJP6VKV.js");
|
|
171
171
|
const mod = await installNpmPlugin(DISCORD_PACKAGE);
|
|
172
172
|
console.log(ok(`${DISCORD_PACKAGE} installed`));
|
|
173
173
|
return mod;
|
|
@@ -676,4 +676,4 @@ function flattenToPaths(obj, prefix = "") {
|
|
|
676
676
|
export {
|
|
677
677
|
runConfigEditor
|
|
678
678
|
};
|
|
679
|
-
//# sourceMappingURL=chunk-
|
|
679
|
+
//# sourceMappingURL=chunk-HRKAXFWR.js.map
|
|
@@ -146,7 +146,7 @@ function createTelegramPlugin() {
|
|
|
146
146
|
ctx.log.info("Telegram disabled (missing botToken or chatId)");
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
|
-
const { TelegramAdapter } = await import("./adapter-
|
|
149
|
+
const { TelegramAdapter } = await import("./adapter-JQFQ3JAO.js");
|
|
150
150
|
adapter = new TelegramAdapter(ctx.core, {
|
|
151
151
|
...config,
|
|
152
152
|
enabled: true,
|
|
@@ -209,4 +209,4 @@ var telegram_default = createTelegramPlugin();
|
|
|
209
209
|
export {
|
|
210
210
|
telegram_default
|
|
211
211
|
};
|
|
212
|
-
//# sourceMappingURL=chunk-
|
|
212
|
+
//# sourceMappingURL=chunk-P2G275VD.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
telegram_default
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P2G275VD.js";
|
|
4
4
|
import {
|
|
5
5
|
slack_default
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZNSO2QVC.js";
|
|
7
7
|
import {
|
|
8
8
|
notifications_default
|
|
9
9
|
} from "./chunk-SNPYTMPR.js";
|
|
@@ -45,4 +45,4 @@ var corePlugins = [
|
|
|
45
45
|
export {
|
|
46
46
|
corePlugins
|
|
47
47
|
};
|
|
48
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-S3ZGPPXY.js.map
|