@openacp/cli 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +17 -2
  2. package/dist/api-client-UN7BXQOQ.js +11 -0
  3. package/dist/{autostart-DZ3MHHMM.js → autostart-K73RQZVV.js} +3 -3
  4. package/dist/chunk-3DIPXFZJ.js +650 -0
  5. package/dist/chunk-3DIPXFZJ.js.map +1 -0
  6. package/dist/{chunk-45DFYWJT.js → chunk-66RVSUAR.js} +1782 -1415
  7. package/dist/chunk-66RVSUAR.js.map +1 -0
  8. package/dist/chunk-BGKQHQB4.js +276 -0
  9. package/dist/chunk-BGKQHQB4.js.map +1 -0
  10. package/dist/chunk-C33LTDZV.js +97 -0
  11. package/dist/chunk-C33LTDZV.js.map +1 -0
  12. package/dist/{chunk-LYKCQTH5.js → chunk-ESOPMQAY.js} +5 -1
  13. package/dist/chunk-ESOPMQAY.js.map +1 -0
  14. package/dist/{chunk-6MJLVZXV.js → chunk-FKOARMAE.js} +58 -21
  15. package/dist/{chunk-6MJLVZXV.js.map → chunk-FKOARMAE.js.map} +1 -1
  16. package/dist/chunk-OORPX73T.js +30 -0
  17. package/dist/chunk-OORPX73T.js.map +1 -0
  18. package/dist/{chunk-V3BA2MJ6.js → chunk-RF3DUYFO.js} +2 -2
  19. package/dist/{chunk-UAUTLC4E.js → chunk-W7QQA6CW.js} +4 -4
  20. package/dist/{chunk-ZRFBLD3W.js → chunk-WYZFGHHI.js} +14 -4
  21. package/dist/chunk-WYZFGHHI.js.map +1 -0
  22. package/dist/{chunk-MRKYJ422.js → chunk-X6LLG7XN.js} +2 -2
  23. package/dist/{chunk-C6YIUTGR.js → chunk-YRJEZD7R.js} +2 -2
  24. package/dist/{chunk-HZD3CGPK.js → chunk-ZW444AQY.js} +3 -3
  25. package/dist/cli.js +141 -52
  26. package/dist/cli.js.map +1 -1
  27. package/dist/{config-H2DSEHNW.js → config-XURP6B3S.js} +3 -3
  28. package/dist/config-editor-AALY3URF.js +11 -0
  29. package/dist/config-registry-OGX4YM2U.js +17 -0
  30. package/dist/{daemon-VF6HJQXD.js → daemon-GWJM2S4A.js} +4 -4
  31. package/dist/doctor-X477CVZN.js +9 -0
  32. package/dist/doctor-X477CVZN.js.map +1 -0
  33. package/dist/index.d.ts +76 -27
  34. package/dist/index.js +33 -13
  35. package/dist/install-cloudflared-BTGUD7SW.js +8 -0
  36. package/dist/install-cloudflared-BTGUD7SW.js.map +1 -0
  37. package/dist/log-SPS2S6FO.js +19 -0
  38. package/dist/log-SPS2S6FO.js.map +1 -0
  39. package/dist/{main-7T5YHFHO.js → main-2QKD2EI2.js} +17 -14
  40. package/dist/{main-7T5YHFHO.js.map → main-2QKD2EI2.js.map} +1 -1
  41. package/dist/menu-CARRTW2F.js +17 -0
  42. package/dist/menu-CARRTW2F.js.map +1 -0
  43. package/dist/{setup-FCVL75K6.js → setup-TTOL7XAN.js} +4 -4
  44. package/dist/setup-TTOL7XAN.js.map +1 -0
  45. package/dist/{tunnel-service-DASSH7OA.js → tunnel-service-LEVPLXAZ.js} +3 -3
  46. package/package.json +1 -1
  47. package/dist/chunk-45DFYWJT.js.map +0 -1
  48. package/dist/chunk-LYKCQTH5.js.map +0 -1
  49. package/dist/chunk-ZRFBLD3W.js.map +0 -1
  50. package/dist/config-editor-SKS4LJLT.js +0 -11
  51. package/dist/install-cloudflared-ILUXKLAC.js +0 -8
  52. /package/dist/{autostart-DZ3MHHMM.js.map → api-client-UN7BXQOQ.js.map} +0 -0
  53. /package/dist/{config-H2DSEHNW.js.map → autostart-K73RQZVV.js.map} +0 -0
  54. /package/dist/{chunk-V3BA2MJ6.js.map → chunk-RF3DUYFO.js.map} +0 -0
  55. /package/dist/{chunk-UAUTLC4E.js.map → chunk-W7QQA6CW.js.map} +0 -0
  56. /package/dist/{chunk-MRKYJ422.js.map → chunk-X6LLG7XN.js.map} +0 -0
  57. /package/dist/{chunk-C6YIUTGR.js.map → chunk-YRJEZD7R.js.map} +0 -0
  58. /package/dist/{chunk-HZD3CGPK.js.map → chunk-ZW444AQY.js.map} +0 -0
  59. /package/dist/{config-editor-SKS4LJLT.js.map → config-XURP6B3S.js.map} +0 -0
  60. /package/dist/{daemon-VF6HJQXD.js.map → config-editor-AALY3URF.js.map} +0 -0
  61. /package/dist/{install-cloudflared-ILUXKLAC.js.map → config-registry-OGX4YM2U.js.map} +0 -0
  62. /package/dist/{setup-FCVL75K6.js.map → daemon-GWJM2S4A.js.map} +0 -0
  63. /package/dist/{tunnel-service-DASSH7OA.js.map → tunnel-service-LEVPLXAZ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/streams.ts","../../src/core/stderr-capture.ts","../../src/core/agent-instance.ts","../../src/core/agent-manager.ts","../../src/core/typed-emitter.ts","../../src/core/prompt-queue.ts","../../src/core/permission-gate.ts","../../src/core/session.ts","../../src/core/session-manager.ts","../../src/core/session-bridge.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/core/topic-manager.ts","../../src/adapters/telegram/adapter.ts","../../src/adapters/telegram/topics.ts","../../src/adapters/telegram/commands/new-session.ts","../../src/adapters/telegram/commands/admin.ts","../../src/adapters/telegram/commands/session.ts","../../src/adapters/telegram/commands/integrate.ts","../../src/adapters/telegram/commands/settings.ts","../../src/adapters/telegram/commands/doctor.ts","../../src/adapters/telegram/commands/index.ts","../../src/adapters/telegram/permissions.ts","../../src/product-guide.ts","../../src/adapters/telegram/assistant.ts","../../src/adapters/telegram/activity.ts","../../src/adapters/telegram/send-queue.ts","../../src/adapters/telegram/action-detect.ts","../../src/adapters/telegram/tool-call-tracker.ts","../../src/adapters/telegram/streaming.ts","../../src/adapters/telegram/draft-manager.ts","../../src/adapters/telegram/skill-command-manager.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 { 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\n// Valid state transitions: from → Set<to>\nconst VALID_TRANSITIONS: Record<SessionStatus, Set<SessionStatus>> = {\n initializing: new Set([\"active\", \"error\"]),\n active: new Set([\"error\", \"finished\", \"cancelled\"]),\n error: new Set([\"active\"]),\n cancelled: new Set([\"active\"]),\n finished: new Set(),\n};\n\nexport interface SessionEvents {\n agent_event: (event: AgentEvent) => void;\n permission_request: (request: PermissionRequest) => void;\n session_end: (reason: string) => void;\n status_change: (from: SessionStatus, to: SessionStatus) => void;\n named: (name: 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 private _status: SessionStatus = \"initializing\";\n name?: string;\n createdAt: Date = new Date();\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.fail(\"Prompt execution failed\");\n this.log.error({ err }, \"Prompt execution failed\");\n },\n );\n }\n\n // --- State Machine ---\n\n get status(): SessionStatus {\n return this._status;\n }\n\n\n /** Transition to active — from initializing, error, or cancelled */\n activate(): void {\n this.transition(\"active\");\n }\n\n /** Transition to error — from initializing or active */\n fail(reason: string): void {\n this.transition(\"error\");\n this.emit(\"error\", new Error(reason));\n }\n\n /** Transition to finished — from active only. Emits session_end for backward compat. */\n finish(reason?: string): void {\n this.transition(\"finished\");\n this.emit(\"session_end\", reason ?? \"completed\");\n }\n\n /** Transition to cancelled — from active only (terminal session cancel) */\n markCancelled(): void {\n this.transition(\"cancelled\");\n }\n\n private transition(to: SessionStatus): void {\n const from = this._status;\n const allowed = VALID_TRANSITIONS[from];\n if (!allowed?.has(to)) {\n throw new Error(\n `Invalid session transition: ${from} → ${to}`,\n );\n }\n this._status = to;\n this.log.debug({ from, to }, \"Session status transition\");\n this.emit(\"status_change\", from, to);\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 if (this._status === \"initializing\") {\n this.activate();\n }\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 // Emit named event — SessionBridge listens to rename the thread\n this.emit(\"named\", this.name);\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.activate();\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 /** Cancel the current prompt and clear the queue. Stays in active state. */\n async abortPrompt(): Promise<void> {\n this.queue.clear();\n this.log.info(\"Prompt aborted\");\n await this.agentInstance.cancel();\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\";\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 dangerousMode: false,\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 getSessionByAgentSessionId(agentSessionId: string): Session | undefined {\n for (const session of this.sessions.values()) {\n if (session.agentSessionId === agentSessionId) {\n return session;\n }\n }\n return undefined;\n }\n\n getRecordByAgentSessionId(agentSessionId: string): import(\"./types.js\").SessionRecord | undefined {\n return this.store?.findByAgentSessionId(agentSessionId);\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 patchRecord(\n sessionId: string,\n patch: Partial<import(\"./types.js\").SessionRecord>,\n ): Promise<void> {\n if (!this.store) return;\n const record = this.store.get(sessionId);\n if (record) {\n await this.store.save({ ...record, ...patch });\n } else if (patch.sessionId) {\n // Initial save — treat patch as full record\n await this.store.save(patch as import(\"./types.js\").SessionRecord);\n }\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.abortPrompt();\n session.markCancelled();\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 listRecords(filter?: { statuses?: string[] }): import(\"./types.js\").SessionRecord[] {\n if (!this.store) return [];\n let records = this.store.list();\n if (filter?.statuses?.length) {\n records = records.filter(r => filter.statuses!.includes(r.status));\n }\n return records;\n }\n\n async removeRecord(sessionId: string): Promise<void> {\n if (!this.store) return;\n await this.store.remove(sessionId);\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 { Session } from \"./session.js\";\nimport type { ChannelAdapter } from \"./channel.js\";\nimport type { MessageTransformer } from \"./message-transformer.js\";\nimport type { NotificationManager } from \"./notification.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { AgentEvent, PermissionRequest, SessionStatus } from \"./types.js\";\nimport { createChildLogger } from \"./log.js\";\n\nconst log = createChildLogger({ module: \"session-bridge\" });\n\nexport interface BridgeDeps {\n messageTransformer: MessageTransformer;\n notificationManager: NotificationManager;\n sessionManager: SessionManager;\n}\n\nexport class SessionBridge {\n private connected = false;\n private agentEventHandler?: (event: AgentEvent) => void;\n private statusChangeHandler?: (from: SessionStatus, to: SessionStatus) => void;\n private namedHandler?: (name: string) => void;\n\n constructor(\n private session: Session,\n private adapter: ChannelAdapter,\n private deps: BridgeDeps,\n ) {}\n\n connect(): void {\n if (this.connected) return;\n this.connected = true;\n\n this.wireAgentToSession();\n this.wireSessionToAdapter();\n this.wirePermissions();\n this.wireLifecycle();\n }\n\n disconnect(): void {\n if (!this.connected) return;\n this.connected = false;\n\n if (this.agentEventHandler) {\n this.session.off(\"agent_event\", this.agentEventHandler);\n }\n if (this.statusChangeHandler) {\n this.session.off(\"status_change\", this.statusChangeHandler);\n }\n if (this.namedHandler) {\n this.session.off(\"named\", this.namedHandler);\n }\n\n // Reset agent callbacks to no-op\n this.session.agentInstance.onSessionUpdate = () => {};\n this.session.agentInstance.onPermissionRequest = async () => \"\";\n }\n\n private wireAgentToSession(): void {\n this.session.agentInstance.onSessionUpdate = (event: AgentEvent) => {\n this.session.emit(\"agent_event\", event);\n };\n }\n\n private wireSessionToAdapter(): void {\n const session = this.session;\n const ctx = {\n get id() { return session.id; },\n get workingDirectory() { return session.workingDirectory; },\n };\n\n this.agentEventHandler = (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 this.adapter.sendMessage(\n this.session.id,\n this.deps.messageTransformer.transform(event, ctx),\n );\n break;\n\n case \"session_end\":\n this.session.finish(event.reason);\n this.adapter.cleanupSkillCommands(this.session.id);\n this.adapter.sendMessage(\n this.session.id,\n this.deps.messageTransformer.transform(event),\n );\n this.deps.notificationManager.notify(this.session.channelId, {\n sessionId: this.session.id,\n sessionName: this.session.name,\n type: \"completed\",\n summary: `Session \"${this.session.name || this.session.id}\" completed`,\n });\n break;\n\n case \"error\":\n this.session.fail(event.message);\n this.adapter.cleanupSkillCommands(this.session.id);\n this.adapter.sendMessage(\n this.session.id,\n this.deps.messageTransformer.transform(event),\n );\n this.deps.notificationManager.notify(this.session.channelId, {\n sessionId: this.session.id,\n sessionName: this.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 this.adapter.sendSkillCommands(this.session.id, event.commands);\n break;\n }\n };\n\n this.session.on(\"agent_event\", this.agentEventHandler);\n }\n\n private wirePermissions(): void {\n this.session.agentInstance.onPermissionRequest = async (\n request: PermissionRequest,\n ) => {\n this.session.emit(\"permission_request\", request);\n\n // Set pending BEFORE sending UI to avoid race condition\n const promise = this.session.permissionGate.setPending(request);\n\n // Send permission UI to session topic\n await this.adapter.sendPermissionRequest(this.session.id, request);\n\n // Wait for user response — adapter resolves this promise\n return promise;\n };\n }\n\n private wireLifecycle(): void {\n // Persist status changes and auto-disconnect on terminal states\n this.statusChangeHandler = (from: SessionStatus, to: SessionStatus) => {\n this.deps.sessionManager.patchRecord(this.session.id, {\n status: to,\n lastActiveAt: new Date().toISOString(),\n });\n\n // Auto-disconnect on terminal states\n if (to === \"finished\" || to === \"cancelled\") {\n // Disconnect on next tick so current event handlers can complete\n queueMicrotask(() => this.disconnect());\n }\n };\n this.session.on(\"status_change\", this.statusChangeHandler);\n\n // Persist and relay name changes\n this.namedHandler = (name: string) => {\n this.deps.sessionManager.patchRecord(this.session.id, { name });\n this.adapter.renameSessionThread(this.session.id, name);\n };\n this.session.on(\"named\", this.namedHandler);\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 { SessionBridge } from \"./session-bridge.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 { IncomingMessage } from \"./types.js\";\nimport type { TunnelService } from \"../tunnel/tunnel-service.js\";\nimport { getAgentCapabilities } from \"./agent-registry.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 // Hot-reload: handle config changes that need side effects\n this.configManager.on('config:changed', async ({ path: configPath, value }: { path: string; value: unknown }) => {\n if (configPath === 'logging.level' && typeof value === 'string') {\n const { setLogLevel } = await import('./log.js')\n setLogLevel(value)\n log.info({ level: value }, 'Log level changed at runtime')\n }\n })\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) {\n log.warn(\n { channelId: message.channelId, threadId: message.threadId },\n \"No session found for thread (in-memory miss + lazy resume returned null)\",\n );\n return;\n }\n\n // Update activity timestamp\n this.sessionManager.patchRecord(session.id, { lastActiveAt: new Date().toISOString() });\n\n // Forward to session\n await session.enqueuePrompt(message.text);\n }\n\n // --- Unified Session Creation Pipeline ---\n\n async createSession(params: {\n channelId: string;\n agentName: string;\n workingDirectory: string;\n resumeAgentSessionId?: string;\n existingSessionId?: string;\n createThread?: boolean;\n initialName?: string;\n }): Promise<Session> {\n // 1. Spawn or resume agent\n const agentInstance = params.resumeAgentSessionId\n ? await this.agentManager.resume(\n params.agentName,\n params.workingDirectory,\n params.resumeAgentSessionId,\n )\n : await this.agentManager.spawn(\n params.agentName,\n params.workingDirectory,\n );\n\n // 2. Create Session instance\n const session = new Session({\n id: params.existingSessionId,\n channelId: params.channelId,\n agentName: params.agentName,\n workingDirectory: params.workingDirectory,\n agentInstance,\n });\n session.agentSessionId = agentInstance.sessionId;\n if (params.initialName) {\n session.name = params.initialName;\n }\n\n // 3. Register in SessionManager\n this.sessionManager.registerSession(session);\n\n // 4. Create thread if needed\n const adapter = this.adapters.get(params.channelId);\n if (params.createThread && adapter) {\n const threadId = await adapter.createSessionThread(\n session.id,\n params.initialName ?? `🔄 ${params.agentName} — New Session`,\n );\n session.threadId = threadId;\n }\n\n // 5. Connect SessionBridge\n if (adapter) {\n const bridge = this.createBridge(session, adapter);\n bridge.connect();\n }\n\n // 6. Persist initial record\n // Preserve existing platform data (e.g. topicId) when resuming an existing session\n const existingRecord = this.sessionStore?.get(session.id);\n const platform: Record<string, unknown> = {\n ...(existingRecord?.platform ?? {}),\n };\n if (session.threadId) {\n platform.topicId = Number(session.threadId);\n }\n await this.sessionManager.patchRecord(session.id, {\n sessionId: session.id,\n agentSessionId: agentInstance.sessionId,\n agentName: params.agentName,\n workingDir: params.workingDirectory,\n channelId: params.channelId,\n status: session.status,\n createdAt: session.createdAt.toISOString(),\n lastActiveAt: new Date().toISOString(),\n name: session.name,\n platform,\n });\n\n log.info(\n { sessionId: session.id, agentName: params.agentName },\n \"Session created via pipeline\",\n );\n return session;\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 return this.createSession({\n channelId,\n agentName: resolvedAgent,\n workingDirectory: resolvedWorkspace,\n });\n }\n\n async adoptSession(\n agentName: string,\n agentSessionId: string,\n cwd: string,\n ): Promise<\n | { ok: true; sessionId: string; threadId: string; status: \"adopted\" | \"existing\" }\n | { ok: false; error: string; message: string }\n > {\n // 1. Validate agent supports resume\n const caps = getAgentCapabilities(agentName);\n if (!caps.supportsResume) {\n return { ok: false, error: \"agent_not_supported\", message: `Agent '${agentName}' does not support session resume` };\n }\n\n const agentDef = this.agentManager.getAgent(agentName);\n if (!agentDef) {\n return { ok: false, error: \"agent_not_supported\", message: `Agent '${agentName}' not found` };\n }\n\n // 2. Validate cwd\n const { existsSync } = await import(\"node:fs\");\n if (!existsSync(cwd)) {\n return { ok: false, error: \"invalid_cwd\", message: `Directory does not exist: ${cwd}` };\n }\n\n // 3. Check session limit\n const maxSessions = this.configManager.get().security.maxConcurrentSessions;\n if (this.sessionManager.listSessions().length >= maxSessions) {\n return { ok: false, error: \"session_limit\", message: \"Maximum concurrent sessions reached\" };\n }\n\n // 4. Check if session already exists\n const existingRecord = this.sessionManager.getRecordByAgentSessionId(agentSessionId);\n if (existingRecord) {\n const platform = existingRecord.platform as { topicId?: number } | undefined;\n if (platform?.topicId) {\n const adapter = this.adapters.values().next().value;\n if (adapter) {\n try {\n await adapter.sendMessage(existingRecord.sessionId, {\n type: \"text\",\n text: \"Session resumed from CLI.\",\n });\n } catch { /* Topic may be deleted */ }\n }\n return {\n ok: true,\n sessionId: existingRecord.sessionId,\n threadId: String(platform.topicId),\n status: \"existing\",\n };\n }\n }\n\n // 5. Find default adapter\n const firstEntry = this.adapters.entries().next().value;\n if (!firstEntry) {\n return { ok: false, error: \"no_adapter\", message: \"No channel adapter registered\" };\n }\n const [adapterChannelId] = firstEntry;\n\n // 6. Create session via unified pipeline\n let session: Session;\n try {\n session = await this.createSession({\n channelId: adapterChannelId,\n agentName,\n workingDirectory: cwd,\n resumeAgentSessionId: agentSessionId,\n createThread: true,\n initialName: \"Adopted session\",\n });\n } catch (err) {\n return {\n ok: false,\n error: \"resume_failed\",\n message: `Failed to resume session: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n\n // 7. Update store with adopt-specific fields\n await this.sessionManager.patchRecord(session.id, {\n originalAgentSessionId: agentSessionId,\n platform: { topicId: Number(session.threadId) },\n });\n\n return {\n ok: true,\n sessionId: session.id,\n threadId: session.threadId,\n status: \"adopted\",\n };\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) {\n log.debug(\n { threadId: message.threadId, channelId: message.channelId },\n \"No session record found for thread\",\n );\n return null;\n }\n\n // Don't resume cancelled/error sessions\n if (record.status === \"cancelled\" || record.status === \"error\") {\n log.debug(\n { threadId: message.threadId, sessionId: record.sessionId, status: record.status },\n \"Skipping resume of cancelled/error session\",\n );\n return null;\n }\n\n log.info(\n { threadId: message.threadId, sessionId: record.sessionId, status: record.status },\n \"Lazy resume: found record, attempting resume\",\n );\n\n const resumePromise = (async (): Promise<Session | null> => {\n try {\n const session = await this.createSession({\n channelId: record.channelId,\n agentName: record.agentName,\n workingDirectory: record.workingDir,\n resumeAgentSessionId: record.agentSessionId,\n existingSessionId: record.sessionId,\n initialName: record.name,\n });\n session.threadId = message.threadId;\n session.activate();\n session.dangerousMode = record.dangerousMode ?? false;\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 // Send error feedback to user instead of silent drop\n const adapter = this.adapters.get(message.channelId);\n if (adapter) {\n try {\n await adapter.sendMessage(message.threadId, {\n type: \"error\",\n text: `⚠️ Failed to resume session: ${err instanceof Error ? err.message : String(err)}`,\n });\n } catch { /* best effort */ }\n }\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 /** Create a SessionBridge for the given session and adapter */\n createBridge(session: Session, adapter: ChannelAdapter): SessionBridge {\n return new SessionBridge(session, adapter, {\n messageTransformer: this.messageTransformer,\n notificationManager: this.notificationManager,\n sessionManager: this.sessionManager,\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 findByAgentSessionId(agentSessionId: string): 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 findByAgentSessionId(agentSessionId: string): SessionRecord | undefined {\n return [...this.records.values()].find(\n (r) =>\n r.agentSessionId === agentSessionId ||\n r.originalAgentSessionId === agentSessionId,\n );\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 deleteSessionThread(sessionId: 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 async deleteSessionThread(_sessionId: 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 { fileURLToPath } from 'node:url'\nimport type { OpenACPCore } from './core.js'\nimport type { TopicManager } from './topic-manager.js'\nimport { createChildLogger } from './log.js'\nimport { getAgentCapabilities } from './agent-registry.js'\n\nconst log = createChildLogger({ module: 'api-server' })\n\nconst DEFAULT_PORT_FILE = path.join(os.homedir(), '.openacp', 'api.port')\n\nlet cachedVersion: string | undefined\n\nfunction getVersion(): string {\n if (cachedVersion) return cachedVersion\n try {\n const __filename = fileURLToPath(import.meta.url)\n const pkgPath = path.resolve(path.dirname(__filename), '../../package.json')\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n cachedVersion = pkg.version ?? '0.0.0-dev'\n } catch {\n cachedVersion = '0.0.0-dev'\n }\n return cachedVersion!\n}\n\nconst SENSITIVE_KEYS = ['botToken', 'token', 'apiKey', 'secret', 'password', 'webhookSecret']\n\nfunction redactConfig(config: unknown): unknown {\n const redacted = structuredClone(config)\n redactDeep(redacted as Record<string, unknown>)\n return redacted\n}\n\nfunction redactDeep(obj: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(obj)) {\n if (SENSITIVE_KEYS.includes(key) && typeof value === 'string') {\n obj[key] = '***'\n } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n redactDeep(value as Record<string, unknown>)\n }\n }\n}\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 private startedAt = Date.now()\n\n constructor(\n private core: OpenACPCore,\n private config: ApiConfig,\n portFilePath?: string,\n private topicManager?: TopicManager,\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/adopt') {\n await this.handleAdoptSession(req, res)\n } else if (method === 'POST' && url === '/api/sessions') {\n await this.handleCreateSession(req, res)\n } else if (method === 'POST' && url.match(/^\\/api\\/sessions\\/([^/]+)\\/prompt$/)) {\n const sessionId = decodeURIComponent(url.match(/^\\/api\\/sessions\\/([^/]+)\\/prompt$/)![1])\n await this.handleSendPrompt(sessionId, req, res)\n } else if (method === 'PATCH' && url.match(/^\\/api\\/sessions\\/([^/]+)\\/dangerous$/)) {\n const sessionId = decodeURIComponent(url.match(/^\\/api\\/sessions\\/([^/]+)\\/dangerous$/)![1])\n await this.handleToggleDangerous(sessionId, req, res)\n } else if (method === 'GET' && url.match(/^\\/api\\/sessions\\/([^/]+)$/)) {\n const sessionId = decodeURIComponent(url.match(/^\\/api\\/sessions\\/([^/]+)$/)![1])\n await this.handleGetSession(sessionId, res)\n } else if (method === 'DELETE' && url.match(/^\\/api\\/sessions\\/([^/]+)$/)) {\n const sessionId = decodeURIComponent(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 if (method === 'GET' && url === '/api/health') {\n await this.handleHealth(res)\n } else if (method === 'GET' && url === '/api/version') {\n await this.handleVersion(res)\n } else if (method === 'GET' && url === '/api/config/editable') {\n await this.handleGetEditableConfig(res)\n } else if (method === 'GET' && url === '/api/config') {\n await this.handleGetConfig(res)\n } else if (method === 'PATCH' && url === '/api/config') {\n await this.handleUpdateConfig(req, res)\n } else if (method === 'GET' && url === '/api/adapters') {\n await this.handleListAdapters(res)\n } else if (method === 'GET' && url === '/api/tunnel') {\n await this.handleTunnelStatus(res)\n } else if (method === 'POST' && url === '/api/notify') {\n await this.handleNotify(req, res)\n } else if (method === 'POST' && url === '/api/restart') {\n await this.handleRestart(res)\n } else if (method === 'GET' && url.match(/^\\/api\\/topics(\\?.*)?$/)) {\n await this.handleListTopics(url, res)\n } else if (method === 'POST' && url === '/api/topics/cleanup') {\n await this.handleCleanupTopics(req, res)\n } else if (method === 'DELETE' && url.match(/^\\/api\\/topics\\/([^/?]+)/)) {\n const match = url.match(/^\\/api\\/topics\\/([^/?]+)/)!\n await this.handleDeleteTopic(decodeURIComponent(match[1]), url, 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 resolvedAgent = agent || config.defaultAgent\n const resolvedWorkspace = this.core.configManager.resolveWorkspace(\n workspace || config.agents[resolvedAgent]?.workingDirectory,\n )\n\n const session = await this.core.createSession({\n channelId,\n agentName: resolvedAgent,\n workingDirectory: resolvedWorkspace,\n createThread: !!adapter,\n initialName: `🔄 ${resolvedAgent} — New Session`,\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 handleSendPrompt(sessionId: string, req: http.IncomingMessage, 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\n if (session.status === 'cancelled' || session.status === 'finished' || session.status === 'error') {\n this.sendJson(res, 400, { error: `Session is ${session.status}` })\n return\n }\n\n const body = await this.readBody(req)\n let prompt: string | undefined\n if (body) {\n try {\n const parsed = JSON.parse(body)\n prompt = parsed.prompt\n } catch {\n this.sendJson(res, 400, { error: 'Invalid JSON body' })\n return\n }\n }\n\n if (!prompt) {\n this.sendJson(res, 400, { error: 'Missing prompt' })\n return\n }\n\n session.enqueuePrompt(prompt).catch(() => {})\n this.sendJson(res, 200, { ok: true, sessionId, queueDepth: session.queueDepth })\n }\n\n private async handleGetSession(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\n this.sendJson(res, 200, {\n session: {\n id: session.id,\n agent: session.agentName,\n status: session.status,\n name: session.name ?? null,\n workspace: session.workingDirectory,\n createdAt: session.createdAt.toISOString(),\n dangerousMode: session.dangerousMode,\n queueDepth: session.queueDepth,\n promptRunning: session.promptRunning,\n threadId: session.threadId,\n channelId: session.channelId,\n agentSessionId: session.agentSessionId,\n },\n })\n }\n\n private async handleToggleDangerous(sessionId: string, req: http.IncomingMessage, 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\n const body = await this.readBody(req)\n let enabled: boolean | undefined\n if (body) {\n try {\n const parsed = JSON.parse(body)\n enabled = parsed.enabled\n } catch {\n this.sendJson(res, 400, { error: 'Invalid JSON body' })\n return\n }\n }\n\n if (typeof enabled !== 'boolean') {\n this.sendJson(res, 400, { error: 'Missing enabled boolean' })\n return\n }\n\n session.dangerousMode = enabled\n await this.core.sessionManager.patchRecord(sessionId, { dangerousMode: enabled })\n this.sendJson(res, 200, { ok: true, dangerousMode: enabled })\n }\n\n private async handleHealth(res: http.ServerResponse): Promise<void> {\n const activeSessions = this.core.sessionManager.listSessions()\n const allRecords = this.core.sessionManager.listRecords()\n const mem = process.memoryUsage()\n const tunnel = this.core.tunnelService\n\n this.sendJson(res, 200, {\n status: 'ok',\n uptime: Date.now() - this.startedAt,\n version: getVersion(),\n memory: {\n rss: mem.rss,\n heapUsed: mem.heapUsed,\n heapTotal: mem.heapTotal,\n },\n sessions: {\n active: activeSessions.filter(s => s.status === 'active' || s.status === 'initializing').length,\n total: allRecords.length,\n },\n adapters: Array.from(this.core.adapters.keys()),\n tunnel: tunnel ? { enabled: true, url: tunnel.getPublicUrl() } : { enabled: false },\n })\n }\n\n private async handleVersion(res: http.ServerResponse): Promise<void> {\n this.sendJson(res, 200, { version: getVersion() })\n }\n\n private async handleGetEditableConfig(res: http.ServerResponse): Promise<void> {\n const { getSafeFields, resolveOptions, getConfigValue } = await import('./config-registry.js')\n const config = this.core.configManager.get()\n const safeFields = getSafeFields()\n\n const fields = safeFields.map((def) => ({\n path: def.path,\n displayName: def.displayName,\n group: def.group,\n type: def.type,\n options: resolveOptions(def, config),\n value: getConfigValue(config, def.path),\n hotReload: def.hotReload,\n }))\n\n this.sendJson(res, 200, { fields })\n }\n\n private async handleGetConfig(res: http.ServerResponse): Promise<void> {\n const config = this.core.configManager.get()\n this.sendJson(res, 200, { config: redactConfig(config) })\n }\n\n private async handleUpdateConfig(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const body = await this.readBody(req)\n let configPath: string | undefined\n let value: unknown\n\n if (body) {\n try {\n const parsed = JSON.parse(body)\n configPath = parsed.path\n value = parsed.value\n } catch {\n this.sendJson(res, 400, { error: 'Invalid JSON body' })\n return\n }\n }\n\n if (!configPath) {\n this.sendJson(res, 400, { error: 'Missing path' })\n return\n }\n\n // Pre-validate by cloning config and applying the change\n const currentConfig = this.core.configManager.get()\n const cloned = structuredClone(currentConfig) as Record<string, unknown>\n const parts = configPath.split('.')\n let target: Record<string, unknown> = cloned\n for (let i = 0; i < parts.length - 1; i++) {\n if (target[parts[i]] && typeof target[parts[i]] === 'object' && !Array.isArray(target[parts[i]])) {\n target = target[parts[i]] as Record<string, unknown>\n } else {\n this.sendJson(res, 400, { error: 'Invalid config path' })\n return\n }\n }\n\n const lastKey = parts[parts.length - 1]\n if (!(lastKey in target)) {\n this.sendJson(res, 400, { error: 'Invalid config path' })\n return\n }\n\n target[lastKey] = value\n\n // Validate with Zod\n const { ConfigSchema } = await import('./config.js')\n const result = ConfigSchema.safeParse(cloned)\n if (!result.success) {\n this.sendJson(res, 400, {\n error: 'Validation failed',\n details: result.error.issues.map(i => ({ path: i.path.join('.'), message: i.message })),\n })\n return\n }\n\n // Convert dot-path to nested object for save\n const updates: Record<string, unknown> = {}\n let updateTarget = updates\n for (let i = 0; i < parts.length - 1; i++) {\n updateTarget[parts[i]] = {}\n updateTarget = updateTarget[parts[i]] as Record<string, unknown>\n }\n updateTarget[lastKey] = value\n\n await this.core.configManager.save(updates, configPath)\n\n const { isHotReloadable } = await import('./config-registry.js')\n const needsRestart = !isHotReloadable(configPath!)\n\n this.sendJson(res, 200, {\n ok: true,\n needsRestart,\n config: redactConfig(this.core.configManager.get()),\n })\n }\n\n private async handleListAdapters(res: http.ServerResponse): Promise<void> {\n const adapters = Array.from(this.core.adapters.entries()).map(([name]) => ({\n name,\n type: 'built-in' as const,\n }))\n this.sendJson(res, 200, { adapters })\n }\n\n private async handleTunnelStatus(res: http.ServerResponse): Promise<void> {\n const tunnel = this.core.tunnelService\n if (tunnel) {\n this.sendJson(res, 200, { enabled: true, url: tunnel.getPublicUrl(), provider: this.core.configManager.get().tunnel.provider })\n } else {\n this.sendJson(res, 200, { enabled: false })\n }\n }\n\n private async handleNotify(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const body = await this.readBody(req)\n let message: string | undefined\n if (body) {\n try {\n const parsed = JSON.parse(body)\n message = parsed.message\n } catch {\n this.sendJson(res, 400, { error: 'Invalid JSON body' })\n return\n }\n }\n\n if (!message) {\n this.sendJson(res, 400, { error: 'Missing message' })\n return\n }\n\n await this.core.notificationManager.notifyAll({\n sessionId: 'system',\n type: 'completed',\n summary: message,\n })\n this.sendJson(res, 200, { ok: true })\n }\n\n private async handleRestart(res: http.ServerResponse): Promise<void> {\n if (!this.core.requestRestart) {\n this.sendJson(res, 501, { error: 'Restart not available' })\n return\n }\n\n this.sendJson(res, 200, { ok: true, message: 'Restarting...' })\n setImmediate(() => this.core.requestRestart!())\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.abortPrompt()\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 handleAdoptSession(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const body = await this.readBody(req)\n if (!body) {\n return this.sendJson(res, 400, { error: 'bad_request', message: 'Empty request body' })\n }\n\n let parsed: { agent?: string; agentSessionId?: string; cwd?: string }\n try {\n parsed = JSON.parse(body)\n } catch {\n return this.sendJson(res, 400, { error: 'bad_request', message: 'Invalid JSON' })\n }\n\n const { agent, agentSessionId, cwd } = parsed\n\n if (!agent || !agentSessionId) {\n return this.sendJson(res, 400, { error: 'bad_request', message: 'Missing required fields: agent, agentSessionId' })\n }\n\n const result = await this.core.adoptSession(agent, agentSessionId, cwd ?? process.cwd())\n\n if (result.ok) {\n return this.sendJson(res, 200, result)\n } else {\n const status = result.error === 'session_limit' ? 429 : result.error === 'agent_not_supported' ? 400 : 500\n return this.sendJson(res, status, result)\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 const agentsWithCaps = agents.map((a) => ({\n ...a,\n capabilities: getAgentCapabilities(a.name),\n }))\n this.sendJson(res, 200, { agents: agentsWithCaps, default: defaultAgent })\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 async handleListTopics(url: string, res: http.ServerResponse): Promise<void> {\n if (!this.topicManager) { this.sendJson(res, 501, { error: 'Topic management not available' }); return }\n const params = new URL(url, 'http://localhost').searchParams\n const statusParam = params.get('status')\n const filter = statusParam ? { statuses: statusParam.split(',') } : undefined\n const topics = this.topicManager.listTopics(filter)\n this.sendJson(res, 200, { topics })\n }\n\n private async handleDeleteTopic(sessionId: string, url: string, res: http.ServerResponse): Promise<void> {\n if (!this.topicManager) { this.sendJson(res, 501, { error: 'Topic management not available' }); return }\n const params = new URL(url, 'http://localhost').searchParams\n const force = params.get('force') === 'true'\n const result = await this.topicManager.deleteTopic(sessionId, force ? { confirmed: true } : undefined)\n if (result.ok) {\n this.sendJson(res, 200, result)\n } else if (result.needsConfirmation) {\n this.sendJson(res, 409, { error: 'Session is active', needsConfirmation: true, session: result.session })\n } else if (result.error === 'Cannot delete system topic') {\n this.sendJson(res, 403, { error: result.error })\n } else {\n this.sendJson(res, 404, { error: result.error ?? 'Not found' })\n }\n }\n\n private async handleCleanupTopics(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n if (!this.topicManager) { this.sendJson(res, 501, { error: 'Topic management not available' }); return }\n const body = await this.readBody(req)\n let statuses: string[] | undefined\n if (body) {\n try { statuses = JSON.parse(body).statuses } catch { /* use defaults */ }\n }\n const result = await this.topicManager.cleanup(statuses)\n this.sendJson(res, 200, result)\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 type { SessionManager } from './session-manager.js'\nimport type { IChannelAdapter } from './channel.js'\nimport type { SessionRecord } from './types.js'\nimport { createChildLogger } from './log.js'\n\nconst log = createChildLogger({ module: 'topic-manager' })\n\nexport interface TopicInfo {\n sessionId: string\n topicId: number | null\n name: string | null\n status: string\n agentName: string\n lastActiveAt: string\n}\n\nexport interface DeleteTopicResult {\n ok: boolean\n needsConfirmation?: boolean\n topicId?: number | null\n session?: { id: string; name: string | null; status: string }\n error?: string\n}\n\nexport interface CleanupResult {\n deleted: string[]\n failed: { sessionId: string; error: string }[]\n}\n\ninterface SystemTopicIds {\n notificationTopicId: number | null\n assistantTopicId: number | null\n}\n\nexport class TopicManager {\n constructor(\n private sessionManager: SessionManager,\n private adapter: IChannelAdapter | null,\n private systemTopicIds: SystemTopicIds,\n ) {}\n\n listTopics(filter?: { statuses?: string[] }): TopicInfo[] {\n const records = this.sessionManager.listRecords(filter)\n return records\n .filter(r => !this.isSystemTopic(r))\n .filter(r => !filter?.statuses?.length || filter.statuses.includes(r.status))\n .map(r => ({\n sessionId: r.sessionId,\n topicId: (r.platform as Record<string, unknown>)?.topicId as number ?? null,\n name: r.name ?? null,\n status: r.status,\n agentName: r.agentName,\n lastActiveAt: r.lastActiveAt,\n }))\n }\n\n async deleteTopic(sessionId: string, options?: { confirmed?: boolean }): Promise<DeleteTopicResult> {\n const records = this.sessionManager.listRecords()\n const record = records.find(r => r.sessionId === sessionId)\n if (!record) return { ok: false, error: 'Session not found' }\n\n if (this.isSystemTopic(record)) return { ok: false, error: 'Cannot delete system topic' }\n\n const isActive = record.status === 'active' || record.status === 'initializing'\n if (isActive && !options?.confirmed) {\n return {\n ok: false,\n needsConfirmation: true,\n session: { id: record.sessionId, name: record.name ?? null, status: record.status },\n }\n }\n\n if (isActive) {\n await this.sessionManager.cancelSession(sessionId)\n }\n\n const topicId = (record.platform as Record<string, unknown>)?.topicId as number ?? null\n if (this.adapter && topicId) {\n try {\n await this.adapter.deleteSessionThread(sessionId)\n } catch (err) {\n log.warn({ err, sessionId, topicId }, 'Failed to delete platform thread, removing record anyway')\n }\n }\n\n await this.sessionManager.removeRecord(sessionId)\n return { ok: true, topicId }\n }\n\n async cleanup(statuses?: string[]): Promise<CleanupResult> {\n const targetStatuses = statuses?.length ? statuses : ['finished', 'error', 'cancelled']\n const records = this.sessionManager.listRecords({ statuses: targetStatuses })\n const targets = records\n .filter(r => !this.isSystemTopic(r))\n .filter(r => targetStatuses.includes(r.status))\n\n const deleted: string[] = []\n const failed: { sessionId: string; error: string }[] = []\n\n for (const record of targets) {\n try {\n // Cancel active/initializing sessions to prevent orphaned agent processes\n const isActive = record.status === 'active' || record.status === 'initializing'\n if (isActive) {\n await this.sessionManager.cancelSession(record.sessionId)\n }\n\n const topicId = (record.platform as Record<string, unknown>)?.topicId as number | undefined\n if (this.adapter && topicId) {\n try {\n await this.adapter.deleteSessionThread(record.sessionId)\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId }, 'Failed to delete platform thread during cleanup')\n }\n }\n await this.sessionManager.removeRecord(record.sessionId)\n deleted.push(record.sessionId)\n } catch (err) {\n failed.push({ sessionId: record.sessionId, error: err instanceof Error ? err.message : String(err) })\n }\n }\n\n return { deleted, failed }\n }\n\n private isSystemTopic(record: SessionRecord): boolean {\n const topicId = (record.platform as Record<string, unknown>)?.topicId as number | undefined\n if (!topicId) return false\n return topicId === this.systemTopicIds.notificationTopicId\n || topicId === this.systemTopicIds.assistantTopicId\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 {\n ensureTopics,\n createSessionTopic,\n renameSessionTopic,\n} from \"./topics.js\";\nimport {\n setupCommands,\n setupMenuCallbacks,\n setupDangerousModeCallbacks,\n setupIntegrateCallbacks,\n buildMenuKeyboard,\n handlePendingWorkspaceInput,\n STATIC_COMMANDS,\n} from \"./commands/index.js\";\nimport { PermissionHandler } from \"./permissions.js\";\nimport {\n spawnAssistant,\n handleAssistantMessage,\n redirectToAssistant,\n buildWelcomeMessage,\n type SpawnAssistantResult,\n} from \"./assistant.js\";\nimport { escapeHtml } from \"./formatting.js\";\nimport { ActivityTracker } from \"./activity.js\";\nimport { TelegramSendQueue } from \"./send-queue.js\";\nimport {\n setupActionCallbacks,\n} from \"./action-detect.js\";\nimport { ToolCallTracker } from \"./tool-call-tracker.js\";\nimport { DraftManager } from \"./draft-manager.js\";\nimport { SkillCommandManager } from \"./skill-command-manager.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 permissionHandler!: PermissionHandler;\n private assistantSession: Session | null = null;\n private assistantInitializing = false;\n private notificationTopicId!: number;\n private assistantTopicId!: number;\n private sendQueue = new TelegramSendQueue(3000);\n\n // Extracted managers\n private toolTracker!: ToolCallTracker;\n private draftManager!: DraftManager;\n private skillManager!: SkillCommandManager;\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 // Initialize extracted managers\n this.toolTracker = new ToolCallTracker(this.bot, this.telegramConfig.chatId, this.sendQueue);\n this.draftManager = new DraftManager(this.bot, this.telegramConfig.chatId, this.sendQueue);\n this.skillManager = new SkillCommandManager(\n this.bot,\n this.telegramConfig.chatId,\n this.sendQueue,\n this.core.sessionManager,\n );\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)\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 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 return prev(method, payload, signal);\n });\n\n // Ensure allowed_updates includes callback_query on every poll\n this.bot.api.config.use((prev, method, payload, signal) => {\n if (method === \"getUpdates\") {\n 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\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 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\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 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 setupIntegrateCallbacks(this.bot, this.core as OpenACPCore);\n setupMenuCallbacks(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n { notificationTopicId: this.notificationTopicId, assistantTopicId: this.assistantTopicId },\n () => {\n if (!this.assistantSession) return undefined;\n return {\n topicId: this.assistantTopicId,\n enqueuePrompt: (p: string) => this.assistantSession!.enqueuePrompt(p),\n };\n },\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 respawn: async () => {\n if (this.assistantSession) {\n await this.assistantSession.destroy();\n this.assistantSession = null;\n }\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 ready.then(() => { this.assistantInitializing = false; });\n },\n },\n );\n this.permissionHandler.setupCallbackHandler();\n\n // /handoff command\n this.bot.command(\"handoff\", async (ctx) => {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n if (threadId === this.notificationTopicId || threadId === this.assistantTopicId) {\n await ctx.reply(\"This command only works in session topics.\", {\n message_thread_id: threadId,\n });\n return;\n }\n\n const session = this.core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n const record = session ? undefined : this.core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n\n const agentName = session?.agentName ?? record?.agentName;\n const agentSessionId = session?.agentSessionId ?? record?.agentSessionId;\n\n if (!agentName || !agentSessionId) {\n await ctx.reply(\"No session found for this topic.\", {\n message_thread_id: threadId,\n });\n return;\n }\n\n const { getAgentCapabilities } = await import(\"../../core/agent-registry.js\");\n const caps = getAgentCapabilities(agentName);\n\n if (!caps.supportsResume || !caps.resumeCommand) {\n await ctx.reply(\"This agent does not support session transfer.\", {\n message_thread_id: threadId,\n });\n return;\n }\n\n const command = caps.resumeCommand(agentSessionId);\n\n await ctx.reply(\n `Run this in your terminal to continue the session:\\n\\n<code>${command}</code>`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n },\n );\n });\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\n try {\n const config = this.core.configManager.get();\n const agents = this.core.agentManager.getAvailableAgents();\n const allRecords = this.core.sessionManager.listRecords();\n\n const welcomeText = buildWelcomeMessage({\n activeCount: allRecords.filter(r => r.status === 'active' || r.status === 'initializing').length,\n errorCount: allRecords.filter(r => r.status === 'error').length,\n totalCount: allRecords.length,\n agents: agents.map(a => a.name),\n defaultAgent: config.defaultAgent,\n });\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\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 // Check for pending workspace input from interactive /new flow\n if (await handlePendingWorkspaceInput(ctx, this.core, this.telegramConfig.chatId, this.assistantTopicId)) {\n return;\n }\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 → 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.draftManager.finalize(this.assistantSession.id, 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 → forward to core\n const sessionId = this.core.sessionManager.getSessionByThread(\"telegram\", String(threadId))?.id;\n if (sessionId) await this.draftManager.finalize(sessionId, this.assistantSession?.id);\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 assistant messages during system prompt\n if (this.assistantInitializing && 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 || isNaN(threadId)) {\n log.warn({ sessionId, threadId: session.threadId }, \"Session has no valid threadId, skipping message\");\n return;\n }\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 if (!this.draftManager.hasDraft(sessionId)) {\n const tracker = this.getOrCreateTracker(sessionId, threadId);\n await tracker.onTextStart();\n }\n const draft = this.draftManager.getOrCreate(sessionId, threadId);\n draft.append(content.text);\n this.draftManager.appendText(sessionId, content.text);\n break;\n }\n\n case \"tool_call\": {\n const tracker = this.getOrCreateTracker(sessionId, threadId);\n await tracker.onToolCall();\n await this.draftManager.finalize(sessionId, this.assistantSession?.id);\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 await this.toolTracker.trackNewCall(sessionId, threadId, {\n ...meta,\n viewerFilePath: (content.metadata as any)?.viewerFilePath,\n });\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 await this.toolTracker.updateCall(sessionId, {\n ...meta,\n viewerFilePath: (content.metadata as any)?.viewerFilePath,\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.draftManager.finalize(sessionId, this.assistantSession?.id);\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.draftManager.finalize(sessionId, this.assistantSession?.id);\n this.draftManager.cleanup(sessionId);\n this.toolTracker.cleanup(sessionId);\n await this.skillManager.cleanup(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.draftManager.finalize(sessionId, this.assistantSession?.id);\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(sessionId);\n if (!session) return;\n\n // Auto-approve openacp CLI commands\n if (request.description.includes(\"openacp\")) {\n const allowOption = request.options.find((o) => o.isAllow);\n if (allowOption && session.permissionGate.requestId === request.id) {\n log.info({ sessionId, requestId: request.id }, \"Auto-approving openacp command\");\n session.permissionGate.resolve(allowOption.id);\n }\n return;\n }\n\n // Dangerous mode: auto-approve\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 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 const deepLink = notification.deepLink ?? (() => {\n const session = this.core.sessionManager.getSession(notification.sessionId);\n const threadId = session?.threadId;\n if (!threadId) return undefined;\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(sessionId);\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.patchRecord(sessionId, { name: newName });\n }\n\n async deleteSessionThread(sessionId: string): Promise<void> {\n const record = this.core.sessionManager.getSessionRecord(sessionId);\n const platform = record?.platform as import(\"../../core/types.js\").TelegramPlatformData | undefined;\n const topicId = platform?.topicId;\n if (!topicId) return;\n\n try {\n await this.bot.api.deleteForumTopic(this.telegramConfig.chatId, topicId);\n } catch (err) {\n log.warn({ err, sessionId, topicId }, \"Failed to delete forum topic (may already be deleted)\");\n }\n }\n\n async sendSkillCommands(\n sessionId: string,\n commands: AgentCommand[],\n ): Promise<void> {\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 await this.skillManager.send(sessionId, threadId, commands);\n }\n\n async cleanupSkillCommands(sessionId: string): Promise<void> {\n await this.skillManager.cleanup(sessionId);\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 { buildDangerousModeKeyboard } from \"./admin.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\nconst log = createChildLogger({ module: \"telegram-cmd-new-session\" });\n\ninterface PendingNewSession {\n agentName?: string;\n workspace?: string;\n step: \"agent\" | \"workspace\" | \"workspace_input\" | \"confirm\";\n messageId: number;\n threadId?: number;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst pendingNewSessions = new Map<number, PendingNewSession>();\n\nconst PENDING_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nfunction cleanupPending(userId: number): void {\n const pending = pendingNewSessions.get(userId);\n if (pending) {\n clearTimeout(pending.timer);\n pendingNewSessions.delete(userId);\n }\n}\n\nfunction botFromCtx(ctx: Context): Bot {\n // createSessionTopic only uses bot.api.createForumTopic\n return { api: ctx.api } as unknown as Bot;\n}\n\nexport async function handleNew(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n assistant?: CommandsAssistantContext,\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 // Full args → create directly\n if (agentName && workspace) {\n await createSessionDirect(ctx, core, chatId, agentName, workspace);\n return;\n }\n\n // In assistant topic → forward to assistant for conversational handling\n const currentThreadId = ctx.message?.message_thread_id;\n if (assistant && currentThreadId === assistant.topicId) {\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 project directory to use as workspace.`\n : `User wants to create a new session. Guide them through choosing an agent and workspace (project directory).`;\n await assistantSession.enqueuePrompt(prompt);\n return;\n }\n }\n\n // Outside assistant topic → interactive flow\n const userId = ctx.from?.id;\n if (!userId) return;\n\n const agents = core.agentManager.getAvailableAgents();\n const config = core.configManager.get();\n\n // If agent provided or only 1 agent → skip to workspace step\n if (agentName || agents.length === 1) {\n const selectedAgent = agentName || config.defaultAgent;\n await startWorkspaceStep(ctx, core, chatId, userId, selectedAgent);\n return;\n }\n\n // Multiple agents → show agent selection\n const keyboard = new InlineKeyboard();\n for (const agent of agents) {\n const label = agent.name === config.defaultAgent\n ? `${agent.name} (default)`\n : agent.name;\n keyboard.text(label, `m:new:agent:${agent.name}`).row();\n }\n keyboard.text(\"❌ Cancel\", \"m:new:cancel\");\n\n const msg = await ctx.reply(\n `🤖 <b>Choose an agent:</b>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n\n cleanupPending(userId);\n pendingNewSessions.set(userId, {\n step: \"agent\",\n messageId: msg.message_id,\n threadId: currentThreadId,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nasync function startWorkspaceStep(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n userId: number,\n agentName: string,\n): Promise<void> {\n const config = core.configManager.get();\n const baseDir = config.workspace.baseDir;\n\n const keyboard = new InlineKeyboard()\n .text(`📁 Use ${baseDir}`, \"m:new:ws:default\")\n .row()\n .text(\"✏️ Enter project path\", \"m:new:ws:custom\")\n .row()\n .text(\"❌ Cancel\", \"m:new:cancel\");\n\n const text =\n `📁 <b>Where should ${escapeHtml(agentName)} work?</b>\\n\\n` +\n `Enter the path to your project folder — the agent will read, write, and run code there.\\n\\n` +\n `Or use the default directory below:`;\n\n let msg;\n try {\n const pending = pendingNewSessions.get(userId);\n if (pending?.messageId) {\n await ctx.api.editMessageText(chatId, pending.messageId, text, {\n parse_mode: \"HTML\",\n reply_markup: keyboard,\n });\n msg = { message_id: pending.messageId };\n } else {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n } catch {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n\n cleanupPending(userId);\n pendingNewSessions.set(userId, {\n agentName,\n step: \"workspace\",\n messageId: msg.message_id,\n threadId: ctx.message?.message_thread_id ?? (ctx.callbackQuery as any)?.message?.message_thread_id,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nasync function startConfirmStep(\n ctx: Context,\n chatId: number,\n userId: number,\n agentName: string,\n workspace: string,\n): Promise<void> {\n const keyboard = new InlineKeyboard()\n .text(\"✅ Create\", \"m:new:confirm\")\n .text(\"❌ Cancel\", \"m:new:cancel\");\n\n const text =\n `✅ <b>Ready to create session?</b>\\n\\n` +\n `<b>Agent:</b> ${escapeHtml(agentName)}\\n` +\n `<b>Project:</b> <code>${escapeHtml(workspace)}</code>`;\n\n let msg;\n try {\n const pending = pendingNewSessions.get(userId);\n if (pending?.messageId) {\n await ctx.api.editMessageText(chatId, pending.messageId, text, {\n parse_mode: \"HTML\",\n reply_markup: keyboard,\n });\n msg = { message_id: pending.messageId };\n } else {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n } catch {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n\n cleanupPending(userId);\n pendingNewSessions.set(userId, {\n agentName,\n workspace,\n step: \"confirm\",\n messageId: msg.message_id,\n threadId: ctx.message?.message_thread_id ?? (ctx.callbackQuery as any)?.message?.message_thread_id,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nasync function createSessionDirect(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n agentName: string,\n workspace: string,\n): Promise<number | null> {\n log.info({ userId: ctx.from?.id, agentName, workspace }, \"New session command (direct)\");\n\n let threadId: number | undefined;\n try {\n const topicName = `🔄 New Session`;\n threadId = await createSessionTopic(botFromCtx(ctx), chatId, topicName);\n\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(\"telegram\", agentName, workspace);\n session.threadId = String(threadId);\n\n await core.sessionManager.patchRecord(session.id, { platform: { topicId: threadId } });\n\n const finalName = `🔄 ${session.agentName} — New Session`;\n try {\n await ctx.api.editForumTopic(chatId, threadId, { name: finalName });\n } catch { /* ignore rename failures */ }\n\n await ctx.api.sendMessage(\n chatId,\n `✅ <b>Session started</b>\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>\\n\\n` +\n `This is your coding session — chat here to work with the agent.`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n reply_markup: buildDangerousModeKeyboard(session.id, false),\n },\n );\n\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n return threadId ?? null;\n } catch (err) {\n log.error({ err }, \"Session creation failed\");\n if (threadId) {\n try { await ctx.api.deleteForumTopic(chatId, threadId); } catch { /* ignore */ }\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 return null;\n }\n}\n\nexport async 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.patchRecord(session.id, { platform: {\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\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.patchRecord(session.id, { platform: {\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\n/**\n * Check if a text message is a workspace path input for the interactive new session flow.\n * Returns true if the message was handled (caller should not process further).\n */\nexport async function handlePendingWorkspaceInput(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n assistantTopicId?: number,\n): Promise<boolean> {\n const userId = ctx.from?.id;\n if (!userId) return false;\n const pending = pendingNewSessions.get(userId);\n if (!pending || !ctx.message?.text) return false;\n // Accept text input at both \"workspace\" step (user types directly instead of pressing buttons)\n // and \"workspace_input\" step (user pressed \"Custom path\" button)\n if (pending.step !== \"workspace_input\" && pending.step !== \"workspace\") return false;\n\n // Only intercept in assistant topic (or no-thread/general) — never in session topics\n const threadId = ctx.message.message_thread_id;\n if (threadId && threadId !== assistantTopicId) return false;\n\n let workspace = ctx.message.text.trim();\n if (!workspace || !pending.agentName) {\n await ctx.reply(\"⚠️ Please enter a valid directory path.\", { parse_mode: \"HTML\" });\n return true;\n }\n\n // Relative path (no / or ~ prefix) → resolve against baseDir\n if (!workspace.startsWith(\"/\") && !workspace.startsWith(\"~\")) {\n const baseDir = core.configManager.get().workspace.baseDir;\n workspace = `${baseDir.replace(/\\/$/, \"\")}/${workspace}`;\n }\n\n await startConfirmStep(ctx, chatId, userId, pending.agentName, workspace);\n return true;\n}\n\n/**\n * Start the interactive new session flow (agent → workspace → confirm).\n * Used by action-detect when workspace is not provided.\n */\nexport async function startInteractiveNewSession(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n agentName?: string,\n): Promise<void> {\n const userId = ctx.from?.id;\n if (!userId) return;\n\n const agents = core.agentManager.getAvailableAgents();\n const config = core.configManager.get();\n\n // If agent provided or only 1 agent → skip to workspace step\n if (agentName || agents.length === 1) {\n const selectedAgent = agentName || config.defaultAgent;\n await startWorkspaceStep(ctx, core, chatId, userId, selectedAgent);\n return;\n }\n\n // Multiple agents → show agent selection\n const keyboard = new InlineKeyboard();\n for (const agent of agents) {\n const label = agent.name === config.defaultAgent\n ? `${agent.name} (default)`\n : agent.name;\n keyboard.text(label, `m:new:agent:${agent.name}`).row();\n }\n keyboard.text(\"❌ Cancel\", \"m:new:cancel\");\n\n const msg = await ctx.reply(\n `🤖 <b>Choose an agent:</b>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n\n cleanupPending(userId);\n pendingNewSessions.set(userId, {\n step: \"agent\",\n messageId: msg.message_id,\n threadId: (ctx.callbackQuery as any)?.message?.message_thread_id,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nexport function setupNewSessionCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n): void {\n bot.callbackQuery(/^m:new:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired or network — ignore */ }\n\n if (data.startsWith(\"m:new:agent:\")) {\n const agentName = data.replace(\"m:new:agent:\", \"\");\n const userId = ctx.from?.id;\n if (userId) await startWorkspaceStep(ctx, core, chatId, userId, agentName);\n return;\n }\n if (data === \"m:new:ws:default\") {\n const userId = ctx.from?.id;\n if (!userId) return;\n const pending = pendingNewSessions.get(userId);\n if (!pending?.agentName) return;\n const workspace = core.configManager.get().workspace.baseDir;\n await startConfirmStep(ctx, chatId, userId, pending.agentName, workspace);\n return;\n }\n if (data === \"m:new:ws:custom\") {\n const userId = ctx.from?.id;\n if (!userId) return;\n const pending = pendingNewSessions.get(userId);\n if (!pending?.agentName) return;\n try {\n await ctx.api.editMessageText(\n chatId,\n pending.messageId,\n `✏️ <b>Enter your project path:</b>\\n\\n` +\n `Full path like <code>~/code/my-project</code>\\n` +\n `Or just the folder name like <code>my-project</code> (will use ${core.configManager.get().workspace.baseDir}/)`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.reply(\n `✏️ <b>Enter your project path:</b>`,\n { parse_mode: \"HTML\" },\n );\n }\n clearTimeout(pending.timer);\n pending.step = \"workspace_input\";\n pending.timer = setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS);\n return;\n }\n if (data === \"m:new:confirm\") {\n const userId = ctx.from?.id;\n if (!userId) return;\n const pending = pendingNewSessions.get(userId);\n if (!pending?.agentName || !pending?.workspace) return;\n cleanupPending(userId);\n const confirmMsgId = pending.messageId;\n try {\n await ctx.api.editMessageText(chatId, confirmMsgId, `⏳ Creating session...`, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n const resultThreadId = await createSessionDirect(ctx, core, chatId, pending.agentName, pending.workspace);\n try {\n if (resultThreadId) {\n const link = buildDeepLink(chatId, resultThreadId);\n await ctx.api.editMessageText(chatId, confirmMsgId, `✅ Session created → <a href=\"${link}\">Open topic</a>`, { parse_mode: \"HTML\" });\n } else {\n await ctx.api.editMessageText(chatId, confirmMsgId, `❌ Session creation failed.`, { parse_mode: \"HTML\" });\n }\n } catch { /* ignore */ }\n return;\n }\n if (data === \"m:new:cancel\") {\n const userId = ctx.from?.id;\n if (userId) cleanupPending(userId);\n try {\n await ctx.editMessageText(\"❌ Session creation cancelled.\", { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n return;\n }\n });\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { escapeHtml } from \"../formatting.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\nconst log = createChildLogger({ module: \"telegram-cmd-admin\" });\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.patchRecord(sessionId, { dangerousMode: 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.patchRecord(sessionId, { dangerousMode: 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\nexport async 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.patchRecord(session.id, { dangerousMode: 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.patchRecord(record.sessionId, { dangerousMode: 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\nexport async 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.patchRecord(session.id, { dangerousMode: 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.patchRecord(record.sessionId, { dangerousMode: false }).catch(() => {});\n }\n await ctx.reply(\"🔐 <b>Dangerous mode disabled</b>\\n\\nPermission requests will be shown normally.\", { parse_mode: \"HTML\" });\n}\n\nexport async 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\nexport async 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","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 { createChildLogger } from \"../../../core/log.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\nconst log = createChildLogger({ module: \"telegram-cmd-session\" });\n\nexport async function handleCancel(\n ctx: Context,\n core: OpenACPCore,\n assistant?: CommandsAssistantContext,\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.abortPrompt();\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\nexport async 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\nexport async function handleTopics(ctx: Context, core: OpenACPCore): Promise<void> {\n try {\n const allRecords = core.sessionManager.listRecords();\n\n // Only show sessions that have a Telegram topic (skip headless/CLI-only)\n const records = allRecords.filter((r) => {\n const platform = r.platform as { topicId?: number };\n return !!platform?.topicId;\n });\n\n const headlessCount = allRecords.length - records.length;\n\n if (records.length === 0) {\n const extra = headlessCount > 0 ? ` (${headlessCount} headless hidden)` : \"\";\n await ctx.reply(`No sessions with topics found.${extra}`, { parse_mode: \"HTML\" });\n return;\n }\n\n const statusEmoji: Record<string, string> = {\n active: \"🟢\",\n initializing: \"🟡\",\n finished: \"✅\",\n error: \"❌\",\n cancelled: \"⛔\",\n };\n\n // Sort: active/initializing first, then by lastActiveAt desc\n const statusOrder: Record<string, number> = { active: 0, initializing: 1, error: 2, finished: 3, cancelled: 4 };\n records.sort((a, b) => (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5));\n\n const MAX_DISPLAY = 30;\n const displayed = records.slice(0, MAX_DISPLAY);\n\n const lines = displayed.map((r) => {\n const emoji = statusEmoji[r.status] || \"⚪\";\n const name = r.name?.trim();\n const label = name ? escapeHtml(name) : `<i>${escapeHtml(r.agentName)} session</i>`;\n return `${emoji} ${label} <code>[${r.status}]</code>`;\n });\n\n const header = `<b>Sessions: ${records.length}</b>` +\n (headlessCount > 0 ? ` (${headlessCount} headless hidden)` : \"\");\n const truncated = records.length > MAX_DISPLAY ? `\\n\\n<i>...and ${records.length - MAX_DISPLAY} more</i>` : \"\";\n\n // Count by status for cleanup buttons (include headless sessions)\n const finishedCount = allRecords.filter((r) => r.status === \"finished\").length;\n const errorCount = allRecords.filter((r) => r.status === \"error\" || r.status === \"cancelled\").length;\n\n const keyboard = new InlineKeyboard();\n if (finishedCount > 0) {\n keyboard.text(`Cleanup finished (${finishedCount})`, \"m:cleanup:finished\").row();\n }\n if (errorCount > 0) {\n keyboard.text(`Cleanup errors (${errorCount})`, \"m:cleanup:errors\").row();\n }\n if (finishedCount + errorCount > 0) {\n keyboard.text(`Cleanup all non-active (${finishedCount + errorCount})`, \"m:cleanup:all\").row();\n }\n keyboard.text(`⚠️ Cleanup ALL (${allRecords.length})`, \"m:cleanup:everything\").row();\n keyboard.text(\"Refresh\", \"m:topics\");\n\n await ctx.reply(\n `${header}\\n\\n${lines.join(\"\\n\")}${truncated}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch (err) {\n log.error({ err }, \"handleTopics error\");\n await ctx.reply(\"❌ Failed to list sessions.\", { parse_mode: \"HTML\" }).catch(() => {});\n }\n}\n\nexport async function handleCleanup(ctx: Context, core: OpenACPCore, chatId: number, statuses: string[]): Promise<void> {\n const allRecords = core.sessionManager.listRecords();\n const cleanable = allRecords.filter((r) => statuses.includes(r.status));\n\n if (cleanable.length === 0) {\n await ctx.reply(\"Nothing to clean up.\", { parse_mode: \"HTML\" });\n return;\n }\n\n let deleted = 0;\n let failed = 0;\n\n for (const record of cleanable) {\n try {\n const topicId = (record.platform as { topicId?: number })?.topicId;\n if (topicId) {\n try {\n await ctx.api.deleteForumTopic(chatId, topicId);\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId, topicId }, \"Failed to delete forum topic during cleanup\");\n }\n }\n await core.sessionManager.removeRecord(record.sessionId);\n deleted++;\n } catch (err) {\n log.error({ err, sessionId: record.sessionId }, \"Failed to cleanup session\");\n failed++;\n }\n }\n\n await ctx.reply(\n `🗑 Cleaned up <b>${deleted}</b> sessions${failed > 0 ? ` (${failed} failed)` : \"\"}.`,\n { parse_mode: \"HTML\" },\n );\n}\n\nexport async function handleCleanupEverything(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n): Promise<void> {\n const allRecords = core.sessionManager.listRecords();\n const cleanable = allRecords.filter((r) => {\n const platform = r.platform as { topicId?: number };\n if (systemTopicIds && platform?.topicId && (platform.topicId === systemTopicIds.notificationTopicId || platform.topicId === systemTopicIds.assistantTopicId)) return false;\n return true;\n });\n\n if (cleanable.length === 0) {\n await ctx.reply(\"Nothing to clean up.\", { parse_mode: \"HTML\" });\n return;\n }\n\n // Group by status for breakdown\n const statusCounts = new Map<string, number>();\n for (const r of cleanable) {\n statusCounts.set(r.status, (statusCounts.get(r.status) ?? 0) + 1);\n }\n\n const statusEmoji: Record<string, string> = {\n active: \"🟢\", initializing: \"🟡\", finished: \"✅\", error: \"❌\", cancelled: \"⛔\",\n };\n\n const breakdown = Array.from(statusCounts.entries())\n .map(([status, count]) => `${statusEmoji[status] ?? \"⚪\"} ${status}: ${count}`)\n .join(\"\\n\");\n\n const activeCount = (statusCounts.get(\"active\") ?? 0) + (statusCounts.get(\"initializing\") ?? 0);\n const activeWarning = activeCount > 0\n ? `\\n\\n⚠️ <b>${activeCount} active session(s) will be cancelled and their agents stopped!</b>`\n : \"\";\n\n const keyboard = new InlineKeyboard()\n .text(\"Yes, delete all\", \"m:cleanup:everything:confirm\")\n .text(\"Cancel\", \"m:topics\");\n\n await ctx.reply(\n `<b>Delete ${cleanable.length} topics?</b>\\n\\n` +\n `This will:\\n` +\n `• Delete all session topics from this group\\n` +\n `• Cancel any running agent sessions\\n` +\n `• Remove all session records\\n\\n` +\n `<b>Breakdown:</b>\\n${breakdown}${activeWarning}\\n\\n` +\n `<i>Notifications and Assistant topics will NOT be deleted.</i>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n}\n\nexport async function handleCleanupEverythingConfirmed(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n): Promise<void> {\n const allRecords = core.sessionManager.listRecords();\n const cleanable = allRecords.filter((r) => {\n const platform = r.platform as { topicId?: number };\n if (systemTopicIds && platform?.topicId && (platform.topicId === systemTopicIds.notificationTopicId || platform.topicId === systemTopicIds.assistantTopicId)) return false;\n return true;\n });\n\n if (cleanable.length === 0) {\n await ctx.reply(\"Nothing to clean up.\", { parse_mode: \"HTML\" });\n return;\n }\n\n let deleted = 0;\n let failed = 0;\n\n for (const record of cleanable) {\n try {\n // Cancel active sessions first\n if (record.status === \"active\" || record.status === \"initializing\") {\n try {\n await core.sessionManager.cancelSession(record.sessionId);\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId }, \"Failed to cancel session during cleanup\");\n }\n }\n\n const topicId = (record.platform as { topicId?: number })?.topicId;\n if (topicId) {\n try {\n await ctx.api.deleteForumTopic(chatId, topicId);\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId, topicId }, \"Failed to delete forum topic during cleanup\");\n }\n }\n await core.sessionManager.removeRecord(record.sessionId);\n deleted++;\n } catch (err) {\n log.error({ err, sessionId: record.sessionId }, \"Failed to cleanup session\");\n failed++;\n }\n }\n\n await ctx.reply(\n `🗑 Cleaned up <b>${deleted}</b> sessions${failed > 0 ? ` (${failed} failed)` : \"\"}.`,\n { parse_mode: \"HTML\" },\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.abortPrompt();\n return session;\n}\n\nexport function setupSessionCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n): void {\n bot.callbackQuery(/^m:cleanup/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired */ }\n\n switch (data) {\n case \"m:cleanup:finished\":\n await handleCleanup(ctx, core, chatId, [\"finished\"]);\n break;\n case \"m:cleanup:errors\":\n await handleCleanup(ctx, core, chatId, [\"error\", \"cancelled\"]);\n break;\n case \"m:cleanup:all\":\n await handleCleanup(ctx, core, chatId, [\"finished\", \"error\", \"cancelled\"]);\n break;\n case \"m:cleanup:everything\":\n await handleCleanupEverything(ctx, core, chatId, systemTopicIds);\n break;\n case \"m:cleanup:everything:confirm\":\n await handleCleanupEverythingConfirmed(ctx, core, chatId, systemTopicIds);\n break;\n }\n });\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { escapeHtml } from \"../formatting.js\";\n\nexport async function handleIntegrate(ctx: Context, _core: OpenACPCore): Promise<void> {\n const { listIntegrations } = await import(\"../../../cli/integrate.js\");\n const agents = listIntegrations();\n\n const keyboard = new InlineKeyboard();\n for (const agent of agents) {\n keyboard.text(`🤖 ${agent}`, `i:agent:${agent}`).row();\n }\n\n await ctx.reply(\n `<b>🔗 Integrations</b>\\n\\nSelect an agent to manage its integrations.`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n}\n\nfunction buildAgentItemsKeyboard(agentName: string, items: import(\"../../../cli/integrate.js\").IntegrationItem[]): InlineKeyboard {\n const keyboard = new InlineKeyboard();\n for (const item of items) {\n const installed = item.isInstalled();\n keyboard.text(\n installed ? `✅ ${item.name} — Uninstall` : `📦 ${item.name} — Install`,\n installed ? `i:uninstall:${agentName}:${item.id}` : `i:install:${agentName}:${item.id}`,\n ).row();\n }\n keyboard.text(\"← Back\", \"i:back\").row();\n return keyboard;\n}\n\nexport function setupIntegrateCallbacks(\n bot: Bot,\n core: OpenACPCore,\n): void {\n bot.callbackQuery(/^i:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch {\n /* expired */\n }\n\n // Back to agent list\n if (data === \"i:back\") {\n const { listIntegrations } = await import(\"../../../cli/integrate.js\");\n const agents = listIntegrations();\n const keyboard = new InlineKeyboard();\n for (const agent of agents) {\n keyboard.text(`🤖 ${agent}`, `i:agent:${agent}`).row();\n }\n try {\n await ctx.editMessageText(\n `<b>🔗 Integrations</b>\\n\\nSelect an agent to manage its integrations.`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch { /* message unchanged */ }\n return;\n }\n\n // Show agent items\n const agentMatch = data.match(/^i:agent:(.+)$/);\n if (agentMatch) {\n const agentName = agentMatch[1];\n const { getIntegration } = await import(\"../../../cli/integrate.js\");\n const integration = getIntegration(agentName);\n if (!integration) {\n await ctx.reply(`❌ No integration available for '${escapeHtml(agentName)}'.`, { parse_mode: \"HTML\" });\n return;\n }\n const keyboard = buildAgentItemsKeyboard(agentName, integration.items);\n try {\n await ctx.editMessageText(\n `<b>🔗 ${escapeHtml(agentName)} Integrations</b>\\n\\n${integration.items.map((i) => `• <b>${escapeHtml(i.name)}</b> — ${escapeHtml(i.description)}`).join(\"\\n\")}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch {\n await ctx.reply(\n `<b>🔗 ${escapeHtml(agentName)} Integrations</b>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n }\n return;\n }\n\n // Install / uninstall item\n const actionMatch = data.match(/^i:(install|uninstall):([^:]+):(.+)$/);\n if (!actionMatch) return;\n\n const action = actionMatch[1] as \"install\" | \"uninstall\";\n const agentName = actionMatch[2];\n const itemId = actionMatch[3];\n\n const { getIntegration } = await import(\"../../../cli/integrate.js\");\n const integration = getIntegration(agentName);\n if (!integration) return;\n\n const item = integration.items.find((i) => i.id === itemId);\n if (!item) return;\n\n const result = action === \"install\"\n ? await item.install()\n : await item.uninstall();\n\n // Save state to config\n const installed = action === \"install\" && result.success;\n await core.configManager.save({\n integrations: {\n [agentName]: {\n installed,\n installedAt: installed ? new Date().toISOString() : undefined,\n },\n },\n });\n\n const statusEmoji = result.success ? \"✅\" : \"❌\";\n const actionLabel = action === \"install\" ? \"installed\" : \"uninstalled\";\n const logsText = result.logs.map((l) => `<code>${escapeHtml(l)}</code>`).join(\"\\n\");\n const resultText = `${statusEmoji} <b>${escapeHtml(item.name)}</b> ${actionLabel}.\\n\\n${logsText}`;\n\n const keyboard = buildAgentItemsKeyboard(agentName, integration.items);\n try {\n await ctx.editMessageText(\n `<b>🔗 ${escapeHtml(agentName)} Integrations</b>\\n\\n${resultText}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch {\n await ctx.reply(resultText, { parse_mode: \"HTML\" });\n }\n });\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { getSafeFields, resolveOptions, getConfigValue, isHotReloadable, type ConfigFieldDef } from \"../../../core/config-registry.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\n\nconst log = createChildLogger({ module: \"telegram-settings\" });\n\nfunction buildSettingsKeyboard(core: OpenACPCore): InlineKeyboard {\n const config = core.configManager.get();\n const fields = getSafeFields();\n const kb = new InlineKeyboard();\n\n for (const field of fields) {\n const value = getConfigValue(config, field.path);\n const label = formatFieldLabel(field, value);\n\n if (field.type === 'toggle') {\n kb.text(`${label}`, `s:toggle:${field.path}`).row();\n } else if (field.type === 'select') {\n kb.text(`${label}`, `s:select:${field.path}`).row();\n } else {\n kb.text(`${label}`, `s:input:${field.path}`).row();\n }\n }\n\n kb.text(\"◀️ Back to Menu\", \"s:back\");\n return kb;\n}\n\nfunction formatFieldLabel(field: ConfigFieldDef, value: unknown): string {\n const icons: Record<string, string> = {\n agent: '🤖', logging: '📝', tunnel: '🔗',\n security: '🔒', workspace: '📁', storage: '💾',\n };\n const icon = icons[field.group] ?? '⚙️';\n\n if (field.type === 'toggle') {\n return `${icon} ${field.displayName}: ${value ? 'ON' : 'OFF'}`;\n }\n return `${icon} ${field.displayName}: ${String(value)}`;\n}\n\nexport async function handleSettings(ctx: Context, core: OpenACPCore): Promise<void> {\n const kb = buildSettingsKeyboard(core);\n await ctx.reply(`<b>⚙️ Settings</b>\\nTap to change:`, {\n parse_mode: \"HTML\",\n reply_markup: kb,\n });\n}\n\nexport function setupSettingsCallbacks(\n bot: Bot,\n core: OpenACPCore,\n getAssistantSession: () => { topicId: number; enqueuePrompt: (p: string) => Promise<void> } | undefined,\n): void {\n bot.callbackQuery(/^s:toggle:/, async (ctx) => {\n const fieldPath = ctx.callbackQuery.data.replace('s:toggle:', '');\n const config = core.configManager.get();\n const currentValue = getConfigValue(config, fieldPath);\n const newValue = !currentValue;\n\n try {\n const updates = buildNestedUpdate(fieldPath, newValue);\n await core.configManager.save(updates, fieldPath);\n\n const toast = isHotReloadable(fieldPath)\n ? `✅ ${fieldPath} = ${newValue}`\n : `✅ ${fieldPath} = ${newValue} (restart needed)`;\n try { await ctx.answerCallbackQuery({ text: toast }); } catch { /* expired */ }\n\n try {\n await ctx.editMessageReplyMarkup({ reply_markup: buildSettingsKeyboard(core) });\n } catch { /* ignore */ }\n } catch (err) {\n log.error({ err, fieldPath }, 'Failed to toggle config');\n try { await ctx.answerCallbackQuery({ text: '❌ Failed to update' }); } catch { /* expired */ }\n }\n });\n\n bot.callbackQuery(/^s:select:/, async (ctx) => {\n const fieldPath = ctx.callbackQuery.data.replace('s:select:', '');\n const config = core.configManager.get();\n const fieldDef = getSafeFields().find(f => f.path === fieldPath);\n if (!fieldDef) return;\n\n const options = resolveOptions(fieldDef, config) ?? [];\n const currentValue = getConfigValue(config, fieldPath);\n const kb = new InlineKeyboard();\n\n for (const opt of options) {\n const marker = opt === String(currentValue) ? ' ✓' : '';\n kb.text(`${opt}${marker}`, `s:pick:${fieldPath}:${opt}`).row();\n }\n kb.text(\"◀️ Back\", \"s:back:refresh\");\n\n try { await ctx.answerCallbackQuery(); } catch { /* expired */ }\n\n try {\n await ctx.editMessageText(`<b>⚙️ ${fieldDef.displayName}</b>\\nSelect a value:`, {\n parse_mode: \"HTML\",\n reply_markup: kb,\n });\n } catch { /* ignore */ }\n });\n\n bot.callbackQuery(/^s:pick:/, async (ctx) => {\n const parts = ctx.callbackQuery.data.replace('s:pick:', '').split(':');\n const fieldPath = parts.slice(0, -1).join(':');\n const newValue = parts[parts.length - 1];\n\n try {\n const updates = buildNestedUpdate(fieldPath, newValue);\n await core.configManager.save(updates, fieldPath);\n\n try { await ctx.answerCallbackQuery({ text: `✅ ${fieldPath} = ${newValue}` }); } catch { /* expired */ }\n try {\n await ctx.editMessageText(`<b>⚙️ Settings</b>\\nTap to change:`, {\n parse_mode: \"HTML\",\n reply_markup: buildSettingsKeyboard(core),\n });\n } catch { /* ignore */ }\n } catch (err) {\n log.error({ err, fieldPath }, 'Failed to set config');\n try { await ctx.answerCallbackQuery({ text: '❌ Failed to update' }); } catch { /* expired */ }\n }\n });\n\n bot.callbackQuery(/^s:input:/, async (ctx) => {\n const fieldPath = ctx.callbackQuery.data.replace('s:input:', '');\n const config = core.configManager.get();\n const fieldDef = getSafeFields().find(f => f.path === fieldPath);\n if (!fieldDef) return;\n\n const currentValue = getConfigValue(config, fieldPath);\n const assistant = getAssistantSession();\n\n if (!assistant) {\n try { await ctx.answerCallbackQuery({ text: '⚠️ Start the assistant first (/assistant)' }); } catch { /* expired */ }\n return;\n }\n\n try { await ctx.answerCallbackQuery({ text: `Delegating to assistant...` }); } catch { /* expired */ }\n\n const prompt = `User wants to change ${fieldDef.displayName} (config path: ${fieldPath}). Current value: ${JSON.stringify(currentValue)}. Ask them for the new value and apply it using: openacp config set ${fieldPath} <value>`;\n await assistant.enqueuePrompt(prompt);\n });\n\n bot.callbackQuery(\"s:back\", async (ctx) => {\n try { await ctx.answerCallbackQuery(); } catch { /* expired */ }\n const { buildMenuKeyboard } = await import('./menu.js');\n try {\n await ctx.editMessageText(`<b>OpenACP Menu</b>\\nChoose an action:`, {\n parse_mode: \"HTML\",\n reply_markup: buildMenuKeyboard(),\n });\n } catch { /* ignore */ }\n });\n\n bot.callbackQuery(\"s:back:refresh\", async (ctx) => {\n try { await ctx.answerCallbackQuery(); } catch { /* expired */ }\n try {\n await ctx.editMessageText(`<b>⚙️ Settings</b>\\nTap to change:`, {\n parse_mode: \"HTML\",\n reply_markup: buildSettingsKeyboard(core),\n });\n } catch { /* ignore */ }\n });\n}\n\nfunction buildNestedUpdate(dotPath: string, value: unknown): Record<string, unknown> {\n const parts = dotPath.split('.');\n const result: Record<string, unknown> = {};\n let target = result;\n for (let i = 0; i < parts.length - 1; i++) {\n target[parts[i]] = {};\n target = target[parts[i]] as Record<string, unknown>;\n }\n target[parts[parts.length - 1]] = value;\n return result;\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport { DoctorEngine } from \"../../../core/doctor/index.js\";\nimport type { DoctorReport, PendingFix } from \"../../../core/doctor/types.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\n\nconst log = createChildLogger({ module: \"telegram-cmd-doctor\" });\n\nconst pendingFixesStore = new Map<string, PendingFix[]>();\n\nfunction renderReport(report: DoctorReport): { text: string; keyboard: InlineKeyboard | undefined } {\n const icons = { pass: \"✅\", warn: \"⚠️\", fail: \"❌\" };\n const lines: string[] = [\"🩺 <b>OpenACP Doctor</b>\\n\"];\n\n for (const category of report.categories) {\n lines.push(`<b>${category.name}</b>`);\n for (const result of category.results) {\n lines.push(` ${icons[result.status]} ${escapeHtml(result.message)}`);\n }\n lines.push(\"\");\n }\n\n const { passed, warnings, failed, fixed } = report.summary;\n const fixedStr = fixed > 0 ? `, ${fixed} fixed` : \"\";\n lines.push(`<b>Result:</b> ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`);\n\n let keyboard: InlineKeyboard | undefined;\n if (report.pendingFixes.length > 0) {\n keyboard = new InlineKeyboard();\n for (let i = 0; i < report.pendingFixes.length; i++) {\n const label = `🔧 Fix: ${report.pendingFixes[i].message.slice(0, 30)}`;\n keyboard.text(label, `m:doctor:fix:${i}`).row();\n }\n }\n\n return { text: lines.join(\"\\n\"), keyboard };\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nexport async function handleDoctor(ctx: Context): Promise<void> {\n const statusMsg = await ctx.reply(\"🩺 Running diagnostics...\", { parse_mode: \"HTML\" });\n\n try {\n const engine = new DoctorEngine();\n const report = await engine.runAll();\n const { text, keyboard } = renderReport(report);\n\n const storeKey = `${ctx.chat!.id}:${statusMsg.message_id}`;\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes);\n }\n\n await ctx.api.editMessageText(ctx.chat!.id, statusMsg.message_id, text, {\n parse_mode: \"HTML\",\n reply_markup: keyboard,\n });\n } catch (err) {\n log.error({ err }, \"Doctor command failed\");\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `❌ Doctor failed: ${err instanceof Error ? err.message : String(err)}`,\n { parse_mode: \"HTML\" },\n );\n }\n}\n\nexport function setupDoctorCallbacks(bot: Bot): void {\n bot.callbackQuery(/^m:doctor:fix:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n const index = parseInt(data.replace(\"m:doctor:fix:\", \"\"), 10);\n const chatId = ctx.callbackQuery.message?.chat.id;\n const messageId = ctx.callbackQuery.message?.message_id;\n\n try {\n await ctx.answerCallbackQuery({ text: \"Applying fix...\" });\n } catch { /* expired */ }\n\n if (chatId === undefined || messageId === undefined) return;\n\n const storeKey = `${chatId}:${messageId}`;\n const fixes = pendingFixesStore.get(storeKey);\n if (!fixes || index < 0 || index >= fixes.length) {\n try { await ctx.answerCallbackQuery({ text: \"Fix no longer available\" }); } catch { /* */ }\n return;\n }\n\n const pending = fixes[index];\n try {\n const result = await pending.fix();\n if (result.success) {\n const engine = new DoctorEngine();\n const report = await engine.runAll();\n const { text, keyboard } = renderReport(report);\n\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes);\n } else {\n pendingFixesStore.delete(storeKey);\n }\n\n await ctx.editMessageText(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n } else {\n try { await ctx.answerCallbackQuery({ text: `Fix failed: ${result.message}` }); } catch { /* */ }\n }\n } catch (err) {\n log.error({ err, index }, \"Doctor fix callback failed\");\n }\n });\n\n bot.callbackQuery(\"m:doctor\", async (ctx) => {\n try { await ctx.answerCallbackQuery(); } catch { /* */ }\n await handleDoctor(ctx);\n });\n}\n","import type { Bot, Context } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\n\n// Domain modules\nimport { handleNew, handleNewChat, setupNewSessionCallbacks } from \"./new-session.js\";\nimport { handleCancel, handleStatus, handleTopics, setupSessionCallbacks } from \"./session.js\";\nimport { handleEnableDangerous, handleDisableDangerous, handleUpdate, handleRestart } from \"./admin.js\";\nimport { handleMenu, handleHelp, handleAgents, handleClear, buildMenuKeyboard } from \"./menu.js\";\nimport { handleIntegrate } from \"./integrate.js\";\nimport { handleSettings, setupSettingsCallbacks } from \"./settings.js\";\nimport { handleDoctor, setupDoctorCallbacks } from \"./doctor.js\";\n\nexport function setupCommands(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n assistant?: CommandsAssistantContext,\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(\"sessions\", (ctx) => handleTopics(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 bot.command(\"integrate\", (ctx) => handleIntegrate(ctx, core));\n bot.command(\"clear\", (ctx) => handleClear(ctx, assistant));\n bot.command(\"doctor\", (ctx) => handleDoctor(ctx));\n}\n\nexport function setupAllCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n getAssistantSession?: () => { topicId: number; enqueuePrompt: (p: string) => Promise<void> } | undefined,\n): void {\n // Register specific prefix handlers FIRST (grammY middleware order matters)\n setupNewSessionCallbacks(bot, core, chatId);\n setupSessionCallbacks(bot, core, chatId, systemTopicIds);\n\n // Settings handlers — must be before broad m: handler\n setupSettingsCallbacks(bot, core, getAssistantSession ?? (() => undefined))\n\n // Doctor handlers — must be before broad m: handler\n setupDoctorCallbacks(bot);\n\n // Broad m: handler for remaining menu dispatch — LAST\n bot.callbackQuery(/^m:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired or network — ignore */ }\n\n switch (data) {\n case \"m:new\":\n await handleNew(ctx, core, chatId);\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 case \"m:integrate\":\n await handleIntegrate(ctx, core);\n break;\n case \"m:topics\":\n await handleTopics(ctx, core);\n break;\n case \"m:settings\":\n await handleSettings(ctx, core);\n break;\n }\n });\n}\n\n// Backward compat alias\nexport { setupAllCallbacks as setupMenuCallbacks };\n\n// Re-exports for external consumers (adapter.ts, action-detect.ts)\nexport { buildMenuKeyboard } from \"./menu.js\";\nexport { buildSkillMessages } from \"./menu.js\";\nexport { handlePendingWorkspaceInput, executeNewSession, startInteractiveNewSession } from \"./new-session.js\";\nexport { executeCancelSession } from \"./session.js\";\nexport { setupDangerousModeCallbacks, buildDangerousModeKeyboard } from \"./admin.js\";\nexport { setupIntegrateCallbacks } from \"./integrate.js\";\nexport { setupSettingsCallbacks } from \"./settings.js\";\nexport { setupDoctorCallbacks } from \"./doctor.js\";\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: \"sessions\", description: \"List all sessions\" },\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: \"integrate\", description: \"Manage agent integrations\" },\n { command: \"handoff\", description: \"Continue this session in your terminal\" },\n { command: \"clear\", description: \"Clear assistant history\" },\n { command: \"restart\", description: \"Restart OpenACP\" },\n { command: \"update\", description: \"Update to latest version and restart\" },\n { command: \"doctor\", description: \"Run system diagnostics\" },\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","/**\n * OpenACP Product Guide — comprehensive reference for the AI assistant.\n * The assistant reads this at runtime to answer user questions about features.\n */\nexport const PRODUCT_GUIDE = `\n# OpenACP — Product Guide\n\nOpenACP lets you chat with AI coding agents (like Claude Code) through Telegram.\nYou type messages in Telegram, the agent reads/writes/runs code in your project folder, and results stream back in real time.\n\n---\n\n## Quick Start\n\n1. Start OpenACP: \\`openacp\\` (or \\`openacp start\\` for background daemon)\n2. Open your Telegram group — you'll see the Assistant topic\n3. Tap 🆕 New Session or type /new\n4. Pick an agent and a project folder\n5. Chat in the session topic — the agent works on your code\n\n---\n\n## Core Concepts\n\n### Sessions\nA session = one conversation with one AI agent working in one project folder.\nEach session gets its own Telegram topic. Chat there to give instructions to the agent.\n\n### Agents\nAn agent is an AI coding tool (e.g., Claude Code). You can configure multiple agents.\nThe default agent is used when you don't specify one.\n\n### Project Folder (Workspace)\nThe directory where the agent reads, writes, and runs code.\nWhen creating a session, you choose which folder the agent works in.\nYou can type a full path like \\`~/code/my-project\\` or just a name like \\`my-project\\` (it becomes \\`<base-dir>/my-project\\`).\n\n### System Topics\n- **Assistant** — Always-on helper that can answer questions, create sessions, check status, troubleshoot\n- **Notifications** — System alerts (permission requests, session errors, completions)\n\n---\n\n## Creating Sessions\n\n### From menu\nTap 🆕 New Session → choose agent (if multiple) → choose project folder → confirm\n\n### From command\n- \\`/new\\` — Interactive flow (asks agent + folder)\n- \\`/new claude ~/code/my-project\\` — Create directly with specific agent and folder\n\n### From Assistant topic\nJust ask: \"Create a session for my-project with claude\" — the assistant handles it\n\n### Quick new chat\n\\`/newchat\\` in a session topic — creates new session with same agent and folder as current one\n\n---\n\n## Working with Sessions\n\n### Chat\nType messages in the session topic. The agent responds with code changes, explanations, tool outputs.\n\n### What you see while the agent works\n- **💭 Thinking indicator** — Shows when the agent is reasoning, with elapsed time\n- **Text responses** — Streamed in real time, updated every few seconds\n- **Tool calls** — When the agent runs commands or edits files, you see tool name, input, status, and output\n- **📋 Plan card** — Visual task progress with completed/in-progress/pending items and progress bar\n- **\"View File\" / \"View Diff\" buttons** — Opens in browser with Monaco editor (requires tunnel)\n\n### Session lifecycle\n1. **Creating** — Topic created, agent spawning\n2. **Warming up** — Agent primes its cache (happens automatically, invisible to you)\n3. **Active** — Ready for your messages\n4. **Auto-naming** — After your first message, the session gets a descriptive name (agent summarizes in ~5 words). The topic title updates automatically.\n5. **Finished/Error** — Session completed or hit an error\n\n### Agent skills\nSome agents provide slash commands (e.g., /compact, /review). Available skills are pinned in the session topic.\n\n### Permission requests\nWhen the agent wants to run a command, it asks for permission.\nYou see buttons: ✅ Allow, ❌ Reject (and sometimes \"Always Allow\").\nA notification also appears in the Notifications topic with a link to the request.\n\n### Dangerous mode\nAuto-approves ALL permission requests — the agent runs any command without asking.\n- Enable: \\`/enable_dangerous\\` or tap the ☠️ button in the session\n- Disable: \\`/disable_dangerous\\` or tap the 🔐 button\n- ⚠️ Use with caution — the agent can execute anything\n\n### Session timeout\nIdle sessions are automatically cancelled after a configurable timeout (default: 60 minutes).\nConfigure via \\`security.sessionTimeoutMinutes\\` in config.\n\n---\n\n## Session Transfer (Handoff)\n\n### Telegram → Terminal\n1. Type \\`/handoff\\` in a session topic\n2. You get a command like \\`claude --resume <SESSION_ID>\\`\n3. Copy and run it in your terminal — the session continues there with full conversation history\n\n### Terminal → Telegram\n1. First time: run \\`openacp integrate claude\\` to install the handoff skill (one-time setup)\n2. In Claude Code, use the /openacp:handoff slash command\n3. The session appears as a new topic in Telegram and you can continue chatting there\n\n### How it works\n- The agent session ID is shared between platforms\n- Conversation history is preserved — pick up where you left off\n- The agent that supports resume (e.g., Claude with \\`--resume\\`) handles the actual transfer\n\n---\n\n## Managing Sessions\n\n### Status\n- \\`/status\\` — Shows active sessions count and details\n- Ask the Assistant: \"What sessions are running?\"\n\n### List all sessions\n- \\`/sessions\\` — Shows all sessions with status (active, finished, error)\n\n### Cancel\n- \\`/cancel\\` in a session topic — cancels that session\n- Ask the Assistant: \"Cancel the stuck session\"\n\n### Cleanup\n- From \\`/sessions\\` → tap cleanup buttons (finished, errors, all)\n- Ask the Assistant: \"Clean up old sessions\"\n\n---\n\n## Assistant Topic\n\nThe Assistant is an always-on AI helper in its own topic. It can:\n- Answer questions about OpenACP\n- Create sessions for you\n- Check status and health\n- Cancel sessions\n- Clean up old sessions\n- Troubleshoot issues\n- Manage configuration\n\nJust chat naturally: \"How do I create a session?\", \"What's the status?\", \"Something is stuck\"\n\n### Clear history\n\\`/clear\\` in the Assistant topic — resets the conversation\n\n---\n\n## System Commands\n\n| Command | Where | What it does |\n|---------|-------|-------------|\n| \\`/new [agent] [path]\\` | Anywhere | Create new session |\n| \\`/newchat\\` | Session topic | New session, same agent + folder |\n| \\`/cancel\\` | Session topic | Cancel current session |\n| \\`/status\\` | Anywhere | Show status |\n| \\`/sessions\\` | Anywhere | List all sessions |\n| \\`/agents\\` | Anywhere | List available agents |\n| \\`/enable_dangerous\\` | Session topic | Auto-approve all permissions |\n| \\`/disable_dangerous\\` | Session topic | Restore permission prompts |\n| \\`/handoff\\` | Session topic | Transfer session to terminal |\n| \\`/clear\\` | Assistant topic | Clear assistant history |\n| \\`/menu\\` | Anywhere | Show action menu |\n| \\`/help\\` | Anywhere | Show help |\n| \\`/restart\\` | Anywhere | Restart OpenACP |\n| \\`/update\\` | Anywhere | Update to latest version |\n| \\`/integrate\\` | Anywhere | Manage agent integrations |\n\n---\n\n## Menu Buttons\n\n| Button | Action |\n|--------|--------|\n| 🆕 New Session | Create new session (interactive) |\n| 📋 Sessions | List all sessions with cleanup options |\n| 📊 Status | Show active/total session count |\n| 🤖 Agents | List available agents |\n| 🔗 Integrate | Manage agent integrations |\n| ❓ Help | Show help text |\n| 🔄 Restart | Restart OpenACP |\n| ⬆️ Update | Check and install updates |\n\n---\n\n## CLI Commands\n\n### Server\n- \\`openacp\\` — Start (uses configured mode: foreground or daemon)\n- \\`openacp start\\` — Start as background daemon\n- \\`openacp stop\\` — Stop daemon\n- \\`openacp status\\` — Show daemon status\n- \\`openacp logs\\` — Tail daemon logs\n- \\`openacp --foreground\\` — Force foreground mode (useful for debugging or containers)\n\n### Auto-start (run on boot)\n- macOS: installs a LaunchAgent in \\`~/Library/LaunchAgents/\\`\n- Linux: installs a systemd user service in \\`~/.config/systemd/user/\\`\n- Enabled automatically when you start the daemon. Remove with \\`openacp stop\\`.\n\n### Configuration\n- \\`openacp config\\` — Interactive config editor\n- \\`openacp reset\\` — Delete all data and start fresh\n\n### Plugins\n- \\`openacp install <package>\\` — Install adapter plugin (e.g., \\`@openacp/adapter-discord\\`)\n- \\`openacp uninstall <package>\\` — Remove adapter plugin\n- \\`openacp plugins\\` — List installed plugins\n\n### Integration\n- \\`openacp integrate <agent>\\` — Install agent integration (e.g., Claude handoff skill)\n- \\`openacp integrate <agent> --uninstall\\` — Remove integration\n\n### API (requires running daemon)\n\\`openacp api <command>\\` — Interact with running daemon:\n\n| Command | Description |\n|---------|-------------|\n| \\`status\\` | List active sessions |\n| \\`session <id>\\` | Session details |\n| \\`new <agent> <path>\\` | Create session |\n| \\`send <id> \"text\"\\` | Send prompt |\n| \\`cancel <id>\\` | Cancel session |\n| \\`dangerous <id> on/off\\` | Toggle dangerous mode |\n| \\`topics [--status x,y]\\` | List topics |\n| \\`delete-topic <id> [--force]\\` | Delete topic |\n| \\`cleanup [--status x,y]\\` | Cleanup old topics |\n| \\`agents\\` | List agents |\n| \\`health\\` | System health |\n| \\`config\\` | Show config |\n| \\`config set <key> <value>\\` | Update config |\n| \\`adapters\\` | List adapters |\n| \\`tunnel\\` | Tunnel status |\n| \\`notify \"message\"\\` | Send notification |\n| \\`version\\` | Daemon version |\n| \\`restart\\` | Restart daemon |\n\n---\n\n## File Viewer (Tunnel)\n\nWhen tunnel is enabled, file edits and diffs get \"View\" buttons that open in your browser:\n- **Monaco Editor** — Full VS Code editor with syntax highlighting\n- **Diff viewer** — Side-by-side or inline comparison\n- **Line highlighting** — Click lines to highlight\n- Dark/light theme toggle\n\n### Setup\nEnable in config: set \\`tunnel.enabled\\` to \\`true\\`.\nProviders: Cloudflare (default, free), ngrok, bore, Tailscale Funnel.\n\n---\n\n## Configuration\n\nConfig file: \\`~/.openacp/config.json\\`\n\n### Telegram\n- **telegram.botToken** — Your Telegram bot token\n- **telegram.chatId** — Your Telegram supergroup ID\n\n### Agents\n- **agents.<name>.command** — Agent executable path (e.g., \\`claude\\`, \\`codex\\`)\n- **agents.<name>.args** — Arguments to pass to the agent command\n- **agents.<name>.env** — Custom environment variables for the agent subprocess\n- **defaultAgent** — Which agent to use by default\n\n### Workspace\n- **workspace.baseDir** — Base directory for project folders (default: \\`~/openacp-workspace\\`)\n\n### Security\n- **security.allowedUserIds** — Restrict who can use the bot (empty = everyone)\n- **security.maxConcurrentSessions** — Max parallel sessions (default: 5)\n- **security.sessionTimeoutMinutes** — Auto-cancel idle sessions (default: 60)\n\n### Tunnel / File Viewer\n- **tunnel.enabled** — Enable file viewer tunnel\n- **tunnel.provider** — Tunnel provider: cloudflare (default, free), ngrok, bore, tailscale\n- **tunnel.port** — Local port for tunnel server (default: 3100)\n- **tunnel.auth.enabled** — Enable authentication for tunnel URLs\n- **tunnel.auth.token** — Auth token for tunnel access\n- **tunnel.storeTtlMinutes** — How long viewer links stay cached (default: 60)\n\n### Logging\n- **logging.level** — Log level: silent, debug, info, warn, error, fatal (default: info)\n- **logging.logDir** — Log directory (default: \\`~/.openacp/logs\\`)\n- **logging.maxFileSize** — Max log file size before rotation\n- **logging.maxFiles** — Max number of rotated log files\n- **logging.sessionLogRetentionDays** — Auto-delete old session logs (default: 30)\n\n### Data Retention\n- **sessionStore.ttlDays** — How long session records persist (default: 30). Old records are cleaned up automatically.\n\n### Environment variables\nOverride config with env vars:\n- \\`OPENACP_TELEGRAM_BOT_TOKEN\\`\n- \\`OPENACP_TELEGRAM_CHAT_ID\\`\n- \\`OPENACP_DEFAULT_AGENT\\`\n- \\`OPENACP_RUN_MODE\\` — foreground or daemon\n- \\`OPENACP_API_PORT\\` — API server port (default: 21420)\n- \\`OPENACP_TUNNEL_ENABLED\\`\n- \\`OPENACP_TUNNEL_PORT\\`\n- \\`OPENACP_TUNNEL_PROVIDER\\`\n- \\`OPENACP_LOG_LEVEL\\`\n- \\`OPENACP_LOG_DIR\\`\n- \\`OPENACP_DEBUG\\` — Sets log level to debug\n\n---\n\n## Troubleshooting\n\n### Session stuck / not responding\n- Check status: ask Assistant \"Is anything stuck?\"\n- Cancel and create new: \\`/cancel\\` then \\`/new\\`\n- Check system health: Assistant can run health check\n\n### Agent not found\n- Check available agents: \\`/agents\\`\n- Verify agent command is installed and in PATH\n- Check config: agent command + args must be correct\n\n### Permission request not showing\n- Check Notifications topic for the alert\n- Try \\`/enable_dangerous\\` to auto-approve (if you trust the agent)\n\n### Session disappeared after restart\n- Sessions persist across restarts\n- Send a message in the old topic — it auto-resumes\n- If topic was deleted, the session record may still exist in status\n\n### Bot not responding at all\n- Check daemon: \\`openacp status\\`\n- Check logs: \\`openacp logs\\`\n- Restart: \\`openacp start\\` or \\`/restart\\`\n\n### Messages going to wrong topic\n- Each session is bound to a specific Telegram topic\n- If you see messages appearing in the Assistant topic instead of the session topic, try creating a new session\n\n### Viewing logs\n- Session-specific logs: \\`~/.openacp/logs/sessions/\\`\n- System logs: \\`openacp logs\\` to tail live\n- Set \\`OPENACP_DEBUG=true\\` for verbose output\n\n---\n\n## Data & Storage\n\nAll data is stored in \\`~/.openacp/\\`:\n- \\`config.json\\` — Configuration\n- \\`sessions/\\` — Session records and state\n- \\`topics/\\` — Topic-to-session mappings\n- \\`logs/\\` — System and session logs\n- \\`plugins/\\` — Installed adapter plugins\n- \\`openacp.pid\\` — Daemon PID file\n\nSession records auto-cleanup: 30 days (configurable via \\`sessionStore.ttlDays\\`).\nSession logs auto-cleanup: 30 days (configurable via \\`logging.sessionLogRetentionDays\\`).\n`;\n","import type { OpenACPCore, ChannelAdapter, Config, Session } from \"../../core/index.js\";\nimport { createChildLogger } from \"../../core/log.js\";\nimport { PRODUCT_GUIDE } from \"../../product-guide.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 via unified pipeline\n log.info({ agent: config.defaultAgent }, \"Creating assistant session...\");\n const session = await core.createSession({\n channelId: \"telegram\",\n agentName: config.defaultAgent,\n workingDirectory: core.configManager.resolveWorkspace(),\n initialName: \"Assistant\", // Prevent auto-naming from triggering after system prompt\n });\n session.threadId = String(assistantTopicId);\n log.info({ sessionId: session.id }, \"Assistant agent spawned\");\n\n // Build dynamic context for system prompt\n const allRecords = core.sessionManager.listRecords();\n const activeCount = allRecords.filter(r => r.status === 'active' || r.status === 'initializing').length;\n const statusCounts = new Map<string, number>();\n for (const r of allRecords) {\n statusCounts.set(r.status, (statusCounts.get(r.status) ?? 0) + 1);\n }\n const topicSummary = Array.from(statusCounts.entries()).map(([status, count]) => ({ status, count }));\n\n const ctx: AssistantContext = {\n config,\n activeSessionCount: activeCount,\n totalSessionCount: allRecords.length,\n topicSummary,\n };\n\n // Fire system prompt in background — don't block startup.\n const systemPrompt = buildAssistantSystemPrompt(ctx);\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 interface AssistantContext {\n config: Config\n activeSessionCount: number\n totalSessionCount: number\n topicSummary: { status: string; count: number }[]\n}\n\nexport interface WelcomeContext {\n activeCount: number;\n errorCount: number;\n totalCount: number;\n agents: string[];\n defaultAgent: string;\n}\n\nexport function buildWelcomeMessage(ctx: WelcomeContext): string {\n const { activeCount, errorCount, totalCount, agents, defaultAgent } = ctx;\n\n const agentList = agents\n .map((a) => `${a}${a === defaultAgent ? \" (default)\" : \"\"}`)\n .join(\", \");\n\n // Variant 1: No sessions\n if (totalCount === 0) {\n return `👋 <b>OpenACP is ready!</b>\\n\\nNo sessions yet. Tap 🆕 New Session to start, or ask me anything!`;\n }\n\n // Variant 2: Has errors\n if (errorCount > 0) {\n return (\n `👋 <b>OpenACP is ready!</b>\\n\\n` +\n `📊 ${activeCount} active, ${errorCount} errors / ${totalCount} total\\n` +\n `⚠️ ${errorCount} session${errorCount > 1 ? \"s have\" : \" has\"} errors — ask me to check if you'd like.\\n\\n` +\n `Agents: ${agentList}`\n );\n }\n\n // Variant 3/4: Has active or fallback\n return (\n `👋 <b>OpenACP is ready!</b>\\n\\n` +\n `📊 ${activeCount} active / ${totalCount} total\\n` +\n `Agents: ${agentList}`\n );\n}\n\nexport function buildAssistantSystemPrompt(ctx: AssistantContext): string {\n const { config, activeSessionCount, totalSessionCount, topicSummary } = ctx;\n const agentNames = Object.keys(config.agents).join(\", \");\n const topicBreakdown =\n topicSummary.map((s) => `${s.status}: ${s.count}`).join(\", \") || \"none\";\n\n return `You are the OpenACP Assistant — a helpful guide for managing AI coding sessions.\n\n## Current State\n- Active sessions: ${activeSessionCount} / ${totalSessionCount} total\n- Topics by status: ${topicBreakdown}\n- Available agents: ${agentNames}\n- Default agent: ${config.defaultAgent}\n- Workspace base directory: ${config.workspace.baseDir}\n\n## Action Playbook\n\n### Create Session\n- The workspace is the project directory where the agent will work (read, write, execute code). It is NOT the base directory — it should be a specific project folder like \\`~/code/my-project\\` or \\`${config.workspace.baseDir}/my-app\\`.\n- Ask which agent to use (if multiple are configured). Show available: ${agentNames}\n- Ask which project directory to use as workspace. Suggest \\`${config.workspace.baseDir}\\` as the base, but explain the user can provide any path.\n- Confirm before creating: show agent name + full workspace path.\n- Create via: \\`openacp api new <agent> <workspace>\\`\n\n### Check Status / List Sessions\n- Run \\`openacp api status\\` for active sessions overview\n- Run \\`openacp api topics\\` for full list with statuses\n- Format the output nicely for the user\n\n### Cancel Session\n- Run \\`openacp api status\\` to see what's active\n- If 1 active session → ask user to confirm → \\`openacp api cancel <id>\\`\n- If multiple → list them, ask user which one to cancel\n\n### Troubleshoot (Session Stuck, Errors)\n- Run \\`openacp api health\\` + \\`openacp api status\\` to diagnose\n- Small issue (stuck session) → suggest cancel + create new\n- Big issue (system-level) → suggest restart, ask for confirmation first\n\n### Cleanup Old Sessions\n- Run \\`openacp api topics --status finished,error\\` to see what can be cleaned\n- Report the count, ask user to confirm\n- Execute: \\`openacp api cleanup --status <statuses>\\`\n\n### Configuration\n- View: \\`openacp config\\` (or \\`openacp api config\\` — deprecated)\n- Update: \\`openacp config set <key> <value>\\`\n- When user asks about \"settings\" or \"config\", use \\`openacp config set\\` directly\n- When receiving a delegated request from the Settings menu, ask user for the new value, then apply with \\`openacp config set <path> <value>\\`\n\n### Restart / Update\n- Always ask for confirmation — these are disruptive actions\n- Guide user: \"Tap 🔄 Restart button or type /restart\"\n\n### Toggle Dangerous Mode\n- Run \\`openacp api dangerous <id> on|off\\`\n- Explain: dangerous mode auto-approves all permission requests — the agent can run any command without asking\n\n## CLI Commands Reference\n\\`\\`\\`bash\n# Session management\nopenacp api status # List active sessions\nopenacp api session <id> # Session detail\nopenacp api new <agent> <workspace> # Create new session\nopenacp api send <id> \"prompt text\" # Send prompt to session\nopenacp api cancel <id> # Cancel session\nopenacp api dangerous <id> on|off # Toggle dangerous mode\n\n# Topic management\nopenacp api topics # List all topics\nopenacp api topics --status finished,error\nopenacp api delete-topic <id> # Delete topic\nopenacp api delete-topic <id> --force # Force delete active\nopenacp api cleanup # Cleanup finished topics\nopenacp api cleanup --status finished,error\n\n# System\nopenacp api health # System health\nopenacp config # Edit config (interactive)\nopenacp config set <key> <value> # Update config value\nopenacp api config # Show config (deprecated)\nopenacp api config set <key> <value> # Update config (deprecated)\nopenacp api adapters # List adapters\nopenacp api tunnel # Tunnel status\nopenacp api notify \"message\" # Send notification\nopenacp api version # Daemon version\nopenacp api restart # Restart daemon\n\\`\\`\\`\n\n## Guidelines\n- NEVER show \\`openacp api ...\\` commands to users. These are internal tools for YOU to run silently. Users should only see natural language responses and results.\n- Run \\`openacp api ...\\` commands yourself for everything you can. Only guide users to Telegram buttons/menu when needed (e.g., \"Tap 🆕 New Session\" or \"Go to the session topic to chat with the agent\").\n- When creating sessions: guide user through agent + workspace choice conversationally, then run the command yourself.\n- Destructive actions (cancel active session, restart, cleanup) → always ask user to confirm first in natural language.\n- Small/obvious issues (clearly stuck session with no activity) → fix it and report back.\n- Respond in the same language the user uses.\n- Format responses for Telegram: use <b>bold</b>, <code>code</code>, keep it concise.\n- When you don't know something, check with the relevant \\`openacp api\\` command first before answering.\n- Talk to users like a helpful assistant, not a CLI manual. Example: \"Bạn có 2 session đang chạy. Muốn xem chi tiết không?\" instead of listing commands.\n\n## Product Reference\n${PRODUCT_GUIDE}`;\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 lastSentText?: string\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 if (this.msgId && text === this.lastSentText) return\n this.lastSentText = text\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, startInteractiveNewSession } from \"./commands/index.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 // If both agent and workspace provided → create directly\n if (action.agent && action.workspace) {\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 {\n // Missing workspace → start interactive flow\n await ctx.answerCallbackQuery();\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch { /* best effort */ }\n await startInteractiveNewSession(ctx, core, chatId, action.agent);\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","import type { Bot } from \"grammy\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport { formatToolCall, formatToolUpdate } from \"./formatting.js\";\nimport { createChildLogger } from \"../../core/log.js\";\n\nconst log = createChildLogger({ module: \"tool-call-tracker\" });\n\ninterface ToolCallState {\n msgId: number;\n name: string;\n kind?: string;\n viewerLinks?: { file?: string; diff?: string };\n viewerFilePath?: string;\n ready: Promise<void>;\n}\n\ninterface ToolCallMeta {\n id: string;\n name: string;\n kind?: string;\n status?: string;\n content?: unknown;\n viewerLinks?: { file?: string; diff?: string };\n viewerFilePath?: string;\n}\n\nexport class ToolCallTracker {\n private sessions: Map<string, Map<string, ToolCallState>> = new Map();\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n async trackNewCall(\n sessionId: string,\n threadId: number,\n meta: ToolCallMeta,\n ): Promise<void> {\n if (!this.sessions.has(sessionId)) {\n this.sessions.set(sessionId, new Map());\n }\n\n let resolveReady!: () => void;\n const ready = new Promise<void>((r) => {\n resolveReady = r;\n });\n\n this.sessions.get(sessionId)!.set(meta.id, {\n msgId: 0,\n name: meta.name,\n kind: meta.kind,\n viewerLinks: meta.viewerLinks,\n viewerFilePath: meta.viewerFilePath,\n ready,\n });\n\n const msg = await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.chatId,\n formatToolCall(meta),\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n\n const toolEntry = this.sessions.get(sessionId)!.get(meta.id)!;\n toolEntry.msgId = msg!.message_id;\n resolveReady();\n }\n\n async updateCall(\n sessionId: string,\n meta: ToolCallMeta & { status: string },\n ): Promise<void> {\n const toolState = this.sessions.get(sessionId)?.get(meta.id);\n if (!toolState) return;\n\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 if (meta.viewerFilePath) toolState.viewerFilePath = meta.viewerFilePath;\n if (meta.name) toolState.name = meta.name;\n if (meta.kind) toolState.kind = meta.kind;\n\n // Only edit on terminal status — minimizes API calls to avoid rate limits\n const isTerminal = meta.status === \"completed\" || meta.status === \"failed\";\n if (!isTerminal) return;\n\n await toolState.ready;\n\n log.debug(\n {\n toolId: meta.id,\n status: meta.status,\n hasViewerLinks: !!toolState.viewerLinks,\n viewerLinks: toolState.viewerLinks,\n name: toolState.name,\n msgId: toolState.msgId,\n },\n \"Tool completed, preparing edit\",\n );\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\n try {\n await this.sendQueue.enqueue(() =>\n this.bot.api.editMessageText(\n this.chatId,\n toolState.msgId,\n formattedText,\n { parse_mode: \"HTML\" },\n ),\n );\n } catch (err) {\n log.warn(\n {\n err,\n msgId: toolState.msgId,\n textLen: formattedText.length,\n hasViewerLinks: !!merged.viewerLinks,\n },\n \"Tool update edit failed\",\n );\n }\n }\n\n cleanup(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\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 private displayTruncated = false\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 // CRITICAL: Snapshot the buffer BEFORE any await.\n // append() can be called synchronously while we're awaiting sendQueue,\n // so this.buffer may change. We must track what was ACTUALLY sent.\n const snapshot = this.buffer\n\n let html = markdownToTelegramHtml(snapshot)\n if (!html) return\n let truncated = false\n if (html.length > 4096) {\n // Estimate markdown cut point proportionally, then find a line boundary\n const ratio = 4000 / html.length\n const targetLen = Math.floor(snapshot.length * ratio)\n let cutAt = snapshot.lastIndexOf('\\n', targetLen)\n if (cutAt < targetLen * 0.5) cutAt = targetLen\n html = markdownToTelegramHtml(snapshot.slice(0, cutAt) + '\\n…')\n truncated = true\n if (html.length > 4096) {\n html = html.slice(0, 4090) + '\\n…'\n }\n }\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, html, {\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 if (!truncated) {\n this.lastSentBuffer = snapshot\n this.displayTruncated = false\n } else {\n this.displayTruncated = true\n }\n }\n } catch {\n // sendMessage failed — next flush will retry\n } finally {\n this.firstFlushPending = false\n }\n } else {\n try {\n const result = await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, html, {\n parse_mode: 'HTML',\n }),\n { type: 'text', key: this.sessionId },\n )\n // Only mark as sent if the edit was actually executed (not dropped by dedup/rate-limit)\n if (result !== undefined) {\n if (!truncated) {\n this.lastSentBuffer = snapshot\n this.displayTruncated = false\n } else {\n this.displayTruncated = true\n }\n }\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 fully sent by flush() and nothing new was appended.\n // Do NOT skip if flush() truncated the display — finalize must send the full content.\n if (this.messageId && this.buffer === this.lastSentBuffer && !this.displayTruncated) {\n return this.messageId\n }\n\n // Try sending full buffer as a single message first (most common case).\n // Only split if HTML exceeds Telegram's 4096 char limit.\n const fullHtml = markdownToTelegramHtml(this.buffer)\n if (fullHtml.length <= 4096) {\n try {\n if (this.messageId) {\n await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, fullHtml, {\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, fullHtml, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n { type: 'other' },\n )\n if (msg) this.messageId = msg.message_id\n }\n return this.messageId\n } catch {\n // HTML send failed — fall through to split/fallback below\n }\n }\n\n // HTML > 4096 or single send failed — split markdown, convert each chunk separately.\n // This prevents breaking HTML tags (e.g. <pre><code>) at split boundaries.\n const mdChunks = splitMessage(this.buffer)\n\n for (let i = 0; i < mdChunks.length; i++) {\n const html = markdownToTelegramHtml(mdChunks[i])\n try {\n if (i === 0 && this.messageId) {\n await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, html, {\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, html, {\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 } catch {\n // HTML failed for this chunk — try plain text fallback\n try {\n if (i === 0 && this.messageId) {\n await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, mdChunks[i].slice(0, 4096)),\n { type: 'other' },\n )\n } else {\n const msg = await this.sendQueue.enqueue(\n () => this.bot.api.sendMessage(this.chatId, mdChunks[i].slice(0, 4096), {\n message_thread_id: this.threadId,\n disable_notification: true,\n }),\n { type: 'other' },\n )\n if (msg) {\n this.messageId = msg.message_id\n }\n }\n } catch {\n // Give up on this chunk\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\";\nimport { MessageDraft } from \"./streaming.js\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport {\n detectAction,\n storeAction,\n buildActionKeyboard,\n} from \"./action-detect.js\";\n\nexport class DraftManager {\n private drafts: Map<string, MessageDraft> = new Map();\n private textBuffers: Map<string, string> = new Map();\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n getOrCreate(sessionId: string, threadId: number): MessageDraft {\n let draft = this.drafts.get(sessionId);\n if (!draft) {\n draft = new MessageDraft(\n this.bot,\n this.chatId,\n threadId,\n this.sendQueue,\n sessionId,\n );\n this.drafts.set(sessionId, draft);\n }\n return draft;\n }\n\n hasDraft(sessionId: string): boolean {\n return this.drafts.has(sessionId);\n }\n\n appendText(sessionId: string, text: string): void {\n this.textBuffers.set(\n sessionId,\n (this.textBuffers.get(sessionId) ?? \"\") + text,\n );\n }\n\n /**\n * Finalize the current draft and return the message ID.\n * Optionally detects actions in assistant responses.\n */\n async finalize(\n sessionId: string,\n assistantSessionId?: string,\n ): Promise<void> {\n const draft = this.drafts.get(sessionId);\n if (!draft) return;\n\n // Delete BEFORE awaiting to prevent concurrent finalizeDraft() calls\n // from double-finalizing the same draft\n this.drafts.delete(sessionId);\n const finalMsgId = await draft.finalize();\n\n // Detect actions in assistant responses and attach keyboard\n if (assistantSessionId && sessionId === assistantSessionId) {\n const fullText = this.textBuffers.get(sessionId);\n this.textBuffers.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.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.textBuffers.delete(sessionId);\n }\n }\n\n cleanup(sessionId: string): void {\n this.drafts.delete(sessionId);\n this.textBuffers.delete(sessionId);\n }\n}\n","import type { Bot } from \"grammy\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport type { AgentCommand } from \"../../core/types.js\";\nimport type { SessionManager } from \"../../core/session-manager.js\";\nimport type { TelegramPlatformData } from \"../../core/types.js\";\nimport { buildSkillMessages } from \"./commands/index.js\";\nimport { createChildLogger } from \"../../core/log.js\";\n\nconst log = createChildLogger({ module: \"skill-commands\" });\n\nexport class SkillCommandManager {\n private messages: Map<string, number> = new Map(); // sessionId → pinned msgId\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private sendQueue: TelegramSendQueue,\n private sessionManager: SessionManager,\n ) {}\n\n async send(\n sessionId: string,\n threadId: number,\n commands: AgentCommand[],\n ): Promise<void> {\n // Restore skillMsgIds from persisted platform data if not in memory\n if (!this.messages.has(sessionId)) {\n const record = this.sessionManager.getSessionRecord(sessionId);\n const platform = record?.platform as TelegramPlatformData | undefined;\n if (platform?.skillMsgId) {\n this.messages.set(sessionId, platform.skillMsgId);\n }\n }\n\n // Empty commands → remove pinned message\n if (commands.length === 0) {\n await this.cleanup(sessionId);\n return;\n }\n\n const messages = buildSkillMessages(commands);\n const existingMsgId = this.messages.get(sessionId);\n\n if (existingMsgId) {\n try {\n await this.bot.api.editMessageText(\n this.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\")) return;\n try {\n await this.bot.api.deleteMessage(this.chatId, existingMsgId);\n } catch { /* already gone */ }\n this.messages.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(this.chatId, text, {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n if (!firstMsgId) firstMsgId = msg!.message_id;\n }\n\n this.messages.set(sessionId, firstMsgId!);\n\n // Persist skillMsgId so it survives restarts\n const record = this.sessionManager.getSessionRecord(sessionId);\n if (record) {\n await this.sessionManager.patchRecord(sessionId, {\n platform: { ...record.platform, skillMsgId: firstMsgId },\n });\n }\n\n await this.bot.api.pinChatMessage(this.chatId, firstMsgId!, {\n disable_notification: true,\n });\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to send skill commands\");\n }\n }\n\n async cleanup(sessionId: string): Promise<void> {\n const msgId = this.messages.get(sessionId);\n if (!msgId) return;\n\n try {\n await this.bot.api.editMessageText(\n this.chatId,\n msgId,\n \"🛠 <i>Session ended</i>\",\n { parse_mode: \"HTML\" },\n );\n await this.bot.api.unpinChatMessage(this.chatId, msgId);\n } catch { /* message may already be deleted */ }\n\n this.messages.delete(sessionId);\n\n // Clear persisted skillMsgId\n const record = this.sessionManager.getSessionRecord(sessionId);\n if (record) {\n const { skillMsgId: _removed, ...rest } = record.platform as unknown as TelegramPlatformData;\n await this.sessionManager.patchRecord(sessionId, { platform: rest });\n }\n }\n}\n"],"mappings":"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","names":["resolve","resolve","resolve","resolve","log","log","id","path","fs","path","log","path","fs","log","path","setLogLevel","fs","path","os","log","resolve","getSafeFields","resolveOptions","getConfigValue","isHotReloadable","log","InlineKeyboard","log","toastText","log","InlineKeyboard","InlineKeyboard","log","InlineKeyboard","InlineKeyboard","InlineKeyboard","keyboard","agentName","getIntegration","integration","InlineKeyboard","log","InlineKeyboard","buildMenuKeyboard","InlineKeyboard","log","escapeHtml","InlineKeyboard","InlineKeyboard","nanoid","log","nanoid","InlineKeyboard","log","log","resolve","nanoid","InlineKeyboard","nanoid","InlineKeyboard","log","log","log","getAgentCapabilities"]}