@openacp/cli 0.4.5 → 0.4.8

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.
Files changed (38) hide show
  1. package/README.md +81 -15
  2. package/dist/agent-registry-7HC6D4CH.js +7 -0
  3. package/dist/{chunk-WHKLPZGK.js → chunk-6MJLVZXV.js} +8 -8
  4. package/dist/{chunk-V5P3K4A5.js → chunk-BBPWAWE3.js} +1137 -119
  5. package/dist/chunk-BBPWAWE3.js.map +1 -0
  6. package/dist/{chunk-3QACY5E3.js → chunk-C6YIUTGR.js} +2 -2
  7. package/dist/{chunk-2SY7Y2VB.js → chunk-HZD3CGPK.js} +2 -2
  8. package/dist/{chunk-BLVZFCKN.js → chunk-UAUTLC4E.js} +27 -3
  9. package/dist/{chunk-BLVZFCKN.js.map → chunk-UAUTLC4E.js.map} +1 -1
  10. package/dist/chunk-VA2M52CM.js +15 -0
  11. package/dist/chunk-VA2M52CM.js.map +1 -0
  12. package/dist/{chunk-WF5XDN4D.js → chunk-ZRFBLD3W.js} +6 -2
  13. package/dist/chunk-ZRFBLD3W.js.map +1 -0
  14. package/dist/cli.js +388 -38
  15. package/dist/cli.js.map +1 -1
  16. package/dist/{config-J5YQOMDU.js → config-H2DSEHNW.js} +2 -2
  17. package/dist/config-editor-SKS4LJLT.js +11 -0
  18. package/dist/{daemon-SLGQGRKO.js → daemon-VF6HJQXD.js} +3 -3
  19. package/dist/index.d.ts +111 -10
  20. package/dist/index.js +13 -10
  21. package/dist/integrate-WUPLRJD3.js +145 -0
  22. package/dist/integrate-WUPLRJD3.js.map +1 -0
  23. package/dist/{main-3CDOICYN.js → main-NV7YN3VY.js} +27 -14
  24. package/dist/main-NV7YN3VY.js.map +1 -0
  25. package/dist/{setup-JQZBPXWS.js → setup-FCVL75K6.js} +3 -3
  26. package/dist/setup-FCVL75K6.js.map +1 -0
  27. package/package.json +1 -1
  28. package/dist/chunk-V5P3K4A5.js.map +0 -1
  29. package/dist/chunk-WF5XDN4D.js.map +0 -1
  30. package/dist/config-editor-IXL4BFG3.js +0 -11
  31. package/dist/main-3CDOICYN.js.map +0 -1
  32. /package/dist/{config-J5YQOMDU.js.map → agent-registry-7HC6D4CH.js.map} +0 -0
  33. /package/dist/{chunk-WHKLPZGK.js.map → chunk-6MJLVZXV.js.map} +0 -0
  34. /package/dist/{chunk-3QACY5E3.js.map → chunk-C6YIUTGR.js.map} +0 -0
  35. /package/dist/{chunk-2SY7Y2VB.js.map → chunk-HZD3CGPK.js.map} +0 -0
  36. /package/dist/{config-editor-IXL4BFG3.js.map → config-H2DSEHNW.js.map} +0 -0
  37. /package/dist/{daemon-SLGQGRKO.js.map → config-editor-SKS4LJLT.js.map} +0 -0
  38. /package/dist/{setup-JQZBPXWS.js.map → daemon-VF6HJQXD.js.map} +0 -0
@@ -1 +0,0 @@
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/typed-emitter.ts","../../src/core/prompt-queue.ts","../../src/core/permission-gate.ts","../../src/core/session.ts","../../src/core/session-manager.ts","../../src/core/notification.ts","../../src/tunnel/extract-file-info.ts","../../src/core/message-transformer.ts","../../src/core/core.ts","../../src/core/session-store.ts","../../src/core/channel.ts","../../src/core/api-server.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","../../src/adapters/telegram/activity.ts","../../src/adapters/telegram/send-queue.ts","../../src/adapters/telegram/action-detect.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 { Transform } from \"node:stream\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { ClientSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\";\nimport type {\n Agent,\n Client,\n PromptResponse,\n PermissionOption as SdkPermissionOption,\n} from \"@agentclientprotocol/sdk\";\nimport { nodeToWebWritable, nodeToWebReadable } from \"./streams.js\";\nimport { StderrCapture } from \"./stderr-capture.js\";\nimport type {\n AgentDefinition,\n AgentEvent,\n PermissionRequest,\n} from \"./types.js\";\nimport { createChildLogger } from \"./log.js\";\nconst log = createChildLogger({ module: \"agent-instance\" });\n\n/** Find the nearest ancestor directory containing package.json */\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, \"package.json\"))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return startDir;\n}\n\n/** Resolve an agent command to a directly executable form (avoids shell wrappers) */\nfunction resolveAgentCommand(cmd: string): { command: string; args: string[] } {\n // Directories to search for node_modules: cwd AND the package's own directory\n const searchRoots = [process.cwd()];\n // Add the directory where this package is installed (for global installs)\n // Use findPackageRoot instead of hardcoded \"../..\" to handle both tsc (dist/core/)\n // and tsup bundle (dist/) directory structures correctly\n const ownDir = findPackageRoot(import.meta.dirname);\n if (ownDir !== process.cwd()) {\n searchRoots.push(ownDir);\n }\n\n // 1. Check node_modules for the package's actual JS entry point\n for (const root of searchRoots) {\n const packageDirs = [\n path.resolve(root, \"node_modules\", \"@zed-industries\", cmd, \"dist\", \"index.js\"),\n path.resolve(root, \"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\n // 2. Check .bin — if it's a JS file with shebang, run with node directly\n for (const root of searchRoots) {\n const localBin = path.resolve(root, \"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\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> =\n async () => \"\";\n\n private constructor(agentName: string) {\n this.agentName = agentName;\n }\n\n private static async spawnSubprocess(\n agentDef: AgentDefinition,\n workingDirectory: string,\n ): Promise<AgentInstance> {\n const instance = new AgentInstance(agentDef.name);\n const resolved = resolveAgentCommand(agentDef.command);\n log.debug(\n {\n agentName: agentDef.name,\n command: resolved.command,\n args: resolved.args,\n },\n \"Resolved agent command\",\n );\n\n instance.child = spawn(\n resolved.command,\n [...resolved.args, ...agentDef.args],\n {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n cwd: workingDirectory,\n env: { ...process.env, ...agentDef.env },\n },\n );\n\n await new Promise<void>((resolve, reject) => {\n instance.child.on(\"error\", (err) => {\n reject(\n new Error(\n `Failed to spawn agent \"${agentDef.name}\": ${err.message}. Is \"${agentDef.command}\" installed?`,\n ),\n );\n });\n instance.child.on(\"spawn\", () => resolve());\n });\n\n instance.stderrCapture = new StderrCapture(50);\n instance.child.stderr!.on(\"data\", (chunk: Buffer) => {\n instance.stderrCapture.append(chunk.toString());\n });\n\n const stdinLogger = new Transform({\n transform(chunk, _enc, cb) {\n log.debug(\n { direction: \"send\", raw: chunk.toString().trimEnd() },\n \"ACP raw\",\n );\n cb(null, chunk);\n },\n });\n stdinLogger.pipe(instance.child.stdin!);\n\n const stdoutLogger = new Transform({\n transform(chunk, _enc, cb) {\n log.debug(\n { direction: \"recv\", raw: chunk.toString().trimEnd() },\n \"ACP raw\",\n );\n cb(null, chunk);\n },\n });\n instance.child.stdout!.pipe(stdoutLogger);\n\n const toAgent = nodeToWebWritable(stdinLogger);\n const fromAgent = nodeToWebReadable(stdoutLogger);\n const stream = ndJsonStream(toAgent, fromAgent);\n\n instance.connection = new ClientSideConnection(\n (_agent: Agent): Client => instance.createClient(_agent),\n stream,\n );\n\n await instance.connection.initialize({\n protocolVersion: 1,\n clientCapabilities: {\n fs: { readTextFile: true, writeTextFile: true },\n terminal: true,\n },\n });\n\n return instance;\n }\n\n private setupCrashDetection(): void {\n this.child.on(\"exit\", (code, signal) => {\n log.info(\n { sessionId: this.sessionId, exitCode: code, signal },\n \"Agent process exited\",\n );\n if (code !== 0 && code !== null) {\n const stderr = this.stderrCapture.getLastLines();\n this.onSessionUpdate({\n type: \"error\",\n message: `Agent crashed (exit code ${code})\\n${stderr}`,\n });\n }\n });\n\n this.connection.closed.then(() => {\n log.debug({ sessionId: this.sessionId }, \"ACP connection closed\");\n });\n }\n\n static async spawn(\n agentDef: AgentDefinition,\n workingDirectory: string,\n ): Promise<AgentInstance> {\n log.debug(\n { agentName: agentDef.name, command: agentDef.command },\n \"Spawning agent\",\n );\n const spawnStart = Date.now();\n\n const instance = await AgentInstance.spawnSubprocess(\n agentDef,\n workingDirectory,\n );\n\n const response = await instance.connection.newSession({\n cwd: workingDirectory,\n mcpServers: [],\n });\n instance.sessionId = response.sessionId;\n instance.setupCrashDetection();\n\n log.info(\n { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },\n \"Agent spawn complete\",\n );\n return instance;\n }\n\n static async resume(\n agentDef: AgentDefinition,\n workingDirectory: string,\n agentSessionId: string,\n ): Promise<AgentInstance> {\n log.debug({ agentName: agentDef.name, agentSessionId }, \"Resuming agent\");\n const spawnStart = Date.now();\n\n const instance = await AgentInstance.spawnSubprocess(\n agentDef,\n workingDirectory,\n );\n\n try {\n const response = await instance.connection.unstable_resumeSession({\n sessionId: agentSessionId,\n cwd: workingDirectory,\n });\n instance.sessionId = response.sessionId;\n log.info(\n { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },\n \"Agent resume complete\",\n );\n } catch (err) {\n log.warn(\n { err, agentSessionId },\n \"Resume failed, falling back to new session\",\n );\n const response = await instance.connection.newSession({\n cwd: workingDirectory,\n mcpServers: [],\n });\n instance.sessionId = response.sessionId;\n log.info(\n { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },\n \"Agent fallback spawn complete\",\n );\n }\n\n instance.setupCrashDetection();\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 rawInput: (update as any).rawInput ?? undefined,\n meta: (update as any)._meta ?? undefined,\n };\n break;\n case \"tool_call_update\":\n event = {\n type: \"tool_update\",\n id: update.toolCallId,\n name: update.title ?? undefined,\n kind: update.kind ?? undefined,\n status: update.status ?? \"pending\",\n content: update.content ?? undefined,\n rawInput: (update as any).rawInput ?? undefined,\n meta: (update as any)._meta ?? 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 = {\n type: \"commands_update\",\n commands: update.availableCommands,\n };\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 =\n 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) =>\n appendOutput(chunk.toString()),\n );\n childProcess.stderr?.on(\"data\", (chunk: Buffer) =>\n appendOutput(chunk.toString()),\n );\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 ? {\n exitCode: state.exitStatus.exitCode,\n signal: state.exitStatus.signal,\n }\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 {\n exitCode: state.exitStatus.exitCode,\n signal: state.exitStatus.signal,\n };\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(\n agentName: string,\n workingDirectory: string,\n ): 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 async resume(\n agentName: string,\n workingDirectory: string,\n agentSessionId: string,\n ): Promise<AgentInstance> {\n const agentDef = this.getAgent(agentName);\n if (!agentDef) throw new Error(`Agent \"${agentName}\" not found in config`);\n return AgentInstance.resume(agentDef, workingDirectory, agentSessionId);\n }\n}\n","/**\n * A minimal, generic typed event emitter.\n *\n * Usage:\n * interface MyEvents {\n * data: (payload: string) => void\n * error: (err: Error) => void\n * }\n * const emitter = new TypedEmitter<MyEvents>()\n * emitter.on('data', (payload) => { ... })\n * emitter.emit('data', 'hello')\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class TypedEmitter<T extends Record<string & keyof T, (...args: any[]) => void>> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private listeners = new Map<keyof T, Set<(...args: any[]) => void>>()\n private paused = false\n private buffer: Array<{ event: keyof T; args: unknown[] }> = []\n\n on<K extends keyof T>(event: K, listener: T[K]): this {\n let set = this.listeners.get(event)\n if (!set) {\n set = new Set()\n this.listeners.set(event, set)\n }\n set.add(listener)\n return this\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): this {\n this.listeners.get(event)?.delete(listener)\n return this\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n if (this.paused) {\n // Check passthrough filter — some events may bypass the pause\n if (this.passthroughFn?.(event, args)) {\n this.deliver(event, args)\n } else {\n this.buffer.push({ event, args })\n }\n return\n }\n this.deliver(event, args)\n }\n\n /**\n * Pause event delivery. Events emitted while paused are buffered.\n * Optionally pass a filter to allow specific events through even while paused.\n */\n pause(passthrough?: (event: keyof T, args: unknown[]) => boolean): void {\n this.paused = true\n this.passthroughFn = passthrough\n }\n private passthroughFn?: (event: keyof T, args: unknown[]) => boolean\n\n /** Resume event delivery and replay buffered events in order. */\n resume(): void {\n this.paused = false\n this.passthroughFn = undefined\n const buffered = this.buffer.splice(0)\n for (const { event, args } of buffered) {\n this.deliver(event, args)\n }\n }\n\n /** Discard all buffered events without delivering them. */\n clearBuffer(): void {\n this.buffer.length = 0\n }\n\n get isPaused(): boolean {\n return this.paused\n }\n\n get bufferSize(): number {\n return this.buffer.length\n }\n\n removeAllListeners(event?: keyof T): void {\n if (event) {\n this.listeners.delete(event)\n } else {\n this.listeners.clear()\n }\n }\n\n private deliver(event: keyof T, args: unknown[]): void {\n const set = this.listeners.get(event)\n if (!set) return\n for (const listener of set) {\n (listener as (...a: unknown[]) => void)(...args)\n }\n }\n}\n","/**\n * Serial prompt queue — ensures prompts are processed one at a time.\n */\nexport class PromptQueue {\n private queue: Array<{ text: string; resolve: () => void }> = []\n private processing = false\n\n constructor(\n private processor: (text: string) => Promise<void>,\n private onError?: (err: unknown) => void,\n ) {}\n\n async enqueue(text: string): Promise<void> {\n if (this.processing) {\n return new Promise<void>((resolve) => {\n this.queue.push({ text, resolve })\n })\n }\n await this.process(text)\n }\n\n private async process(text: string): Promise<void> {\n this.processing = true\n try {\n await this.processor(text)\n } catch (err) {\n this.onError?.(err)\n } finally {\n this.processing = false\n this.drainNext()\n }\n }\n\n private drainNext(): void {\n const next = this.queue.shift()\n if (next) {\n this.process(next.text).then(next.resolve)\n }\n }\n\n clear(): void {\n // Resolve pending promises so callers don't hang\n for (const item of this.queue) {\n item.resolve()\n }\n this.queue = []\n }\n\n get pending(): number {\n return this.queue.length\n }\n\n get isProcessing(): boolean {\n return this.processing\n }\n}\n","import type { PermissionRequest } from \"./types.js\";\n\n/**\n * Encapsulates pending permission state with a typed Promise API.\n */\nexport class PermissionGate {\n private request?: PermissionRequest;\n private resolveFn?: (optionId: string) => void;\n private rejectFn?: (reason: Error) => void;\n private settled = false;\n\n setPending(request: PermissionRequest): Promise<string> {\n this.request = request;\n this.settled = false;\n\n return new Promise<string>((resolve, reject) => {\n this.resolveFn = resolve;\n this.rejectFn = reject;\n });\n }\n\n resolve(optionId: string): void {\n if (this.settled || !this.resolveFn) return;\n this.settled = true;\n this.resolveFn(optionId);\n this.cleanup();\n }\n\n reject(reason?: string): void {\n if (this.settled || !this.rejectFn) return;\n this.settled = true;\n this.rejectFn(new Error(reason ?? \"Permission rejected\"));\n this.cleanup();\n }\n\n get isPending(): boolean {\n return !!this.request && !this.settled;\n }\n\n get currentRequest(): PermissionRequest | undefined {\n return this.isPending ? this.request : undefined;\n }\n\n /** The request ID of the current pending request, undefined after settlement */\n get requestId(): string | undefined {\n return this.request?.id;\n }\n\n private cleanup(): void {\n this.request = undefined;\n this.resolveFn = undefined;\n this.rejectFn = undefined;\n }\n}\n","import { nanoid } from \"nanoid\";\nimport type { AgentInstance } from \"./agent-instance.js\";\nimport type { ChannelAdapter } from \"./channel.js\";\nimport type { AgentEvent, PermissionRequest, SessionStatus } from \"./types.js\";\nimport { TypedEmitter } from \"./typed-emitter.js\";\nimport { PromptQueue } from \"./prompt-queue.js\";\nimport { PermissionGate } from \"./permission-gate.js\";\nimport { createChildLogger, createSessionLogger, type Logger } from \"./log.js\";\nconst moduleLog = createChildLogger({ module: \"session\" });\n\nexport interface SessionEvents {\n agent_event: (event: AgentEvent) => void;\n permission_request: (request: PermissionRequest) => void;\n session_end: (reason: string) => void;\n error: (error: Error) => void;\n}\n\nexport class Session extends TypedEmitter<SessionEvents> {\n id: string;\n channelId: string;\n threadId: string = \"\";\n agentName: string;\n workingDirectory: string;\n agentInstance: AgentInstance;\n agentSessionId: string = \"\";\n status: SessionStatus = \"initializing\";\n name?: string;\n createdAt: Date = new Date();\n adapter?: ChannelAdapter; // Set by wireSessionEvents for renaming\n dangerousMode: boolean = false;\n log: Logger;\n\n readonly permissionGate = new PermissionGate();\n private readonly queue: PromptQueue;\n\n constructor(opts: {\n id?: string;\n channelId: string;\n agentName: string;\n workingDirectory: string;\n agentInstance: AgentInstance;\n }) {\n super();\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 this.log = createSessionLogger(this.id, moduleLog);\n this.log.info({ agentName: this.agentName }, \"Session created\");\n\n this.queue = new PromptQueue(\n (text) => this.processPrompt(text),\n (err) => {\n this.status = \"error\";\n this.log.error({ err }, \"Prompt execution failed\");\n },\n );\n }\n\n // --- Backward-compatible properties ---\n\n /** @deprecated Use permissionGate directly */\n get pendingPermission():\n | { requestId: string; resolve: (optionId: string) => void }\n | undefined {\n if (!this.permissionGate.isPending) return undefined;\n return {\n requestId: this.permissionGate.requestId!,\n resolve: (optionId: string) => this.permissionGate.resolve(optionId),\n };\n }\n\n set pendingPermission(\n val: { requestId: string; resolve: (optionId: string) => void } | undefined,\n ) {\n // No-op setter for backward compatibility — permission state is managed by PermissionGate\n // The core.ts wireSessionEvents still sets this; we ignore it.\n }\n\n /** Number of prompts waiting in queue */\n get queueDepth(): number {\n return this.queue.pending;\n }\n\n get promptRunning(): boolean {\n return this.queue.isProcessing;\n }\n\n // --- Public API ---\n\n async enqueuePrompt(text: string): Promise<void> {\n await this.queue.enqueue(text);\n }\n\n private async processPrompt(text: string): Promise<void> {\n // Handle warmup sentinel\n if (text === \"\\x00__warmup__\") {\n await this.runWarmup();\n return;\n }\n\n this.status = \"active\";\n const promptStart = Date.now();\n this.log.debug(\"Prompt execution started\");\n\n await this.agentInstance.prompt(text);\n this.log.info(\n { durationMs: Date.now() - promptStart },\n \"Prompt execution completed\",\n );\n\n // Auto-name after first user prompt\n if (!this.name) {\n await this.autoName();\n }\n }\n\n // NOTE: This injects a summary prompt into the agent's conversation history.\n private async autoName(): Promise<void> {\n let title = \"\";\n\n // Intercept at the source — capture text before it reaches the emitter,\n // so adapter listeners never see auto-name output.\n const originalHandler = this.agentInstance.onSessionUpdate;\n this.agentInstance.onSessionUpdate = (event: AgentEvent) => {\n if (event.type === \"text\") title += event.content;\n // Swallow all events from auto-name prompt\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) || `Session ${this.id.slice(0, 6)}`;\n this.log.info({ name: this.name }, \"Session auto-named\");\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 = originalHandler;\n }\n }\n\n /** Fire-and-forget warm-up: primes model cache while user types their first message */\n async warmup(): Promise<void> {\n // Route through PromptQueue to prevent concurrent prompt execution.\n // Any user prompts arriving during warmup will be queued and drained after.\n await this.queue.enqueue(\"\\x00__warmup__\");\n }\n\n private async runWarmup(): Promise<void> {\n // Pause events but let commands_update pass through\n this.pause((_event, args) => {\n const agentEvent = args[0] as AgentEvent;\n return agentEvent?.type === \"commands_update\";\n });\n\n try {\n const start = Date.now();\n await this.agentInstance.prompt('Reply with only \"ready\".');\n this.status = \"active\";\n this.log.info({ durationMs: Date.now() - start }, \"Warm-up complete\");\n } catch (err) {\n this.log.error({ err }, \"Warm-up failed\");\n } finally {\n this.clearBuffer();\n this.resume();\n }\n }\n\n async cancel(): Promise<void> {\n this.queue.clear();\n this.log.info(\"Session cancelled\");\n await this.agentInstance.cancel();\n this.status = \"active\";\n }\n\n async destroy(): Promise<void> {\n this.log.info(\"Session destroyed\");\n await this.agentInstance.destroy();\n }\n}\n","import type { AgentManager } from \"./agent-manager.js\";\nimport { Session } from \"./session.js\";\nimport type { SessionStore } from \"./session-store.js\";\nimport type { SessionStatus } from \"./types.js\";\n\nexport class SessionManager {\n private sessions: Map<string, Session> = new Map();\n private store: SessionStore | null;\n\n constructor(store: SessionStore | null = null) {\n this.store = store;\n }\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({\n channelId,\n agentName,\n workingDirectory,\n agentInstance,\n });\n this.sessions.set(session.id, session);\n session.agentSessionId = session.agentInstance.sessionId;\n\n if (this.store) {\n await this.store.save({\n sessionId: session.id,\n agentSessionId: session.agentInstance.sessionId,\n agentName: session.agentName,\n workingDir: session.workingDirectory,\n channelId,\n status: session.status,\n createdAt: session.createdAt.toISOString(),\n lastActiveAt: new Date().toISOString(),\n name: session.name,\n platform: {},\n });\n }\n\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 getRecordByThread(channelId: string, threadId: string): import(\"./types.js\").SessionRecord | undefined {\n return this.store?.findByPlatform(\n channelId,\n (p) => String(p.topicId) === threadId,\n );\n }\n\n registerSession(session: Session): void {\n this.sessions.set(session.id, session);\n }\n\n async updateSessionPlatform(\n sessionId: string,\n platform: Record<string, unknown>,\n ): Promise<void> {\n if (!this.store) return;\n const record = this.store.get(sessionId);\n if (record) {\n await this.store.save({ ...record, platform });\n }\n }\n\n async updateSessionActivity(sessionId: string): Promise<void> {\n if (!this.store) return;\n const record = this.store.get(sessionId);\n if (record) {\n await this.store.save({\n ...record,\n lastActiveAt: new Date().toISOString(),\n });\n }\n }\n\n async updateSessionStatus(\n sessionId: string,\n status: SessionStatus,\n ): Promise<void> {\n if (!this.store) return;\n const record = this.store.get(sessionId);\n if (record) {\n await this.store.save({ ...record, status });\n }\n }\n\n async updateSessionDangerousMode(sessionId: string, dangerousMode: boolean): Promise<void> {\n if (!this.store) return;\n const record = this.store.get(sessionId);\n if (record) {\n await this.store.save({ ...record, dangerousMode });\n }\n }\n\n async updateSessionName(sessionId: string, name: string): Promise<void> {\n if (!this.store) return;\n const record = this.store.get(sessionId);\n if (record) {\n await this.store.save({ ...record, name });\n }\n }\n\n getSessionRecord(sessionId: string): import(\"./types.js\").SessionRecord | undefined {\n return this.store?.get(sessionId);\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (session) {\n await session.cancel();\n }\n if (this.store) {\n const record = this.store.get(sessionId);\n if (record && record.status !== \"cancelled\") {\n await this.store.save({ ...record, status: \"cancelled\" });\n }\n }\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 if (this.store) {\n for (const session of this.sessions.values()) {\n const record = this.store.get(session.id);\n if (record) {\n await this.store.save({ ...record, status: \"finished\" });\n }\n }\n }\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","export interface FileInfo {\n filePath: string\n content: string\n oldContent?: string\n}\n\n/**\n * Extract file path and content from ACP tool_call/tool_update content.\n *\n * ACP content formats observed:\n * - Diff block: [{ type: \"diff\", path: \"...\", oldText: \"...\", newText: \"...\" }]\n * - Content wrapper: [{ type: \"content\", content: { type: \"text\", text: \"...\" } }]\n * - Text block: { type: \"text\", text: \"...\" }\n * - rawInput: { file_path: \"...\", content: \"...\" }\n */\nexport function extractFileInfo(\n name: string,\n kind: string | undefined,\n content: unknown,\n rawInput?: unknown,\n meta?: unknown,\n): FileInfo | null {\n // Only process file-related tool kinds\n if (kind && !['read', 'edit', 'write'].includes(kind)) return null\n\n let info: Partial<FileInfo> | null = null\n\n // 1. Try _meta.claudeCode.toolResponse (Claude Code puts raw file data here)\n if (meta) {\n const m = meta as any\n const tr = m?.claudeCode?.toolResponse\n // Read tool: toolResponse.file.filePath + toolResponse.file.content\n const file = tr?.file\n if (file?.filePath && file?.content) {\n info = { filePath: file.filePath, content: file.content }\n }\n // Write/Edit tool: toolResponse.filePath + toolResponse.content (direct)\n if (!info && tr?.filePath && tr?.content) {\n info = { filePath: tr.filePath, content: tr.content }\n }\n }\n\n // 2. Try rawInput for file path + content from regular content\n if (!info && rawInput) {\n const ri = rawInput as any\n const filePath = ri?.file_path || ri?.filePath || ri?.path\n if (typeof filePath === 'string') {\n // Try to get content from the content field (including oldContent for diffs)\n const parsed = content ? parseContent(content) : null\n info = { filePath, content: parsed?.content || ri?.content, oldContent: parsed?.oldContent }\n }\n }\n\n // 3. Try to extract from known ACP content patterns\n if (!info && content) {\n info = parseContent(content)\n }\n\n if (!info) return null\n\n // Infer file path from tool name if not in content\n if (!info.filePath) {\n const pathMatch = name.match(/(?:Read|Edit|Write|View)\\s+(.+)/i)\n if (pathMatch) info.filePath = pathMatch[1].trim()\n }\n\n if (!info.filePath || !info.content) return null\n return info as FileInfo\n}\n\nfunction parseContent(content: unknown): Partial<FileInfo> | null {\n if (typeof content === 'string') {\n return { content }\n }\n\n if (Array.isArray(content)) {\n // Array of content blocks — try each\n for (const block of content) {\n const result = parseContent(block)\n if (result?.content || result?.filePath) return result\n }\n return null\n }\n\n if (typeof content === 'object' && content !== null) {\n const c = content as Record<string, unknown>\n\n // ACP diff block: { type: 'diff', path: '...', oldText: '...', newText: '...' }\n if (c.type === 'diff' && typeof c.path === 'string') {\n const newText = c.newText as string | null | undefined\n const oldText = c.oldText as string | null | undefined\n if (newText) {\n return {\n filePath: c.path as string,\n content: newText,\n oldContent: oldText ?? undefined,\n }\n }\n }\n\n // ACP content wrapper: { type: 'content', content: { type: 'text', text: '...' } }\n if (c.type === 'content' && c.content) {\n return parseContent(c.content)\n }\n\n // ACP text block: { type: 'text', text: '...' }\n if (c.type === 'text' && typeof c.text === 'string') {\n return { content: c.text, filePath: c.filePath as string | undefined }\n }\n\n // Direct fields\n if (typeof c.text === 'string') {\n return { content: c.text, filePath: c.filePath as string | undefined }\n }\n\n // Tool input with file path: { file_path: '...', content: '...' }\n if (typeof c.file_path === 'string' || typeof c.filePath === 'string' || typeof c.path === 'string') {\n const filePath = (c.file_path || c.filePath || c.path) as string\n const fileContent = (c.content || c.text || c.output || c.newText) as string | undefined\n if (typeof fileContent === 'string') {\n return {\n filePath,\n content: fileContent,\n oldContent: (c.old_content || c.oldText) as string | undefined,\n }\n }\n }\n\n // Nested input/output\n if (c.input) {\n const result = parseContent(c.input)\n if (result) return result\n }\n if (c.output) {\n const result = parseContent(c.output)\n if (result) return result\n }\n }\n\n return null\n}\n","import type { AgentEvent, OutgoingMessage } from \"./types.js\";\nimport type { TunnelService } from \"../tunnel/tunnel-service.js\";\nimport { extractFileInfo } from \"../tunnel/extract-file-info.js\";\nimport { createChildLogger } from \"./log.js\";\n\nconst log = createChildLogger({ module: \"message-transformer\" });\n\nexport class MessageTransformer {\n constructor(private tunnelService?: TunnelService) {}\n\n transform(\n event: AgentEvent,\n sessionContext?: { id: string; workingDirectory: string },\n ): 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 const metadata: Record<string, unknown> = {\n id: event.id,\n name: event.name,\n kind: event.kind,\n status: event.status,\n content: event.content,\n locations: event.locations,\n };\n this.enrichWithViewerLinks(event, metadata, sessionContext);\n return { type: \"tool_call\", text: event.name, metadata };\n }\n case \"tool_update\": {\n const metadata: Record<string, unknown> = {\n id: event.id,\n name: event.name,\n kind: event.kind,\n status: event.status,\n content: event.content,\n };\n this.enrichWithViewerLinks(event, metadata, sessionContext);\n return { type: \"tool_update\", text: \"\", metadata };\n }\n case \"plan\":\n return {\n type: \"plan\",\n text: \"\",\n metadata: { entries: event.entries },\n };\n case \"usage\":\n return {\n type: \"usage\",\n text: \"\",\n metadata: {\n tokensUsed: event.tokensUsed,\n contextSize: event.contextSize,\n cost: event.cost,\n },\n };\n case \"session_end\":\n return { type: \"session_end\", text: `Done (${event.reason})` };\n case \"error\":\n return { type: \"error\", text: event.message };\n default:\n return { type: \"text\", text: \"\" };\n }\n }\n\n private enrichWithViewerLinks(\n event: AgentEvent & { type: \"tool_call\" | \"tool_update\" },\n metadata: Record<string, unknown>,\n sessionContext?: { id: string; workingDirectory: string },\n ): void {\n if (!this.tunnelService || !sessionContext) return;\n\n const name = \"name\" in event ? event.name || \"\" : \"\";\n const kind = \"kind\" in event ? event.kind : undefined;\n\n log.debug(\n { name, kind, status: event.status, hasContent: !!event.content },\n \"enrichWithViewerLinks: inspecting event\",\n );\n\n const fileInfo = extractFileInfo(\n name,\n kind,\n event.content,\n event.rawInput,\n event.meta,\n );\n if (!fileInfo) return;\n\n log.info(\n {\n name,\n kind,\n filePath: fileInfo.filePath,\n hasOldContent: !!fileInfo.oldContent,\n },\n \"enrichWithViewerLinks: extracted file info\",\n );\n\n const store = this.tunnelService.getStore();\n const viewerLinks: Record<string, string> = {};\n\n // For edits/writes with diff data (oldText + newText)\n if (fileInfo.oldContent) {\n const id = store.storeDiff(\n sessionContext.id,\n fileInfo.filePath,\n fileInfo.oldContent,\n fileInfo.content,\n sessionContext.workingDirectory,\n );\n if (id) viewerLinks.diff = this.tunnelService.diffUrl(id);\n }\n\n // Always store as file view (new file creation or read)\n const id = store.storeFile(\n sessionContext.id,\n fileInfo.filePath,\n fileInfo.content,\n sessionContext.workingDirectory,\n );\n if (id) viewerLinks.file = this.tunnelService.fileUrl(id);\n\n if (Object.keys(viewerLinks).length > 0) {\n metadata.viewerLinks = viewerLinks;\n metadata.viewerFilePath = fileInfo.filePath;\n }\n }\n}\n","import path from \"node:path\";\nimport os from \"node:os\";\nimport { 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 { MessageTransformer } from \"./message-transformer.js\";\nimport { JsonFileSessionStore, type SessionStore } from \"./session-store.js\";\nimport type {\n IncomingMessage,\n AgentEvent,\n PermissionRequest,\n} from \"./types.js\";\nimport type { TunnelService } from \"../tunnel/tunnel-service.js\";\nimport { createChildLogger } from \"./log.js\";\nconst log = createChildLogger({ module: \"core\" });\n\nexport class OpenACPCore {\n configManager: ConfigManager;\n agentManager: AgentManager;\n sessionManager: SessionManager;\n notificationManager: NotificationManager;\n messageTransformer: MessageTransformer;\n adapters: Map<string, ChannelAdapter> = new Map();\n /** Set by main.ts — triggers graceful shutdown with restart exit code */\n requestRestart: (() => Promise<void>) | null = null;\n private _tunnelService?: TunnelService;\n private sessionStore: SessionStore | null = null;\n private resumeLocks: Map<string, Promise<Session | null>> = new Map();\n\n constructor(configManager: ConfigManager) {\n this.configManager = configManager;\n const config = configManager.get();\n this.agentManager = new AgentManager(config);\n const storePath = path.join(os.homedir(), \".openacp\", \"sessions.json\");\n this.sessionStore = new JsonFileSessionStore(\n storePath,\n config.sessionStore.ttlDays,\n );\n this.sessionManager = new SessionManager(this.sessionStore);\n this.notificationManager = new NotificationManager(this.adapters);\n this.messageTransformer = new MessageTransformer();\n }\n\n get tunnelService(): TunnelService | undefined {\n return this._tunnelService;\n }\n\n set tunnelService(service: TunnelService | undefined) {\n this._tunnelService = service;\n this.messageTransformer = new MessageTransformer(service);\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 {\n /* best effort */\n }\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 log.debug(\n {\n channelId: message.channelId,\n threadId: message.threadId,\n userId: message.userId,\n },\n \"Incoming message\",\n );\n\n // Security: check allowed user IDs\n if (config.security.allowedUserIds.length > 0) {\n if (!config.security.allowedUserIds.includes(message.userId)) {\n log.warn(\n { userId: message.userId },\n \"Rejected message from unauthorized user\",\n );\n return;\n }\n }\n\n // Check concurrent session limit\n const activeSessions = this.sessionManager\n .listSessions()\n .filter((s) => s.status === \"active\" || s.status === \"initializing\");\n if (activeSessions.length >= config.security.maxConcurrentSessions) {\n log.warn(\n {\n userId: message.userId,\n currentCount: activeSessions.length,\n max: config.security.maxConcurrentSessions,\n },\n \"Session limit reached\",\n );\n const adapter = this.adapters.get(message.channelId);\n if (adapter) {\n await adapter.sendMessage(message.threadId, {\n type: \"error\",\n text: `⚠️ Session limit reached (${config.security.maxConcurrentSessions}). Please cancel existing sessions with /cancel before starting new ones.`,\n });\n }\n return;\n }\n\n // Find session by thread\n let session = this.sessionManager.getSessionByThread(\n message.channelId,\n message.threadId,\n );\n\n // Lazy resume: try to restore session from store\n if (!session) {\n session = (await this.lazyResume(message)) ?? undefined;\n }\n\n if (!session) return;\n\n // Update activity timestamp\n this.sessionManager.updateSessionActivity(session.id);\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 log.info({ channelId, agentName: resolvedAgent }, \"New session request\");\n const resolvedWorkspace = this.configManager.resolveWorkspace(\n workspacePath || config.agents[resolvedAgent]?.workingDirectory,\n );\n\n const session = await this.sessionManager.createSession(\n channelId,\n resolvedAgent,\n resolvedWorkspace,\n 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(\n channelId,\n currentThreadId,\n );\n\n if (currentSession) {\n return this.handleNewSession(\n channelId,\n currentSession.agentName,\n currentSession.workingDirectory,\n );\n }\n\n // Fallback: look up from store (e.g. after restart before lazy resume)\n const record = this.sessionManager.getRecordByThread(channelId, currentThreadId);\n if (!record || record.status === \"cancelled\" || record.status === \"error\") return null;\n\n return this.handleNewSession(\n channelId,\n record.agentName,\n record.workingDir,\n );\n }\n\n // --- Lazy Resume ---\n\n private async lazyResume(message: IncomingMessage): Promise<Session | null> {\n const store = this.sessionStore;\n if (!store) return null;\n\n const lockKey = `${message.channelId}:${message.threadId}`;\n\n // Check for existing resume in progress\n const existing = this.resumeLocks.get(lockKey);\n if (existing) return existing;\n\n const record = store.findByPlatform(\n message.channelId,\n (p) => String(p.topicId) === message.threadId,\n );\n if (!record) return null;\n\n // Don't resume cancelled/error sessions\n if (record.status === \"cancelled\" || record.status === \"error\") return null;\n\n const resumePromise = (async (): Promise<Session | null> => {\n try {\n const agentInstance = await this.agentManager.resume(\n record.agentName,\n record.workingDir,\n record.agentSessionId,\n );\n\n const session = new Session({\n id: record.sessionId,\n channelId: record.channelId,\n agentName: record.agentName,\n workingDirectory: record.workingDir,\n agentInstance,\n });\n session.threadId = message.threadId;\n session.agentSessionId = agentInstance.sessionId;\n session.status = \"active\";\n session.name = record.name;\n session.dangerousMode = record.dangerousMode ?? false;\n\n this.sessionManager.registerSession(session);\n\n const adapter = this.adapters.get(message.channelId);\n if (adapter) {\n this.wireSessionEvents(session, adapter);\n }\n\n // Update store with new agentSessionId (may differ after resume)\n await store.save({\n ...record,\n agentSessionId: agentInstance.sessionId,\n status: \"active\",\n lastActiveAt: new Date().toISOString(),\n });\n\n log.info(\n { sessionId: session.id, threadId: message.threadId },\n \"Lazy resume successful\",\n );\n return session;\n } catch (err) {\n log.error({ err, record }, \"Lazy resume failed\");\n return null;\n } finally {\n this.resumeLocks.delete(lockKey);\n }\n })();\n\n this.resumeLocks.set(lockKey, resumePromise);\n return resumePromise;\n }\n\n // --- Event Wiring ---\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 // Wire AgentInstance callbacks → Session event emitter\n session.agentInstance.onSessionUpdate = (event: AgentEvent) => {\n session.emit(\"agent_event\", event);\n };\n\n session.agentInstance.onPermissionRequest = async (\n request: PermissionRequest,\n ) => {\n session.emit(\"permission_request\", request);\n\n // Set pending BEFORE sending UI to avoid race condition\n const promise = session.permissionGate.setPending(request);\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 const sessionContext = {\n get id() { return session.id; },\n get workingDirectory() { return session.workingDirectory; },\n };\n\n // Subscribe to Session events for adapter delivery\n session.on(\"agent_event\", (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(\n session.id,\n this.messageTransformer.transform(event, sessionContext),\n );\n break;\n\n case \"session_end\":\n session.status = \"finished\";\n this.sessionManager.updateSessionStatus(session.id, \"finished\");\n adapter.cleanupSkillCommands(session.id);\n adapter.sendMessage(\n session.id,\n this.messageTransformer.transform(event),\n );\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 this.sessionManager.updateSessionStatus(session.id, \"error\");\n adapter.cleanupSkillCommands(session.id);\n adapter.sendMessage(\n session.id,\n this.messageTransformer.transform(event),\n );\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: event.commands }, \"Commands available\");\n adapter.sendSkillCommands(session.id, event.commands);\n break;\n }\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SessionRecord } from \"./types.js\";\nimport { createChildLogger } from \"./log.js\";\n\nconst log = createChildLogger({ module: \"session-store\" });\n\nexport interface SessionStore {\n save(record: SessionRecord): Promise<void>;\n get(sessionId: string): SessionRecord | undefined;\n findByPlatform(\n channelId: string,\n predicate: (platform: Record<string, unknown>) => boolean,\n ): SessionRecord | undefined;\n list(channelId?: string): SessionRecord[];\n remove(sessionId: string): Promise<void>;\n}\n\ninterface StoreFile {\n version: number;\n sessions: Record<string, SessionRecord>;\n}\n\nconst DEBOUNCE_MS = 2000;\n\nexport class JsonFileSessionStore implements SessionStore {\n private records: Map<string, SessionRecord> = new Map();\n private filePath: string;\n private ttlDays: number;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n private flushHandler: (() => void) | null = null;\n\n constructor(filePath: string, ttlDays: number) {\n this.filePath = filePath;\n this.ttlDays = ttlDays;\n this.load();\n this.cleanup();\n\n // Daily cleanup for long-running instances\n this.cleanupInterval = setInterval(\n () => this.cleanup(),\n 24 * 60 * 60 * 1000,\n );\n\n // Force flush on shutdown\n this.flushHandler = () => this.flushSync();\n process.on(\"SIGTERM\", this.flushHandler);\n process.on(\"SIGINT\", this.flushHandler);\n process.on(\"exit\", this.flushHandler);\n }\n\n async save(record: SessionRecord): Promise<void> {\n this.records.set(record.sessionId, { ...record });\n this.scheduleDiskWrite();\n }\n\n get(sessionId: string): SessionRecord | undefined {\n return this.records.get(sessionId);\n }\n\n findByPlatform(\n channelId: string,\n predicate: (platform: Record<string, unknown>) => boolean,\n ): SessionRecord | undefined {\n for (const record of this.records.values()) {\n if (record.channelId === channelId && predicate(record.platform)) {\n return record;\n }\n }\n return undefined;\n }\n\n list(channelId?: string): SessionRecord[] {\n const all = [...this.records.values()];\n if (channelId) return all.filter((r) => r.channelId === channelId);\n return all;\n }\n\n async remove(sessionId: string): Promise<void> {\n this.records.delete(sessionId);\n this.scheduleDiskWrite();\n }\n\n flushSync(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n const data: StoreFile = {\n version: 1,\n sessions: Object.fromEntries(this.records),\n };\n const dir = path.dirname(this.filePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));\n }\n\n destroy(): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n if (this.cleanupInterval) clearInterval(this.cleanupInterval);\n if (this.flushHandler) {\n process.removeListener(\"SIGTERM\", this.flushHandler);\n process.removeListener(\"SIGINT\", this.flushHandler);\n process.removeListener(\"exit\", this.flushHandler);\n this.flushHandler = null;\n }\n }\n\n private load(): void {\n if (!fs.existsSync(this.filePath)) return;\n try {\n const raw = JSON.parse(\n fs.readFileSync(this.filePath, \"utf-8\"),\n ) as StoreFile;\n if (raw.version !== 1) {\n log.warn(\n { version: raw.version },\n \"Unknown session store version, skipping load\",\n );\n return;\n }\n for (const [id, record] of Object.entries(raw.sessions)) {\n this.records.set(id, record);\n }\n log.info({ count: this.records.size }, \"Loaded session records\");\n } catch (err) {\n log.error({ err }, \"Failed to load session store\");\n }\n }\n\n private cleanup(): void {\n const cutoff = Date.now() - this.ttlDays * 24 * 60 * 60 * 1000;\n let removed = 0;\n for (const [id, record] of this.records) {\n if (record.status === \"active\" || record.status === \"initializing\")\n continue;\n const lastActive = new Date(record.lastActiveAt).getTime();\n if (lastActive < cutoff) {\n this.records.delete(id);\n removed++;\n }\n }\n if (removed > 0) {\n log.info({ removed }, \"Cleaned up expired session records\");\n this.scheduleDiskWrite();\n }\n }\n\n private scheduleDiskWrite(): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n this.flushSync();\n }, DEBOUNCE_MS);\n }\n}\n","import type { OutgoingMessage, PermissionRequest, NotificationMessage, AgentCommand } from './types.js'\n\nexport interface ChannelConfig {\n enabled: boolean\n [key: string]: unknown\n}\n\nexport interface IChannelAdapter {\n start(): Promise<void>\n stop(): Promise<void>\n\n // Outgoing: core → channel\n sendMessage(sessionId: string, content: OutgoingMessage): Promise<void>\n sendPermissionRequest(sessionId: string, request: PermissionRequest): Promise<void>\n sendNotification(notification: NotificationMessage): Promise<void>\n\n // Session lifecycle on channel side\n createSessionThread(sessionId: string, name: string): Promise<string> // returns threadId\n renameSessionThread(sessionId: string, newName: string): Promise<void>\n\n // Skill commands — optional\n sendSkillCommands(sessionId: string, commands: AgentCommand[]): Promise<void>\n cleanupSkillCommands(sessionId: string): Promise<void>\n}\n\n/**\n * Base class providing default no-op implementations for optional methods.\n * Adapters can extend this or implement IChannelAdapter directly.\n */\nexport abstract class ChannelAdapter<TCore = unknown> implements IChannelAdapter {\n constructor(protected core: TCore, 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 // Skill commands — override in adapters that support dynamic commands\n async sendSkillCommands(_sessionId: string, _commands: AgentCommand[]): Promise<void> {}\n async cleanupSkillCommands(_sessionId: string): Promise<void> {}\n}\n","import * as http from 'node:http'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport type { OpenACPCore } from './core.js'\nimport { createChildLogger } from './log.js'\n\nconst log = createChildLogger({ module: 'api-server' })\n\nconst DEFAULT_PORT_FILE = path.join(os.homedir(), '.openacp', 'api.port')\n\nexport interface ApiConfig {\n port: number\n host: string\n}\n\nexport class ApiServer {\n private server: http.Server | null = null\n private actualPort: number = 0\n private portFilePath: string\n\n constructor(\n private core: OpenACPCore,\n private config: ApiConfig,\n portFilePath?: string,\n ) {\n this.portFilePath = portFilePath ?? DEFAULT_PORT_FILE\n }\n\n async start(): Promise<void> {\n this.server = http.createServer((req, res) => this.handleRequest(req, res))\n\n await new Promise<void>((resolve, reject) => {\n this.server!.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n log.warn({ port: this.config.port }, 'API port in use, continuing without API server')\n this.server = null\n // actualPort stays 0, port file not written\n resolve()\n } else {\n reject(err)\n }\n })\n\n this.server!.listen(this.config.port, this.config.host, () => {\n const addr = this.server!.address()\n if (addr && typeof addr === 'object') {\n this.actualPort = addr.port\n }\n this.writePortFile()\n log.info({ host: this.config.host, port: this.actualPort }, 'API server listening')\n resolve()\n })\n })\n }\n\n async stop(): Promise<void> {\n this.removePortFile()\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server!.close(() => resolve())\n })\n this.server = null\n }\n }\n\n getPort(): number {\n return this.actualPort\n }\n\n private writePortFile(): void {\n const dir = path.dirname(this.portFilePath)\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(this.portFilePath, String(this.actualPort))\n }\n\n private removePortFile(): void {\n try { fs.unlinkSync(this.portFilePath) } catch { /* ignore */ }\n }\n\n private async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const method = req.method?.toUpperCase()\n const url = req.url || ''\n\n try {\n if (method === 'POST' && url === '/api/sessions') {\n await this.handleCreateSession(req, res)\n } else if (method === 'DELETE' && url.match(/^\\/api\\/sessions\\/(.+)$/)) {\n const sessionId = url.match(/^\\/api\\/sessions\\/(.+)$/)![1]\n await this.handleCancelSession(sessionId, res)\n } else if (method === 'GET' && url === '/api/sessions') {\n await this.handleListSessions(res)\n } else if (method === 'GET' && url === '/api/agents') {\n await this.handleListAgents(res)\n } else {\n this.sendJson(res, 404, { error: 'Not found' })\n }\n } catch (err) {\n log.error({ err }, 'API request error')\n this.sendJson(res, 500, { error: 'Internal server error' })\n }\n }\n\n private async handleCreateSession(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const body = await this.readBody(req)\n let agent: string | undefined\n let workspace: string | undefined\n\n if (body) {\n try {\n const parsed = JSON.parse(body)\n agent = parsed.agent\n workspace = parsed.workspace\n } catch {\n this.sendJson(res, 400, { error: 'Invalid JSON body' })\n return\n }\n }\n\n // Check max concurrent sessions\n const config = this.core.configManager.get()\n const activeSessions = this.core.sessionManager.listSessions()\n .filter(s => s.status === 'active' || s.status === 'initializing')\n if (activeSessions.length >= config.security.maxConcurrentSessions) {\n this.sendJson(res, 429, {\n error: `Max concurrent sessions (${config.security.maxConcurrentSessions}) reached. Cancel a session first.`,\n })\n return\n }\n\n // Use the first registered adapter (e.g. Telegram) so API sessions appear in the channel\n const [adapterId, adapter] = this.core.adapters.entries().next().value ?? [null, null]\n const channelId = adapterId ?? 'api'\n\n const session = await this.core.handleNewSession(channelId, agent, workspace)\n\n // If an adapter is available, create a session thread (Telegram topic) and wire events\n if (adapter) {\n try {\n const threadId = await adapter.createSessionThread(session.id, `🔄 ${session.agentName} — New Session`)\n session.threadId = threadId\n this.core.wireSessionEvents(session, adapter)\n } catch (err) {\n log.warn({ err, sessionId: session.id }, 'Failed to create session thread on adapter, running headless')\n }\n }\n\n // If no adapter wired events (headless), auto-approve permissions\n if (!adapter) {\n session.agentInstance.onPermissionRequest = async (request) => {\n const allowOption = request.options.find(o => o.isAllow)\n log.debug({ sessionId: session.id, permissionId: request.id, option: allowOption?.id }, 'Auto-approving permission for API session')\n return allowOption?.id ?? request.options[0]?.id ?? ''\n }\n }\n\n // Warmup in background so session moves from 'initializing' to 'active'\n session.warmup().catch(err => log.warn({ err, sessionId: session.id }, 'API session warmup failed'))\n\n this.sendJson(res, 200, {\n sessionId: session.id,\n agent: session.agentName,\n status: session.status,\n workspace: session.workingDirectory,\n })\n }\n\n private async handleCancelSession(sessionId: string, res: http.ServerResponse): Promise<void> {\n const session = this.core.sessionManager.getSession(sessionId)\n if (!session) {\n this.sendJson(res, 404, { error: `Session \"${sessionId}\" not found` })\n return\n }\n await session.cancel()\n this.sendJson(res, 200, { ok: true })\n }\n\n private async handleListSessions(res: http.ServerResponse): Promise<void> {\n const sessions = this.core.sessionManager.listSessions()\n this.sendJson(res, 200, {\n sessions: sessions.map(s => ({\n id: s.id,\n agent: s.agentName,\n status: s.status,\n name: s.name ?? null,\n workspace: s.workingDirectory,\n })),\n })\n }\n\n private async handleListAgents(res: http.ServerResponse): Promise<void> {\n const agents = this.core.agentManager.getAvailableAgents()\n const defaultAgent = this.core.configManager.get().defaultAgent\n this.sendJson(res, 200, {\n agents: agents.map(a => ({\n name: a.name,\n command: a.command,\n args: a.args,\n })),\n default: defaultAgent,\n })\n }\n\n private sendJson(res: http.ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(data))\n }\n\n private readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = ''\n req.on('data', (chunk) => { data += chunk })\n req.on('end', () => resolve(data))\n req.on('error', () => resolve(''))\n })\n }\n}\n","import { Bot } from \"grammy\";\nimport {\n ChannelAdapter,\n type OpenACPCore,\n type OutgoingMessage,\n type PermissionRequest,\n type NotificationMessage,\n type Session,\n type AgentCommand,\n} from \"../../core/index.js\";\nimport { createChildLogger } from \"../../core/log.js\";\nconst log = createChildLogger({ module: \"telegram\" });\nimport type { TelegramChannelConfig } from \"./types.js\";\nimport { MessageDraft } from \"./streaming.js\";\nimport {\n ensureTopics,\n createSessionTopic,\n renameSessionTopic,\n} from \"./topics.js\";\nimport {\n setupCommands,\n setupMenuCallbacks,\n setupDangerousModeCallbacks,\n buildMenuKeyboard,\n buildSkillMessages,\n STATIC_COMMANDS,\n} from \"./commands.js\";\nimport { PermissionHandler } from \"./permissions.js\";\nimport {\n spawnAssistant,\n handleAssistantMessage,\n redirectToAssistant,\n type SpawnAssistantResult,\n} from \"./assistant.js\";\nimport {\n escapeHtml,\n formatToolCall,\n formatToolUpdate,\n} from \"./formatting.js\";\nimport { ActivityTracker } from \"./activity.js\";\nimport { TelegramSendQueue } from \"./send-queue.js\";\nimport {\n detectAction,\n storeAction,\n buildActionKeyboard,\n setupActionCallbacks,\n} from \"./action-detect.js\";\n\n/**\n * Wraps native fetch to work around grammY's polyfilled AbortController.\n * grammY uses abort-controller polyfill whose AbortSignal fails instanceof\n * checks in Node 24+ native fetch. This wrapper re-creates a native\n * AbortSignal from the polyfilled one before passing it to fetch.\n */\nfunction patchedFetch(\n input: RequestInfo | URL,\n init?: RequestInit,\n): Promise<Response> {\n if (init?.signal && !(init.signal instanceof AbortSignal)) {\n const nativeController = new AbortController();\n const polyfillSignal = init.signal as unknown as {\n aborted: boolean;\n addEventListener: (event: string, fn: () => void) => void;\n };\n if (polyfillSignal.aborted) {\n nativeController.abort();\n } else {\n polyfillSignal.addEventListener(\"abort\", () => nativeController.abort());\n }\n init = { ...init, signal: nativeController.signal };\n }\n return fetch(input, init);\n}\n\nexport class TelegramAdapter extends ChannelAdapter<OpenACPCore> {\n private bot!: Bot;\n private telegramConfig: TelegramChannelConfig;\n private sessionDrafts: Map<string, MessageDraft> = new Map();\n private sessionTextBuffers: Map<string, string> = new Map();\n private toolCallMessages: Map<\n string,\n Map<\n string,\n {\n msgId: number;\n name: string;\n kind?: string;\n viewerLinks?: { file?: string; diff?: string };\n viewerFilePath?: string;\n ready: Promise<void>;\n }\n >\n > = new Map(); // sessionId → (toolCallId → state)\n private permissionHandler!: PermissionHandler;\n private assistantSession: Session | null = null;\n private assistantInitializing = false;\n private notificationTopicId!: number;\n private assistantTopicId!: number;\n private skillMessages: Map<string, number> = new Map(); // sessionId → pinned messageId\n private sendQueue = new TelegramSendQueue(3000)\n private sessionTrackers: Map<string, ActivityTracker> = new Map()\n\n private getOrCreateTracker(sessionId: string, threadId: number): ActivityTracker {\n let tracker = this.sessionTrackers.get(sessionId)\n if (!tracker) {\n tracker = new ActivityTracker(\n this.bot.api,\n this.telegramConfig.chatId,\n threadId,\n this.sendQueue,\n )\n this.sessionTrackers.set(sessionId, tracker)\n }\n return tracker\n }\n\n constructor(core: OpenACPCore, config: TelegramChannelConfig) {\n super(core, config as never);\n this.telegramConfig = config;\n }\n\n async start(): Promise<void> {\n this.bot = new Bot(this.telegramConfig.botToken, { client: { fetch: patchedFetch } });\n\n // Global error handler — prevent unhandled errors from crashing the bot\n this.bot.catch((err) => {\n const rootCause = err.error instanceof Error ? err.error : err;\n log.error({ err: rootCause }, \"Telegram bot error\");\n });\n\n // Auto-retry on 429 (Too Many Requests) — waits the retry_after duration\n // and retries the request. Applies to ALL API calls globally.\n this.bot.api.config.use(async (prev, method, payload, signal) => {\n const maxRetries = 3;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const result = await prev(method, payload, signal);\n if (\n result.ok ||\n (result as { error_code?: number }).error_code !== 429 ||\n attempt === maxRetries\n ) {\n return result;\n }\n const retryAfter =\n ((result as { parameters?: { retry_after?: number } }).parameters\n ?.retry_after ?? 5) + 1;\n // Drop pending text items on message-related 429\n const rateLimitedMethods = ['sendMessage', 'editMessageText', 'editMessageReplyMarkup'];\n if (rateLimitedMethods.includes(method)) {\n this.sendQueue.onRateLimited();\n }\n log.warn(\n { method, retryAfter, attempt: attempt + 1 },\n \"Rate limited by Telegram, retrying\",\n );\n await new Promise((r) => setTimeout(r, retryAfter * 1000));\n }\n // Unreachable, but satisfies TypeScript\n return prev(method, payload, signal);\n });\n\n // Ensure allowed_updates includes callback_query on every poll.\n // bot.start() passes allowed_updates, but grammY only sends it on the first\n // getUpdates call. Subsequent polls may omit the parameter, causing Telegram\n // to fall back to its default (which excludes callback_query). This transformer\n // guarantees callback_query is always requested.\n this.bot.api.config.use((prev, method, payload, signal) => {\n if (method === \"getUpdates\") {\n const p = payload as never as Record<string, unknown>;\n p.allowed_updates = (p.allowed_updates as string[] | undefined) ?? [\n \"message\",\n \"callback_query\",\n ];\n }\n return prev(method, payload, signal);\n });\n\n // Register static commands for Telegram autocomplete (scoped to this chat)\n await this.bot.api.setMyCommands(STATIC_COMMANDS, {\n scope: { type: \"chat\", chat_id: this.telegramConfig.chatId },\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.configManager.save({\n channels: { telegram: updates },\n });\n },\n );\n this.notificationTopicId = topics.notificationTopicId;\n this.assistantTopicId = topics.assistantTopicId;\n\n // Setup permission handler (instance only, callback registered later)\n this.permissionHandler = new PermissionHandler(\n this.bot,\n this.telegramConfig.chatId,\n (sessionId) =>\n this.core.sessionManager.getSession(sessionId),\n (notification) => this.sendNotification(notification),\n );\n\n // Callback registration order matters!\n // Specific regex handlers first, catch-all last.\n setupDangerousModeCallbacks(this.bot, this.core as OpenACPCore);\n setupActionCallbacks(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n () => this.assistantSession?.id,\n );\n setupMenuCallbacks(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n );\n setupCommands(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n {\n topicId: this.assistantTopicId,\n getSession: () => this.assistantSession,\n },\n );\n this.permissionHandler.setupCallbackHandler();\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: () =>\n log.info(\n { chatId: this.telegramConfig.chatId },\n \"Telegram bot started\",\n ),\n });\n\n // Send welcome message immediately — no need to wait for assistant session\n try {\n const config = this.core.configManager.get();\n const agents = this.core.agentManager.getAvailableAgents();\n const agentList = agents\n .map((a) => `${escapeHtml(a.name)}${a.name === config.defaultAgent ? \" (default)\" : \"\"}`)\n .join(\", \");\n const workspace = escapeHtml(config.workspace.baseDir);\n\n const welcomeText =\n `👋 <b>OpenACP Assistant</b> is online.\\n\\n` +\n `Available agents: ${agentList}\\n` +\n `Workspace: <code>${workspace}</code>\\n\\n` +\n `<b>Select an action:</b>`;\n\n await this.bot.api.sendMessage(this.telegramConfig.chatId, welcomeText, {\n message_thread_id: this.assistantTopicId,\n parse_mode: \"HTML\",\n reply_markup: buildMenuKeyboard(),\n });\n } catch (err) {\n log.warn({ err }, \"Failed to send welcome message\");\n }\n\n // Spawn assistant in background — system prompt runs without blocking startup.\n // Messages are suppressed via assistantInitializing until the prompt completes.\n try {\n log.info(\"Spawning assistant session...\");\n const { session, ready } = await spawnAssistant(\n this.core as OpenACPCore,\n this,\n this.assistantTopicId,\n );\n this.assistantSession = session;\n this.assistantInitializing = true;\n log.info({ sessionId: session.id }, \"Assistant session ready, system prompt running in background\");\n ready.then(() => {\n this.assistantInitializing = false;\n log.info({ sessionId: session.id }, \"Assistant ready for user messages\");\n });\n } catch (err) {\n log.error({ err }, \"Failed to spawn assistant\");\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n `⚠️ <b>Failed to start assistant session.</b>\\n\\n<code>${err instanceof Error ? err.message : String(err)}</code>`,\n { message_thread_id: this.assistantTopicId, parse_mode: \"HTML\" },\n ).catch(() => {});\n }\n }\n\n async stop(): Promise<void> {\n if (this.assistantSession) {\n await this.assistantSession.destroy();\n }\n await this.bot.stop();\n log.info(\"Telegram bot stopped\");\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(\n this.telegramConfig.chatId,\n this.assistantTopicId,\n );\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 → send typing indicator and forward to assistant session\n if (threadId === this.assistantTopicId) {\n if (!this.assistantSession) {\n await ctx.reply(\"⚠️ Assistant is not available yet. Please try again shortly.\", { parse_mode: \"HTML\" });\n return;\n }\n await this.finalizeDraft(this.assistantSession.id);\n ctx.replyWithChatAction(\"typing\").catch(() => {});\n handleAssistantMessage(this.assistantSession, ctx.message.text).catch(\n (err) => log.error({ err }, \"Assistant error\"),\n );\n return;\n }\n\n // Session topic → send typing indicator and forward to core\n const sessionId = this.core.sessionManager.getSessionByThread(\"telegram\", String(threadId))?.id;\n if (sessionId) await this.finalizeDraft(sessionId);\n if (sessionId) {\n const tracker = this.sessionTrackers.get(sessionId)\n if (tracker) await tracker.onNewPrompt()\n }\n ctx.replyWithChatAction(\"typing\").catch(() => {});\n this.core\n .handleMessage({\n channelId: \"telegram\",\n threadId: String(threadId),\n userId: String(ctx.from.id),\n text: ctx.message.text,\n })\n .catch((err) => log.error({ err }, \"handleMessage error\"));\n });\n }\n\n // --- ChannelAdapter implementations ---\n\n async sendMessage(\n sessionId: string,\n content: OutgoingMessage,\n ): Promise<void> {\n // Suppress all messages from the assistant session while it is processing\n // its background system prompt — those responses are not for the user.\n if (this.assistantInitializing && sessionId === this.assistantSession?.id) return;\n\n // log.debug({ sessionId, type: content.type }, \"Sending message to Telegram\");\n const session = this.core.sessionManager.getSession(\n sessionId,\n );\n if (!session) return;\n const threadId = Number(session.threadId);\n\n switch (content.type) {\n case \"thought\": {\n const tracker = this.getOrCreateTracker(sessionId, threadId)\n await tracker.onThought()\n break;\n }\n\n case \"text\": {\n let draft = this.sessionDrafts.get(sessionId);\n if (!draft) {\n const tracker = this.getOrCreateTracker(sessionId, threadId)\n await tracker.onTextStart()\n draft = new MessageDraft(\n this.bot,\n this.telegramConfig.chatId,\n threadId,\n this.sendQueue,\n sessionId,\n );\n this.sessionDrafts.set(sessionId, draft);\n }\n draft.append(content.text);\n this.sessionTextBuffers.set(\n sessionId,\n (this.sessionTextBuffers.get(sessionId) ?? '') + content.text,\n );\n break;\n }\n\n case \"tool_call\": {\n const tracker = this.getOrCreateTracker(sessionId, threadId)\n await tracker.onToolCall()\n await this.finalizeDraft(sessionId);\n const meta = content.metadata as never as {\n id: string;\n name: string;\n kind?: string;\n status?: string;\n content?: unknown;\n viewerLinks?: { file?: string; diff?: string };\n };\n // Store state immediately so tool_updates can find it while sendMessage is queued\n if (!this.toolCallMessages.has(sessionId)) {\n this.toolCallMessages.set(sessionId, new Map());\n }\n let resolveReady!: () => void;\n const ready = new Promise<void>((r) => {\n resolveReady = r;\n });\n this.toolCallMessages.get(sessionId)!.set(meta.id, {\n msgId: 0,\n name: meta.name,\n kind: meta.kind,\n viewerLinks: meta.viewerLinks,\n viewerFilePath: (content.metadata as any)?.viewerFilePath,\n ready,\n });\n const msg = await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n formatToolCall(meta),\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n const toolEntry = this.toolCallMessages.get(sessionId)!.get(meta.id)!;\n toolEntry.msgId = msg!.message_id;\n resolveReady();\n break;\n }\n\n case \"tool_update\": {\n const meta = content.metadata as never as {\n id: string;\n name: string;\n kind?: string;\n status: string;\n content?: unknown;\n viewerLinks?: { file?: string; diff?: string };\n };\n const toolState = this.toolCallMessages.get(sessionId)?.get(meta.id);\n if (toolState) {\n // Accumulate state from intermediate updates\n if (meta.viewerLinks) {\n toolState.viewerLinks = meta.viewerLinks;\n log.debug({ toolId: meta.id, viewerLinks: meta.viewerLinks }, \"Accumulated viewerLinks\");\n }\n const viewerFilePath = (content.metadata as any)?.viewerFilePath;\n if (viewerFilePath) toolState.viewerFilePath = viewerFilePath;\n if (meta.name) toolState.name = meta.name;\n if (meta.kind) toolState.kind = meta.kind;\n // Edit on terminal status OR when viewer links are available (for permission review)\n const isTerminal = meta.status === \"completed\" || meta.status === \"failed\";\n if (!isTerminal && !meta.viewerLinks) break;\n await toolState.ready;\n log.debug(\n { toolId: meta.id, status: meta.status, hasViewerLinks: !!toolState.viewerLinks, viewerLinks: toolState.viewerLinks, name: toolState.name, msgId: toolState.msgId },\n \"Tool completed, preparing edit\",\n );\n const merged = {\n ...meta,\n name: toolState.name,\n kind: toolState.kind,\n viewerLinks: toolState.viewerLinks,\n viewerFilePath: toolState.viewerFilePath,\n };\n const formattedText = formatToolUpdate(merged);\n try {\n await this.sendQueue.enqueue(() =>\n this.bot.api.editMessageText(\n this.telegramConfig.chatId,\n toolState.msgId,\n formattedText,\n { parse_mode: \"HTML\" },\n ),\n );\n } catch (err) {\n log.warn(\n { err, msgId: toolState.msgId, textLen: formattedText.length, hasViewerLinks: !!merged.viewerLinks },\n \"Tool update edit failed\",\n );\n }\n }\n break;\n }\n\n case \"plan\": {\n const meta = content.metadata as never as {\n entries: Array<{ content: string; status: string; priority: string }>\n }\n const tracker = this.getOrCreateTracker(sessionId, threadId)\n await tracker.onPlan(\n meta.entries.map(e => ({\n content: e.content,\n status: e.status as 'pending' | 'in_progress' | 'completed',\n priority: (e.priority ?? 'medium') as 'high' | 'medium' | 'low',\n })),\n )\n break;\n }\n\n case \"usage\": {\n const meta = content.metadata as never as {\n tokensUsed?: number;\n contextSize?: number;\n }\n await this.finalizeDraft(sessionId)\n const tracker = this.getOrCreateTracker(sessionId, threadId)\n await tracker.sendUsage(meta)\n\n // Notify the Notifications topic that a prompt has completed\n if (this.notificationTopicId && sessionId !== this.assistantSession?.id) {\n const sess = this.core.sessionManager.getSession(sessionId)\n const sessionName = sess?.name || 'Session'\n const chatIdStr = String(this.telegramConfig.chatId)\n const numericId = chatIdStr.startsWith('-100') ? chatIdStr.slice(4) : chatIdStr.replace('-', '')\n const usageMsgId = tracker.getUsageMsgId()\n const deepLink = `https://t.me/c/${numericId}/${usageMsgId ?? threadId}`\n const text = `✅ <b>${escapeHtml(sessionName)}</b>\\nTask completed.\\n\\n<a href=\"${deepLink}\">→ Go to topic</a>`\n this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(this.telegramConfig.chatId, text, {\n message_thread_id: this.notificationTopicId,\n parse_mode: 'HTML',\n disable_notification: false,\n }),\n ).catch(() => {})\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.cleanupSkillCommands(sessionId);\n const tracker = this.sessionTrackers.get(sessionId)\n if (tracker) {\n await tracker.onComplete()\n tracker.destroy()\n this.sessionTrackers.delete(sessionId)\n } else {\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n `✅ <b>Done</b>`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n )\n }\n break;\n }\n\n case \"error\": {\n await this.finalizeDraft(sessionId);\n const tracker = this.sessionTrackers.get(sessionId)\n if (tracker) {\n tracker.destroy()\n this.sessionTrackers.delete(sessionId)\n }\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n `❌ <b>Error:</b> ${escapeHtml(content.text)}`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n break;\n }\n }\n }\n\n async sendPermissionRequest(\n sessionId: string,\n request: PermissionRequest,\n ): Promise<void> {\n log.info({ sessionId, requestId: request.id }, \"Permission request sent\");\n const session = this.core.sessionManager.getSession(\n sessionId,\n );\n if (!session) return;\n\n // Dangerous mode: auto-approve without prompting the user\n if (session.dangerousMode) {\n const allowOption = request.options.find((o) => o.isAllow);\n if (allowOption && session.permissionGate.requestId === request.id) {\n log.info({ sessionId, requestId: request.id, optionId: allowOption.id }, \"Dangerous mode: auto-approving permission\");\n session.permissionGate.resolve(allowOption.id);\n }\n return;\n }\n\n await this.sendQueue.enqueue(() =>\n this.permissionHandler.sendPermissionRequest(session, request),\n );\n }\n\n async sendNotification(notification: NotificationMessage): Promise<void> {\n // Skip notifications for the assistant session (system session, not user-visible)\n if (notification.sessionId === this.assistantSession?.id) return;\n\n log.info(\n { sessionId: notification.sessionId, type: notification.type },\n \"Notification sent\",\n );\n if (!this.notificationTopicId) return;\n const emoji: Record<string, string> = {\n completed: \"✅\",\n error: \"❌\",\n permission: \"🔐\",\n input_required: \"💬\",\n };\n let text = `${emoji[notification.type] || \"ℹ️\"} <b>${escapeHtml(notification.sessionName || \"New session\")}</b>\\n`;\n text += escapeHtml(notification.summary);\n\n // Build deep link to session topic (Telegram supergroup format: /c/{chatId}/{threadId})\n const deepLink = notification.deepLink ?? (() => {\n const session = this.core.sessionManager.getSession(notification.sessionId);\n const threadId = session?.threadId;\n if (!threadId) return undefined;\n // chatId for supergroups looks like -1001234567890; strip -100 prefix\n const chatIdStr = String(this.telegramConfig.chatId);\n const numericId = chatIdStr.startsWith(\"-100\") ? chatIdStr.slice(4) : chatIdStr.replace(\"-\", \"\");\n return `https://t.me/c/${numericId}/${threadId}`;\n })();\n\n if (deepLink) {\n text += `\\n\\n<a href=\"${deepLink}\">→ Go to topic</a>`;\n }\n await this.sendQueue.enqueue(() =>\n 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\n async createSessionThread(sessionId: string, name: string): Promise<string> {\n log.info({ sessionId, name }, \"Session topic created\");\n return String(\n await createSessionTopic(this.bot, this.telegramConfig.chatId, name),\n );\n }\n\n async renameSessionThread(sessionId: string, newName: string): Promise<void> {\n const session = this.core.sessionManager.getSession(\n sessionId,\n );\n if (!session) return;\n await renameSessionTopic(\n this.bot,\n this.telegramConfig.chatId,\n Number(session.threadId),\n newName,\n );\n await this.core.sessionManager.updateSessionName(\n sessionId,\n newName,\n );\n }\n\n async sendSkillCommands(\n sessionId: string,\n commands: AgentCommand[],\n ): Promise<void> {\n // Suppress skill commands for the assistant session entirely\n if (sessionId === this.assistantSession?.id) return;\n\n const session = this.core.sessionManager.getSession(sessionId);\n if (!session) return;\n const threadId = Number(session.threadId);\n if (!threadId) return;\n\n // Restore skillMsgIds from persisted platform data if not in memory (e.g. after restart)\n if (!this.skillMessages.has(sessionId)) {\n const record = this.core.sessionManager.getSessionRecord(sessionId);\n const platform = record?.platform as import(\"../../core/types.js\").TelegramPlatformData | undefined;\n if (platform?.skillMsgId) {\n this.skillMessages.set(sessionId, platform.skillMsgId);\n }\n }\n\n // Empty commands → remove pinned message\n if (commands.length === 0) {\n await this.cleanupSkillCommands(sessionId);\n return;\n }\n\n const messages = buildSkillMessages(commands);\n const existingMsgId = this.skillMessages.get(sessionId);\n\n if (existingMsgId) {\n // Update existing pinned message\n try {\n await this.bot.api.editMessageText(\n this.telegramConfig.chatId,\n existingMsgId,\n messages[0],\n { parse_mode: \"HTML\" },\n );\n return;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"\";\n if (msg.includes(\"message is not modified\")) {\n // Content unchanged — nothing to do\n return;\n }\n // Message may have been deleted or format changed — clean up and create new\n try {\n await this.bot.api.deleteMessage(this.telegramConfig.chatId, existingMsgId);\n } catch { /* already gone */ }\n this.skillMessages.delete(sessionId);\n }\n }\n\n // Send new messages and pin the first one\n try {\n let firstMsgId: number | undefined;\n for (const text of messages) {\n const msg = await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n text,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n if (!firstMsgId) firstMsgId = msg!.message_id;\n }\n\n this.skillMessages.set(sessionId, firstMsgId!);\n\n // Persist skillMsgId so it survives restarts\n const record = this.core.sessionManager.getSessionRecord(sessionId);\n if (record) {\n await this.core.sessionManager.updateSessionPlatform(\n sessionId,\n { ...record.platform, skillMsgId: firstMsgId },\n );\n }\n\n await this.bot.api.pinChatMessage(\n this.telegramConfig.chatId,\n firstMsgId!,\n { disable_notification: true },\n );\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to send skill commands\");\n }\n }\n\n async cleanupSkillCommands(sessionId: string): Promise<void> {\n const msgId = this.skillMessages.get(sessionId);\n if (!msgId) return;\n\n try {\n await this.bot.api.editMessageText(\n this.telegramConfig.chatId,\n msgId,\n \"🛠 <i>Session ended</i>\",\n { parse_mode: \"HTML\" },\n );\n await this.bot.api.unpinChatMessage(this.telegramConfig.chatId, msgId);\n } catch {\n /* message may already be deleted */\n }\n\n this.skillMessages.delete(sessionId);\n\n // Clear persisted skillMsgId\n const record = this.core.sessionManager.getSessionRecord(sessionId);\n if (record) {\n const { skillMsgId: _removed, ...rest } = record.platform as unknown as import(\"../../core/types.js\").TelegramPlatformData;\n await this.core.sessionManager.updateSessionPlatform(sessionId, rest);\n }\n }\n\n\n private async finalizeDraft(sessionId: string): Promise<void> {\n const draft = this.sessionDrafts.get(sessionId);\n if (!draft) return;\n\n // Delete BEFORE awaiting to prevent concurrent finalizeDraft() calls\n // from double-finalizing the same draft (events are not awaited in\n // wireSessionEvents, so tool_call/usage/session_end can race).\n this.sessionDrafts.delete(sessionId);\n const finalMsgId = await draft.finalize();\n\n // Detect actions in assistant responses and attach keyboard via editMessageReplyMarkup\n if (sessionId === this.assistantSession?.id) {\n const fullText = this.sessionTextBuffers.get(sessionId);\n this.sessionTextBuffers.delete(sessionId);\n if (fullText && finalMsgId) {\n const detected = detectAction(fullText);\n if (detected) {\n const actionId = storeAction(detected);\n const keyboard = buildActionKeyboard(actionId, detected);\n try {\n await this.bot.api.editMessageReplyMarkup(\n this.telegramConfig.chatId,\n finalMsgId,\n { reply_markup: keyboard },\n );\n } catch {\n // Best effort — keyboard attachment is non-critical\n }\n }\n }\n } else {\n this.sessionTextBuffers.delete(sessionId);\n }\n }\n}\n","export function escapeHtml(text: string | undefined | null): string {\n if (!text) return ''\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\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, 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: unknown) => extractContentText(c, depth + 1))\n .filter(Boolean)\n .join('\\n')\n }\n if (typeof content === 'object' && content !== null) {\n const c = content as Record<string, unknown>\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 // ACP content wrapper: {type: \"content\", content: {type: \"text\", text: \"...\"}}\n if (c.content && typeof c.content === 'object') return extractContentText(c.content, depth + 1)\n // Tool input/output objects\n if (c.input) return extractContentText(c.input, depth + 1)\n if (c.output) return extractContentText(c.output, depth + 1)\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; viewerLinks?: { file?: string; diff?: string }; viewerFilePath?: string }): 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 text += formatViewerLinks(tool.viewerLinks, tool.viewerFilePath)\n if (!tool.viewerLinks) {\n const details = extractContentText(tool.content)\n if (details) {\n text += `\\n<pre>${escapeHtml(truncateContent(details))}</pre>`\n }\n }\n return text\n}\n\nexport function formatToolUpdate(update: { id: string; name?: string; kind?: string; status: string; content?: unknown; viewerLinks?: { file?: string; diff?: string }; viewerFilePath?: string }): 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 text += formatViewerLinks(update.viewerLinks, update.viewerFilePath)\n if (!update.viewerLinks) {\n const details = extractContentText(update.content)\n if (details) {\n text += `\\n<pre>${escapeHtml(truncateContent(details))}</pre>`\n }\n }\n return text\n}\n\nfunction formatViewerLinks(links?: { file?: string; diff?: string }, filePath?: string): string {\n if (!links) return ''\n const fileName = filePath ? filePath.split('/').pop() || filePath : ''\n let text = '\\n'\n if (links.file) text += `\\n📄 <a href=\"${escapeHtml(links.file)}\">View ${escapeHtml(fileName || 'file')}</a>`\n if (links.diff) text += `\\n📝 <a href=\"${escapeHtml(links.diff)}\">View diff${fileName ? ` — ${escapeHtml(fileName)}` : ''}</a>`\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\nfunction formatTokens(n: number): string {\n return n >= 1000 ? `${Math.round(n / 1000)}k` : String(n)\n}\n\nfunction progressBar(ratio: number): string {\n const filled = Math.round(Math.min(ratio, 1) * 10)\n return '▓'.repeat(filled) + '░'.repeat(10 - filled)\n}\n\nexport function formatUsage(usage: { tokensUsed?: number; contextSize?: number }): string {\n const { tokensUsed, contextSize } = usage\n if (tokensUsed == null) return '📊 Usage data unavailable'\n if (contextSize == null) return `📊 ${formatTokens(tokensUsed)} tokens`\n\n const ratio = tokensUsed / contextSize\n const pct = Math.round(ratio * 100)\n const bar = progressBar(ratio)\n const emoji = pct >= 85 ? '⚠️' : '📊'\n return `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens\\n${bar} ${pct}%`\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'\nimport type { TelegramSendQueue } from './send-queue.js'\n\nconst FLUSH_INTERVAL = 5000\n\nexport class MessageDraft {\n private buffer: string = ''\n private messageId?: number\n private firstFlushPending = false\n private flushTimer?: ReturnType<typeof setTimeout>\n private flushPromise: Promise<void> = Promise.resolve()\n private lastSentBuffer: string = ''\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n private sessionId: string,\n ) {}\n\n append(text: string): void {\n if (!text) return\n this.buffer += text\n this.scheduleFlush()\n }\n\n private scheduleFlush(): void {\n if (this.flushTimer) return\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined\n this.flushPromise = this.flushPromise\n .then(() => this.flush())\n .catch(() => {})\n }, FLUSH_INTERVAL)\n }\n\n private async flush(): Promise<void> {\n if (!this.buffer) return\n if (this.firstFlushPending) return\n\n const html = markdownToTelegramHtml(this.buffer)\n const truncated = html.length > 4096 ? html.slice(0, 4090) + '\\n...' : html\n if (!truncated) return\n\n if (!this.messageId) {\n this.firstFlushPending = true\n try {\n const result = await this.sendQueue.enqueue(\n () => this.bot.api.sendMessage(this.chatId, truncated, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n { type: 'other' },\n )\n if (result) {\n this.messageId = result.message_id\n this.lastSentBuffer = this.buffer\n }\n } catch {\n // sendMessage failed — next flush will retry\n } finally {\n this.firstFlushPending = false\n }\n } else {\n try {\n await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, truncated, {\n parse_mode: 'HTML',\n }),\n { type: 'text', key: this.sessionId },\n )\n this.lastSentBuffer = this.buffer\n } catch {\n // Don't reset messageId — transient errors (rate limit, network) would cause\n // the next flush to sendMessage the full buffer as a NEW message, creating duplicates.\n // If the message was truly deleted, finalize() handles the fallback.\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 await this.flushPromise\n\n if (!this.buffer) return this.messageId\n\n // Skip if buffer was already sent by flush() and nothing new was appended\n if (this.messageId && this.buffer === this.lastSentBuffer) {\n return this.messageId\n }\n\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 await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, chunk, {\n parse_mode: 'HTML',\n }),\n { type: 'other' },\n )\n } else {\n const msg = await this.sendQueue.enqueue(\n () => this.bot.api.sendMessage(this.chatId, chunk, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n { type: 'other' },\n )\n if (msg) {\n this.messageId = msg.message_id\n }\n }\n }\n } catch {\n // Edit/send with HTML failed — only retry if content is new\n if (this.buffer !== this.lastSentBuffer) {\n try {\n await this.sendQueue.enqueue(\n () => this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {\n message_thread_id: this.threadId,\n disable_notification: true,\n }),\n { type: 'other' },\n )\n } catch {\n // Give up\n }\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 type { Session } from \"../../core/session.js\";\nimport { escapeHtml } from \"./formatting.js\";\nimport { createSessionTopic, renameSessionTopic, buildDeepLink } from \"./topics.js\";\nimport { createChildLogger } from \"../../core/log.js\";\nimport type { AgentCommand } from \"../../core/index.js\";\nconst log = createChildLogger({ module: \"telegram-commands\" });\n\ninterface AssistantContext {\n topicId: number;\n getSession: () => Session | null;\n}\n\nexport function setupCommands(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n assistant?: AssistantContext,\n): void {\n bot.command(\"new\", (ctx) => handleNew(ctx, core, chatId, assistant));\n bot.command(\"newchat\", (ctx) => handleNewChat(ctx, core, chatId));\n bot.command(\"cancel\", (ctx) => handleCancel(ctx, core, assistant));\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 bot.command(\"enable_dangerous\", (ctx) => handleEnableDangerous(ctx, core));\n bot.command(\"disable_dangerous\", (ctx) => handleDisableDangerous(ctx, core));\n bot.command(\"restart\", (ctx) => handleRestart(ctx, core));\n bot.command(\"update\", (ctx) => handleUpdate(ctx, core));\n}\n\nexport function buildMenuKeyboard(): InlineKeyboard {\n return new InlineKeyboard()\n .text(\"🆕 New Session\", \"m:new\")\n .text(\"💬 New Chat\", \"m:newchat\")\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 .row()\n .text(\"🔄 Restart\", \"m:restart\")\n .text(\"⬆️ Update\", \"m:update\");\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:newchat\":\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 case \"m:restart\":\n await handleRestart(ctx, core);\n break;\n case \"m:update\":\n await handleUpdate(ctx, core);\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 assistant?: AssistantContext,\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 // In assistant topic: if missing params, forward to assistant for conversational gathering\n const currentThreadId = ctx.message?.message_thread_id;\n if (\n assistant &&\n currentThreadId === assistant.topicId &&\n (!agentName || !workspace)\n ) {\n const assistantSession = assistant.getSession();\n if (assistantSession) {\n const prompt = agentName\n ? `User wants to create a new session with agent \"${agentName}\" but didn't specify a workspace. Ask them which workspace to use.`\n : `User wants to create a new session. Ask them which agent and workspace to use.`;\n await assistantSession.enqueuePrompt(prompt);\n return;\n }\n }\n\n log.info({ userId: ctx.from?.id, agentName }, \"New session command\");\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 // Let user know we're setting up (spawn + warm-up can take a while)\n await ctx.api.sendMessage(chatId, `⏳ Setting up session, please wait...`, {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n\n const session = await core.handleNewSession(\n \"telegram\",\n agentName,\n workspace,\n );\n session.threadId = String(threadId);\n\n // Persist platform mapping\n await core.sessionManager.updateSessionPlatform(session.id, {\n topicId: threadId,\n });\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 reply_markup: buildDangerousModeKeyboard(session.id, false),\n },\n );\n\n // Warm up model cache in background while user types\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n } catch (err) {\n log.error({ err }, \"Session creation failed\");\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 : (typeof err === 'object' ? JSON.stringify(err) : 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 /newchat inside a session topic to inherit its config.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n // Resolve agent config from existing session/record BEFORE spawning\n const currentSession = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n let agentName: string | undefined;\n let workspace: string | undefined;\n\n if (currentSession) {\n agentName = currentSession.agentName;\n workspace = currentSession.workingDirectory;\n } else {\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await ctx.reply(\"No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n agentName = record.agentName;\n workspace = record.workingDir;\n }\n\n let newThreadId: number | undefined;\n try {\n // Create topic FIRST so threadId is ready before session events fire\n const topicName = `🔄 ${agentName} — New Chat`;\n newThreadId = await createSessionTopic(\n botFromCtx(ctx),\n chatId,\n topicName,\n );\n\n // Notify in the original topic immediately with a deep link to the new one\n const topicLink = buildDeepLink(chatId, newThreadId);\n await ctx.reply(\n `✅ New chat created → <a href=\"${topicLink}\">Open topic</a>`,\n { parse_mode: \"HTML\" },\n );\n\n await ctx.api.sendMessage(chatId, `⏳ Setting up session, please wait...`, {\n message_thread_id: newThreadId,\n parse_mode: \"HTML\",\n });\n\n const session = await core.handleNewSession(\n \"telegram\",\n agentName,\n workspace,\n );\n session.threadId = String(newThreadId);\n\n // Persist platform mapping for new chat\n await core.sessionManager.updateSessionPlatform(session.id, {\n topicId: newThreadId,\n });\n\n await ctx.api.sendMessage(\n chatId,\n `✅ New chat (same agent &amp; 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 reply_markup: buildDangerousModeKeyboard(session.id, false),\n },\n );\n\n // Warm up model cache in background while user types\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n } catch (err) {\n // Clean up orphaned topic if session creation failed\n if (newThreadId) {\n try {\n await ctx.api.deleteForumTopic(chatId, newThreadId);\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 handleCancel(\n ctx: Context,\n core: OpenACPCore,\n assistant?: AssistantContext,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n // In assistant topic: forward to assistant for confirmation\n if (assistant && threadId === assistant.topicId) {\n const assistantSession = assistant.getSession();\n if (assistantSession) {\n await assistantSession.enqueuePrompt(\n \"User wants to cancel a session. Confirm which session to cancel.\",\n );\n return;\n }\n }\n\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n log.info({ sessionId: session.id }, \"Cancel session command\");\n await session.cancel();\n await ctx.reply(\"⛔ Session cancelled.\", { parse_mode: \"HTML\" });\n return;\n }\n\n // Fallback: cancel from store when session not in memory (e.g. after restart)\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (record && record.status !== \"cancelled\" && record.status !== \"error\") {\n log.info({ sessionId: record.sessionId }, \"Cancel session command (from store)\");\n await core.sessionManager.cancelSession(record.sessionId);\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.queueDepth} pending`,\n { parse_mode: \"HTML\" },\n );\n } else {\n // Fallback: show stored session info when not loaded in memory (e.g. after restart)\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (record) {\n await ctx.reply(\n `<b>Session:</b> ${escapeHtml(record.name || record.sessionId)}\\n` +\n `<b>Agent:</b> ${escapeHtml(record.agentName)}\\n` +\n `<b>Status:</b> ${escapeHtml(record.status)} (not loaded)\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(record.workingDir)}</code>`,\n { parse_mode: \"HTML\" },\n );\n } else {\n await ctx.reply(\"No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\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 `/newchat — New chat, same agent &amp; 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 `/restart — Restart OpenACP\\n` +\n `/update — Update to latest version and restart\\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\nexport function buildDangerousModeKeyboard(sessionId: string, enabled: boolean): InlineKeyboard {\n return new InlineKeyboard().text(\n enabled ? \"🔐 Disable Dangerous Mode\" : \"☠️ Enable Dangerous Mode\",\n `d:${sessionId}`,\n );\n}\n\nexport function setupDangerousModeCallbacks(bot: Bot, core: OpenACPCore): void {\n bot.callbackQuery(/^d:/, async (ctx) => {\n const sessionId = ctx.callbackQuery.data.slice(2);\n const session = core.sessionManager.getSession(sessionId);\n\n // Session live in memory — toggle directly\n if (session) {\n session.dangerousMode = !session.dangerousMode;\n log.info({ sessionId, dangerousMode: session.dangerousMode }, \"Dangerous mode toggled via button\");\n core.sessionManager.updateSessionDangerousMode(sessionId, session.dangerousMode).catch(() => {});\n\n const toastText = session.dangerousMode\n ? \"☠️ Dangerous mode enabled — permissions auto-approved\"\n : \"🔐 Dangerous mode disabled — permissions shown normally\";\n try { await ctx.answerCallbackQuery({ text: toastText }); } catch { /* expired */ }\n\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: buildDangerousModeKeyboard(sessionId, session.dangerousMode),\n });\n } catch { /* ignore */ }\n return;\n }\n\n // Session not in memory (e.g. after restart) — toggle directly in store\n const record = core.sessionManager.getSessionRecord(sessionId);\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n try { await ctx.answerCallbackQuery({ text: \"⚠️ Session not found or already ended.\" }); } catch { /* expired */ }\n return;\n }\n\n const newDangerousMode = !(record.dangerousMode ?? false);\n core.sessionManager.updateSessionDangerousMode(sessionId, newDangerousMode).catch(() => {});\n log.info({ sessionId, dangerousMode: newDangerousMode }, \"Dangerous mode toggled via button (store-only, session not in memory)\");\n\n const toastText = newDangerousMode\n ? \"☠️ Dangerous mode enabled — permissions auto-approved\"\n : \"🔐 Dangerous mode disabled — permissions shown normally\";\n try { await ctx.answerCallbackQuery({ text: toastText }); } catch { /* expired */ }\n\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: buildDangerousModeKeyboard(sessionId, newDangerousMode),\n });\n } catch { /* ignore */ }\n });\n}\n\nasync function handleEnableDangerous(ctx: Context, core: OpenACPCore): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\"⚠️ This command only works inside a session topic.\", { parse_mode: \"HTML\" });\n return;\n }\n const session = core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n if (session) {\n if (session.dangerousMode) {\n await ctx.reply(\"☠️ Dangerous mode is already enabled.\", { parse_mode: \"HTML\" });\n return;\n }\n session.dangerousMode = true;\n core.sessionManager.updateSessionDangerousMode(session.id, true).catch(() => {});\n } else {\n // Session not in memory (e.g. after restart) — update store directly\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await ctx.reply(\"⚠️ No active session in this topic.\", { parse_mode: \"HTML\" });\n return;\n }\n if (record.dangerousMode) {\n await ctx.reply(\"☠️ Dangerous mode is already enabled.\", { parse_mode: \"HTML\" });\n return;\n }\n core.sessionManager.updateSessionDangerousMode(record.sessionId, true).catch(() => {});\n }\n await ctx.reply(\n `⚠️ <b>Dangerous mode enabled</b>\\n\\nAll permission requests will be auto-approved. Claude can run arbitrary commands without asking.\\n\\nUse /disable_dangerous to restore normal behaviour.`,\n { parse_mode: \"HTML\" },\n );\n}\n\nasync function handleUpdate(ctx: Context, core: OpenACPCore): Promise<void> {\n if (!core.requestRestart) {\n await ctx.reply(\"⚠️ Update is not available (no restart handler registered).\", { parse_mode: \"HTML\" });\n return;\n }\n\n const { getCurrentVersion, getLatestVersion, compareVersions, runUpdate } = await import(\"../../cli/version.js\");\n const current = getCurrentVersion();\n const statusMsg = await ctx.reply(`🔍 Checking for updates... (current: v${escapeHtml(current)})`, { parse_mode: \"HTML\" });\n\n const latest = await getLatestVersion();\n if (!latest) {\n await ctx.api.editMessageText(ctx.chat!.id, statusMsg.message_id, \"❌ Could not check for updates.\", { parse_mode: \"HTML\" });\n return;\n }\n\n if (compareVersions(current, latest) >= 0) {\n await ctx.api.editMessageText(ctx.chat!.id, statusMsg.message_id, `✅ Already up to date (v${escapeHtml(current)}).`, { parse_mode: \"HTML\" });\n return;\n }\n\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `⬇️ Updating v${escapeHtml(current)} → v${escapeHtml(latest)}...`,\n { parse_mode: \"HTML\" },\n );\n\n const ok = await runUpdate();\n if (!ok) {\n await ctx.api.editMessageText(ctx.chat!.id, statusMsg.message_id, \"❌ Update failed. Try manually: <code>npm install -g @openacp/cli@latest</code>\", { parse_mode: \"HTML\" });\n return;\n }\n\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `✅ Updated to v${escapeHtml(latest)}. Restarting...`,\n { parse_mode: \"HTML\" },\n );\n\n await new Promise((r) => setTimeout(r, 500));\n await core.requestRestart();\n}\n\nasync function handleRestart(ctx: Context, core: OpenACPCore): Promise<void> {\n if (!core.requestRestart) {\n await ctx.reply(\"⚠️ Restart is not available (no restart handler registered).\", { parse_mode: \"HTML\" });\n return;\n }\n await ctx.reply(\"🔄 <b>Restarting OpenACP...</b>\\nRebuilding and restarting. Be back shortly.\", { parse_mode: \"HTML\" });\n // Give Telegram a moment to deliver the message before shutting down\n await new Promise((r) => setTimeout(r, 500));\n await core.requestRestart();\n}\n\nasync function handleDisableDangerous(ctx: Context, core: OpenACPCore): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\"⚠️ This command only works inside a session topic.\", { parse_mode: \"HTML\" });\n return;\n }\n const session = core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n if (session) {\n if (!session.dangerousMode) {\n await ctx.reply(\"🔐 Dangerous mode is already disabled.\", { parse_mode: \"HTML\" });\n return;\n }\n session.dangerousMode = false;\n core.sessionManager.updateSessionDangerousMode(session.id, false).catch(() => {});\n } else {\n // Session not in memory (e.g. after restart) — update store directly\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await ctx.reply(\"⚠️ No active session in this topic.\", { parse_mode: \"HTML\" });\n return;\n }\n if (!record.dangerousMode) {\n await ctx.reply(\"🔐 Dangerous mode is already disabled.\", { parse_mode: \"HTML\" });\n return;\n }\n core.sessionManager.updateSessionDangerousMode(record.sessionId, false).catch(() => {});\n }\n await ctx.reply(\"🔐 <b>Dangerous mode disabled</b>\\n\\nPermission requests will be shown normally.\", { parse_mode: \"HTML\" });\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\nconst TELEGRAM_MSG_LIMIT = 4096;\n\n/**\n * Build plain-text skill command messages. Each command is on its own line\n * wrapped in <code> for tap-to-copy. If the list exceeds Telegram's message\n * limit, it is split into multiple messages (cut at line boundaries).\n */\nexport function buildSkillMessages(commands: AgentCommand[]): string[] {\n const sorted = [...commands].sort((a, b) => a.name.localeCompare(b.name));\n const header = \"🛠 <b>Available Skills</b>\\n\";\n const lines = sorted.map((c) => `<code>/${c.name}</code>`);\n\n const messages: string[] = [];\n let current = header;\n\n for (const line of lines) {\n const candidate = current + \"\\n\" + line;\n if (candidate.length > TELEGRAM_MSG_LIMIT) {\n messages.push(current);\n current = line;\n } else {\n current = candidate;\n }\n }\n if (current) messages.push(current);\n return messages;\n}\n\nexport async function executeNewSession(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n agentName?: string,\n workspace?: string,\n): Promise<{ session: Session; threadId: number; firstMsgId: number }> {\n // Create topic with generic name first (same as original handleNew)\n const threadId = await createSessionTopic(bot, chatId, \"🔄 New Session\");\n\n const setupMsg = await bot.api.sendMessage(chatId, \"⏳ Setting up session, please wait...\", {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n const firstMsgId = setupMsg.message_id;\n\n try {\n // core.handleNewSession() already wires events internally — do NOT call wireSessionEvents again\n const session = await core.handleNewSession(\n \"telegram\",\n agentName,\n workspace,\n );\n session.threadId = String(threadId);\n\n await core.sessionManager.updateSessionPlatform(session.id, {\n topicId: threadId,\n });\n\n // Rename topic with agent name after session is created\n const finalName = `🔄 ${session.agentName} — New Session`;\n await renameSessionTopic(bot, chatId, threadId, finalName);\n\n // Warm up model cache in background while user types\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n\n return { session, threadId, firstMsgId };\n } catch (err) {\n // Clean up orphaned topic on failure\n try {\n await bot.api.deleteForumTopic(chatId, threadId);\n } catch {\n /* best effort */\n }\n throw err;\n }\n}\n\nexport async function executeCancelSession(\n core: OpenACPCore,\n excludeSessionId?: string,\n): Promise<Session | null> {\n const sessions = core.sessionManager\n .listSessions(\"telegram\")\n .filter((s) => s.status === \"active\" && s.id !== excludeSessionId)\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n const session = sessions[0];\n if (!session) return null;\n\n await session.cancel();\n return session;\n}\n\nexport const STATIC_COMMANDS = [\n { command: \"new\", description: \"Create new session\" },\n { command: \"newchat\", description: \"New chat, same agent & workspace\" },\n { command: \"cancel\", description: \"Cancel current session\" },\n { command: \"status\", description: \"Show status\" },\n { command: \"agents\", description: \"List available agents\" },\n { command: \"help\", description: \"Help\" },\n { command: \"menu\", description: \"Show menu\" },\n { command: \"enable_dangerous\", description: \"Auto-approve all permission requests (session only)\" },\n { command: \"disable_dangerous\", description: \"Restore normal permission prompts (session only)\" },\n { command: \"restart\", description: \"Restart OpenACP\" },\n { command: \"update\", description: \"Update to latest version and restart\" },\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'\nimport { createChildLogger } from '../../core/log.js'\nconst log = createChildLogger({ module: 'telegram-permissions' })\n\n// Stored pending permission callbacks: callbackKey → { sessionId, requestId, options }\ninterface PendingPermission {\n sessionId: string\n requestId: string\n options: { id: string; isAllow: boolean }[]\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, {\n sessionId: session.id,\n requestId: request.id,\n options: request.options.map(o => ({ id: o.id, isAllow: o.isAllow })),\n })\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 (fire-and-forget to avoid sendQueue deadlock:\n // this method runs INSIDE a sendQueue item, so awaiting another enqueue() deadlocks)\n void 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 const isAllow = pending.options.find(o => o.id === optionId)?.isAllow ?? false\n log.info({ requestId: pending.requestId, optionId, isAllow }, 'Permission responded')\n if (session?.permissionGate.requestId === pending.requestId) {\n session.permissionGate.resolve(optionId)\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\";\nimport { createChildLogger } from \"../../core/log.js\";\nconst log = createChildLogger({ module: \"telegram-assistant\" });\n\nexport type SpawnAssistantResult = {\n session: Session;\n /** Resolves when the background system prompt completes (or fails). */\n ready: Promise<void>;\n};\n\nexport async function spawnAssistant(\n core: OpenACPCore,\n adapter: ChannelAdapter,\n assistantTopicId: number,\n): Promise<SpawnAssistantResult> {\n const config = core.configManager.get();\n\n // Create session with default agent\n log.info({ agent: config.defaultAgent }, \"Creating assistant session...\");\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 session.name = \"Assistant\"; // Prevent auto-naming from triggering after system prompt\n log.info({ sessionId: session.id }, \"Assistant agent spawned\");\n\n // Wire events first so the adapter is ready to receive real user responses.\n // The system prompt response will be suppressed by the adapter via the\n // assistantInitializing flag — it checks the flag before routing messages.\n core.wireSessionEvents(session, adapter);\n\n // Fire system prompt in background — don't block startup.\n const systemPrompt = buildAssistantSystemPrompt(config);\n const ready = session.enqueuePrompt(systemPrompt)\n .then(() => { log.info({ sessionId: session.id }, \"Assistant system prompt completed\"); })\n .catch((err) => { log.warn({ err }, \"Assistant system prompt failed\"); });\n\n return { session, ready };\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- /newchat — 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","import type { Bot } from 'grammy'\nimport { createChildLogger } from '../../core/log.js'\nimport { formatUsage } from './formatting.js'\nimport type { TelegramSendQueue } from './send-queue.js'\nimport type { PlanEntry } from '../../core/types.js'\n\nconst log = createChildLogger({ module: 'telegram:activity' })\n\n// ─── ThinkingIndicator ────────────────────────────────────────────────────────\n\nconst THINKING_REFRESH_MS = 15_000\nconst THINKING_MAX_MS = 3 * 60 * 1000\n\nexport class ThinkingIndicator {\n private msgId?: number\n private sending = false\n private dismissed = false\n private refreshTimer?: ReturnType<typeof setInterval>\n private showTime = 0\n\n constructor(\n private api: Bot['api'],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n async show(): Promise<void> {\n if (this.msgId || this.sending || this.dismissed) return\n this.sending = true\n this.showTime = Date.now()\n try {\n const result = await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, '💭 <i>Thinking...</i>', {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n )\n if (result && !this.dismissed) {\n this.msgId = result.message_id\n this.startRefreshTimer()\n }\n } catch (err) {\n log.warn({ err }, 'ThinkingIndicator.show() failed')\n } finally {\n this.sending = false\n }\n }\n\n /** Clear state — stops refresh timer, no Telegram API call */\n dismiss(): void {\n this.dismissed = true\n this.msgId = undefined\n this.stopRefreshTimer()\n }\n\n /** Reset for a new prompt cycle */\n reset(): void {\n this.dismissed = false\n }\n\n private startRefreshTimer(): void {\n this.stopRefreshTimer()\n this.refreshTimer = setInterval(() => {\n if (this.dismissed || !this.msgId || (Date.now() - this.showTime) >= THINKING_MAX_MS) {\n this.stopRefreshTimer()\n return\n }\n const elapsed = Math.round((Date.now() - this.showTime) / 1000)\n this.sendQueue.enqueue(() => {\n // Re-check after waiting in queue — dismiss may have been called\n if (this.dismissed) return Promise.resolve(undefined)\n return this.api.sendMessage(this.chatId, `💭 <i>Still thinking... (${elapsed}s)</i>`, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n })\n }).then(result => {\n if (result && !this.dismissed) {\n this.msgId = result.message_id\n }\n }).catch(() => {})\n }, THINKING_REFRESH_MS)\n }\n\n private stopRefreshTimer(): void {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = undefined\n }\n }\n}\n\n// ─── UsageMessage ─────────────────────────────────────────────────────────────\n\nexport class UsageMessage {\n private msgId?: number\n\n constructor(\n private api: Bot['api'],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n async send(usage: { tokensUsed?: number; contextSize?: number }): Promise<void> {\n const text = formatUsage(usage)\n try {\n if (this.msgId) {\n await this.sendQueue.enqueue(() =>\n this.api.editMessageText(this.chatId, this.msgId!, text, {\n parse_mode: 'HTML',\n }),\n )\n } else {\n const result = await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, text, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n )\n if (result) this.msgId = result.message_id\n }\n } catch (err) {\n log.warn({ err }, 'UsageMessage.send() failed')\n }\n }\n\n getMsgId(): number | undefined {\n return this.msgId\n }\n\n async delete(): Promise<void> {\n if (!this.msgId) return\n const id = this.msgId\n this.msgId = undefined\n try {\n await this.sendQueue.enqueue(() => this.api.deleteMessage(this.chatId, id))\n } catch (err) {\n log.warn({ err }, 'UsageMessage.delete() failed')\n }\n }\n}\n\n// ─── PlanCard ─────────────────────────────────────────────────────────────────\n\nfunction formatPlanCard(entries: PlanEntry[]): string {\n const statusIcon: Record<string, string> = {\n completed: '✅',\n in_progress: '🔄',\n pending: '⬜',\n failed: '❌',\n }\n const total = entries.length\n const done = entries.filter(e => e.status === 'completed').length\n const ratio = total > 0 ? done / total : 0\n const filled = Math.round(ratio * 10)\n const bar = '▓'.repeat(filled) + '░'.repeat(10 - filled)\n const pct = Math.round(ratio * 100)\n const header = `📋 <b>Plan</b>\\n${bar} ${pct}% · ${done}/${total}`\n const lines = entries.map((e, i) => {\n const icon = statusIcon[e.status] ?? '⬜'\n return `${icon} ${i + 1}. ${e.content}`\n })\n return [header, ...lines].join('\\n')\n}\n\nexport class PlanCard {\n private msgId?: number\n private flushPromise: Promise<void> = Promise.resolve()\n private latestEntries?: PlanEntry[]\n private flushTimer?: ReturnType<typeof setTimeout>\n\n constructor(\n private api: Bot['api'],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n update(entries: PlanEntry[]): void {\n this.latestEntries = entries\n if (this.flushTimer) clearTimeout(this.flushTimer)\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined\n this.flushPromise = this.flushPromise\n .then(() => this._flush())\n .catch(() => {})\n }, 3500)\n }\n\n async finalize(): Promise<void> {\n if (!this.latestEntries) return\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = undefined\n }\n await this.flushPromise\n this.flushPromise = this.flushPromise\n .then(() => this._flush())\n .catch(() => {})\n await this.flushPromise\n }\n\n destroy(): void {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = undefined\n }\n }\n\n private async _flush(): Promise<void> {\n if (!this.latestEntries) return\n const text = formatPlanCard(this.latestEntries)\n try {\n if (this.msgId) {\n await this.sendQueue.enqueue(() =>\n this.api.editMessageText(this.chatId, this.msgId!, text, {\n parse_mode: 'HTML',\n }),\n )\n } else {\n const result = await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, text, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n )\n if (result) this.msgId = result.message_id\n }\n } catch (err) {\n log.warn({ err }, 'PlanCard flush failed')\n }\n }\n}\n\n// ─── ActivityTracker ──────────────────────────────────────────────────────────\n\nexport class ActivityTracker {\n private isFirstEvent = true\n private hasPlanCard = false\n private thinking: ThinkingIndicator\n private planCard: PlanCard\n private usage: UsageMessage\n\n constructor(\n private api: Bot['api'],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {\n this.thinking = new ThinkingIndicator(api, chatId, threadId, sendQueue)\n this.planCard = new PlanCard(api, chatId, threadId, sendQueue)\n this.usage = new UsageMessage(api, chatId, threadId, sendQueue)\n }\n\n async onNewPrompt(): Promise<void> {\n this.isFirstEvent = true\n this.hasPlanCard = false\n this.thinking.dismiss()\n this.thinking.reset()\n }\n\n async onThought(): Promise<void> {\n await this._firstEventGuard()\n await this.thinking.show()\n }\n\n async onPlan(entries: PlanEntry[]): Promise<void> {\n await this._firstEventGuard()\n this.thinking.dismiss()\n this.hasPlanCard = true\n this.planCard.update(entries)\n }\n\n async onToolCall(): Promise<void> {\n await this._firstEventGuard()\n this.thinking.dismiss()\n this.thinking.reset()\n }\n\n async onTextStart(): Promise<void> {\n await this._firstEventGuard()\n this.thinking.dismiss()\n }\n\n async sendUsage(data: { tokensUsed?: number; contextSize?: number }): Promise<void> {\n await this.usage.send(data)\n }\n\n getUsageMsgId(): number | undefined {\n return this.usage.getMsgId()\n }\n\n async onComplete(): Promise<void> {\n if (this.hasPlanCard) {\n await this.planCard.finalize()\n } else {\n try {\n await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, '✅ <b>Done</b>', {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n )\n } catch (err) {\n log.warn({ err }, 'ActivityTracker.onComplete() Done send failed')\n }\n }\n }\n\n destroy(): void {\n this.thinking.dismiss()\n this.planCard.destroy()\n }\n\n private async _firstEventGuard(): Promise<void> {\n if (!this.isFirstEvent) return\n this.isFirstEvent = false\n await this.usage.delete()\n }\n}\n","export type QueueItemType = 'text' | 'other'\n\ninterface QueueItem<T = unknown> {\n fn: () => Promise<T>\n type: QueueItemType\n key?: string\n resolve: (value: T | undefined) => void\n reject: (err: unknown) => void\n}\n\nexport class TelegramSendQueue {\n private items: QueueItem[] = []\n private processing = false\n private lastExec = 0\n private minInterval: number\n\n constructor(minInterval = 3000) {\n this.minInterval = minInterval\n }\n\n enqueue<T>(\n fn: () => Promise<T>,\n opts?: { type?: QueueItemType; key?: string },\n ): Promise<T | undefined> {\n const type = opts?.type ?? 'other'\n const key = opts?.key\n\n return new Promise<T | undefined>((resolve, reject) => {\n if (type === 'text' && key) {\n const idx = this.items.findIndex(\n (item) => item.type === 'text' && item.key === key,\n )\n if (idx !== -1) {\n this.items[idx].resolve(undefined)\n this.items[idx] = { fn, type, key, resolve, reject } as QueueItem\n this.scheduleProcess()\n return\n }\n }\n\n this.items.push({ fn, type, key, resolve, reject } as QueueItem)\n this.scheduleProcess()\n })\n }\n\n onRateLimited(): void {\n const remaining: QueueItem[] = []\n for (const item of this.items) {\n if (item.type === 'text') {\n item.resolve(undefined)\n } else {\n remaining.push(item)\n }\n }\n this.items = remaining\n }\n\n private scheduleProcess(): void {\n if (this.processing) return\n if (this.items.length === 0) return\n\n const elapsed = Date.now() - this.lastExec\n const delay = Math.max(0, this.minInterval - elapsed)\n\n this.processing = true\n setTimeout(() => void this.processNext(), delay)\n }\n\n private async processNext(): Promise<void> {\n const item = this.items.shift()\n if (!item) {\n this.processing = false\n return\n }\n\n try {\n const result = await item.fn()\n item.resolve(result)\n } catch (err) {\n item.reject(err)\n } finally {\n this.lastExec = Date.now()\n this.processing = false\n this.scheduleProcess()\n }\n }\n}\n","import { nanoid } from \"nanoid\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { Bot } from \"grammy\";\nimport type { OpenACPCore } from \"../../core/core.js\";\nimport { executeNewSession, executeCancelSession } from \"./commands.js\";\n\nexport interface DetectedAction {\n action: \"new_session\" | \"cancel_session\";\n agent?: string;\n workspace?: string;\n}\n\n// Command patterns: /new [agent] [workspace], /cancel\n// Agent and workspace are ASCII-only tokens (no Unicode letters) to avoid matching non-ASCII words\nconst CMD_NEW_RE =\n /\\/new(?:\\s+([^\\s\\u0080-\\uFFFF]+)(?:\\s+([^\\s\\u0080-\\uFFFF]+))?)?/;\nconst CMD_CANCEL_RE = /\\/cancel\\b/;\n\n// Keyword patterns (compound phrases only to avoid false positives)\nconst KW_NEW_RE = /(?:create|new)\\s+session/i;\nconst KW_CANCEL_RE = /(?:cancel|stop)\\s+session/i;\n\nexport function detectAction(text: string): DetectedAction | null {\n if (!text) return null;\n\n // Priority 1: command pattern\n const cancelCmd = CMD_CANCEL_RE.exec(text);\n if (cancelCmd) return { action: \"cancel_session\" };\n\n const newCmd = CMD_NEW_RE.exec(text);\n if (newCmd) {\n return {\n action: \"new_session\",\n agent: newCmd[1] || undefined,\n workspace: newCmd[2] || undefined,\n };\n }\n\n // Priority 2: keyword matching\n if (KW_CANCEL_RE.test(text)) return { action: \"cancel_session\" };\n if (KW_NEW_RE.test(text))\n return { action: \"new_session\", agent: undefined, workspace: undefined };\n\n return null;\n}\n\n// --- Callback map for action buttons ---\n\nconst ACTION_TTL_MS = 5 * 60 * 1000; // 5 minutes\nconst actionMap: Map<string, { action: DetectedAction; createdAt: number }> =\n new Map();\n\nexport function storeAction(action: DetectedAction): string {\n const id = nanoid(10);\n actionMap.set(id, { action, createdAt: Date.now() });\n // Cleanup expired entries\n for (const [key, entry] of actionMap) {\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(key);\n }\n }\n return id;\n}\n\nexport function getAction(id: string): DetectedAction | undefined {\n const entry = actionMap.get(id);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(id);\n return undefined;\n }\n return entry.action;\n}\n\nexport function removeAction(id: string): void {\n actionMap.delete(id);\n}\n\nexport function buildActionKeyboard(\n actionId: string,\n action: DetectedAction,\n): InlineKeyboard {\n const keyboard = new InlineKeyboard();\n if (action.action === \"new_session\") {\n keyboard.text(\"✅ Create session\", `a:${actionId}`);\n keyboard.text(\"❌ Cancel\", `a:dismiss:${actionId}`);\n } else {\n keyboard.text(\"⛔ Cancel session\", `a:${actionId}`);\n keyboard.text(\"❌ No\", `a:dismiss:${actionId}`);\n }\n return keyboard;\n}\n\nexport function setupActionCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n getAssistantSessionId: () => string | undefined,\n): void {\n // IMPORTANT: dismiss handler MUST be registered BEFORE generic a: handler\n // because grammY routes to the first matching handler and /^a:/ also matches a:dismiss:\n bot.callbackQuery(/^a:dismiss:/, async (ctx) => {\n const actionId = ctx.callbackQuery.data.replace(\"a:dismiss:\", \"\");\n removeAction(actionId);\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch {\n /* message may be old */\n }\n await ctx.answerCallbackQuery({ text: \"Dismissed\" });\n });\n\n bot.callbackQuery(/^a:(?!dismiss)/, async (ctx) => {\n const actionId = ctx.callbackQuery.data.replace(\"a:\", \"\");\n const action = getAction(actionId);\n if (!action) {\n await ctx.answerCallbackQuery({ text: \"Action expired\" });\n return;\n }\n removeAction(actionId);\n\n try {\n if (action.action === \"new_session\") {\n await ctx.answerCallbackQuery({ text: \"⏳ Creating session...\" });\n const { threadId, firstMsgId } = await executeNewSession(\n bot,\n core,\n chatId,\n action.agent,\n action.workspace,\n );\n const topicLink = `https://t.me/c/${String(chatId).replace(\"-100\", \"\")}/${firstMsgId ?? threadId}`;\n const originalText = ctx.callbackQuery.message?.text ?? \"\";\n try {\n await ctx.editMessageText(\n originalText +\n `\\n\\n✅ Session created → <a href=\"${topicLink}\">Go to topic</a>`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n }\n } else if (action.action === \"cancel_session\") {\n const assistantId = getAssistantSessionId();\n const cancelled = await executeCancelSession(core, assistantId);\n if (cancelled) {\n await ctx.answerCallbackQuery({ text: \"⛔ Session cancelled\" });\n const originalText = ctx.callbackQuery.message?.text ?? \"\";\n try {\n await ctx.editMessageText(\n originalText +\n `\\n\\n⛔ Session \"${cancelled.name ?? cancelled.id}\" cancelled`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n }\n } else {\n await ctx.answerCallbackQuery({\n text: \"No active session\",\n });\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch {\n /* best effort */\n }\n }\n }\n } catch {\n await ctx.answerCallbackQuery({ text: \"❌ Error, try again later\" });\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch {\n /* best effort */\n }\n }\n });\n}\n"],"mappings":"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","names":["log","id","path","fs","path","log","path","fs","log","path","fs","path","os","log","log","toastText","InlineKeyboard","nanoid","log","nanoid","InlineKeyboard","log","log","nanoid","InlineKeyboard","nanoid","InlineKeyboard","log"]}