@openacp/cli 0.2.4 → 0.2.11
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/chunk-I6KXISAR.js +1481 -0
- package/dist/chunk-I6KXISAR.js.map +1 -0
- package/dist/{chunk-M5ZYTPZY.js → chunk-KADEDKIM.js} +4 -4
- package/dist/chunk-KADEDKIM.js.map +1 -0
- package/dist/cli.js +3 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/dist/{main-GIN2OHQV.js → main-L5JD5STD.js} +8 -17
- package/dist/main-L5JD5STD.js.map +1 -0
- package/dist/setup-2UVU4YYA.js +284 -0
- package/dist/setup-2UVU4YYA.js.map +1 -0
- package/package.json +3 -3
- package/dist/chunk-6YLIH7L5.js +0 -669
- package/dist/chunk-6YLIH7L5.js.map +0 -1
- package/dist/chunk-LZOMFHX3.js +0 -38
- package/dist/chunk-LZOMFHX3.js.map +0 -1
- package/dist/chunk-M5ZYTPZY.js.map +0 -1
- package/dist/main-GIN2OHQV.js.map +0 -1
- package/dist/setup-KOMX6WTE.js +0 -2200
- package/dist/setup-KOMX6WTE.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/streams.ts","../../src/core/stderr-capture.ts","../../src/core/agent-instance.ts","../../src/core/agent-manager.ts","../../src/core/session.ts","../../src/core/session-manager.ts","../../src/core/notification.ts","../../src/core/core.ts","../../src/core/channel.ts","../../src/adapters/telegram/adapter.ts","../../src/adapters/telegram/formatting.ts","../../src/adapters/telegram/streaming.ts","../../src/adapters/telegram/topics.ts","../../src/adapters/telegram/commands.ts","../../src/adapters/telegram/permissions.ts","../../src/adapters/telegram/assistant.ts"],"sourcesContent":["import type { Writable, Readable } from 'node:stream'\n\nexport function nodeToWebWritable(nodeStream: Writable): WritableStream<Uint8Array> {\n return new WritableStream<Uint8Array>({\n write(chunk) {\n return new Promise<void>((resolve, reject) => {\n nodeStream.write(Buffer.from(chunk), (err) => {\n if (err) reject(err)\n else resolve()\n })\n })\n },\n })\n}\n\nexport function nodeToWebReadable(nodeStream: Readable): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n nodeStream.on('data', (chunk: Buffer) => {\n controller.enqueue(new Uint8Array(chunk))\n })\n nodeStream.on('end', () => controller.close())\n nodeStream.on('error', (err) => controller.error(err))\n },\n })\n}\n","export class StderrCapture {\n private lines: string[] = []\n\n constructor(private maxLines: number = 50) {}\n\n append(chunk: string): void {\n this.lines.push(...chunk.split('\\n').filter(Boolean))\n if (this.lines.length > this.maxLines) {\n this.lines = this.lines.slice(-this.maxLines)\n }\n }\n\n getLastLines(): string {\n return this.lines.join('\\n')\n }\n}\n","import { spawn, execSync, type ChildProcess } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { ClientSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'\nimport type { Agent, Client, PromptResponse, PermissionOption as SdkPermissionOption } from '@agentclientprotocol/sdk'\nimport { nodeToWebWritable, nodeToWebReadable } from './streams.js'\nimport { StderrCapture } from './stderr-capture.js'\nimport type { AgentDefinition, AgentEvent, PermissionRequest } from './types.js'\nimport { log } from './log.js'\n\n/** Resolve an agent command to a directly executable form (avoids shell wrappers) */\nfunction resolveAgentCommand(cmd: string): { command: string; args: string[] } {\n // 1. Check local node_modules for the package's actual JS entry point\n const packageDirs = [\n path.resolve(process.cwd(), 'node_modules', '@zed-industries', cmd, 'dist', 'index.js'),\n path.resolve(process.cwd(), 'node_modules', cmd, 'dist', 'index.js'),\n ]\n for (const jsPath of packageDirs) {\n if (fs.existsSync(jsPath)) {\n return { command: process.execPath, args: [jsPath] }\n }\n }\n\n // 2. Check local .bin — if it's a JS file with shebang, run with node directly\n const localBin = path.resolve(process.cwd(), 'node_modules', '.bin', cmd)\n if (fs.existsSync(localBin)) {\n const content = fs.readFileSync(localBin, 'utf-8')\n if (content.startsWith('#!/usr/bin/env node')) {\n return { command: process.execPath, args: [localBin] }\n }\n // Shell wrapper — try to find the target JS file\n const match = content.match(/\"([^\"]+\\.js)\"/)\n if (match) {\n const target = path.resolve(path.dirname(localBin), match[1])\n if (fs.existsSync(target)) {\n return { command: process.execPath, args: [target] }\n }\n }\n }\n\n // 3. Try resolving from PATH using which\n try {\n const fullPath = execSync(`which ${cmd}`, { encoding: 'utf-8' }).trim()\n if (fullPath) {\n const content = fs.readFileSync(fullPath, 'utf-8')\n if (content.startsWith('#!/usr/bin/env node')) {\n return { command: process.execPath, args: [fullPath] }\n }\n }\n } catch {\n // which failed\n }\n\n // 4. Fallback: use command as-is\n return { command: cmd, args: [] }\n}\n\ninterface TerminalState {\n process: ChildProcess\n output: string\n exitStatus: { exitCode: number | null; signal: string | null } | null\n}\n\nexport class AgentInstance {\n private connection!: ClientSideConnection\n private child!: ChildProcess\n private stderrCapture!: StderrCapture\n private terminals: Map<string, TerminalState> = new Map()\n\n sessionId!: string\n agentName: string\n\n // Callbacks — set by core when wiring events\n onSessionUpdate: (event: AgentEvent) => void = () => {}\n onPermissionRequest: (request: PermissionRequest) => Promise<string> = async () => ''\n\n private constructor(agentName: string) {\n this.agentName = agentName\n }\n\n static async spawn(agentDef: AgentDefinition, workingDirectory: string): Promise<AgentInstance> {\n const instance = new AgentInstance(agentDef.name)\n\n // 1. Resolve command: find the actual JS entry point to avoid shell wrappers\n const resolved = resolveAgentCommand(agentDef.command)\n log.debug(`Spawning agent \"${agentDef.name}\" → ${resolved.command} ${resolved.args.join(' ')}`)\n\n // Spawn subprocess\n instance.child = spawn(resolved.command, [...resolved.args, ...agentDef.args], {\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: workingDirectory,\n env: { ...process.env, ...agentDef.env },\n })\n\n // 2. Handle spawn errors (e.g., command not found)\n await new Promise<void>((resolve, reject) => {\n instance.child.on('error', (err) => {\n reject(new Error(`Failed to spawn agent \"${agentDef.name}\": ${err.message}. Is \"${agentDef.command}\" installed?`))\n })\n instance.child.on('spawn', () => resolve())\n })\n\n // 3. Capture stderr\n instance.stderrCapture = new StderrCapture(50)\n instance.child.stderr!.on('data', (chunk: Buffer) => {\n instance.stderrCapture.append(chunk.toString())\n })\n\n // 3. Create ACP stream\n const toAgent = nodeToWebWritable(instance.child.stdin!)\n const fromAgent = nodeToWebReadable(instance.child.stdout!)\n const stream = ndJsonStream(toAgent, fromAgent)\n\n // 4. Create ClientSideConnection\n instance.connection = new ClientSideConnection(\n (_agent: Agent): Client => instance.createClient(_agent),\n stream,\n )\n\n // 5. ACP handshake\n await instance.connection.initialize({\n protocolVersion: 1,\n clientCapabilities: {\n fs: { readTextFile: true, writeTextFile: true },\n terminal: true,\n },\n })\n\n // 6. Create session\n const response = await instance.connection.newSession({\n cwd: workingDirectory,\n mcpServers: [],\n })\n instance.sessionId = response.sessionId\n\n // 7. Crash detection\n instance.child.on('exit', (code, signal) => {\n if (code !== 0 && code !== null) {\n const stderr = instance.stderrCapture.getLastLines()\n instance.onSessionUpdate({\n type: 'error',\n message: `Agent crashed (exit code ${code})\\n${stderr}`,\n })\n }\n })\n\n instance.connection.closed.then(() => {\n // Connection closed — may be normal shutdown or crash\n log.debug('ACP connection closed for', instance.agentName)\n })\n\n log.info(`Agent \"${agentDef.name}\" spawned with session ${response.sessionId}`)\n return instance\n }\n\n // createClient — implemented in Task 6b\n private createClient(_agent: Agent): Client {\n const self = this\n const MAX_OUTPUT_BYTES = 1024 * 1024 // 1MB cap\n\n return {\n // ── Session updates ──────────────────────────────────────────────────\n async sessionUpdate(params) {\n const update = params.update\n let event: AgentEvent | null = null\n\n switch (update.sessionUpdate) {\n case 'agent_message_chunk':\n if (update.content.type === 'text') {\n event = { type: 'text', content: update.content.text }\n }\n break\n case 'agent_thought_chunk':\n if (update.content.type === 'text') {\n event = { type: 'thought', content: update.content.text }\n }\n break\n case 'tool_call':\n event = {\n type: 'tool_call',\n id: update.toolCallId,\n name: update.title,\n kind: update.kind ?? undefined,\n status: update.status ?? 'pending',\n content: update.content ?? undefined,\n }\n break\n case 'tool_call_update':\n event = {\n type: 'tool_update',\n id: update.toolCallId,\n status: update.status ?? 'pending',\n content: update.content ?? undefined,\n }\n break\n case 'plan':\n event = { type: 'plan', entries: update.entries }\n break\n case 'usage_update':\n event = {\n type: 'usage',\n tokensUsed: update.used,\n contextSize: update.size,\n cost: update.cost ?? undefined,\n }\n break\n case 'available_commands_update':\n event = { type: 'commands_update', commands: update.availableCommands }\n break\n default:\n // Unknown update type — ignore\n return\n }\n\n if (event !== null) {\n self.onSessionUpdate(event)\n }\n },\n\n // ── Permission requests ──────────────────────────────────────────────\n async requestPermission(params) {\n const permissionRequest: PermissionRequest = {\n id: params.toolCall.toolCallId,\n description: params.toolCall.title ?? params.toolCall.toolCallId,\n options: params.options.map((opt: SdkPermissionOption) => ({\n id: opt.optionId,\n label: opt.name,\n isAllow: opt.kind === 'allow_once' || opt.kind === 'allow_always',\n })),\n }\n\n const selectedOptionId = await self.onPermissionRequest(permissionRequest)\n return {\n outcome: { outcome: 'selected' as const, optionId: selectedOptionId },\n }\n },\n\n // ── File operations ──────────────────────────────────────────────────\n async readTextFile(params) {\n const content = await fs.promises.readFile(params.path, 'utf-8')\n return { content }\n },\n\n async writeTextFile(params) {\n await fs.promises.mkdir(path.dirname(params.path), { recursive: true })\n await fs.promises.writeFile(params.path, params.content, 'utf-8')\n return {}\n },\n\n // ── Terminal operations ──────────────────────────────────────────────\n async createTerminal(params) {\n const terminalId = randomUUID()\n const args = params.args ?? []\n const env: Record<string, string> = {}\n for (const ev of params.env ?? []) {\n env[ev.name] = ev.value\n }\n\n const childProcess = spawn(params.command, args, {\n cwd: params.cwd ?? undefined,\n env: { ...process.env, ...env },\n shell: false,\n })\n\n const state: TerminalState = {\n process: childProcess,\n output: '',\n exitStatus: null,\n }\n self.terminals.set(terminalId, state)\n\n const outputByteLimit = params.outputByteLimit ?? MAX_OUTPUT_BYTES\n\n const appendOutput = (chunk: string) => {\n state.output += chunk\n // Truncate from the beginning if over limit\n const bytes = Buffer.byteLength(state.output, 'utf-8')\n if (bytes > outputByteLimit) {\n // Find truncation point at character boundary\n const excess = bytes - outputByteLimit\n state.output = state.output.slice(excess)\n }\n }\n\n childProcess.stdout?.on('data', (chunk: Buffer) => appendOutput(chunk.toString()))\n childProcess.stderr?.on('data', (chunk: Buffer) => appendOutput(chunk.toString()))\n\n childProcess.on('exit', (code, signal) => {\n state.exitStatus = { exitCode: code, signal }\n })\n\n return { terminalId }\n },\n\n async terminalOutput(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n throw new Error(`Terminal not found: ${params.terminalId}`)\n }\n return {\n output: state.output,\n truncated: false,\n exitStatus: state.exitStatus\n ? { exitCode: state.exitStatus.exitCode, signal: state.exitStatus.signal }\n : undefined,\n }\n },\n\n async waitForTerminalExit(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n throw new Error(`Terminal not found: ${params.terminalId}`)\n }\n if (state.exitStatus !== null) {\n return { exitCode: state.exitStatus.exitCode, signal: state.exitStatus.signal }\n }\n return new Promise((resolve) => {\n state.process.on('exit', (code, signal) => {\n resolve({ exitCode: code, signal })\n })\n })\n },\n\n async killTerminal(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n throw new Error(`Terminal not found: ${params.terminalId}`)\n }\n state.process.kill('SIGTERM')\n return {}\n },\n\n async releaseTerminal(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n return\n }\n state.process.kill('SIGKILL')\n self.terminals.delete(params.terminalId)\n },\n }\n }\n\n async prompt(text: string): Promise<PromptResponse> {\n return this.connection.prompt({\n sessionId: this.sessionId,\n prompt: [{ type: 'text', text }],\n })\n }\n\n async cancel(): Promise<void> {\n await this.connection.cancel({ sessionId: this.sessionId })\n }\n\n async destroy(): Promise<void> {\n // Cleanup terminals\n for (const [, t] of this.terminals) {\n t.process.kill('SIGKILL')\n }\n this.terminals.clear()\n\n // Kill agent subprocess\n this.child.kill('SIGTERM')\n setTimeout(() => {\n if (!this.child.killed) this.child.kill('SIGKILL')\n }, 10_000)\n }\n}\n","import type { Config } from './config.js'\nimport type { AgentDefinition } from './types.js'\nimport { AgentInstance } from './agent-instance.js'\n\nexport class AgentManager {\n constructor(private config: Config) {}\n\n getAvailableAgents(): AgentDefinition[] {\n return Object.entries(this.config.agents).map(([name, cfg]) => ({\n name,\n command: cfg.command,\n args: cfg.args,\n workingDirectory: cfg.workingDirectory,\n env: cfg.env,\n }))\n }\n\n getAgent(name: string): AgentDefinition | undefined {\n const cfg = this.config.agents[name]\n if (!cfg) return undefined\n return { name, ...cfg }\n }\n\n async spawn(agentName: string, workingDirectory: string): Promise<AgentInstance> {\n const agentDef = this.getAgent(agentName)\n if (!agentDef) throw new Error(`Agent \"${agentName}\" not found in config`)\n return AgentInstance.spawn(agentDef, workingDirectory)\n }\n}\n","import { nanoid } from 'nanoid'\nimport type { AgentInstance } from './agent-instance.js'\nimport type { ChannelAdapter } from './channel.js'\nimport type { SessionStatus } from './types.js'\nimport { log } from './log.js'\n\nexport class Session {\n id: string\n channelId: string\n threadId: string = ''\n agentName: string\n workingDirectory: string\n agentInstance: AgentInstance\n status: SessionStatus = 'initializing'\n name?: string\n promptQueue: string[] = []\n promptRunning: boolean = false\n createdAt: Date = new Date()\n adapter?: ChannelAdapter // Set by wireSessionEvents for renaming\n pendingPermission?: { requestId: string; resolve: (optionId: string) => void }\n\n constructor(opts: {\n id?: string\n channelId: string\n agentName: string\n workingDirectory: string\n agentInstance: AgentInstance\n }) {\n this.id = opts.id || nanoid(12)\n this.channelId = opts.channelId\n this.agentName = opts.agentName\n this.workingDirectory = opts.workingDirectory\n this.agentInstance = opts.agentInstance\n }\n\n async enqueuePrompt(text: string): Promise<void> {\n if (this.promptRunning) {\n this.promptQueue.push(text)\n log.debug(`Prompt queued for session ${this.id} (${this.promptQueue.length} in queue)`)\n return\n }\n await this.runPrompt(text)\n }\n\n private async runPrompt(text: string): Promise<void> {\n this.promptRunning = true\n this.status = 'active'\n\n try {\n await this.agentInstance.prompt(text)\n\n // Auto-name after first user prompt\n if (!this.name) {\n await this.autoName()\n }\n } catch (err) {\n this.status = 'error'\n log.error(`Prompt failed for session ${this.id}:`, err)\n } finally {\n this.promptRunning = false\n\n // Process next queued prompt\n if (this.promptQueue.length > 0) {\n const next = this.promptQueue.shift()!\n await this.runPrompt(next)\n }\n }\n }\n\n // NOTE: This injects a summary prompt into the agent's conversation history.\n // Known Phase 1 limitation — the agent sees this prompt in its context.\n private async autoName(): Promise<void> {\n let title = ''\n const prevHandler = this.agentInstance.onSessionUpdate\n this.agentInstance.onSessionUpdate = (event) => {\n if (event.type === 'text') title += event.content\n }\n\n try {\n await this.agentInstance.prompt(\n 'Summarize this conversation in max 5 words for a topic title. Reply ONLY with the title, nothing else.'\n )\n this.name = title.trim().slice(0, 50)\n\n // Rename the topic on the channel\n if (this.adapter && this.name) {\n await this.adapter.renameSessionThread(this.id, this.name)\n }\n } catch {\n this.name = `Session ${this.id.slice(0, 6)}`\n } finally {\n this.agentInstance.onSessionUpdate = prevHandler\n }\n }\n\n async cancel(): Promise<void> {\n this.status = 'cancelled'\n await this.agentInstance.cancel()\n }\n\n async destroy(): Promise<void> {\n await this.agentInstance.destroy()\n }\n}\n","import type { AgentManager } from './agent-manager.js'\nimport { Session } from './session.js'\n\nexport class SessionManager {\n private sessions: Map<string, Session> = new Map()\n\n async createSession(\n channelId: string,\n agentName: string,\n workingDirectory: string,\n agentManager: AgentManager,\n ): Promise<Session> {\n const agentInstance = await agentManager.spawn(agentName, workingDirectory)\n const session = new Session({ channelId, agentName, workingDirectory, agentInstance })\n this.sessions.set(session.id, session)\n return session\n }\n\n getSession(sessionId: string): Session | undefined {\n return this.sessions.get(sessionId)\n }\n\n getSessionByThread(channelId: string, threadId: string): Session | undefined {\n for (const session of this.sessions.values()) {\n if (session.channelId === channelId && session.threadId === threadId) {\n return session\n }\n }\n return undefined\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId)\n if (session) await session.cancel()\n }\n\n listSessions(channelId?: string): Session[] {\n const all = Array.from(this.sessions.values())\n if (channelId) return all.filter(s => s.channelId === channelId)\n return all\n }\n\n async destroyAll(): Promise<void> {\n for (const session of this.sessions.values()) {\n await session.destroy()\n }\n this.sessions.clear()\n }\n}\n","import type { ChannelAdapter } from './channel.js'\nimport type { NotificationMessage } from './types.js'\n\nexport class NotificationManager {\n constructor(private adapters: Map<string, ChannelAdapter>) {}\n\n async notify(channelId: string, notification: NotificationMessage): Promise<void> {\n const adapter = this.adapters.get(channelId)\n if (adapter) {\n await adapter.sendNotification(notification)\n }\n }\n\n async notifyAll(notification: NotificationMessage): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.sendNotification(notification)\n }\n }\n}\n","import { ConfigManager } from './config.js'\nimport { AgentManager } from './agent-manager.js'\nimport { SessionManager } from './session-manager.js'\nimport { NotificationManager } from './notification.js'\nimport { ChannelAdapter } from './channel.js'\nimport { Session } from './session.js'\nimport type { IncomingMessage, AgentEvent, OutgoingMessage, PermissionRequest } from './types.js'\nimport { log } from './log.js'\n\nexport class OpenACPCore {\n configManager: ConfigManager\n agentManager: AgentManager\n sessionManager: SessionManager\n notificationManager: NotificationManager\n adapters: Map<string, ChannelAdapter> = new Map()\n\n constructor(configManager: ConfigManager) {\n this.configManager = configManager\n const config = configManager.get()\n this.agentManager = new AgentManager(config)\n this.sessionManager = new SessionManager()\n this.notificationManager = new NotificationManager(this.adapters)\n }\n\n registerAdapter(name: string, adapter: ChannelAdapter): void {\n this.adapters.set(name, adapter)\n }\n\n async start(): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.start()\n }\n }\n\n async stop(): Promise<void> {\n // 1. Notify users\n try {\n await this.notificationManager.notifyAll({\n sessionId: 'system',\n type: 'error',\n summary: 'OpenACP is shutting down',\n })\n } catch { /* best effort */ }\n\n // 2. Destroy all sessions\n await this.sessionManager.destroyAll()\n\n // 3. Stop adapters\n for (const adapter of this.adapters.values()) {\n await adapter.stop()\n }\n }\n\n // --- Message Routing ---\n\n async handleMessage(message: IncomingMessage): Promise<void> {\n const config = this.configManager.get()\n\n // Security: check allowed user IDs\n if (config.security.allowedUserIds.length > 0) {\n if (!config.security.allowedUserIds.includes(message.userId)) return\n }\n\n // Check concurrent session limit\n const activeSessions = this.sessionManager.listSessions()\n .filter(s => s.status === 'active' || s.status === 'initializing')\n if (activeSessions.length >= config.security.maxConcurrentSessions) {\n const adapter = this.adapters.get(message.channelId)\n if (adapter) {\n await adapter.sendMessage('system', {\n type: 'error',\n text: `Max concurrent sessions (${config.security.maxConcurrentSessions}) reached. Cancel a session first.`,\n })\n }\n return\n }\n\n // Find session by thread\n const session = this.sessionManager.getSessionByThread(message.channelId, message.threadId)\n if (!session) return\n\n // Forward to session\n await session.enqueuePrompt(message.text)\n }\n\n async handleNewSession(\n channelId: string,\n agentName?: string,\n workspacePath?: string,\n ): Promise<Session> {\n const config = this.configManager.get()\n const resolvedAgent = agentName || config.defaultAgent\n const resolvedWorkspace = this.configManager.resolveWorkspace(\n workspacePath || config.agents[resolvedAgent]?.workingDirectory\n )\n\n const session = await this.sessionManager.createSession(\n channelId, resolvedAgent, resolvedWorkspace, this.agentManager\n )\n\n // Wire events\n const adapter = this.adapters.get(channelId)\n if (adapter) {\n this.wireSessionEvents(session, adapter)\n }\n\n return session\n }\n\n async handleNewChat(\n channelId: string,\n currentThreadId: string,\n ): Promise<Session | null> {\n const currentSession = this.sessionManager.getSessionByThread(channelId, currentThreadId)\n if (!currentSession) return null\n\n return this.handleNewSession(\n channelId,\n currentSession.agentName,\n currentSession.workingDirectory,\n )\n }\n\n // --- Event Wiring ---\n\n private toOutgoingMessage(event: AgentEvent): OutgoingMessage {\n switch (event.type) {\n case 'text':\n return { type: 'text', text: event.content }\n case 'thought':\n return { type: 'thought', text: event.content }\n case 'tool_call':\n return { type: 'tool_call', text: event.name, metadata: { id: event.id, kind: event.kind, status: event.status, content: event.content, locations: event.locations } }\n case 'tool_update':\n return { type: 'tool_update', text: '', metadata: { id: event.id, status: event.status, content: event.content } }\n case 'plan':\n return { type: 'plan', text: '', metadata: { entries: event.entries } }\n case 'usage':\n return { type: 'usage', text: '', metadata: { tokensUsed: event.tokensUsed, contextSize: event.contextSize, cost: event.cost } }\n case 'commands_update':\n // Log but don't surface to user (Phase 3 feature)\n log.debug('Commands update:', event.commands)\n return { type: 'text', text: '' } // no-op for now\n default:\n return { type: 'text', text: '' }\n }\n }\n\n // Public — adapters call this for assistant session wiring\n wireSessionEvents(session: Session, adapter: ChannelAdapter): void {\n // Set adapter reference for autoName → renameSessionThread\n session.adapter = adapter\n\n session.agentInstance.onSessionUpdate = (event: AgentEvent) => {\n switch (event.type) {\n case 'text':\n case 'thought':\n case 'tool_call':\n case 'tool_update':\n case 'plan':\n case 'usage':\n adapter.sendMessage(session.id, this.toOutgoingMessage(event))\n break\n\n case 'session_end':\n session.status = 'finished'\n adapter.sendMessage(session.id, { type: 'session_end', text: `Done (${event.reason})` })\n this.notificationManager.notify(session.channelId, {\n sessionId: session.id,\n sessionName: session.name,\n type: 'completed',\n summary: `Session \"${session.name || session.id}\" completed`,\n })\n break\n\n case 'error':\n adapter.sendMessage(session.id, { type: 'error', text: event.message })\n this.notificationManager.notify(session.channelId, {\n sessionId: session.id,\n sessionName: session.name,\n type: 'error',\n summary: event.message,\n })\n break\n\n case 'commands_update':\n log.debug('Commands available:', event.commands)\n break\n }\n }\n\n session.agentInstance.onPermissionRequest = async (request: PermissionRequest) => {\n // Set pending BEFORE sending UI to avoid race condition\n const promise = new Promise<string>((resolve) => {\n session.pendingPermission = { requestId: request.id, resolve }\n })\n\n // Send permission UI to session topic (notification is sent by adapter)\n await adapter.sendPermissionRequest(session.id, request)\n\n // Wait for user response — adapter resolves this promise\n return promise\n }\n }\n}\n","import type { OutgoingMessage, PermissionRequest, NotificationMessage } from './types.js'\n\nexport interface ChannelConfig {\n enabled: boolean\n [key: string]: unknown\n}\n\nexport abstract class ChannelAdapter {\n constructor(protected core: any, protected config: ChannelConfig) {}\n\n abstract start(): Promise<void>\n abstract stop(): Promise<void>\n\n // Outgoing: core → channel\n abstract sendMessage(sessionId: string, content: OutgoingMessage): Promise<void>\n abstract sendPermissionRequest(sessionId: string, request: PermissionRequest): Promise<void>\n abstract sendNotification(notification: NotificationMessage): Promise<void>\n\n // Session lifecycle on channel side\n abstract createSessionThread(sessionId: string, name: string): Promise<string> // returns threadId\n abstract renameSessionThread(sessionId: string, newName: string): Promise<void>\n}\n","import { Bot } from 'grammy'\nimport { ChannelAdapter, type OpenACPCore, type OutgoingMessage, type PermissionRequest, type NotificationMessage, type Session, log } from '../../core/index.js'\nimport type { TelegramChannelConfig } from './types.js'\nimport { MessageDraft } from './streaming.js'\nimport { ensureTopics, createSessionTopic, renameSessionTopic } from './topics.js'\nimport { setupCommands } from './commands.js'\nimport { PermissionHandler } from './permissions.js'\nimport { spawnAssistant, handleAssistantMessage, redirectToAssistant } from './assistant.js'\nimport { escapeHtml, formatToolCall, formatToolUpdate, formatPlan, formatUsage } from './formatting.js'\n\nexport class TelegramAdapter extends ChannelAdapter {\n private bot!: Bot\n private telegramConfig: TelegramChannelConfig\n private sessionDrafts: Map<string, MessageDraft> = new Map()\n private toolCallMessages: Map<string, Map<string, { msgId: number; name: string; kind?: string }>> = new Map() // sessionId → (toolCallId → state)\n private permissionHandler!: PermissionHandler\n private assistantSession: Session | null = null\n private notificationTopicId!: number\n private assistantTopicId!: number\n\n constructor(core: OpenACPCore, config: TelegramChannelConfig) {\n super(core, config as any)\n this.telegramConfig = config\n }\n\n async start(): Promise<void> {\n this.bot = new Bot(this.telegramConfig.botToken)\n\n // Global error handler — prevent unhandled errors from crashing the bot\n this.bot.catch((err) => {\n log.error('Bot error:', err.message || err)\n })\n\n // Ensure allowed_updates includes callback_query on every poll\n this.bot.api.config.use((prev, method, payload, signal) => {\n if (method === 'getUpdates') {\n (payload as any).allowed_updates = (payload as any).allowed_updates ?? ['message', 'callback_query']\n }\n return prev(method, payload, signal)\n })\n\n // Middleware: only accept updates from configured chatId\n this.bot.use((ctx, next) => {\n const chatId = ctx.chat?.id ?? ctx.callbackQuery?.message?.chat?.id\n if (chatId !== this.telegramConfig.chatId) return\n return next()\n })\n\n // Ensure system topics exist\n const topics = await ensureTopics(\n this.bot,\n this.telegramConfig.chatId,\n this.telegramConfig,\n async (updates) => {\n // Save topic IDs to config\n await (this.core as OpenACPCore).configManager.save({\n channels: { telegram: updates }\n })\n }\n )\n this.notificationTopicId = topics.notificationTopicId\n this.assistantTopicId = topics.assistantTopicId\n\n // Setup permission handler\n this.permissionHandler = new PermissionHandler(\n this.bot,\n this.telegramConfig.chatId,\n (sessionId) => (this.core as OpenACPCore).sessionManager.getSession(sessionId),\n (notification) => this.sendNotification(notification),\n )\n this.permissionHandler.setupCallbackHandler()\n\n // Setup commands\n setupCommands(this.bot, this.core as OpenACPCore, this.telegramConfig.chatId)\n\n // Setup message routing\n this.setupRoutes()\n\n // Start bot polling\n this.bot.start({\n allowed_updates: ['message', 'callback_query'],\n onStart: () => log.info('Telegram bot started'),\n })\n\n // Spawn assistant (after bot is started so it can send messages)\n try {\n this.assistantSession = await spawnAssistant(\n this.core as OpenACPCore,\n this,\n this.assistantTopicId,\n )\n } catch (err) {\n log.error('Failed to spawn assistant:', err)\n }\n }\n\n async stop(): Promise<void> {\n if (this.assistantSession) {\n await this.assistantSession.destroy()\n }\n await this.bot.stop()\n }\n\n private setupRoutes(): void {\n this.bot.on('message:text', async (ctx) => {\n const threadId = ctx.message.message_thread_id\n\n // General topic or no thread → redirect to assistant\n if (!threadId) {\n const html = redirectToAssistant(this.telegramConfig.chatId, this.assistantTopicId)\n await ctx.reply(html, { parse_mode: 'HTML' })\n return\n }\n\n // Notification topic → ignore\n if (threadId === this.notificationTopicId) return\n\n // Assistant topic → forward to assistant session (fire-and-forget)\n if (threadId === this.assistantTopicId) {\n handleAssistantMessage(this.assistantSession, ctx.message.text).catch(err => log.error('Assistant error:', err))\n return\n }\n\n // Session topic → forward to core (fire-and-forget to avoid blocking polling)\n ;(this.core as OpenACPCore).handleMessage({\n channelId: 'telegram',\n threadId: String(threadId),\n userId: String(ctx.from.id),\n text: ctx.message.text,\n }).catch(err => log.error('handleMessage error:', err))\n })\n }\n\n // --- ChannelAdapter implementations ---\n\n async sendMessage(sessionId: string, content: OutgoingMessage): Promise<void> {\n const session = (this.core as OpenACPCore).sessionManager.getSession(sessionId)\n if (!session) return\n const threadId = Number(session.threadId)\n\n switch (content.type) {\n case 'thought': {\n // Skip thought/thinking content — it's internal agent reasoning\n // Users don't need to see it\n break\n }\n\n case 'text': {\n let draft = this.sessionDrafts.get(sessionId)\n if (!draft) {\n draft = new MessageDraft(this.bot, this.telegramConfig.chatId, threadId)\n this.sessionDrafts.set(sessionId, draft)\n }\n draft.append(content.text)\n break\n }\n\n case 'tool_call': {\n await this.finalizeDraft(sessionId)\n const meta = content.metadata as any\n const msg = await this.bot.api.sendMessage(this.telegramConfig.chatId,\n formatToolCall(meta),\n { message_thread_id: threadId, parse_mode: 'HTML', disable_notification: true }\n )\n if (!this.toolCallMessages.has(sessionId)) {\n this.toolCallMessages.set(sessionId, new Map())\n }\n this.toolCallMessages.get(sessionId)!.set(meta.id, { msgId: msg.message_id, name: meta.name, kind: meta.kind })\n break\n }\n\n case 'tool_update': {\n const meta = content.metadata as any\n const toolState = this.toolCallMessages.get(sessionId)?.get(meta.id)\n if (toolState) {\n // Merge name/kind from original tool_call\n const merged = { ...meta, name: meta.name || toolState.name, kind: meta.kind || toolState.kind }\n try {\n await this.bot.api.editMessageText(this.telegramConfig.chatId, toolState.msgId,\n formatToolUpdate(merged),\n { parse_mode: 'HTML' }\n )\n } catch { /* edit failed */ }\n }\n break\n }\n\n case 'plan': {\n await this.finalizeDraft(sessionId)\n await this.bot.api.sendMessage(this.telegramConfig.chatId,\n formatPlan(content.metadata as any),\n { message_thread_id: threadId, parse_mode: 'HTML', disable_notification: true }\n )\n break\n }\n\n case 'usage': {\n // Show usage stats\n await this.bot.api.sendMessage(this.telegramConfig.chatId,\n formatUsage(content.metadata as any),\n { message_thread_id: threadId, parse_mode: 'HTML', disable_notification: true }\n )\n break\n }\n\n case 'session_end': {\n await this.finalizeDraft(sessionId)\n this.sessionDrafts.delete(sessionId)\n this.toolCallMessages.delete(sessionId)\n await this.bot.api.sendMessage(this.telegramConfig.chatId,\n `✅ <b>Done</b>`,\n { message_thread_id: threadId, parse_mode: 'HTML', disable_notification: true }\n )\n break\n }\n\n case 'error': {\n await this.finalizeDraft(sessionId)\n await this.bot.api.sendMessage(this.telegramConfig.chatId,\n `❌ <b>Error:</b> ${escapeHtml(content.text)}`,\n { message_thread_id: threadId, parse_mode: 'HTML', disable_notification: true }\n )\n break\n }\n }\n }\n\n async sendPermissionRequest(sessionId: string, request: PermissionRequest): Promise<void> {\n const session = (this.core as OpenACPCore).sessionManager.getSession(sessionId)\n if (!session) return\n await this.permissionHandler.sendPermissionRequest(session, request)\n }\n\n async sendNotification(notification: NotificationMessage): Promise<void> {\n if (!this.notificationTopicId) return\n const emoji: Record<string, string> = {\n completed: '✅', error: '❌', permission: '🔐', input_required: '💬',\n }\n let text = `${emoji[notification.type] || 'ℹ️'} <b>${escapeHtml(notification.sessionName || notification.sessionId)}</b>\\n`\n text += escapeHtml(notification.summary)\n if (notification.deepLink) {\n text += `\\n\\n<a href=\"${notification.deepLink}\">→ Go to message</a>`\n }\n await this.bot.api.sendMessage(this.telegramConfig.chatId, text, {\n message_thread_id: this.notificationTopicId,\n parse_mode: 'HTML',\n disable_notification: false,\n })\n }\n\n async createSessionThread(sessionId: string, name: string): Promise<string> {\n return String(await createSessionTopic(this.bot, this.telegramConfig.chatId, name))\n }\n\n async renameSessionThread(sessionId: string, newName: string): Promise<void> {\n const session = (this.core as OpenACPCore).sessionManager.getSession(sessionId)\n if (!session) return\n await renameSessionTopic(this.bot, this.telegramConfig.chatId, Number(session.threadId), newName)\n }\n\n private async finalizeDraft(sessionId: string): Promise<void> {\n const draft = this.sessionDrafts.get(sessionId)\n if (draft) {\n await draft.finalize()\n this.sessionDrafts.delete(sessionId)\n }\n }\n}\n","export function escapeHtml(text: string | undefined | null): string {\n if (!text) return ''\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n}\n\nexport function markdownToTelegramHtml(md: string): string {\n // Step 1: Extract code blocks and inline code into placeholders\n const codeBlocks: string[] = []\n const inlineCodes: string[] = []\n\n // Extract fenced code blocks (```lang\\n...\\n```)\n let text = md.replace(/```(\\w*)\\n?([\\s\\S]*?)```/g, (_match, lang: string, code: string) => {\n const index = codeBlocks.length\n const escapedCode = escapeHtml(code)\n const langAttr = lang ? ` class=\"language-${escapeHtml(lang)}\"` : ''\n codeBlocks.push(`<pre><code${langAttr}>${escapedCode}</code></pre>`)\n return `\\x00CODE_BLOCK_${index}\\x00`\n })\n\n // Extract inline code (`...`)\n text = text.replace(/`([^`]+)`/g, (_match, code: string) => {\n const index = inlineCodes.length\n inlineCodes.push(`<code>${escapeHtml(code)}</code>`)\n return `\\x00INLINE_CODE_${index}\\x00`\n })\n\n // Step 2: Escape HTML in remaining text\n text = escapeHtml(text)\n\n // Step 3: Apply markdown transformations\n // Bold: **text** → <b>text</b>\n text = text.replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>')\n\n // Italic: *text* → <i>text</i> (but not the ** used for bold)\n text = text.replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, '<i>$1</i>')\n\n // Links: [text](url) → <a href=\"url\">text</a>\n // Note: after escapeHtml, parentheses are not affected, but we need to handle\n // the escaped brackets properly. Since [ ] and ( ) are not escaped, this works directly.\n text = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\">$1</a>')\n\n // Step 4: Restore fenced code blocks\n text = text.replace(/\\x00CODE_BLOCK_(\\d+)\\x00/g, (_match, idx: string) => {\n return codeBlocks[parseInt(idx, 10)]\n })\n\n // Step 5: Restore inline code\n text = text.replace(/\\x00INLINE_CODE_(\\d+)\\x00/g, (_match, idx: string) => {\n return inlineCodes[parseInt(idx, 10)]\n })\n\n return text\n}\n\nconst STATUS_ICON: Record<string, string> = {\n pending: '⏳',\n in_progress: '🔄',\n completed: '✅',\n failed: '❌',\n}\n\nconst KIND_ICON: Record<string, string> = {\n read: '📖', edit: '✏️', delete: '🗑️', execute: '▶️',\n search: '🔍', fetch: '🌐', think: '🧠', move: '📦', other: '🛠️',\n}\n\nfunction extractContentText(content: unknown): string {\n if (!content) return ''\n if (typeof content === 'string') return content\n if (Array.isArray(content)) {\n return content\n .map((c: any) => extractContentText(c))\n .filter(Boolean)\n .join('\\n')\n }\n if (typeof content === 'object' && content !== null) {\n const c = content as any\n // ACP content blocks: {type: ..., text: ...} or {type: ..., content: ...}\n if (c.type === 'text' && typeof c.text === 'string') return c.text\n if (typeof c.text === 'string') return c.text\n if (typeof c.content === 'string') return c.content\n // Tool input/output objects\n if (c.input) return extractContentText(c.input)\n if (c.output) return extractContentText(c.output)\n // Fallback: pretty-print JSON (but skip type-only objects)\n const keys = Object.keys(c).filter(k => k !== 'type')\n if (keys.length === 0) return ''\n return JSON.stringify(c, null, 2)\n }\n return String(content)\n}\n\nfunction truncateContent(text: string, maxLen = 3800): string {\n if (text.length <= maxLen) return text\n return text.slice(0, maxLen) + '\\n… (truncated)'\n}\n\nexport function formatToolCall(tool: { id: string; name?: string; kind?: string; status?: string; content?: unknown }): string {\n const si = STATUS_ICON[tool.status || ''] || '🔧'\n const ki = KIND_ICON[tool.kind || ''] || '🛠️'\n let text = `${si} ${ki} <b>${escapeHtml(tool.name || 'Tool')}</b>`\n const details = extractContentText(tool.content)\n if (details) {\n text += `\\n<pre>${escapeHtml(truncateContent(details))}</pre>`\n }\n return text\n}\n\nexport function formatToolUpdate(update: { id: string; name?: string; kind?: string; status: string; content?: unknown }): string {\n const si = STATUS_ICON[update.status] || '🔧'\n const ki = KIND_ICON[update.kind || ''] || '🛠️'\n const name = update.name || 'Tool'\n let text = `${si} ${ki} <b>${escapeHtml(name)}</b>`\n const details = extractContentText(update.content)\n if (details) {\n text += `\\n<pre>${escapeHtml(truncateContent(details))}</pre>`\n }\n return text\n}\n\nexport function formatPlan(plan: { entries: Array<{ content: string; status: string }> }): string {\n const statusIcon: Record<string, string> = { pending: '⬜', in_progress: '🔄', completed: '✅' }\n const lines = plan.entries.map((e, i) =>\n `${statusIcon[e.status] || '⬜'} ${i + 1}. ${escapeHtml(e.content)}`\n )\n return `<b>Plan:</b>\\n${lines.join('\\n')}`\n}\n\nexport function formatUsage(usage: { tokensUsed?: number; contextSize?: number; cost?: { amount: number; currency: string } }): string {\n const parts: string[] = []\n if (usage.tokensUsed != null) parts.push(`Tokens: ${usage.tokensUsed.toLocaleString()}`)\n if (usage.contextSize != null) parts.push(`Context: ${usage.contextSize.toLocaleString()}`)\n if (usage.cost) parts.push(`Cost: $${usage.cost.amount.toFixed(4)}`)\n return `📊 ${parts.join(' | ')}`\n}\n\nexport function splitMessage(text: string, maxLength = 4096): 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 let splitAt = remaining.lastIndexOf('\\n\\n', maxLength)\n if (splitAt === -1 || splitAt < maxLength * 0.5) {\n splitAt = remaining.lastIndexOf('\\n', maxLength)\n }\n if (splitAt === -1 || splitAt < maxLength * 0.5) {\n splitAt = maxLength\n }\n chunks.push(remaining.slice(0, splitAt))\n remaining = remaining.slice(splitAt).trimStart()\n }\n return chunks\n}\n","import type { Bot } from 'grammy'\nimport { markdownToTelegramHtml, splitMessage } from './formatting.js'\n\nexport class MessageDraft {\n private messageId?: number\n private buffer: string = ''\n private lastFlush: number = 0\n private flushTimer?: ReturnType<typeof setTimeout>\n private flushPromise: Promise<void> = Promise.resolve() // serialize flushes\n private minInterval = 1000 // 1 second throttle\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private threadId: number,\n ) {}\n\n append(text: string): void {\n this.buffer += text\n this.scheduleFlush()\n }\n\n private scheduleFlush(): void {\n const now = Date.now()\n const elapsed = now - this.lastFlush\n\n if (elapsed >= this.minInterval) {\n // Chain flush to prevent concurrent sends\n this.flushPromise = this.flushPromise.then(() => this.flush()).catch(() => {})\n } else if (!this.flushTimer) {\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined\n this.flushPromise = this.flushPromise.then(() => this.flush()).catch(() => {})\n }, this.minInterval - elapsed)\n }\n }\n\n private async flush(): Promise<void> {\n if (!this.buffer) return\n this.lastFlush = Date.now()\n\n const html = markdownToTelegramHtml(this.buffer)\n // Truncate for streaming (will send full on finalize)\n const truncated = html.length > 4096 ? html.slice(0, 4090) + '\\n...' : html\n if (!truncated) return\n\n try {\n if (!this.messageId) {\n const msg = await this.bot.api.sendMessage(this.chatId, truncated, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n })\n this.messageId = msg.message_id\n } else {\n await this.bot.api.editMessageText(this.chatId, this.messageId, truncated, {\n parse_mode: 'HTML',\n })\n }\n } catch {\n // Edit failed — try plain text without HTML parse mode\n try {\n if (!this.messageId) {\n const msg = await this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {\n message_thread_id: this.threadId,\n disable_notification: true,\n })\n this.messageId = msg.message_id\n }\n } catch {\n // Give up on this flush\n }\n }\n }\n\n async finalize(): Promise<number | undefined> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = undefined\n }\n\n // Wait for any in-flight flush to complete\n await this.flushPromise\n\n if (!this.buffer) return this.messageId\n\n // Final send with full content + splitting\n const html = markdownToTelegramHtml(this.buffer)\n const chunks = splitMessage(html)\n\n try {\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i]\n if (i === 0 && this.messageId) {\n // Edit existing message with first chunk\n await this.bot.api.editMessageText(this.chatId, this.messageId, chunk, {\n parse_mode: 'HTML',\n })\n } else {\n // Send new message\n const msg = await this.bot.api.sendMessage(this.chatId, chunk, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n })\n this.messageId = msg.message_id\n }\n }\n } catch {\n // Best effort — try plain text\n try {\n await this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {\n message_thread_id: this.threadId,\n disable_notification: true,\n })\n } catch {\n // Give up\n }\n }\n\n return this.messageId\n }\n\n getMessageId(): number | undefined {\n return this.messageId\n }\n}\n","import type { Bot } from 'grammy'\n\n// Ensure notification and assistant topics exist, create if needed\n// Returns updated topic IDs\nexport async function ensureTopics(\n bot: Bot,\n chatId: number,\n config: { notificationTopicId: number | null; assistantTopicId: number | null },\n saveConfig: (updates: { notificationTopicId?: number; assistantTopicId?: number }) => Promise<void>,\n): Promise<{ notificationTopicId: number; assistantTopicId: number }> {\n let notificationTopicId = config.notificationTopicId\n let assistantTopicId = config.assistantTopicId\n\n if (notificationTopicId === null) {\n const topic = await bot.api.createForumTopic(chatId, '📋 Notifications')\n notificationTopicId = topic.message_thread_id\n await saveConfig({ notificationTopicId })\n }\n\n if (assistantTopicId === null) {\n const topic = await bot.api.createForumTopic(chatId, '🤖 Assistant')\n assistantTopicId = topic.message_thread_id\n await saveConfig({ assistantTopicId })\n }\n\n return { notificationTopicId, assistantTopicId }\n}\n\n// Create a new forum topic for a session\nexport async function createSessionTopic(\n bot: Bot,\n chatId: number,\n name: string,\n): Promise<number> {\n const topic = await bot.api.createForumTopic(chatId, name)\n return topic.message_thread_id\n}\n\n// Rename an existing forum topic\nexport async function renameSessionTopic(\n bot: Bot,\n chatId: number,\n threadId: number,\n name: string,\n): Promise<void> {\n try {\n await bot.api.editForumTopic(chatId, threadId, { name })\n } catch {\n // Ignore rename failures (topic may be closed/deleted)\n }\n}\n\n// Build a Telegram deep link to a specific message\nexport function buildDeepLink(chatId: number, messageId: number): string {\n // chatId for supergroups starts with -100, need to strip it for the link\n const cleanId = String(chatId).replace('-100', '')\n return `https://t.me/c/${cleanId}/${messageId}`\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../core/index.js\";\nimport { escapeHtml } from \"./formatting.js\";\nimport { createSessionTopic } from \"./topics.js\";\n\nexport function setupCommands(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n): void {\n bot.command(\"new\", (ctx) => handleNew(ctx, core, chatId));\n bot.command(\"new_chat\", (ctx) => handleNewChat(ctx, core, chatId));\n bot.command(\"cancel\", (ctx) => handleCancel(ctx, core));\n bot.command(\"status\", (ctx) => handleStatus(ctx, core));\n bot.command(\"agents\", (ctx) => handleAgents(ctx, core));\n bot.command(\"help\", (ctx) => handleHelp(ctx));\n bot.command(\"menu\", (ctx) => handleMenu(ctx));\n}\n\nexport function buildMenuKeyboard(): InlineKeyboard {\n return new InlineKeyboard()\n .text(\"🆕 New Session\", \"m:new\")\n .text(\"💬 New Chat\", \"m:new_chat\")\n .row()\n .text(\"⛔ Cancel\", \"m:cancel\")\n .text(\"📊 Status\", \"m:status\")\n .row()\n .text(\"🤖 Agents\", \"m:agents\")\n .text(\"❓ Help\", \"m:help\");\n}\n\nexport function setupMenuCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n): void {\n bot.callbackQuery(/^m:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch {\n /* expired or network — ignore */\n }\n\n switch (data) {\n case \"m:new\":\n await handleNew(ctx, core, chatId);\n break;\n case \"m:new_chat\":\n await handleNewChat(ctx, core, chatId);\n break;\n case \"m:cancel\":\n await handleCancel(ctx, core);\n break;\n case \"m:status\":\n await handleStatus(ctx, core);\n break;\n case \"m:agents\":\n await handleAgents(ctx, core);\n break;\n case \"m:help\":\n await handleHelp(ctx);\n break;\n }\n });\n}\n\nasync function handleMenu(ctx: Context): Promise<void> {\n await ctx.reply(`<b>OpenACP Menu</b>\\nChoose an action:`, {\n parse_mode: \"HTML\",\n reply_markup: buildMenuKeyboard(),\n });\n}\n\nasync function handleNew(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n): Promise<void> {\n const rawMatch = (ctx as Context & { match: unknown }).match;\n const matchStr = typeof rawMatch === \"string\" ? rawMatch : \"\";\n const args = matchStr.split(\" \").filter(Boolean);\n const agentName = args[0];\n const workspace = args[1];\n\n // Create topic first so threadId is ready before session events fire\n let threadId: number | undefined;\n try {\n const topicName = `🔄 New Session`;\n threadId = await createSessionTopic(botFromCtx(ctx), chatId, topicName);\n\n const session = await core.handleNewSession(\n \"telegram\",\n agentName,\n workspace,\n );\n session.threadId = String(threadId);\n\n // Rename topic with actual agent name\n const finalName = `🔄 ${session.agentName} — New Session`;\n try {\n await ctx.api.editForumTopic(chatId, threadId, { name: finalName });\n } catch {\n /* ignore rename failures */\n }\n\n await ctx.api.sendMessage(\n chatId,\n `✅ Session started\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n },\n );\n } catch (err) {\n // Clean up orphaned topic if session creation failed\n if (threadId) {\n try {\n await ctx.api.deleteForumTopic(chatId, threadId);\n } catch {\n /* ignore cleanup failures */\n }\n }\n const message = err instanceof Error ? err.message : String(err);\n await ctx.reply(`❌ ${escapeHtml(message)}`, { parse_mode: \"HTML\" });\n }\n}\n\nasync function handleNewChat(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\n \"Use /new_chat inside a session topic to inherit its config.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n try {\n const session = await core.handleNewChat(\"telegram\", String(threadId));\n if (!session) {\n await ctx.reply(\"No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n\n const topicName = `🔄 ${session.agentName} — New Chat`;\n const newThreadId = await createSessionTopic(\n botFromCtx(ctx),\n chatId,\n topicName,\n );\n session.threadId = String(newThreadId);\n\n await ctx.api.sendMessage(\n chatId,\n `✅ New chat (same agent & workspace)\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`,\n {\n message_thread_id: newThreadId,\n parse_mode: \"HTML\",\n },\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await ctx.reply(`❌ ${escapeHtml(message)}`, { parse_mode: \"HTML\" });\n }\n}\n\nasync function handleCancel(ctx: Context, core: OpenACPCore): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n await session.cancel();\n await ctx.reply(\"⛔ Session cancelled.\", { parse_mode: \"HTML\" });\n }\n}\n\nasync function handleStatus(ctx: Context, core: OpenACPCore): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (threadId) {\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n await ctx.reply(\n `<b>Session:</b> ${escapeHtml(session.name || session.id)}\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Status:</b> ${escapeHtml(session.status)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>\\n` +\n `<b>Queue:</b> ${session.promptQueue.length} pending`,\n { parse_mode: \"HTML\" },\n );\n } else {\n await ctx.reply(\"No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n }\n } else {\n const sessions = core.sessionManager.listSessions(\"telegram\");\n const active = sessions.filter(\n (s) => s.status === \"active\" || s.status === \"initializing\",\n );\n await ctx.reply(\n `<b>OpenACP Status</b>\\n` +\n `Active sessions: ${active.length}\\n` +\n `Total sessions: ${sessions.length}`,\n { parse_mode: \"HTML\" },\n );\n }\n}\n\nasync function handleAgents(ctx: Context, core: OpenACPCore): Promise<void> {\n const agents = core.agentManager.getAvailableAgents();\n const defaultAgent = core.configManager.get().defaultAgent;\n const lines = agents.map(\n (a) =>\n `• <b>${escapeHtml(a.name)}</b>${a.name === defaultAgent ? \" (default)\" : \"\"}\\n` +\n ` <code>${escapeHtml(a.command)} ${a.args.map((arg) => escapeHtml(arg)).join(\" \")}</code>`,\n );\n const text =\n lines.length > 0\n ? `<b>Available Agents:</b>\\n\\n${lines.join(\"\\n\")}`\n : `<b>Available Agents:</b>\\n\\nNo agents configured.`;\n await ctx.reply(text, { parse_mode: \"HTML\" });\n}\n\nasync function handleHelp(ctx: Context): Promise<void> {\n await ctx.reply(\n `<b>OpenACP Commands:</b>\\n\\n` +\n `/new [agent] [workspace] — Create new session\\n` +\n `/new_chat — New chat, same agent & workspace\\n` +\n `/cancel — Cancel current session\\n` +\n `/status — Show session/system status\\n` +\n `/agents — List available agents\\n` +\n `/menu — Show interactive menu\\n` +\n `/help — Show this help\\n\\n` +\n `Or just chat in the 🤖 Assistant topic for help!`,\n { parse_mode: \"HTML\" },\n );\n}\n\n// grammy's Context exposes .api (the bot's Api instance) and internally the bot\n// We need access to the bot instance for createSessionTopic (which uses bot.api.createForumTopic).\n// ctx.api is the same Api object as bot.api, so we can pass a minimal shim.\nfunction botFromCtx(ctx: Context): Bot {\n // createSessionTopic only uses bot.api.createForumTopic\n return { api: ctx.api } as unknown as Bot;\n}\n","import type { Bot } from 'grammy'\nimport { InlineKeyboard } from 'grammy'\nimport { nanoid } from 'nanoid'\nimport type { PermissionRequest, NotificationMessage, Session } from '../../core/index.js'\nimport { escapeHtml } from './formatting.js'\nimport { buildDeepLink } from './topics.js'\n\n// Stored pending permission callbacks: callbackKey → { sessionId, requestId }\ninterface PendingPermission {\n sessionId: string\n requestId: string\n}\n\nexport class PermissionHandler {\n private pending: Map<string, PendingPermission> = new Map()\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private getSession: (sessionId: string) => Session | undefined,\n private sendNotification: (notification: NotificationMessage) => Promise<void>,\n ) {}\n\n async sendPermissionRequest(session: Session, request: PermissionRequest): Promise<void> {\n const threadId = Number(session.threadId)\n\n // Short callback key (Telegram 64-byte limit on callback_data)\n const callbackKey = nanoid(8)\n this.pending.set(callbackKey, { sessionId: session.id, requestId: request.id })\n\n // Build inline keyboard\n const keyboard = new InlineKeyboard()\n for (const option of request.options) {\n const emoji = option.isAllow ? '✅' : '❌'\n keyboard.text(`${emoji} ${option.label}`, `p:${callbackKey}:${option.id}`)\n }\n\n // Send in session topic WITH notification\n const msg = await this.bot.api.sendMessage(this.chatId,\n `🔐 <b>Permission request:</b>\\n\\n${escapeHtml(request.description)}`,\n {\n message_thread_id: threadId,\n parse_mode: 'HTML',\n reply_markup: keyboard,\n disable_notification: false,\n }\n )\n\n // Deep link for notification\n const deepLink = buildDeepLink(this.chatId, msg.message_id)\n\n // Notify in notification topic\n await this.sendNotification({\n sessionId: session.id,\n sessionName: session.name,\n type: 'permission',\n summary: request.description,\n deepLink,\n })\n }\n\n setupCallbackHandler(): void {\n this.bot.on('callback_query:data', async (ctx) => {\n const data = ctx.callbackQuery.data\n if (!data.startsWith('p:')) return\n\n const parts = data.split(':')\n if (parts.length < 3) return\n const [, callbackKey, optionId] = parts\n\n const pending = this.pending.get(callbackKey)\n if (!pending) {\n try { await ctx.answerCallbackQuery({ text: '❌ Expired' }) } catch { /* old query */ }\n return\n }\n\n const session = this.getSession(pending.sessionId)\n if (session?.pendingPermission?.requestId === pending.requestId) {\n session.pendingPermission.resolve(optionId)\n session.pendingPermission = undefined\n }\n this.pending.delete(callbackKey)\n\n try { await ctx.answerCallbackQuery({ text: '✅ Responded' }) } catch { /* old query */ }\n\n // Remove buttons\n try {\n await ctx.editMessageReplyMarkup({ reply_markup: undefined })\n } catch { /* ignore */ }\n })\n }\n}\n","import type { OpenACPCore, ChannelAdapter, Config, Session } from \"../../core/index.js\";\n\nexport async function spawnAssistant(\n core: OpenACPCore,\n adapter: ChannelAdapter,\n assistantTopicId: number,\n): Promise<Session> {\n const config = core.configManager.get();\n\n // Create session with default agent\n const session = await core.sessionManager.createSession(\n \"telegram\",\n config.defaultAgent,\n core.configManager.resolveWorkspace(),\n core.agentManager,\n );\n session.threadId = String(assistantTopicId);\n\n // Send system prompt BEFORE wiring events. enqueuePrompt awaits the full\n // agent response, so by the time it returns the system prompt conversation\n // is complete. Since no event handler is wired yet, the response is\n // intentionally discarded — users only see responses to their own messages.\n const systemPrompt = buildAssistantSystemPrompt(config);\n await session.enqueuePrompt(systemPrompt);\n\n // Wire events to adapter — only messages after this point reach the user\n core.wireSessionEvents(session, adapter);\n\n return session;\n}\n\nexport function buildAssistantSystemPrompt(config: Config): string {\n const agentNames = Object.keys(config.agents).join(\", \");\n return `You are the OpenACP Assistant. Help users manage their AI coding sessions.\n\nAvailable agents: ${agentNames}\nDefault agent: ${config.defaultAgent}\nWorkspace base: ${config.workspace.baseDir}\n\nWhen a user wants to create a session, guide them through:\n1. Which agent to use\n2. Which workspace/project\n3. Confirm and create\n\nCommands reference:\n- /new [agent] [workspace] — Create new session\n- /new_chat — New chat with same agent & workspace\n- /cancel — Cancel current session\n- /status — Show status\n- /agents — List agents\n- /help — Show help\n\nBe concise and helpful. When the user confirms session creation, tell them you'll create it now.`;\n}\n\nexport async function handleAssistantMessage(\n session: Session | null,\n text: string,\n): Promise<void> {\n if (!session) return;\n await session.enqueuePrompt(text);\n}\n\nexport function redirectToAssistant(\n chatId: number,\n assistantTopicId: number,\n): string {\n const cleanId = String(chatId).replace(\"-100\", \"\");\n const link = `https://t.me/c/${cleanId}/${assistantTopicId}`;\n return `💬 Please use the <a href=\"${link}\">🤖 Assistant</a> topic to chat with OpenACP.`;\n}\n"],"mappings":"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","names":["InlineKeyboard","nanoid","nanoid","InlineKeyboard"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// src/core/log.ts
|
|
2
2
|
var log = {
|
|
3
3
|
info: (...args) => console.log((/* @__PURE__ */ new Date()).toISOString(), "[INFO]", ...args),
|
|
4
4
|
warn: (...args) => console.warn((/* @__PURE__ */ new Date()).toISOString(), "[WARN]", ...args),
|
|
@@ -8,7 +8,7 @@ var log = {
|
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// src/core/config.ts
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
import * as fs from "fs";
|
|
14
14
|
import * as path from "path";
|
|
@@ -159,7 +159,7 @@ var ConfigManager = class {
|
|
|
159
159
|
}
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
-
//
|
|
162
|
+
// src/core/plugin-manager.ts
|
|
163
163
|
import { execSync } from "child_process";
|
|
164
164
|
import * as fs2 from "fs";
|
|
165
165
|
import * as path2 from "path";
|
|
@@ -217,4 +217,4 @@ export {
|
|
|
217
217
|
listPlugins,
|
|
218
218
|
loadAdapterFactory
|
|
219
219
|
};
|
|
220
|
-
//# sourceMappingURL=chunk-
|
|
220
|
+
//# sourceMappingURL=chunk-KADEDKIM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/log.ts","../../src/core/config.ts","../../src/core/plugin-manager.ts"],"sourcesContent":["export const log = {\n info: (...args: unknown[]) => console.log(new Date().toISOString(), '[INFO]', ...args),\n warn: (...args: unknown[]) => console.warn(new Date().toISOString(), '[WARN]', ...args),\n error: (...args: unknown[]) => console.error(new Date().toISOString(), '[ERROR]', ...args),\n debug: (...args: unknown[]) => {\n if (process.env.OPENACP_DEBUG) console.log(new Date().toISOString(), '[DEBUG]', ...args)\n },\n}\n","import { z } from 'zod'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport { log } from './log.js'\n\nconst BaseChannelSchema = z.object({\n enabled: z.boolean().default(false),\n adapter: z.string().optional(), // package name for plugin adapters\n}).passthrough()\n\nexport const PLUGINS_DIR = path.join(os.homedir(), '.openacp', 'plugins')\n\nconst AgentSchema = z.object({\n command: z.string(),\n args: z.array(z.string()).default([]),\n workingDirectory: z.string().optional(),\n env: z.record(z.string(), z.string()).default({}),\n})\n\nexport const ConfigSchema = z.object({\n channels: z.record(z.string(), BaseChannelSchema),\n agents: z.record(z.string(), AgentSchema),\n defaultAgent: z.string(),\n workspace: z.object({\n baseDir: z.string().default('~/openacp-workspace'),\n }).default({}),\n security: z.object({\n allowedUserIds: z.array(z.string()).default([]),\n maxConcurrentSessions: z.number().default(5),\n sessionTimeoutMinutes: z.number().default(60),\n }).default({}),\n})\n\nexport type Config = z.infer<typeof ConfigSchema>\n\nexport function expandHome(p: string): string {\n if (p.startsWith('~')) {\n return path.join(os.homedir(), p.slice(1))\n }\n return p\n}\n\nconst DEFAULT_CONFIG = {\n channels: {\n telegram: {\n enabled: false,\n botToken: \"YOUR_BOT_TOKEN_HERE\",\n chatId: 0,\n notificationTopicId: null,\n assistantTopicId: null\n }\n },\n agents: {\n claude: { command: \"claude-agent-acp\", args: [], env: {} },\n codex: { command: \"codex\", args: [\"--acp\"], env: {} }\n },\n defaultAgent: \"claude\",\n workspace: { baseDir: \"~/openacp-workspace\" },\n security: { allowedUserIds: [], maxConcurrentSessions: 5, sessionTimeoutMinutes: 60 }\n}\n\nexport class ConfigManager {\n private config!: Config\n private configPath: string\n\n constructor() {\n this.configPath = process.env.OPENACP_CONFIG_PATH || expandHome('~/.openacp/config.json')\n }\n\n async load(): Promise<void> {\n // 1. Ensure directory exists\n const dir = path.dirname(this.configPath)\n fs.mkdirSync(dir, { recursive: true })\n\n // 2. If config file doesn't exist, create default\n if (!fs.existsSync(this.configPath)) {\n fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2))\n log.info(`Config created at ${this.configPath}`)\n log.info('Please edit it with your Telegram bot token and chat ID, then restart.')\n process.exit(1)\n }\n\n // 3. Read and parse\n const raw = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'))\n\n // 4. Apply env var overrides\n this.applyEnvOverrides(raw)\n\n // 5. Validate with Zod\n const result = ConfigSchema.safeParse(raw)\n if (!result.success) {\n log.error('Config validation failed:')\n for (const issue of result.error.issues) {\n log.error(` ${issue.path.join('.')}: ${issue.message}`)\n }\n process.exit(1)\n }\n this.config = result.data\n }\n\n get(): Config {\n return this.config\n }\n\n async save(updates: Record<string, unknown>): Promise<void> {\n // Read current file, merge updates, write back\n const raw = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'))\n this.deepMerge(raw, updates)\n fs.writeFileSync(this.configPath, JSON.stringify(raw, null, 2))\n // Re-validate and update in-memory config\n const result = ConfigSchema.safeParse(raw)\n if (result.success) {\n this.config = result.data\n }\n }\n\n resolveWorkspace(input?: string): string {\n if (!input) {\n const resolved = expandHome(this.config.workspace.baseDir)\n fs.mkdirSync(resolved, { recursive: true })\n return resolved\n }\n if (input.startsWith('/') || input.startsWith('~')) {\n const resolved = expandHome(input)\n fs.mkdirSync(resolved, { recursive: true })\n return resolved\n }\n // Named workspace → lowercase, under baseDir\n const name = input.toLowerCase()\n const resolved = path.join(expandHome(this.config.workspace.baseDir), name)\n fs.mkdirSync(resolved, { recursive: true })\n return resolved\n }\n\n async exists(): Promise<boolean> {\n return fs.existsSync(this.configPath)\n }\n\n getConfigPath(): string {\n return this.configPath\n }\n\n async writeNew(config: Config): Promise<void> {\n const dir = path.dirname(this.configPath)\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2))\n }\n\n private applyEnvOverrides(raw: Record<string, unknown>): void {\n const overrides: [string, string[]][] = [\n ['OPENACP_TELEGRAM_BOT_TOKEN', ['channels', 'telegram', 'botToken']],\n ['OPENACP_TELEGRAM_CHAT_ID', ['channels', 'telegram', 'chatId']],\n ['OPENACP_DEFAULT_AGENT', ['defaultAgent']],\n ]\n for (const [envVar, configPath] of overrides) {\n const value = process.env[envVar]\n if (value !== undefined) {\n let target = raw as Record<string, any>\n for (let i = 0; i < configPath.length - 1; i++) {\n if (!target[configPath[i]]) target[configPath[i]] = {}\n target = target[configPath[i]]\n }\n const key = configPath[configPath.length - 1]\n // Convert chatId to number\n target[key] = key === 'chatId' ? Number(value) : value\n }\n }\n }\n\n private deepMerge(target: Record<string, any>, source: Record<string, any>): void {\n for (const key of Object.keys(source)) {\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n if (!target[key]) target[key] = {}\n this.deepMerge(target[key], source[key])\n } else {\n target[key] = source[key]\n }\n }\n }\n}\n","import { execSync } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { createRequire } from 'node:module'\nimport { PLUGINS_DIR } from './config.js'\nimport { log } from './log.js'\nimport type { ChannelAdapter } from './channel.js'\n\nexport interface AdapterFactory {\n name: string\n createAdapter(core: any, config: any): ChannelAdapter\n}\n\nfunction ensurePluginsDir(): void {\n fs.mkdirSync(PLUGINS_DIR, { recursive: true })\n const pkgPath = path.join(PLUGINS_DIR, 'package.json')\n if (!fs.existsSync(pkgPath)) {\n fs.writeFileSync(pkgPath, JSON.stringify({ name: 'openacp-plugins', private: true, dependencies: {} }, null, 2))\n }\n}\n\nexport function installPlugin(packageName: string): void {\n ensurePluginsDir()\n log.info(`Installing ${packageName}...`)\n execSync(`npm install ${packageName} --prefix \"${PLUGINS_DIR}\"`, { stdio: 'inherit' })\n log.info(`${packageName} installed successfully.`)\n}\n\nexport function uninstallPlugin(packageName: string): void {\n ensurePluginsDir()\n log.info(`Uninstalling ${packageName}...`)\n execSync(`npm uninstall ${packageName} --prefix \"${PLUGINS_DIR}\"`, { stdio: 'inherit' })\n log.info(`${packageName} uninstalled.`)\n}\n\nexport function listPlugins(): Record<string, string> {\n const pkgPath = path.join(PLUGINS_DIR, 'package.json')\n if (!fs.existsSync(pkgPath)) return {}\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n return pkg.dependencies || {}\n}\n\nexport async function loadAdapterFactory(packageName: string): Promise<AdapterFactory | null> {\n try {\n const require = createRequire(path.join(PLUGINS_DIR, 'package.json'))\n const resolved = require.resolve(packageName)\n const mod = await import(resolved)\n\n // Plugin must export `adapterFactory` or default export conforming to AdapterFactory\n const factory: AdapterFactory | undefined = mod.adapterFactory || mod.default\n if (!factory || typeof factory.createAdapter !== 'function') {\n log.error(`Plugin ${packageName} does not export a valid AdapterFactory (needs .createAdapter())`)\n return null\n }\n return factory\n } catch (err) {\n log.error(`Failed to load plugin ${packageName}:`, err)\n log.error(`Run: npx openacp install ${packageName}`)\n return null\n }\n}\n"],"mappings":"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","names":["resolved","fs","path","require"]}
|
package/dist/cli.js
CHANGED
|
@@ -3,10 +3,9 @@ import {
|
|
|
3
3
|
installPlugin,
|
|
4
4
|
listPlugins,
|
|
5
5
|
uninstallPlugin
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-LZOMFHX3.js";
|
|
6
|
+
} from "./chunk-KADEDKIM.js";
|
|
8
7
|
|
|
9
|
-
//
|
|
8
|
+
// src/cli.ts
|
|
10
9
|
var args = process.argv.slice(2);
|
|
11
10
|
var command = args[0];
|
|
12
11
|
function printHelp() {
|
|
@@ -82,7 +81,7 @@ async function main() {
|
|
|
82
81
|
printHelp();
|
|
83
82
|
process.exit(1);
|
|
84
83
|
}
|
|
85
|
-
const { startServer } = await import("./main-
|
|
84
|
+
const { startServer } = await import("./main-L5JD5STD.js");
|
|
86
85
|
await startServer();
|
|
87
86
|
}
|
|
88
87
|
main().catch((err) => {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../
|
|
1
|
+
{"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { installPlugin, uninstallPlugin, listPlugins } from './core/plugin-manager.js'\n\nconst args = process.argv.slice(2)\nconst command = args[0]\n\nfunction printHelp(): void {\n console.log(`\nOpenACP - Self-hosted bridge for AI coding agents\n\nUsage:\n openacp Start the server\n openacp install <package> Install a plugin adapter\n openacp uninstall <package> Uninstall a plugin adapter\n openacp plugins List installed plugins\n openacp --version Show version\n openacp --help Show this help\n\nInstall:\n npm install -g @openacp/cli\n\nExamples:\n openacp\n openacp install @openacp/adapter-discord\n openacp uninstall @openacp/adapter-discord\n`)\n}\n\nasync function main() {\n if (command === '--help' || command === '-h') {\n printHelp()\n return\n }\n\n if (command === '--version' || command === '-v') {\n // In published build: read version from own package.json via createRequire\n // In dev: fallback to 'dev'\n try {\n const { createRequire } = await import('node:module')\n const require = createRequire(import.meta.url)\n const pkg = require('../package.json')\n console.log(`openacp v${pkg.version}`)\n } catch {\n console.log('openacp v0.0.0-dev')\n }\n return\n }\n\n if (command === 'install') {\n const pkg = args[1]\n if (!pkg) {\n console.error('Usage: openacp install <package>')\n process.exit(1)\n }\n installPlugin(pkg)\n return\n }\n\n if (command === 'uninstall') {\n const pkg = args[1]\n if (!pkg) {\n console.error('Usage: openacp uninstall <package>')\n process.exit(1)\n }\n uninstallPlugin(pkg)\n return\n }\n\n if (command === 'plugins') {\n const plugins = listPlugins()\n const entries = Object.entries(plugins)\n if (entries.length === 0) {\n console.log('No plugins installed.')\n } else {\n console.log('Installed plugins:')\n for (const [name, version] of entries) {\n console.log(` ${name}@${version}`)\n }\n }\n return\n }\n\n // Default: start server\n if (command && !command.startsWith('-')) {\n console.error(`Unknown command: ${command}`)\n printHelp()\n process.exit(1)\n }\n\n // Import and run server start\n const { startServer } = await import('./main.js')\n await startServer()\n}\n\nmain().catch((err) => {\n console.error('Fatal:', err)\n process.exit(1)\n})\n"],"mappings":";;;;;;;;AAIA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAkBb;AACD;AAEA,eAAe,OAAO;AACpB,MAAI,YAAY,YAAY,YAAY,MAAM;AAC5C,cAAU;AACV;AAAA,EACF;AAEA,MAAI,YAAY,eAAe,YAAY,MAAM;AAG/C,QAAI;AACF,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,QAAa;AACpD,YAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,YAAM,MAAMA,SAAQ,iBAAiB;AACrC,cAAQ,IAAI,YAAY,IAAI,OAAO,EAAE;AAAA,IACvC,QAAQ;AACN,cAAQ,IAAI,oBAAoB;AAAA,IAClC;AACA;AAAA,EACF;AAEA,MAAI,YAAY,WAAW;AACzB,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,kCAAkC;AAChD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,kBAAc,GAAG;AACjB;AAAA,EACF;AAEA,MAAI,YAAY,aAAa;AAC3B,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,oCAAoC;AAClD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,oBAAgB,GAAG;AACnB;AAAA,EACF;AAEA,MAAI,YAAY,WAAW;AACzB,UAAM,UAAU,YAAY;AAC5B,UAAM,UAAU,OAAO,QAAQ,OAAO;AACtC,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,uBAAuB;AAAA,IACrC,OAAO;AACL,cAAQ,IAAI,oBAAoB;AAChC,iBAAW,CAAC,MAAM,OAAO,KAAK,SAAS;AACrC,gBAAQ,IAAI,KAAK,IAAI,IAAI,OAAO,EAAE;AAAA,MACpC;AAAA,IACF;AACA;AAAA,EACF;AAGA,MAAI,WAAW,CAAC,QAAQ,WAAW,GAAG,GAAG;AACvC,YAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,cAAU;AACV,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,oBAAW;AAChD,QAAM,YAAY;AACpB;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,UAAU,GAAG;AAC3B,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["require"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -326,4 +326,33 @@ declare function uninstallPlugin(packageName: string): void;
|
|
|
326
326
|
declare function listPlugins(): Record<string, string>;
|
|
327
327
|
declare function loadAdapterFactory(packageName: string): Promise<AdapterFactory | null>;
|
|
328
328
|
|
|
329
|
-
|
|
329
|
+
interface TelegramChannelConfig {
|
|
330
|
+
enabled: boolean;
|
|
331
|
+
botToken: string;
|
|
332
|
+
chatId: number;
|
|
333
|
+
notificationTopicId: number | null;
|
|
334
|
+
assistantTopicId: number | null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
declare class TelegramAdapter extends ChannelAdapter {
|
|
338
|
+
private bot;
|
|
339
|
+
private telegramConfig;
|
|
340
|
+
private sessionDrafts;
|
|
341
|
+
private toolCallMessages;
|
|
342
|
+
private permissionHandler;
|
|
343
|
+
private assistantSession;
|
|
344
|
+
private notificationTopicId;
|
|
345
|
+
private assistantTopicId;
|
|
346
|
+
constructor(core: OpenACPCore, config: TelegramChannelConfig);
|
|
347
|
+
start(): Promise<void>;
|
|
348
|
+
stop(): Promise<void>;
|
|
349
|
+
private setupRoutes;
|
|
350
|
+
sendMessage(sessionId: string, content: OutgoingMessage): Promise<void>;
|
|
351
|
+
sendPermissionRequest(sessionId: string, request: PermissionRequest): Promise<void>;
|
|
352
|
+
sendNotification(notification: NotificationMessage): Promise<void>;
|
|
353
|
+
createSessionThread(sessionId: string, name: string): Promise<string>;
|
|
354
|
+
renameSessionThread(sessionId: string, newName: string): Promise<void>;
|
|
355
|
+
private finalizeDraft;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export { type AdapterFactory, type AgentDefinition, type AgentEvent, AgentInstance, AgentManager, ChannelAdapter, type ChannelConfig, type Config, ConfigManager, type IncomingMessage, NotificationManager, type NotificationMessage, OpenACPCore, type OutgoingMessage, PLUGINS_DIR, type PermissionOption, type PermissionRequest, type PlanEntry, Session, SessionManager, type SessionStatus, StderrCapture, TelegramAdapter, expandHome, installPlugin, listPlugins, loadAdapterFactory, log, nodeToWebReadable, nodeToWebWritable, uninstallPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentInstance,
|
|
3
3
|
AgentManager,
|
|
4
|
+
ChannelAdapter,
|
|
4
5
|
NotificationManager,
|
|
5
6
|
OpenACPCore,
|
|
6
7
|
Session,
|
|
7
8
|
SessionManager,
|
|
8
9
|
StderrCapture,
|
|
10
|
+
TelegramAdapter,
|
|
9
11
|
nodeToWebReadable,
|
|
10
12
|
nodeToWebWritable
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-I6KXISAR.js";
|
|
12
14
|
import {
|
|
13
15
|
ConfigManager,
|
|
14
16
|
PLUGINS_DIR,
|
|
@@ -18,16 +20,7 @@ import {
|
|
|
18
20
|
loadAdapterFactory,
|
|
19
21
|
log,
|
|
20
22
|
uninstallPlugin
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-LZOMFHX3.js";
|
|
23
|
-
|
|
24
|
-
// packages/core/src/channel.ts
|
|
25
|
-
var ChannelAdapter = class {
|
|
26
|
-
constructor(core, config) {
|
|
27
|
-
this.core = core;
|
|
28
|
-
this.config = config;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
23
|
+
} from "./chunk-KADEDKIM.js";
|
|
31
24
|
export {
|
|
32
25
|
AgentInstance,
|
|
33
26
|
AgentManager,
|
|
@@ -39,6 +32,7 @@ export {
|
|
|
39
32
|
Session,
|
|
40
33
|
SessionManager,
|
|
41
34
|
StderrCapture,
|
|
35
|
+
TelegramAdapter,
|
|
42
36
|
expandHome,
|
|
43
37
|
installPlugin,
|
|
44
38
|
listPlugins,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
OpenACPCore
|
|
4
|
-
|
|
3
|
+
OpenACPCore,
|
|
4
|
+
TelegramAdapter
|
|
5
|
+
} from "./chunk-I6KXISAR.js";
|
|
5
6
|
import {
|
|
6
7
|
ConfigManager,
|
|
7
8
|
loadAdapterFactory,
|
|
8
9
|
log
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-LZOMFHX3.js";
|
|
10
|
+
} from "./chunk-KADEDKIM.js";
|
|
11
11
|
|
|
12
|
-
//
|
|
12
|
+
// src/main.ts
|
|
13
13
|
var shuttingDown = false;
|
|
14
14
|
async function startServer() {
|
|
15
15
|
const configManager = new ConfigManager();
|
|
16
16
|
const configExists = await configManager.exists();
|
|
17
17
|
if (!configExists) {
|
|
18
|
-
const { runSetup } = await import("./setup-
|
|
18
|
+
const { runSetup } = await import("./setup-2UVU4YYA.js");
|
|
19
19
|
const shouldStart = await runSetup(configManager);
|
|
20
20
|
if (!shouldStart) process.exit(0);
|
|
21
21
|
}
|
|
@@ -26,17 +26,8 @@ async function startServer() {
|
|
|
26
26
|
for (const [channelName, channelConfig] of Object.entries(config.channels)) {
|
|
27
27
|
if (!channelConfig.enabled) continue;
|
|
28
28
|
if (channelName === "telegram") {
|
|
29
|
-
let TelegramAdapter;
|
|
30
|
-
try {
|
|
31
|
-
const mod = await import("@openacp/adapter-telegram");
|
|
32
|
-
TelegramAdapter = mod.TelegramAdapter;
|
|
33
|
-
} catch {
|
|
34
|
-
const adapterPath = new URL("../../adapters/telegram/dist/index.js", import.meta.url).pathname;
|
|
35
|
-
const mod = await import(adapterPath);
|
|
36
|
-
TelegramAdapter = mod.TelegramAdapter;
|
|
37
|
-
}
|
|
38
29
|
core.registerAdapter("telegram", new TelegramAdapter(core, channelConfig));
|
|
39
|
-
log.info("Telegram adapter registered
|
|
30
|
+
log.info("Telegram adapter registered");
|
|
40
31
|
} else if (channelConfig.adapter) {
|
|
41
32
|
const factory = await loadAdapterFactory(channelConfig.adapter);
|
|
42
33
|
if (factory) {
|
|
@@ -88,4 +79,4 @@ if (isDirectExecution) {
|
|
|
88
79
|
export {
|
|
89
80
|
startServer
|
|
90
81
|
};
|
|
91
|
-
//# sourceMappingURL=main-
|
|
82
|
+
//# sourceMappingURL=main-L5JD5STD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ConfigManager } from './core/config.js'\nimport { OpenACPCore } from './core/core.js'\nimport { loadAdapterFactory } from './core/plugin-manager.js'\nimport { log } from './core/log.js'\nimport { TelegramAdapter } from './adapters/telegram/index.js'\n\nlet shuttingDown = false\n\nexport async function startServer() {\n // 1. Check config exists, run setup if not\n const configManager = new ConfigManager()\n const configExists = await configManager.exists()\n\n if (!configExists) {\n const { runSetup } = await import('./core/setup.js')\n const shouldStart = await runSetup(configManager)\n if (!shouldStart) process.exit(0)\n }\n\n // 2. Load config (validates with Zod)\n await configManager.load()\n const config = configManager.get()\n log.info('Config loaded from', configManager.getConfigPath())\n\n // 3. Create core\n const core = new OpenACPCore(configManager)\n\n // 4. Register adapters from config\n for (const [channelName, channelConfig] of Object.entries(config.channels)) {\n if (!channelConfig.enabled) continue\n\n if (channelName === 'telegram') {\n core.registerAdapter('telegram', new TelegramAdapter(core, channelConfig))\n log.info('Telegram adapter registered')\n } else if (channelConfig.adapter) {\n // Plugin adapter\n const factory = await loadAdapterFactory(channelConfig.adapter)\n if (factory) {\n const adapter = factory.createAdapter(core, channelConfig)\n core.registerAdapter(channelName, adapter)\n log.info(`${channelName} adapter registered (plugin: ${channelConfig.adapter})`)\n } else {\n log.error(`Skipping channel \"${channelName}\" — adapter \"${channelConfig.adapter}\" failed to load`)\n }\n } else {\n log.error(`Channel \"${channelName}\" has no built-in adapter. Set \"adapter\" field to a plugin package.`)\n }\n }\n\n if (core.adapters.size === 0) {\n log.error('No channels enabled. Enable at least one channel in config.')\n process.exit(1)\n }\n\n // 5. Start\n await core.start()\n\n // 6. Log ready\n const agents = Object.keys(config.agents).join(', ')\n log.info(`OpenACP started. Agents: ${agents}`)\n log.info('Press Ctrl+C to stop.')\n\n // 7. Graceful shutdown\n const shutdown = async (signal: string) => {\n if (shuttingDown) return\n shuttingDown = true\n log.info(`${signal} received. Shutting down...`)\n\n try {\n await core.stop()\n } catch (err) {\n log.error('Error during shutdown:', err)\n }\n\n process.exit(0)\n }\n\n process.on('SIGINT', () => shutdown('SIGINT'))\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n\n process.on('uncaughtException', (err) => {\n log.error('Uncaught exception:', err)\n })\n\n process.on('unhandledRejection', (err) => {\n log.error('Unhandled rejection:', err)\n })\n}\n\n// Direct execution for dev (node packages/core/dist/main.js)\nconst isDirectExecution = process.argv[1]?.endsWith('main.js')\nif (isDirectExecution) {\n startServer().catch((err) => {\n log.error('Fatal:', err)\n process.exit(1)\n })\n}\n"],"mappings":";;;;;;;;;;;;AAQA,IAAI,eAAe;AAEnB,eAAsB,cAAc;AAElC,QAAM,gBAAgB,IAAI,cAAc;AACxC,QAAM,eAAe,MAAM,cAAc,OAAO;AAEhD,MAAI,CAAC,cAAc;AACjB,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,qBAAiB;AACnD,UAAM,cAAc,MAAM,SAAS,aAAa;AAChD,QAAI,CAAC,YAAa,SAAQ,KAAK,CAAC;AAAA,EAClC;AAGA,QAAM,cAAc,KAAK;AACzB,QAAM,SAAS,cAAc,IAAI;AACjC,MAAI,KAAK,sBAAsB,cAAc,cAAc,CAAC;AAG5D,QAAM,OAAO,IAAI,YAAY,aAAa;AAG1C,aAAW,CAAC,aAAa,aAAa,KAAK,OAAO,QAAQ,OAAO,QAAQ,GAAG;AAC1E,QAAI,CAAC,cAAc,QAAS;AAE5B,QAAI,gBAAgB,YAAY;AAC9B,WAAK,gBAAgB,YAAY,IAAI,gBAAgB,MAAM,aAAa,CAAC;AACzE,UAAI,KAAK,6BAA6B;AAAA,IACxC,WAAW,cAAc,SAAS;AAEhC,YAAM,UAAU,MAAM,mBAAmB,cAAc,OAAO;AAC9D,UAAI,SAAS;AACX,cAAM,UAAU,QAAQ,cAAc,MAAM,aAAa;AACzD,aAAK,gBAAgB,aAAa,OAAO;AACzC,YAAI,KAAK,GAAG,WAAW,gCAAgC,cAAc,OAAO,GAAG;AAAA,MACjF,OAAO;AACL,YAAI,MAAM,qBAAqB,WAAW,qBAAgB,cAAc,OAAO,kBAAkB;AAAA,MACnG;AAAA,IACF,OAAO;AACL,UAAI,MAAM,YAAY,WAAW,qEAAqE;AAAA,IACxG;AAAA,EACF;AAEA,MAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,QAAI,MAAM,6DAA6D;AACvE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,KAAK,MAAM;AAGjB,QAAM,SAAS,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AACnD,MAAI,KAAK,4BAA4B,MAAM,EAAE;AAC7C,MAAI,KAAK,uBAAuB;AAGhC,QAAM,WAAW,OAAO,WAAmB;AACzC,QAAI,aAAc;AAClB,mBAAe;AACf,QAAI,KAAK,GAAG,MAAM,6BAA6B;AAE/C,QAAI;AACF,YAAM,KAAK,KAAK;AAAA,IAClB,SAAS,KAAK;AACZ,UAAI,MAAM,0BAA0B,GAAG;AAAA,IACzC;AAEA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,UAAU,MAAM,SAAS,QAAQ,CAAC;AAC7C,UAAQ,GAAG,WAAW,MAAM,SAAS,SAAS,CAAC;AAE/C,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,QAAI,MAAM,uBAAuB,GAAG;AAAA,EACtC,CAAC;AAED,UAAQ,GAAG,sBAAsB,CAAC,QAAQ;AACxC,QAAI,MAAM,wBAAwB,GAAG;AAAA,EACvC,CAAC;AACH;AAGA,IAAM,oBAAoB,QAAQ,KAAK,CAAC,GAAG,SAAS,SAAS;AAC7D,IAAI,mBAAmB;AACrB,cAAY,EAAE,MAAM,CAAC,QAAQ;AAC3B,QAAI,MAAM,UAAU,GAAG;AACvB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":[]}
|